@ -271,6 +271,102 @@ static struct ast_datastore_info transport_info = {
. destroy = transport_info_destroy ,
} ;
/*!
* \ brief Determine the local signaling address used for an outgoing request .
*
* For unreliable transports , the transport local address may be a wildcard
* address . Ask the PJSIP transport manager for the local interface selected
* for the request destination , then fall back to the transport local address
* if needed .
*/
static int set_transport_info_local_addr ( struct pjsip_tx_data * tdata , pj_sockaddr * local_addr )
{
if ( ! ( tdata - > tp_info . transport - > flag & PJSIP_TRANSPORT_RELIABLE ) ) {
pjsip_tpmgr_fla2_param prm ;
pjsip_tpmgr_fla2_param_default ( & prm ) ;
prm . tp_type = tdata - > tp_info . transport - > key . type ;
pj_strset2 ( & prm . dst_host , tdata - > tp_info . dst_name ) ;
prm . local_if = PJ_TRUE ;
if ( pjsip_tpmgr_find_local_addr2 ( pjsip_endpt_get_tpmgr ( ast_sip_get_pjsip_endpoint ( ) ) ,
tdata - > pool , & prm ) = = PJ_SUCCESS ) {
int af = prm . tp_type & PJSIP_TRANSPORT_IPV6 ? pj_AF_INET6 ( ) : pj_AF_INET ( ) ;
if ( prm . tp_type = = PJSIP_TRANSPORT_UDP | | prm . tp_type = = PJSIP_TRANSPORT_UDP6 ) {
prm . ret_port = tdata - > tp_info . transport - > local_name . port ;
}
if ( pj_sockaddr_init ( af , local_addr , & prm . ret_addr , prm . ret_port ) = = PJ_SUCCESS ) {
return 0 ;
}
}
}
pj_sockaddr_cp ( local_addr , & tdata - > tp_info . transport - > local_addr ) ;
return pj_sockaddr_has_addr ( local_addr ) ? 0 : - 1 ;
}
/*!
* \ brief Store transport information for outgoing PJSIP session requests .
*
* Incoming PJSIP channels get their transport information from the received
* request . Outgoing channels may not have this information available through
* the channel datastore , so store the selected transport addresses once the
* outgoing request has been created and a destination is known .
*/
static pj_status_t transport_info_on_tx_request ( pjsip_tx_data * tdata )
{
RAII_VAR ( struct ast_sip_session * , session , NULL , ao2_cleanup ) ;
RAII_VAR ( struct ast_datastore * , datastore , NULL , ao2_cleanup ) ;
struct transport_info_data * transport_data ;
pjsip_dialog * dlg ;
if ( ! tdata - > tp_info . transport
| | ! pj_sockaddr_has_addr ( & tdata - > tp_info . dst_addr ) ) {
return PJ_SUCCESS ;
}
dlg = pjsip_tdata_get_dlg ( tdata ) ;
if ( ! dlg ) {
return PJ_SUCCESS ;
}
session = ast_sip_dialog_get_session ( dlg ) ;
if ( ! session
| | ! session - > inv_session
| | session - > inv_session - > role ! = PJSIP_ROLE_UAC ) {
return PJ_SUCCESS ;
}
datastore = ast_sip_session_get_datastore ( session , " transport_info " ) ;
if ( datastore ) {
return PJ_SUCCESS ;
}
datastore = ast_sip_session_alloc_datastore ( & transport_info , " transport_info " ) ;
if ( ! datastore ) {
return PJ_SUCCESS ;
}
transport_data = ast_calloc ( 1 , sizeof ( * transport_data ) ) ;
if ( ! transport_data ) {
return PJ_SUCCESS ;
}
if ( set_transport_info_local_addr ( tdata , & transport_data - > local_addr ) ) {
ast_free ( transport_data ) ;
return PJ_SUCCESS ;
}
pj_sockaddr_cp ( & transport_data - > remote_addr , & tdata - > tp_info . dst_addr ) ;
datastore - > data = transport_data ;
ast_sip_session_add_datastore ( session , datastore ) ;
return PJ_SUCCESS ;
}
static struct ast_datastore_info direct_media_mitigation_info = { } ;
static int direct_media_mitigate_glare ( struct ast_sip_session * session )
@ -1956,10 +2052,11 @@ static void transfer_redirect(struct ast_sip_session *session, const char *targe
ast_queue_control_data ( session - > channel , AST_CONTROL_TRANSFER , & message , sizeof ( message ) ) ;
}
/*! \brief REFER Callback module, used to attach session data structure to subscription */
static pjsip_module refer_callback _module = {
. name = { " REFER Callback" , 14 } ,
/*! \brief General PJSIP module for chan_pjsip, currently used for REFER subscription data and outgoing request callbacks */
static pjsip_module chan_pjsip _module = {
. name = { " chan_pjsip" , 10 } ,
. id = - 1 ,
. on_tx_request = transport_info_on_tx_request ,
} ;
/*!
@ -1979,7 +2076,7 @@ static void xfer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
return ;
}
chan = pjsip_evsub_get_mod_data ( sub , refer_callback _module. id ) ;
chan = pjsip_evsub_get_mod_data ( sub , chan_pjsip _module. id ) ;
if ( ! chan ) {
return ;
}
@ -2007,7 +2104,7 @@ static void xfer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
/* Since no subscription is desired, assume that call has been transferred successfully. */
/* Channel reference will be released at end of function */
/* Terminate subscription. */
pjsip_evsub_set_mod_data ( sub , refer_callback _module. id , NULL ) ;
pjsip_evsub_set_mod_data ( sub , chan_pjsip _module. id , NULL ) ;
pjsip_evsub_terminate ( sub , PJ_TRUE ) ;
res = - 1 ;
}
@ -2071,7 +2168,7 @@ static void xfer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
}
}
/* Finished. Remove session from subscription */
pjsip_evsub_set_mod_data ( sub , refer_callback _module. id , NULL ) ;
pjsip_evsub_set_mod_data ( sub , chan_pjsip _module. id , NULL ) ;
ast_debug ( 3 , " Transfer channel %s completed: %d %.*s (%s) \n " ,
ast_channel_name ( chan ) ,
status_line . code ,
@ -2107,10 +2204,10 @@ static void transfer_refer(struct ast_sip_session *session, const char *target)
return ;
}
/* refer_callback _module requires a reference to chan
/* chan_pjsip _module requires a reference to chan
* which will be released in xfer_client_on_evsub_state ( )
* when the implicit REFER subscription terminates */
pjsip_evsub_set_mod_data ( sub , refer_callback _module. id , chan ) ;
pjsip_evsub_set_mod_data ( sub , chan_pjsip _module. id , chan ) ;
ao2_ref ( chan , + 1 ) ;
if ( pjsip_xfer_initiate ( sub , pj_cstr ( & tmp , target ) , & packet ) ! = PJ_SUCCESS ) {
@ -2132,7 +2229,7 @@ static void transfer_refer(struct ast_sip_session *session, const char *target)
failure :
message = AST_TRANSFER_FAILED ;
ast_queue_control_data ( chan , AST_CONTROL_TRANSFER , & message , sizeof ( message ) ) ;
pjsip_evsub_set_mod_data ( sub , refer_callback _module. id , NULL ) ;
pjsip_evsub_set_mod_data ( sub , chan_pjsip _module. id , NULL ) ;
pjsip_evsub_terminate ( sub , PJ_FALSE ) ;
ao2_ref ( chan , - 1 ) ;
@ -3493,7 +3590,7 @@ static int load_module(void)
ast_manager_register_xml ( app_pjsip_hangup , EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL , pjsip_action_hangup ) ;
ast_sip_register_service ( & refer_callback _module) ;
ast_sip_register_service ( & chan_pjsip _module) ;
ast_sip_session_register_supplement ( & chan_pjsip_supplement ) ;
ast_sip_session_register_supplement ( & chan_pjsip_supplement_response ) ;
@ -3533,7 +3630,7 @@ end:
ast_sip_session_unregister_supplement ( & chan_pjsip_supplement_response ) ;
ast_sip_session_unregister_supplement ( & chan_pjsip_supplement ) ;
ast_sip_session_unregister_supplement ( & call_pickup_supplement ) ;
ast_sip_unregister_service ( & refer_callback _module) ;
ast_sip_unregister_service ( & chan_pjsip _module) ;
ast_custom_function_unregister ( & dtmf_mode_function ) ;
ast_custom_function_unregister ( & moh_passthrough_function ) ;
ast_custom_function_unregister ( & media_offer_function ) ;
@ -3566,7 +3663,7 @@ static int unload_module(void)
ast_sip_session_unregister_supplement ( & chan_pjsip_prack_supplement ) ;
ast_sip_session_unregister_supplement ( & call_pickup_supplement ) ;
ast_sip_unregister_service ( & refer_callback _module) ;
ast_sip_unregister_service ( & chan_pjsip _module) ;
ast_custom_function_unregister ( & dtmf_mode_function ) ;
ast_custom_function_unregister ( & moh_passthrough_function ) ;