@ -21,6 +21,8 @@
# include <pjsip.h>
/* Needed for SUBSCRIBE, NOTIFY, and PUBLISH method definitions */
# include <pjsip_simple.h>
# include <pjsip/sip_transaction.h>
# include <pj/timer.h>
# include <pjlib.h>
# include "asterisk/res_pjsip.h"
@ -1009,6 +1011,14 @@
If < literal > 0 < / literal > never qualify . Time in seconds .
< / para > < / description >
< / configOption >
< configOption name = " qualify_timeout " default = " 3.0 " >
< synopsis > Timeout for qualify < / synopsis >
< description > < para >
If the contact doesn ' t repond to the OPTIONS request before the timeout ,
the contact is marked unavailable .
If < literal > 0 < / literal > no timeout . Time in fractional seconds .
< / para > < / description >
< / configOption >
< configOption name = " outbound_proxy " >
< synopsis > Outbound proxy used when sending OPTIONS request < / synopsis >
< description > < para >
@ -1123,6 +1133,14 @@
If < literal > 0 < / literal > never qualify . Time in seconds .
< / para > < / description >
< / configOption >
< configOption name = " qualify_timeout " default = " 3.0 " >
< synopsis > Timeout for qualify < / synopsis >
< description > < para >
If the contact doesn ' t repond to the OPTIONS request before the timeout ,
the contact is marked unavailable .
If < literal > 0 < / literal > no timeout . Time in fractional seconds .
< / para > < / description >
< / configOption >
< configOption name = " authenticate_qualify " default = " no " >
< synopsis > Authenticates a qualify request if needed < / synopsis >
< description > < para >
@ -1211,6 +1229,10 @@
< configOption name = " keep_alive_interval " default = " 0 " >
< synopsis > The interval ( in seconds ) to send keepalives to active connection - oriented transports . < / synopsis >
< / configOption >
< configOption name = " max_initial_qualify_time " default = " 0 " >
< synopsis > The maximum amount of time from startup that qualifies should be attempted on all contacts .
If greater than the qualify_frequency for an aor , qualify_frequency will be used instead . < / synopsis >
< / configOption >
< configOption name = " type " >
< synopsis > Must be of type ' global ' . < / synopsis >
< / configOption >
@ -2815,6 +2837,128 @@ static pj_bool_t does_method_match(const pj_str_t *message_method, const char *s
/*! Maximum number of challenges before assuming that we are in a loop */
# define MAX_RX_CHALLENGES 10
# define TIMER_INACTIVE 0
# define TIMEOUT_TIMER2 5
struct tsx_data {
void * token ;
void ( * cb ) ( void * , pjsip_event * ) ;
pjsip_transaction * tsx ;
pj_timer_entry * timeout_timer ;
} ;
static void send_tsx_on_tsx_state ( pjsip_transaction * tsx , pjsip_event * event ) ;
pjsip_module send_tsx_module = {
. name = { " send_tsx_module " , 23 } ,
. id = - 1 ,
. priority = PJSIP_MOD_PRIORITY_APPLICATION ,
. on_tsx_state = & send_tsx_on_tsx_state ,
} ;
/*! \brief This is the pjsip_tsx_send_msg callback */
static void send_tsx_on_tsx_state ( pjsip_transaction * tsx , pjsip_event * event )
{
struct tsx_data * tsx_data ;
if ( event - > type ! = PJSIP_EVENT_TSX_STATE ) {
return ;
}
tsx_data = ( struct tsx_data * ) tsx - > mod_data [ send_tsx_module . id ] ;
if ( tsx_data = = NULL ) {
return ;
}
if ( tsx - > status_code < 200 ) {
return ;
}
if ( event - > body . tsx_state . type = = PJSIP_EVENT_TIMER ) {
ast_debug ( 1 , " PJSIP tsx timer expired \n " ) ;
}
if ( tsx_data - > timeout_timer & & tsx_data - > timeout_timer - > id ! = TIMER_INACTIVE ) {
pj_mutex_lock ( tsx - > mutex_b ) ;
pj_timer_heap_cancel_if_active ( pjsip_endpt_get_timer_heap ( tsx - > endpt ) ,
tsx_data - > timeout_timer , TIMER_INACTIVE ) ;
pj_mutex_unlock ( tsx - > mutex_b ) ;
}
/* Call the callback, if any, and prevent the callback from being called again
* by clearing the transaction ' s module_data .
*/
tsx - > mod_data [ send_tsx_module . id ] = NULL ;
if ( tsx_data - > cb ) {
( * tsx_data - > cb ) ( tsx_data - > token , event ) ;
}
}
static void tsx_timer_callback ( pj_timer_heap_t * theap , pj_timer_entry * entry )
{
struct tsx_data * tsx_data = entry - > user_data ;
entry - > id = TIMER_INACTIVE ;
ast_debug ( 1 , " Internal tsx timer expired \n " ) ;
pjsip_tsx_terminate ( tsx_data - > tsx , PJSIP_SC_TSX_TIMEOUT ) ;
}
static pj_status_t endpt_send_transaction ( pjsip_endpoint * endpt ,
pjsip_tx_data * tdata , int timeout , void * token ,
pjsip_endpt_send_callback cb )
{
pjsip_transaction * tsx ;
struct tsx_data * tsx_data ;
pj_status_t status ;
pjsip_event event ;
ast_assert ( endpt & & tdata ) ;
status = pjsip_tsx_create_uac ( & send_tsx_module , tdata , & tsx ) ;
if ( status ! = PJ_SUCCESS ) {
pjsip_tx_data_dec_ref ( tdata ) ;
ast_log ( LOG_ERROR , " Unable to create pjsip uac \n " ) ;
return status ;
}
tsx_data = PJ_POOL_ALLOC_T ( tsx - > pool , struct tsx_data ) ;
tsx_data - > token = token ;
tsx_data - > cb = cb ;
tsx_data - > tsx = tsx ;
if ( timeout > 0 ) {
tsx_data - > timeout_timer = PJ_POOL_ALLOC_T ( tsx - > pool , pj_timer_entry ) ;
} else {
tsx_data - > timeout_timer = NULL ;
}
tsx - > mod_data [ send_tsx_module . id ] = tsx_data ;
PJSIP_EVENT_INIT_TX_MSG ( event , tdata ) ;
pjsip_tx_data_set_transport ( tdata , & tsx - > tp_sel ) ;
if ( timeout > 0 ) {
pj_time_val timeout_timer_val = { timeout / 1000 , timeout % 1000 } ;
pj_timer_entry_init ( tsx_data - > timeout_timer , TIMEOUT_TIMER2 ,
tsx_data , & tsx_timer_callback ) ;
pj_mutex_lock ( tsx - > mutex_b ) ;
pj_timer_heap_cancel_if_active ( pjsip_endpt_get_timer_heap ( tsx - > endpt ) ,
tsx_data - > timeout_timer , TIMER_INACTIVE ) ;
pj_timer_heap_schedule ( pjsip_endpt_get_timer_heap ( tsx - > endpt ) ,
tsx_data - > timeout_timer , & timeout_timer_val ) ;
tsx_data - > timeout_timer - > id = TIMEOUT_TIMER2 ;
pj_mutex_unlock ( tsx - > mutex_b ) ;
}
status = ( * tsx - > state_handler ) ( tsx , & event ) ;
pjsip_tx_data_dec_ref ( tdata ) ;
if ( status ! = PJ_SUCCESS ) {
ast_log ( LOG_ERROR , " Unable to send message \n " ) ;
return status ;
}
return status ;
}
/*! \brief Structure to hold information about an outbound request */
struct send_request_data {
@ -2874,7 +3018,7 @@ static void endpt_send_request_wrapper(void *token, pjsip_event *e)
}
static pj_status_t endpt_send_request ( struct ast_sip_endpoint * endpoint ,
pjsip_tx_data * tdata , pj_ int32_ t timeout , void * token , pjsip_endpt_send_callback cb )
pjsip_tx_data * tdata , int timeout , void * token , pjsip_endpt_send_callback cb )
{
struct send_request_wrapper * req_wrapper ;
pj_status_t ret_val ;
@ -2890,7 +3034,7 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint,
req_wrapper - > callback = cb ;
ao2_ref ( req_wrapper , + 1 ) ;
ret_val = pjsip_endpt_send_request ( ast_sip_get_pjsip_endpoint ( ) , tdata , timeout ,
ret_val = endpt_send_transaction ( ast_sip_get_pjsip_endpoint ( ) , tdata , timeout ,
req_wrapper , endpt_send_request_wrapper ) ;
if ( ret_val ! = PJ_SUCCESS ) {
char errmsg [ PJ_ERR_MSG_SIZE ] ;
@ -2930,6 +3074,10 @@ static void send_request_cb(void *token, pjsip_event *e)
int res ;
switch ( e - > body . tsx_state . type ) {
case PJSIP_EVENT_USER :
/* Map USER (transaction cancelled by timeout) to TIMER */
e - > body . tsx_state . type = PJSIP_EVENT_TIMER ;
break ;
case PJSIP_EVENT_TRANSPORT_ERROR :
case PJSIP_EVENT_TIMER :
break ;
@ -2980,8 +3128,9 @@ static void send_request_cb(void *token, pjsip_event *e)
ao2_ref ( req_data , - 1 ) ;
}
static int send_out_of_dialog_request ( pjsip_tx_data * tdata , struct ast_sip_endpoint * endpoint ,
void * token , void ( * callback ) ( void * token , pjsip_event * e ) )
int ast_sip_send_out_of_dialog_request ( pjsip_tx_data * tdata ,
struct ast_sip_endpoint * endpoint , int timeout , void * token ,
void ( * callback ) ( void * token , pjsip_event * e ) )
{
struct ast_sip_supplement * supplement ;
struct send_request_data * req_data ;
@ -3007,7 +3156,7 @@ static int send_out_of_dialog_request(pjsip_tx_data *tdata, struct ast_sip_endpo
ast_sip_mod_data_set ( tdata - > pool , tdata - > mod_data , supplement_module . id , MOD_DATA_CONTACT , NULL ) ;
ao2_cleanup ( contact ) ;
if ( endpt_send_request ( endpoint , tdata , - 1 , req_data , send_request_cb )
if ( endpt_send_request ( endpoint , tdata , timeout , req_data , send_request_cb )
! = PJ_SUCCESS ) {
ao2_cleanup ( req_data ) ;
return - 1 ;
@ -3025,7 +3174,7 @@ int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg,
if ( dlg ) {
return send_in_dialog_request ( tdata , dlg ) ;
} else {
return send_out_of_dialog_request( tdata , endpoint , token , callback ) ;
return ast_sip_ send_out_of_dialog_request( tdata , endpoint , - 1 , token , callback ) ;
}
}
@ -3544,8 +3693,25 @@ static int load_module(void)
return AST_MODULE_LOAD_DECLINE ;
}
if ( internal_sip_register_service ( & send_tsx_module ) ) {
ast_log ( LOG_ERROR , " Failed to initialize send request module. Aborting load \n " ) ;
internal_sip_unregister_service ( & supplement_module ) ;
ast_sip_destroy_distributor ( ) ;
ast_res_pjsip_destroy_configuration ( ) ;
ast_sip_destroy_global_headers ( ) ;
stop_monitor_thread ( ) ;
ast_sip_destroy_system ( ) ;
pj_pool_release ( memory_pool ) ;
memory_pool = NULL ;
pjsip_endpt_destroy ( ast_pjsip_endpoint ) ;
ast_pjsip_endpoint = NULL ;
pj_caching_pool_destroy ( & caching_pool ) ;
return AST_MODULE_LOAD_DECLINE ;
}
if ( internal_sip_initialize_outbound_authentication ( ) ) {
ast_log ( LOG_ERROR , " Failed to initialize outbound authentication. Aborting load \n " ) ;
internal_sip_unregister_service ( & send_tsx_module ) ;
internal_sip_unregister_service ( & supplement_module ) ;
ast_sip_destroy_distributor ( ) ;
ast_res_pjsip_destroy_configuration ( ) ;
@ -3589,6 +3755,7 @@ static int unload_pjsip(void *data)
ast_res_pjsip_destroy_configuration ( ) ;
ast_sip_destroy_system ( ) ;
ast_sip_destroy_global_headers ( ) ;
internal_sip_unregister_service ( & send_tsx_module ) ;
internal_sip_unregister_service ( & supplement_module ) ;
if ( monitor_thread ) {
stop_monitor_thread ( ) ;