2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								/*
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Asterisk  - -  An  open  source  telephony  toolkit . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Copyright  ( C )  2013 ,  Digium ,  Inc . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Joshua  Colp  < jcolp @ digium . com > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  See  http : //www.asterisk.org for more information about
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  the  Asterisk  project .  Please  do  not  directly  contact 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  any  of  the  maintainers  of  this  project  for  assistance ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  the  project  provides  a  web  site ,  mailing  lists  and  IRC 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  channels  for  your  use . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  This  program  is  free  software ,  distributed  under  the  terms  of 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  the  GNU  General  Public  License  Version  2.  See  the  LICENSE  file 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  at  the  top  of  the  source  tree . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*** MODULEINFO
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									< depend > pjproject < / depend > 
							 
						 
					
						
							
								
									
										
										
										
											2013-07-30 18:14:50 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									< depend > res_pjsip < / depend > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									< depend > res_pjsip_session < / depend > 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									< support_level > core < / support_level > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * * */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <pjsip.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <pjsip_ua.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-07-30 18:14:50 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "asterisk/res_pjsip.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/res_pjsip_session.h" 
  
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/module.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/pbx.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/taskprocessor.h" 
  
						 
					
						
							
								
									
										
										
										
											2013-07-25 04:06:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "asterisk/bridge.h" 
  
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/framehook.h" 
  
						 
					
						
							
								
									
										
										
										
											2013-08-28 21:09:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "asterisk/stasis_bridges.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/stasis_channels.h" 
  
						 
					
						
							
								
									
										
										
										
											2015-02-19 17:30:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "asterisk/causes.h" 
  
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief REFER Progress structure */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								struct  refer_progress  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief Subscription to provide updates on */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_evsub  * sub ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief Dialog for subscription */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_dialog  * dlg ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief Received packet, used to construct final response in case no subscription exists */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_rx_data  * rdata ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief Frame hook for monitoring REFER progress */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  framehook ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief Last received subclass in frame hook */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  subclass ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief Serializer for notifications */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_taskprocessor  * serializer ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-08-28 21:09:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/*! \brief Stasis subscription for bridge events */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  stasis_subscription  * bridge_sub ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-05-22 15:52:30 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/*! \brief Reference to transfer_channel_data related to the refer */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  transfer_channel_data  * transfer_data ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-08-28 21:09:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/*! \brief Uniqueid of transferee channel */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * transferee ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-03-01 18:08:52 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/*! \brief Non-zero if the 100 notify has been sent */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  sent_100 ; 
							 
						 
					
						
							
								
									
										
										
										
											2017-05-08 16:56:32 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/*! \brief Whether to notifies all the progress details on blind transfer */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  int  refer_blind_progress ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief REFER Progress notification structure */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								struct  refer_progress_notification  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief Refer progress structure to send notification on */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  refer_progress  * progress ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief SIP response code to send */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  response ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief Subscription state */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_evsub_state  state ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief REFER Progress module, used to attach REFER progress structure to subscriptions */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  pjsip_module  refer_progress_module  =  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. name  =  {  " REFER Progress " ,  14  } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. id  =  - 1 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Destructor for REFER Progress notification structure */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  refer_progress_notification_destroy ( void  * obj )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  refer_progress_notification  * notification  =  obj ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_cleanup ( notification - > progress ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Allocator for REFER Progress notification structure */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  struct  refer_progress_notification  * refer_progress_notification_alloc ( struct  refer_progress  * progress ,  int  response ,  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_evsub_state  state ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  refer_progress_notification  * notification  =  ao2_alloc ( sizeof ( * notification ) ,  refer_progress_notification_destroy ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! notification )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_ref ( progress ,  + 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									notification - > progress  =  progress ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									notification - > response  =  response ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									notification - > state  =  state ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  notification ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Serialized callback for subscription notification */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  refer_progress_notify ( void  * data )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									RAII_VAR ( struct  refer_progress_notification  * ,  notification ,  data ,  ao2_cleanup ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_evsub  * sub ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_tx_data  * tdata ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* If the subscription has already been terminated we can't send a notification */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! ( sub  =  notification - > progress - > sub ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-05-09 22:49:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " Not sending NOTIFY of response '%d' and state '%u' on progress monitor '%p' as subscription has been terminated \n " , 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											notification - > response ,  notification - > state ,  notification - > progress ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* If the subscription is being terminated we want to actually remove the progress structure here to
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  stop  a  deadlock  from  occurring  -  basically  terminated  changes  the  state  which  queues  a  synchronous  task 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  but  we  are  already  running  a  task . . .  thus  it  would  deadlock  */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( notification - > state  = =  PJSIP_EVSUB_STATE_TERMINATED )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " Subscription '%p' is being terminated as a result of a NOTIFY, removing REFER progress structure early on progress monitor '%p' \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											notification - > progress - > sub ,  notification - > progress ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pjsip_dlg_inc_lock ( notification - > progress - > dlg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pjsip_evsub_set_mod_data ( notification - > progress - > sub ,  refer_progress_module . id ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pjsip_dlg_dec_lock ( notification - > progress - > dlg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* This is for dropping the reference on the subscription */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_cleanup ( notification - > progress ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										notification - > progress - > sub  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-03-01 18:08:52 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/* Send a deferred initial 100 Trying SIP frag NOTIFY if we haven't already. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! notification - > progress - > sent_100 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										notification - > progress - > sent_100  =  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( notification - > response  ! =  100 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_debug ( 3 ,  " Sending initial 100 Trying NOTIFY for progress monitor '%p' \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												notification - > progress ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( pjsip_xfer_notify ( sub ,  PJSIP_EVSUB_STATE_ACTIVE ,  100 ,  NULL ,  & tdata )  = =  PJ_SUCCESS )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												pjsip_xfer_send_request ( sub ,  tdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-05-09 22:49:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_debug ( 3 ,  " Sending NOTIFY with response '%d' and state '%u' on subscription '%p' and progress monitor '%p' \n " , 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										notification - > response ,  notification - > state ,  sub ,  notification - > progress ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Actually send the notification */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( pjsip_xfer_notify ( sub ,  notification - > state ,  notification - > response ,  NULL ,  & tdata )  = =  PJ_SUCCESS )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pjsip_xfer_send_request ( sub ,  tdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-08-28 21:09:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  void  refer_progress_bridge ( void  * data ,  struct  stasis_subscription  * sub ,  
						 
					
						
							
								
									
										
											 
										
											
												Multiple revisions 399887,400138,400178,400180-400181
........
  r399887 | dlee | 2013-09-26 10:41:47 -0500 (Thu, 26 Sep 2013) | 1 line
  
  Minor performance bump by not allocate manager variable struct if we don't need it
........
  r400138 | dlee | 2013-09-30 10:24:00 -0500 (Mon, 30 Sep 2013) | 23 lines
  
  Stasis performance improvements
  
  This patch addresses several performance problems that were found in
  the initial performance testing of Asterisk 12.
  
  The Stasis dispatch object was allocated as an AO2 object, even though
  it has a very confined lifecycle. This was replaced with a straight
  ast_malloc().
  
  The Stasis message router was spending an inordinate amount of time
  searching hash tables. In this case, most of our routers had 6 or
  fewer routes in them to begin with. This was replaced with an array
  that's searched linearly for the route.
  
  We more heavily rely on AO2 objects in Asterisk 12, and the memset()
  in ao2_ref() actually became noticeable on the profile. This was
  #ifdef'ed to only run when AO2_DEBUG was enabled.
  
  After being misled by an erroneous comment in taskprocessor.c during
  profiling, the wrong comment was removed.
  
  Review: https://reviewboard.asterisk.org/r/2873/
........
  r400178 | dlee | 2013-09-30 13:26:27 -0500 (Mon, 30 Sep 2013) | 24 lines
  
  Taskprocessor optimization; switch Stasis to use taskprocessors
  
  This patch optimizes taskprocessor to use a semaphore for signaling,
  which the OS can do a better job at managing contention and waiting
  that we can with a mutex and condition.
  
  The taskprocessor execution was also slightly optimized to reduce the
  number of locks taken.
  
  The only observable difference in the taskprocessor implementation is
  that when the final reference to the taskprocessor goes away, it will
  execute all tasks to completion instead of discarding the unexecuted
  tasks.
  
  For systems where unnamed semaphores are not supported, a really
  simple semaphore implementation is provided. (Which gives identical
  performance as the original taskprocessor implementation).
  
  The way we ended up implementing Stasis caused the threadpool to be a
  burden instead of a boost to performance. This was switched to just
  use taskprocessors directly for subscriptions.
  
  Review: https://reviewboard.asterisk.org/r/2881/
........
  r400180 | dlee | 2013-09-30 13:39:34 -0500 (Mon, 30 Sep 2013) | 28 lines
  
  Optimize how Stasis forwards are dispatched
  
  This patch optimizes how forwards are dispatched in Stasis.
  
  Originally, forwards were dispatched as subscriptions that are invoked
  on the publishing thread. This did not account for the vast number of
  forwards we would end up having in the system, and the amount of work it
  would take to walk though the forward subscriptions.
  
  This patch modifies Stasis so that rather than walking the tree of
  forwards on every dispatch, when forwards and subscriptions are changed,
  the subscriber list for every topic in the tree is changed.
  
  This has a couple of benefits. First, this reduces the workload of
  dispatching messages. It also reduces contention when dispatching to
  different topics that happen to forward to the same aggregation topic
  (as happens with all of the channel, bridge and endpoint topics).
  
  Since forwards are no longer subscriptions, the bulk of this patch is
  simply changing stasis_subscription objects to stasis_forward objects
  (which, admittedly, I should have done in the first place.)
  
  Since this required me to yet again put in a growing array, I finally
  abstracted that out into a set of ast_vector macros in
  asterisk/vector.h.
  
  Review: https://reviewboard.asterisk.org/r/2883/
........
  r400181 | dlee | 2013-09-30 13:48:57 -0500 (Mon, 30 Sep 2013) | 28 lines
  
  Remove dispatch object allocation from Stasis publishing
  
  While looking for areas for performance improvement, I realized that an
  unused feature in Stasis was negatively impacting performance.
  
  When a message is sent to a subscriber, a dispatch object is allocated
  for the dispatch, containing the topic the message was published to, the
  subscriber the message is being sent to, and the message itself.
  
  The topic is actually unused by any subscriber in Asterisk today. And
  the subscriber is associated with the taskprocessor the message is being
  dispatched to.
  
  First, this patch removes the unused topic parameter from Stasis
  subscription callbacks.
  
  Second, this patch introduces the concept of taskprocessor local data,
  data that may be set on a taskprocessor and provided along with the data
  pointer when a task is pushed using the ast_taskprocessor_push_local()
  call. This allows the task to have both data specific to that
  taskprocessor, in addition to data specific to that invocation.
  
  With those two changes, the dispatch object can be removed completely,
  and the message is simply refcounted and sent directly to the
  taskprocessor.
  
  Review: https://reviewboard.asterisk.org/r/2884/
........
Merged revisions 399887,400138,400178,400180-400181 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@400186 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2013-09-30 18:55:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										struct  stasis_message  * message ) 
							 
						 
					
						
							
								
									
										
										
										
											2013-08-28 21:09:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  refer_progress  * progress  =  data ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_bridge_blob  * enter_blob ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  refer_progress_notification  * notification ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-12-02 12:20:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  ast_channel  * chan ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-08-28 21:09:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( stasis_subscription_final_message ( sub ,  message ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_ref ( progress ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ast_channel_entered_bridge_type ( )  ! =  stasis_message_type ( message ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* Don't care */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									enter_blob  =  stasis_message_data ( message ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( strcmp ( enter_blob - > channel - > uniqueid ,  progress - > transferee ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* Don't care */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-05-22 15:52:30 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ! progress - > transfer_data - > completed )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* We can't act on this message because the transfer_channel_data doesn't show that
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *  the  transfer  is  ready  to  progress  */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-08-28 21:09:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/* OMG the transferee is joining a bridge. His call got answered! */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									notification  =  refer_progress_notification_alloc ( progress ,  200 ,  PJSIP_EVSUB_STATE_TERMINATED ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( notification )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ast_sip_push_task ( progress - > serializer ,  refer_progress_notify ,  notification ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ao2_cleanup ( notification ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										progress - > bridge_sub  =  stasis_unsubscribe ( progress - > bridge_sub ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-12-02 12:20:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									chan  =  ast_channel_get_by_name ( progress - > transferee ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! chan )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* The channel is already gone */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_channel_lock ( chan ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_debug ( 3 ,  " Detaching REFER progress monitoring hook from '%s' as it has joined a bridge \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_channel_name ( chan ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_framehook_detach ( chan ,  progress - > framehook ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_channel_unlock ( chan ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_channel_unref ( chan ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-08-28 21:09:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								/*! \brief Progress monitoring frame hook - examines frames to determine state of transfer */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  struct  ast_frame  * refer_progress_framehook ( struct  ast_channel  * chan ,  struct  ast_frame  * f ,  enum  ast_framehook_event  event ,  void  * data )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  refer_progress  * progress  =  data ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  refer_progress_notification  * notification  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* We only care about frames *to* the channel */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! f  | |  ( event  ! =  AST_FRAMEHOOK_EVENT_WRITE ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  f ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-05-22 15:52:30 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/* If the completed flag hasn't been raised, skip this pass. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! progress - > transfer_data - > completed )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  f ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									/* Determine the state of the REFER based on the control frames (or voice frames) passing */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( f - > frametype  = =  AST_FRAME_VOICE  & &  ! progress - > subclass )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* Media is passing without progress, this means the call has been answered */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										notification  =  refer_progress_notification_alloc ( progress ,  200 ,  PJSIP_EVSUB_STATE_TERMINATED ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  if  ( f - > frametype  = =  AST_FRAME_CONTROL )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* Based on the control frame being written we can send a NOTIFY advising of the progress */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ( f - > subclass . integer  = =  AST_CONTROL_RING )  | |  ( f - > subclass . integer  = =  AST_CONTROL_RINGING ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2013-12-20 20:28:19 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											progress - > subclass  =  f - > subclass . integer ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											notification  =  refer_progress_notification_alloc ( progress ,  180 ,  PJSIP_EVSUB_STATE_ACTIVE ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  if  ( f - > subclass . integer  = =  AST_CONTROL_BUSY )  { 
							 
						 
					
						
							
								
									
										
										
										
											2013-12-20 20:28:19 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											progress - > subclass  =  f - > subclass . integer ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											notification  =  refer_progress_notification_alloc ( progress ,  486 ,  PJSIP_EVSUB_STATE_TERMINATED ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  if  ( f - > subclass . integer  = =  AST_CONTROL_CONGESTION )  { 
							 
						 
					
						
							
								
									
										
										
										
											2013-12-20 20:28:19 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											progress - > subclass  =  f - > subclass . integer ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											notification  =  refer_progress_notification_alloc ( progress ,  503 ,  PJSIP_EVSUB_STATE_TERMINATED ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  if  ( f - > subclass . integer  = =  AST_CONTROL_PROGRESS )  { 
							 
						 
					
						
							
								
									
										
										
										
											2013-12-20 20:28:19 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											progress - > subclass  =  f - > subclass . integer ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											notification  =  refer_progress_notification_alloc ( progress ,  183 ,  PJSIP_EVSUB_STATE_ACTIVE ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  if  ( f - > subclass . integer  = =  AST_CONTROL_PROCEEDING )  { 
							 
						 
					
						
							
								
									
										
										
										
											2013-12-20 20:28:19 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											progress - > subclass  =  f - > subclass . integer ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											notification  =  refer_progress_notification_alloc ( progress ,  100 ,  PJSIP_EVSUB_STATE_ACTIVE ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  if  ( f - > subclass . integer  = =  AST_CONTROL_ANSWER )  { 
							 
						 
					
						
							
								
									
										
										
										
											2013-12-20 20:28:19 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											progress - > subclass  =  f - > subclass . integer ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											notification  =  refer_progress_notification_alloc ( progress ,  200 ,  PJSIP_EVSUB_STATE_TERMINATED ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* If a notification is due to be sent push it to the thread pool */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( notification )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* If the subscription is being terminated we don't need the frame hook any longer */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( notification - > state  = =  PJSIP_EVSUB_STATE_TERMINATED )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_debug ( 3 ,  " Detaching REFER progress monitoring hook from '%s' as subscription is being terminated \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_channel_name ( chan ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_framehook_detach ( chan ,  progress - > framehook ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2015-01-30 16:47:50 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ast_sip_push_task ( progress - > serializer ,  refer_progress_notify ,  notification ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ao2_cleanup ( notification ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  f ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Destroy callback for monitoring framehook */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  refer_progress_framehook_destroy ( void  * data )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  refer_progress  * progress  =  data ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  refer_progress_notification  * notification  =  refer_progress_notification_alloc ( progress ,  503 ,  PJSIP_EVSUB_STATE_TERMINATED ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( notification  & &  ast_sip_push_task ( progress - > serializer ,  refer_progress_notify ,  notification ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_cleanup ( notification ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-05-22 15:52:30 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( progress - > bridge_sub )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										progress - > bridge_sub  =  stasis_unsubscribe ( progress - > bridge_sub ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									ao2_cleanup ( progress ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Serialized callback for subscription termination */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  refer_progress_terminate ( void  * data )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  refer_progress  * progress  =  data ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* The subscription is no longer valid */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									progress - > sub  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Callback for REFER subscription state changes */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  refer_progress_on_evsub_state ( pjsip_evsub  * sub ,  pjsip_event  * event )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  refer_progress  * progress  =  pjsip_evsub_get_mod_data ( sub ,  refer_progress_module . id ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* If being destroyed queue it up to the serializer */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( progress  & &  ( pjsip_evsub_get_state ( sub )  = =  PJSIP_EVSUB_STATE_TERMINATED ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* To prevent a deadlock race condition we unlock the dialog so other serialized tasks can execute */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " Subscription '%p' has been remotely terminated, waiting for other tasks to complete on progress monitor '%p' \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											sub ,  progress ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* It's possible that a task is waiting to remove us already, so bump the refcount of progress so it doesn't get destroyed */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_ref ( progress ,  + 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pjsip_dlg_dec_lock ( progress - > dlg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_sip_push_task_synchronous ( progress - > serializer ,  refer_progress_terminate ,  progress ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pjsip_dlg_inc_lock ( progress - > dlg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_ref ( progress ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " Subscription '%p' removed from progress monitor '%p' \n " ,  sub ,  progress ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* Since it was unlocked it is possible for this to have been removed already, so check again */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( pjsip_evsub_get_mod_data ( sub ,  refer_progress_module . id ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											pjsip_evsub_set_mod_data ( sub ,  refer_progress_module . id ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ao2_cleanup ( progress ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Callback structure for subscription */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  pjsip_evsub_user  refer_progress_evsub_cb  =  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. on_evsub_state  =  refer_progress_on_evsub_state , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Destructor for REFER progress sutrcture */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  refer_progress_destroy ( void  * obj )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  refer_progress  * progress  =  obj ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-08-28 21:09:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( progress - > bridge_sub )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										progress - > bridge_sub  =  stasis_unsubscribe ( progress - > bridge_sub ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-05-22 15:52:30 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_cleanup ( progress - > transfer_data ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-08-28 21:09:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_free ( progress - > transferee ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									ast_taskprocessor_unreference ( progress - > serializer ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Internal helper function which sets up a refer progress structure if needed */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  refer_progress_alloc ( struct  ast_sip_session  * session ,  pjsip_rx_data  * rdata ,  struct  refer_progress  * * progress )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									const  pj_str_t  str_refer_sub  =  {  " Refer-Sub " ,  9  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_generic_string_hdr  * refer_sub  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									const  pj_str_t  str_true  =  {  " true " ,  4  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_hdr  hdr_list ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-01-06 19:10:16 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									char  tps_name [ AST_TASKPROCESSOR_MAX_NAME  +  1 ] ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									* progress  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Grab the optional Refer-Sub header, it can be used to suppress the implicit subscription */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									refer_sub  =  pjsip_msg_find_hdr_by_name ( rdata - > msg_info . msg ,  & str_refer_sub ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ( refer_sub  & &  pj_strnicmp ( & refer_sub - > hvalue ,  & str_true ,  4 ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! ( * progress  =  ao2_alloc ( sizeof ( struct  refer_progress ) ,  refer_progress_destroy ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_debug ( 3 ,  " Created progress monitor '%p' for transfer occurring from channel '%s' and endpoint '%s' \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										progress ,  ast_channel_name ( session - > channel ) ,  ast_sorcery_object_get_id ( session - > endpoint ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-05-08 16:56:32 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									( * progress ) - > refer_blind_progress  =  session - > endpoint - > refer_blind_progress ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									( * progress ) - > framehook  =  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* To prevent a potential deadlock we need the dialog so we can lock/unlock */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									( * progress ) - > dlg  =  session - > inv_session - > dlg ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-01-06 19:10:16 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/* Create name with seq number appended. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_taskprocessor_build_name ( tps_name ,  sizeof ( tps_name ) ,  " pjsip/refer/%s " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_sorcery_object_get_id ( session - > endpoint ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! ( ( * progress ) - > serializer  =  ast_sip_create_serializer_named ( tps_name ) ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										goto  error ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Create the implicit subscription for monitoring of this transfer */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( pjsip_xfer_create_uas ( session - > inv_session - > dlg ,  & refer_progress_evsub_cb ,  rdata ,  & ( * progress ) - > sub )  ! =  PJ_SUCCESS )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										goto  error ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Associate the REFER progress structure with the subscription */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_ref ( * progress ,  + 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_evsub_set_mod_data ( ( * progress ) - > sub ,  refer_progress_module . id ,  * progress ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pj_list_init ( & hdr_list ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( refer_sub )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pjsip_hdr  * hdr  =  ( pjsip_hdr * ) pjsip_generic_string_hdr_create ( session - > inv_session - > dlg - > pool ,  & str_refer_sub ,  & str_true ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pj_list_push_back ( & hdr_list ,  hdr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Accept the REFER request */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_debug ( 3 ,  " Accepting REFER request for progress monitor '%p' \n " ,  * progress ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_xfer_accept ( ( * progress ) - > sub ,  rdata ,  202 ,  & hdr_list ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								error :  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_cleanup ( * progress ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									* progress  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Structure for attended transfer task */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								struct  refer_attended  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief Transferer session */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_sip_session  * transferer ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief Transferer channel */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_channel  * transferer_chan ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief Second transferer session */ 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-06 22:12:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  ast_sip_session  * transferer_second ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									/*! \brief Optional refer progress structure */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  refer_progress  * progress ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Destructor for attended transfer task */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  refer_attended_destroy ( void  * obj )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  refer_attended  * attended  =  obj ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_cleanup ( attended - > transferer ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-17 15:31:46 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_channel_cleanup ( attended - > transferer_chan ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									ao2_cleanup ( attended - > transferer_second ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-01-30 16:47:50 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_cleanup ( attended - > progress ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Allocator for attended transfer task */  
						 
					
						
							
								
									
										
										
										
											2015-03-06 22:12:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  struct  refer_attended  * refer_attended_alloc ( struct  ast_sip_session  * transferer ,  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_sip_session  * transferer_second , 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									struct  refer_progress  * progress ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2015-03-06 22:12:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  refer_attended  * attended ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-06 22:12:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									attended  =  ao2_alloc_options ( sizeof ( * attended ) ,  refer_attended_destroy , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										AO2_ALLOC_OPT_LOCK_NOLOCK ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  ( ! attended )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_ref ( transferer ,  + 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									attended - > transferer  =  transferer ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_channel_ref ( transferer - > channel ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									attended - > transferer_chan  =  transferer - > channel ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_ref ( transferer_second ,  + 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									attended - > transferer_second  =  transferer_second ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( progress )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_ref ( progress ,  + 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										attended - > progress  =  progress ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  attended ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  int  defer_termination_cancel ( void  * data )  
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  ast_sip_session  * session  =  data ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_sip_session_defer_termination_cancel ( session ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_ref ( session ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2014-02-26 13:45:12 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/*!
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ internal 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ brief  Convert  transfer  enum  to  SIP  response  code . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ since  13.3 .0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ param  xfer_code  Core  transfer  function  enum  result . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ return  SIP  response  code 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  xfer_response_code2sip ( enum  ast_transfer_result  xfer_code )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  response ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									response  =  503 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									switch  ( xfer_code )  { 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									case  AST_BRIDGE_TRANSFER_INVALID : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										response  =  400 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  AST_BRIDGE_TRANSFER_NOT_PERMITTED : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										response  =  403 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  AST_BRIDGE_TRANSFER_FAIL : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										response  =  500 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  AST_BRIDGE_TRANSFER_SUCCESS : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										response  =  200 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  response ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Task for attended transfer executed by attended->transferer_second serializer */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  refer_attended_task ( void  * data )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  refer_attended  * attended  =  data ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  response ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( attended - > transferer_second - > channel )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " Performing a REFER attended transfer - Transferer #1: %s Transferer #2: %s \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_channel_name ( attended - > transferer_chan ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_channel_name ( attended - > transferer_second - > channel ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										response  =  xfer_response_code2sip ( ast_bridge_transfer_attended ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											attended - > transferer_chan , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											attended - > transferer_second - > channel ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " Final response for REFER attended transfer - Transferer #1: %s Transferer #2: %s is '%d' \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_channel_name ( attended - > transferer_chan ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_channel_name ( attended - > transferer_second - > channel ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											response ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " Received REFER request on channel '%s' but other channel has gone. \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_channel_name ( attended - > transferer_chan ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										response  =  603 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( attended - > progress )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										struct  refer_progress_notification  * notification ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										notification  =  refer_progress_notification_alloc ( attended - > progress ,  response , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											PJSIP_EVSUB_STATE_TERMINATED ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										if  ( notification )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											refer_progress_notify ( notification ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-06-13 14:17:29 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_sip_session_end_if_deferred ( attended - > transferer ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( response  ! =  200 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! ast_sip_push_task ( attended - > transferer - > serializer , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											defer_termination_cancel ,  attended - > transferer ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											/* Gave the ref to the pushed task. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											attended - > transferer  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_ref ( attended ,  - 1 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Structure for blind transfer callback details */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								struct  refer_blind  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief Context being used for transfer */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									const  char  * context ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief Optional progress structure */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  refer_progress  * progress ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief REFER message */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_rx_data  * rdata ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief Optional Replaces header */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_replaces_hdr  * replaces ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief Optional Refer-To header */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_sip_uri  * refer_to ; 
							 
						 
					
						
							
								
									
										
										
										
											2017-05-08 16:56:32 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/*! \brief Attended transfer flag */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  int  attended : 1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Blind transfer callback function */  
						 
					
						
							
								
									
										
										
										
											2014-05-22 15:52:30 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  void  refer_blind_callback ( struct  ast_channel  * chan ,  struct  transfer_channel_data  * user_data_wrapper ,  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									enum  ast_transfer_type  transfer_type ) 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2014-05-22 15:52:30 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  refer_blind  * refer  =  user_data_wrapper - > data ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-05-02 16:39:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									pjsip_generic_string_hdr  * referred_by ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									static  const  pj_str_t  str_referred_by  =  {  " Referred-By " ,  11  } ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-12-31 18:56:09 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									static  const  pj_str_t  str_referred_by_s  =  {  " b " ,  1  } ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pbx_builtin_setvar_helper ( chan ,  " SIPTRANSFER " ,  " yes " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-05-08 16:56:32 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( refer - > progress  & &  ! refer - > attended  & &  ! refer - > progress - > refer_blind_progress )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* If blind transfer and endpoint doesn't want to receive all the progress details */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										struct  refer_progress_notification  * notification  =  refer_progress_notification_alloc ( refer - > progress ,  200 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											PJSIP_EVSUB_STATE_TERMINATED ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( notification )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											refer_progress_notify ( notification ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  if  ( refer - > progress )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* If attended transfer and progress monitoring is being done attach a frame hook so we can monitor it */ 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										struct  ast_framehook_interface  hook  =  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											. version  =  AST_FRAMEHOOK_INTERFACE_VERSION , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											. event_cb  =  refer_progress_framehook , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											. destroy_cb  =  refer_progress_framehook_destroy , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											. data  =  refer - > progress , 
							 
						 
					
						
							
								
									
										
										
										
											2014-07-18 16:28:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											. disable_inheritance  =  1 , 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-08-28 21:09:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										refer - > progress - > transferee  =  ast_strdup ( ast_channel_uniqueid ( chan ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! refer - > progress - > transferee )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											struct  refer_progress_notification  * notification  =  refer_progress_notification_alloc ( refer - > progress ,  200 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												PJSIP_EVSUB_STATE_TERMINATED ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_WARNING ,  " Could not copy channel name '%s' during transfer - assuming success \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_channel_name ( chan ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( notification )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												refer_progress_notify ( notification ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-05-22 15:52:30 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										/* Progress needs a reference to the transfer_channel_data so that it can track the completed status of the transfer */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_ref ( user_data_wrapper ,  + 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										refer - > progress - > transfer_data  =  user_data_wrapper ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										/* We need to bump the reference count up on the progress structure since it is in the frame hook now */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_ref ( refer - > progress ,  + 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* If we can't attach a frame hook for whatever reason send a notification of success immediately */ 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-22 15:01:37 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_channel_lock ( chan ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										refer - > progress - > framehook  =  ast_framehook_attach ( chan ,  & hook ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_channel_unlock ( chan ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( refer - > progress - > framehook  <  0 )  { 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											struct  refer_progress_notification  * notification  =  refer_progress_notification_alloc ( refer - > progress ,  200 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												PJSIP_EVSUB_STATE_TERMINATED ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_WARNING ,  " Could not attach REFER transfer progress monitoring hook to channel '%s' - assuming success \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_channel_name ( chan ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( notification )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												refer_progress_notify ( notification ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ao2_cleanup ( refer - > progress ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2013-08-28 21:09:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* We need to bump the reference count for the stasis subscription */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_ref ( refer - > progress ,  + 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* We also will need to detect if the transferee enters a bridge. This is currently the only reliable way to
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *  detect  if  the  transfer  target  has  answered  the  call 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 */ 
							 
						 
					
						
							
								
									
										
											 
										
											
												main/stasis: Allow subscriptions to use a threadpool for message delivery
Prior to this patch, all Stasis subscriptions would receive a dedicated
thread for servicing published messages. In contrast, prior to r400178
(see review https://reviewboard.asterisk.org/r/2881/), the subscriptions
shared a thread pool. It was discovered during some initial work on Stasis
that, for a low subscription count with high message throughput, the
threadpool was not as performant as simply having a dedicated thread per
subscriber.
For situations where a subscriber receives a substantial number of messages
and is always present, the model of having a dedicated thread per subscriber
makes sense. While we still have plenty of subscriptions that would follow
this model, e.g., AMI, CDRs, CEL, etc., there are plenty that also fall into
the following two categories:
* Large number of subscriptions, specifically those tied to endpoints/peers.
* Low number of messages. Some subscriptions exist specifically to coordinate
  a single message - the subscription is created, a message is published, the
  delivery is synchronized, and the subscription is destroyed.
In both of the latter two cases, creating a dedicated thread is wasteful (and
in the case of a large number of peers/endpoints, harmful). In those cases,
having shared delivery threads is far more performant.
This patch adds the ability of a subscriber to Stasis to choose whether or not
their messages are dispatched on a dedicated thread or on a threadpool. The
threadpool is configurable through stasis.conf.
Review: https://reviewboard.asterisk.org/r/4193
ASTERISK-24533 #close
Reported by: xrobau
Tested by: xrobau
........
Merged revisions 428681 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/13@428687 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2014-12-01 17:57:12 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										refer - > progress - > bridge_sub  =  stasis_subscribe_pool ( ast_bridge_topic_all ( ) ,  refer_progress_bridge ,  refer - > progress ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-08-28 21:09:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( ! refer - > progress - > bridge_sub )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											struct  refer_progress_notification  * notification  =  refer_progress_notification_alloc ( refer - > progress ,  200 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												PJSIP_EVSUB_STATE_TERMINATED ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_WARNING ,  " Could not create bridge stasis subscription for monitoring progress on transfer of channel '%s' - assuming success \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													ast_channel_name ( chan ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( notification )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												refer_progress_notify ( notification ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-08-23 10:42:08 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_channel_lock ( chan ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-08-28 21:09:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_framehook_detach ( chan ,  refer - > progress - > framehook ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-23 10:42:08 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_channel_unlock ( chan ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-08-28 21:09:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ao2_cleanup ( refer - > progress ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-05-02 16:39:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									pbx_builtin_setvar_helper ( chan ,  " SIPREFERRINGCONTEXT " ,  S_OR ( refer - > context ,  NULL ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-12-31 18:56:09 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									referred_by  =  pjsip_msg_find_hdr_by_names ( refer - > rdata - > msg_info . msg , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										& str_referred_by ,  & str_referred_by_s ,  NULL ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  ( referred_by )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-05-02 16:39:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										size_t  uri_size  =  pj_strlen ( & referred_by - > hvalue )  +  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										char  * uri  =  ast_alloca ( uri_size ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-05-02 16:39:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_copy_pj_str ( uri ,  & referred_by - > hvalue ,  uri_size ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pbx_builtin_setvar_helper ( chan ,  " __SIPREFERREDBYHDR " ,  S_OR ( uri ,  NULL ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pbx_builtin_setvar_helper ( chan ,  " SIPREFERREDBYHDR " ,  NULL ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( refer - > replaces )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										char  replaces [ 512 ] ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-01-07 17:35:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										char  * replaces_val  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										int  len ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										len  =  pjsip_hdr_print_on ( refer - > replaces ,  replaces ,  sizeof ( replaces )  -  1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( len  ! =  - 1 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											/* pjsip_hdr_print_on does not NULL terminate the buffer */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											replaces [ len ]  =  ' \0 ' ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											replaces_val  =  replaces  +  sizeof ( " Replaces: " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pbx_builtin_setvar_helper ( chan ,  " __SIPREPLACESHDR " ,  replaces_val ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-05-02 16:39:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pbx_builtin_setvar_helper ( chan ,  " SIPREPLACESHDR " ,  NULL ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( refer - > refer_to )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										char  refer_to [ PJSIP_MAX_URL_SIZE ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pjsip_uri_print ( PJSIP_URI_IN_REQ_URI ,  refer - > refer_to ,  refer_to ,  sizeof ( refer_to ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-05-02 16:39:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										pbx_builtin_setvar_helper ( chan ,  " SIPREFERTOHDR " ,  S_OR ( refer_to ,  NULL ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pbx_builtin_setvar_helper ( chan ,  " SIPREFERTOHDR " ,  NULL ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-06 22:50:40 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/*!
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ internal 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ brief  Set  the  passed  in  context  variable  to  the  determined  transfer  context . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ since  13.3 .0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ param  context  Set  to  the  determined  transfer  context . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ param  session  INVITE  dialog  SIP  session . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# define DETERMINE_TRANSFER_CONTEXT(context, session)									\ 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									do  { 																				\
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_channel_lock ( ( session ) - > channel ) ; 											\
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										context  =  pbx_builtin_getvar_helper ( ( session ) - > channel ,  " TRANSFER_CONTEXT " ) ; 	\
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ast_strlen_zero ( context ) )  { 													\
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											context  =  ( session ) - > endpoint - > context ; 										\
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  { 																		\
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											context  =  ast_strdupa ( context ) ; 												\
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 																				\
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_channel_unlock ( ( session ) - > channel ) ; 											\
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  while  ( 0 ) 																			\
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								static  int  refer_incoming_attended_request ( struct  ast_sip_session  * session ,  pjsip_rx_data  * rdata ,  pjsip_sip_uri  * target_uri ,  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_param  * replaces_param ,  struct  refer_progress  * progress ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									const  pj_str_t  str_replaces  =  {  " Replaces " ,  8  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pj_str_t  replaces_content ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_replaces_hdr  * replaces ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  parsed_len ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_dialog  * dlg ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pj_strdup_with_null ( rdata - > tp_info . pool ,  & replaces_content ,  & replaces_param - > value ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Parsing the parameter as a Replaces header easily grabs the needed information */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! ( replaces  =  pjsip_parse_hdr ( rdata - > tp_info . pool ,  & str_replaces ,  replaces_content . ptr , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pj_strlen ( & replaces_content ) ,  & parsed_len ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_ERROR ,  " Received REFER request on channel '%s' from endpoint '%s' with invalid Replaces header, rejecting \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_channel_name ( session - > channel ) ,  ast_sorcery_object_get_id ( session - > endpoint ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  400 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* See if the dialog is local, or remote */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ( dlg  =  pjsip_ua_find_dialog ( & replaces - > call_id ,  & replaces - > to_tag ,  & replaces - > from_tag ,  PJ_TRUE ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										RAII_VAR ( struct  ast_sip_session  * ,  other_session ,  ast_sip_dialog_get_session ( dlg ) ,  ao2_cleanup ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										struct  refer_attended  * attended ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pjsip_dlg_dec_lock ( dlg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! other_session )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_debug ( 3 ,  " Received REFER request on channel '%s' from endpoint '%s' for local dialog but no session exists on it \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_channel_name ( session - > channel ) ,  ast_sorcery_object_get_id ( session - > endpoint ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  603 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* We defer actually doing the attended transfer to the other session so no deadlock can occur */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! ( attended  =  refer_attended_alloc ( session ,  other_session ,  progress ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_ERROR ,  " Received REFER request on channel '%s' from endpoint '%s' for local dialog but could not allocate structure to complete, rejecting \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_channel_name ( session - > channel ) ,  ast_sorcery_object_get_id ( session - > endpoint ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  500 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( ast_sip_session_defer_termination ( session ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_ERROR ,  " Received REFER request on channel '%s' from endpoint '%s' for local dialog but could not defer termination, rejecting \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_channel_name ( session - > channel ) ,  ast_sorcery_object_get_id ( session - > endpoint ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ao2_cleanup ( attended ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  500 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										/* Push it to the other session, which will have both channels with minimal locking */ 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( ast_sip_push_task ( other_session - > serializer ,  refer_attended_task ,  attended ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2017-06-13 14:17:29 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_sip_session_end_if_deferred ( session ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_sip_session_defer_termination_cancel ( session ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											ao2_cleanup ( attended ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  500 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " Attended transfer from '%s' pushed to second channel serializer \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_channel_name ( session - > channel ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  200 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-06 22:50:40 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										const  char  * context ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										struct  refer_blind  refer  =  {  0 ,  } ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										int  response ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-06 22:50:40 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										DETERMINE_TRANSFER_CONTEXT ( context ,  session ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! ast_exists_extension ( NULL ,  context ,  " external_replaces " ,  1 ,  NULL ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-01-07 17:35:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_log ( LOG_ERROR ,  " Received REFER for remote session on channel '%s' from endpoint '%s' but 'external_replaces' extension not found in context %s \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_channel_name ( session - > channel ) ,  ast_sorcery_object_get_id ( session - > endpoint ) ,  context ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											return  404 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										refer . context  =  context ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										refer . progress  =  progress ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										refer . rdata  =  rdata ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										refer . replaces  =  replaces ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										refer . refer_to  =  target_uri ; 
							 
						 
					
						
							
								
									
										
										
										
											2017-05-08 16:56:32 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										refer . attended  =  1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( ast_sip_session_defer_termination ( session ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_ERROR ,  " Received REFER for remote session on channel '%s' from endpoint '%s' but could not defer termination, rejecting \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_channel_name ( session - > channel ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_sorcery_object_get_id ( session - > endpoint ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											return  500 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										response  =  xfer_response_code2sip ( ast_bridge_transfer_blind ( 1 ,  session - > channel , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											" external_replaces " ,  context ,  refer_blind_callback ,  & refer ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2017-06-13 14:17:29 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_sip_session_end_if_deferred ( session ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( response  ! =  200 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_sip_session_defer_termination_cancel ( session ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2017-06-13 14:17:29 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  response ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  refer_incoming_blind_request ( struct  ast_sip_session  * session ,  pjsip_rx_data  * rdata ,  pjsip_sip_uri  * target ,  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  refer_progress  * progress ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2014-05-30 14:53:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									const  char  * context ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									char  exten [ AST_MAX_EXTENSION ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  refer_blind  refer  =  {  0 ,  } ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									int  response ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* If no explicit transfer context has been provided use their configured context */ 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-06 22:50:40 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									DETERMINE_TRANSFER_CONTEXT ( context ,  session ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Using the user portion of the target URI see if it exists as a valid extension in their context */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_copy_pj_str ( exten ,  & target - > user ,  sizeof ( exten ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-29 18:08:22 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  We  may  want  to  match  in  the  dialplan  without  any  user 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  options  getting  in  the  way . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AST_SIP_USER_OPTIONS_TRUNCATE_CHECK ( exten ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-03-14 14:49:54 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/* Uri without exten */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ast_strlen_zero ( exten ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_copy_string ( exten ,  " s " ,  sizeof ( exten ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " Channel '%s' from endpoint '%s' attempted blind transfer to a target without extension. Target was set to 's@%s' \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_channel_name ( session - > channel ) ,  ast_sorcery_object_get_id ( session - > endpoint ) ,  context ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  ( ! ast_exists_extension ( NULL ,  context ,  exten ,  1 ,  NULL ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_ERROR ,  " Channel '%s' from endpoint '%s' attempted blind transfer to '%s@%s' but target does not exist \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_channel_name ( session - > channel ) ,  ast_sorcery_object_get_id ( session - > endpoint ) ,  exten ,  context ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  404 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									refer . context  =  context ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									refer . progress  =  progress ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									refer . rdata  =  rdata ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-04-17 15:17:39 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									refer . refer_to  =  target ; 
							 
						 
					
						
							
								
									
										
										
										
											2017-05-08 16:56:32 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									refer . attended  =  0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ast_sip_session_defer_termination ( session ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_ERROR ,  " Channel '%s' from endpoint '%s' attempted blind transfer but could not defer termination, rejecting \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_channel_name ( session - > channel ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_sorcery_object_get_id ( session - > endpoint ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  500 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									response  =  xfer_response_code2sip ( ast_bridge_transfer_blind ( 1 ,  session - > channel , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										exten ,  context ,  refer_blind_callback ,  & refer ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2017-06-13 14:17:29 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_sip_session_end_if_deferred ( session ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( response  ! =  200 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_sip_session_defer_termination_cancel ( session ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2017-06-13 14:17:29 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-10 16:04:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  response ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Structure used to retrieve channel from another session */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								struct  invite_replaces  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief Session we want the channel from */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_sip_session  * session ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief Channel from the session (with reference) */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_channel  * channel ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! \brief Bridge the channel is in */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_bridge  * bridge ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Task for invite replaces */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  invite_replaces ( void  * data )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  invite_replaces  * invite  =  data ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! invite - > session - > channel )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_channel_ref ( invite - > session - > channel ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									invite - > channel  =  invite - > session - > channel ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_channel_lock ( invite - > channel ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									invite - > bridge  =  ast_channel_get_bridge ( invite - > channel ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_channel_unlock ( invite - > channel ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  refer_incoming_invite_request ( struct  ast_sip_session  * session ,  struct  pjsip_rx_data  * rdata )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_dialog  * other_dlg  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_tx_data  * packet ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  response  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									RAII_VAR ( struct  ast_sip_session  * ,  other_session ,  NULL ,  ao2_cleanup ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  invite_replaces  invite ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* If a Replaces header is present make sure it is valid */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( pjsip_replaces_verify_request ( rdata ,  & other_dlg ,  PJ_TRUE ,  & packet )  ! =  PJ_SUCCESS )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										response  =  packet - > msg - > line . status . code ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-19 17:30:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_assert ( response  ! =  0 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										pjsip_tx_data_dec_ref ( packet ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-19 17:30:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										goto  inv_replace_failed ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* If no other dialog exists then this INVITE request does not have a Replaces header */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! other_dlg )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									other_session  =  ast_sip_dialog_get_session ( other_dlg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_dlg_dec_lock ( other_dlg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-11-20 14:55:45 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/* Don't accept an in-dialog INVITE with Replaces as it does not make much sense */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( session - > inv_session - > dlg - > state  = =  PJSIP_DIALOG_STATE_ESTABLISHED )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										response  =  488 ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-19 17:30:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										goto  inv_replace_failed ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-20 14:55:45 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  ( ! other_session )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " INVITE with Replaces received on channel '%s' from endpoint '%s', but requested session does not exist \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_channel_name ( session - > channel ) ,  ast_sorcery_object_get_id ( session - > endpoint ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-19 17:30:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										response  =  481 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										goto  inv_replace_failed ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									invite . session  =  other_session ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ast_sip_push_task_synchronous ( other_session - > serializer ,  invite_replaces ,  & invite ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										response  =  481 ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-19 17:30:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										goto  inv_replace_failed ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-12-18 20:33:37 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_channel_lock ( session - > channel ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									ast_setstate ( session - > channel ,  AST_STATE_RING ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-12-18 20:33:37 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_channel_unlock ( session - > channel ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									ast_raw_answer ( session - > channel ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-02-19 17:30:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_debug ( 3 ,  " INVITE with Replaces being attempted.  '%s' --> '%s' \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_channel_name ( session - > channel ) ,  ast_channel_name ( invite . channel ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  ( ! invite . bridge )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										struct  ast_channel  * chan  =  session - > channel ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-02-19 17:30:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										/*
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *  This  will  use  a  synchronous  task  but  we  aren ' t  operating  in 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *  the  serializer  at  this  point  in  time ,  so  it  won ' t  deadlock . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! ast_channel_move ( invite . channel ,  chan ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											/*
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 *  We  can ' t  directly  use  session - > channel  because  ast_channel_move ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 *  does  a  masquerade  which  changes  session - > channel  to  a  different 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 *  channel .   To  ensure  we  work  on  the  right  channel  we  store  a 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 *  pointer  locally  before  we  begin  so  it  remains  valid . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 */ 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											ast_hangup ( chan ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-19 17:30:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											response  =  AST_CAUSE_FAILURE ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2013-09-13 22:19:23 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( ast_bridge_impart ( invite . bridge ,  session - > channel ,  invite . channel ,  NULL , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											AST_BRIDGE_IMPART_CHAN_INDEPENDENT ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-19 17:30:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											response  =  AST_CAUSE_FAILURE ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-02-19 17:30:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_channel_unref ( invite . channel ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_cleanup ( invite . bridge ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  ( ! response )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-19 17:30:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										/*
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *  On  success  we  cannot  use  session - > channel  in  the  debug  message . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *  This  thread  either  no  longer  has  a  ref  to  session - > channel  or 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *  session - > channel  is  no  longer  the  original  channel . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " INVITE with Replaces successfully completed. \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " INVITE with Replaces failed on channel '%s', hanging up with cause '%d' \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_channel_name ( session - > channel ) ,  response ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_channel_lock ( session - > channel ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_channel_hangupcause_set ( session - > channel ,  response ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_channel_unlock ( session - > channel ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_hangup ( session - > channel ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-02-19 17:30:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-02-19 17:30:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								inv_replace_failed :  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( session - > inv_session - > dlg - > state  ! =  PJSIP_DIALOG_STATE_ESTABLISHED )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " INVITE with Replaces failed on channel '%s', sending response of '%d' \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_channel_name ( session - > channel ) ,  response ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										session - > defer_terminate  =  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_hangup ( session - > channel ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-22 18:02:59 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( pjsip_inv_end_session ( session - > inv_session ,  response ,  NULL ,  & packet )  = =  PJ_SUCCESS 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											& &  packet )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-19 17:30:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_sip_session_send_response ( session ,  packet ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-19 17:30:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " INVITE with Replaces in-dialog on channel '%s', hanging up \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_channel_name ( session - > channel ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_queue_hangup ( session - > channel ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  refer_incoming_refer_request ( struct  ast_sip_session  * session ,  struct  pjsip_rx_data  * rdata )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_generic_string_hdr  * refer_to ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-19 11:50:54 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									char  * uri ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-03-03 10:43:59 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									size_t  uri_size ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-19 11:50:54 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									pjsip_uri  * target ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									pjsip_sip_uri  * target_uri ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									RAII_VAR ( struct  refer_progress  * ,  progress ,  NULL ,  ao2_cleanup ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_param  * replaces ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  response ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-05-02 16:39:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									static  const  pj_str_t  str_refer_to  =  {  " Refer-To " ,  8  } ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-12-30 08:10:09 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									static  const  pj_str_t  str_refer_to_s  =  {  " r " ,  1  } ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-05-02 16:39:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									static  const  pj_str_t  str_replaces  =  {  " Replaces " ,  8  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-02-17 15:31:46 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ! session - > channel )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* No channel to refer.  Likely because the call was just hung up. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pjsip_dlg_respond ( session - > inv_session - > dlg ,  rdata ,  404 ,  NULL ,  NULL ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " Received a REFER on a session with no channel from endpoint '%s'. \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_sorcery_object_get_id ( session - > endpoint ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-07-18 19:25:51 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ! session - > endpoint - > allowtransfer )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pjsip_dlg_respond ( session - > inv_session - > dlg ,  rdata ,  603 ,  NULL ,  NULL ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_WARNING ,  " Endpoint %s transfer attempt blocked due to configuration \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_sorcery_object_get_id ( session - > endpoint ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									/* A Refer-To header is required */ 
							 
						 
					
						
							
								
									
										
										
										
											2016-12-30 08:10:09 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									refer_to  =  pjsip_msg_find_hdr_by_names ( rdata - > msg_info . msg ,  & str_refer_to ,  & str_refer_to_s ,  NULL ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-05-02 16:39:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ! refer_to )  { 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										pjsip_dlg_respond ( session - > inv_session - > dlg ,  rdata ,  400 ,  NULL ,  NULL ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " Received a REFER without Refer-To on channel '%s' from endpoint '%s' \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_channel_name ( session - > channel ) ,  ast_sorcery_object_get_id ( session - > endpoint ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-03-03 10:43:59 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/* The ast_copy_pj_str to uri is needed because it puts the NULL terminator to the uri
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  as  pjsip_parse_uri  require  a  NULL  terminated  uri 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-19 11:50:54 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-03-03 10:43:59 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									uri_size  =  pj_strlen ( & refer_to - > hvalue )  +  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									uri  =  ast_alloca ( uri_size ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_copy_pj_str ( uri ,  & refer_to - > hvalue ,  uri_size ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									target  =  pjsip_parse_uri ( rdata - > tp_info . pool ,  uri ,  uri_size  -  1 ,  0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-05-02 16:39:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ! target 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-19 11:50:54 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										| |  ( ! PJSIP_URI_SCHEME_IS_SIP ( target ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											& &  ! PJSIP_URI_SCHEME_IS_SIPS ( target ) ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-05-02 16:39:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										pjsip_dlg_respond ( session - > inv_session - > dlg ,  rdata ,  400 ,  NULL ,  NULL ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " Received a REFER without a parseable Refer-To ('%s') on channel '%s' from endpoint '%s' \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											uri ,  ast_channel_name ( session - > channel ) ,  ast_sorcery_object_get_id ( session - > endpoint ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-19 11:50:54 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									target_uri  =  pjsip_uri_get_uri ( target ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Set up REFER progress subscription if requested/possible */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( refer_progress_alloc ( session ,  rdata ,  & progress ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pjsip_dlg_respond ( session - > inv_session - > dlg ,  rdata ,  500 ,  NULL ,  NULL ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " Could not set up subscription for REFER on channel '%s' from endpoint '%s' \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_channel_name ( session - > channel ) ,  ast_sorcery_object_get_id ( session - > endpoint ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Determine if this is an attended or blind transfer */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ( replaces  =  pjsip_param_find ( & target_uri - > header_param ,  & str_replaces ) )  | | 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										( replaces  =  pjsip_param_find ( & target_uri - > other_param ,  & str_replaces ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										response  =  refer_incoming_attended_request ( session ,  rdata ,  target_uri ,  replaces ,  progress ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										response  =  refer_incoming_blind_request ( session ,  rdata ,  target_uri ,  progress ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! progress )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* The transferer has requested no subscription, so send a final response immediately */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pjsip_tx_data  * tdata ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										const  pj_str_t  str_refer_sub  =  {  " Refer-Sub " ,  9  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										const  pj_str_t  str_false  =  {  " false " ,  5  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pjsip_hdr  * hdr ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " Progress monitoring not requested for REFER on channel '%s' from endpoint '%s', sending immediate response of '%d' \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_channel_name ( session - > channel ) ,  ast_sorcery_object_get_id ( session - > endpoint ) ,  response ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( pjsip_dlg_create_response ( session - > inv_session - > dlg ,  rdata ,  response ,  NULL ,  & tdata )  ! =  PJ_SUCCESS )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											pjsip_dlg_respond ( session - > inv_session - > dlg ,  rdata ,  response ,  NULL ,  NULL ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										hdr  =  ( pjsip_hdr * ) pjsip_generic_string_hdr_create ( tdata - > pool ,  & str_refer_sub ,  & str_false ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pjsip_msg_add_hdr ( tdata - > msg ,  hdr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pjsip_dlg_send_response ( session - > inv_session - > dlg ,  pjsip_rdata_get_tsx ( rdata ) ,  tdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  if  ( response  ! =  200 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* Since this failed we can send a final NOTIFY now and terminate the subscription */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										struct  refer_progress_notification  * notification  =  refer_progress_notification_alloc ( progress ,  response ,  PJSIP_EVSUB_STATE_TERMINATED ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( notification )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											/* The refer_progress_notify function will call ao2_cleanup on this for us */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											refer_progress_notify ( notification ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  refer_incoming_request ( struct  ast_sip_session  * session ,  pjsip_rx_data  * rdata )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! pjsip_method_cmp ( & rdata - > msg_info . msg - > line . req . method ,  pjsip_get_refer_method ( ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  refer_incoming_refer_request ( session ,  rdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  if  ( ! pjsip_method_cmp ( & rdata - > msg_info . msg - > line . req . method ,  & pjsip_invite_method ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  refer_incoming_invite_request ( session ,  rdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-06-26 10:41:05 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/*!
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ brief  Use  the  value  of  a  channel  variable  as  the  value  of  a  SIP  header 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  This  looks  up  a  variable  name  on  a  channel ,  then  takes  that  value  and  adds 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  it  to  an  outgoing  SIP  request .  If  the  header  already  exists  on  the  message , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  then  no  action  is  taken . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ pre  chan  is  locked . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ param  chan  The  channel  on  which  to  find  the  variable . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ param  var_name  The  name  of  the  channel  variable  to  use . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ param  header_name  The  name  of  the  SIP  header  to  add  to  the  outgoing  message . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ param  tdata  The  outgoing  SIP  message  on  which  to  add  the  header 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  add_header_from_channel_var ( struct  ast_channel  * chan ,  const  char  * var_name ,  const  char  * header_name ,  pjsip_tx_data  * tdata )  
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2015-06-26 10:41:05 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									const  char  * var_value ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pj_str_t  pj_header_name ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_hdr  * header ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var_value  =  pbx_builtin_getvar_helper ( chan ,  var_name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ast_strlen_zero ( var_value ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-06-26 10:41:05 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									pj_cstr ( & pj_header_name ,  header_name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									header  =  pjsip_msg_find_hdr_by_name ( tdata - > msg ,  & pj_header_name ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( header )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_sip_add_header ( tdata ,  header_name ,  var_value ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  refer_outgoing_request ( struct  ast_sip_session  * session ,  struct  pjsip_tx_data  * tdata )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2014-05-02 16:39:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( pjsip_method_cmp ( & tdata - > msg - > line . req . method ,  & pjsip_invite_method ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										| |  ! session - > channel 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										| |  session - > inv_session - > state  ! =  PJSIP_INV_STATE_NULL )  { 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-05-02 16:39:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_channel_lock ( session - > channel ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-06-26 10:41:05 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									add_header_from_channel_var ( session - > channel ,  " SIPREPLACESHDR " ,  " Replaces " ,  tdata ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									add_header_from_channel_var ( session - > channel ,  " SIPREFERREDBYHDR " ,  " Referred-By " ,  tdata ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-05-02 16:39:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_channel_unlock ( session - > channel ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  struct  ast_sip_session_supplement  refer_supplement  =  {  
						 
					
						
							
								
									
										
										
										
											2014-01-15 13:16:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									. priority  =  AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL  +  1 , 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									. incoming_request  =  refer_incoming_request , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. outgoing_request  =  refer_outgoing_request , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  load_module ( void )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									const  pj_str_t  str_norefersub  =  {  " norefersub " ,  10  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-16 14:35:00 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									CHECK_PJSIP_SESSION_MODULE_LOADED ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									pjsip_replaces_init_module ( ast_sip_get_pjsip_endpoint ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_xfer_init_module ( ast_sip_get_pjsip_endpoint ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									pjsip_endpt_add_capability ( ast_sip_get_pjsip_endpoint ( ) ,  NULL ,  PJSIP_H_SUPPORTED ,  NULL ,  1 ,  & str_norefersub ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_sip_register_service ( & refer_progress_module ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_sip_session_register_supplement ( & refer_supplement ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-10-18 14:37:57 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_module_shutdown_ref ( ast_module_info - > self ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									return  AST_MODULE_LOAD_SUCCESS ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  unload_module ( void )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_sip_session_unregister_supplement ( & refer_supplement ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_sip_unregister_service ( & refer_progress_module ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-07-30 18:14:50 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								AST_MODULE_INFO ( ASTERISK_GPL_KEY ,  AST_MODFLAG_LOAD_ORDER ,  " PJSIP Blind and Attended Transfer Support " ,  
						 
					
						
							
								
									
										
										
										
											2014-07-25 16:47:17 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										. support_level  =  AST_MODULE_SUPPORT_CORE , 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-22 14:03:22 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										. load  =  load_module , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										. unload  =  unload_module , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										. load_pri  =  AST_MODPRI_APP_DEPEND , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										   ) ;