diff --git a/pjsip/include/pjsip/sip_config.h b/pjsip/include/pjsip/sip_config.h index 61d013cb8c..dbc3312c3b 100644 --- a/pjsip/include/pjsip/sip_config.h +++ b/pjsip/include/pjsip/sip_config.h @@ -1045,6 +1045,19 @@ PJ_INLINE(pjsip_cfg_t*) pjsip_cfg(void) # define PJSIP_TSX_1XX_RETRANS_DELAY 60 #endif +/** + * Setting to determine if certain SIP UAS transaction, such as + * INVITE UAS tsx that hasn't been confirmed, is allowed to continue + * upon transport error. If disabled, the transaction will always be + * terminated, which is the default behavior prior to the introduction + * of this setting. + * + * Default: 1 (transaction will continue) + */ +#ifndef PJSIP_TSX_UAS_CONTINUE_ON_TP_ERROR +# define PJSIP_TSX_UAS_CONTINUE_ON_TP_ERROR 1 +#endif + #define PJSIP_MAX_TSX_KEY_LEN (PJSIP_MAX_URL_SIZE*2) /* User agent. */ diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c index f663c7f4b0..6affceb45e 100644 --- a/pjsip/src/pjsip/sip_transaction.c +++ b/pjsip/src/pjsip/sip_transaction.c @@ -137,6 +137,7 @@ static pj_time_val timeout_timer_val = { (64*PJSIP_T1_TIMEOUT)/1000, #define RETRANSMIT_TIMER 1 #define TIMEOUT_TIMER 2 #define TRANSPORT_ERR_TIMER 3 +#define TRANSPORT_DISC_TIMER 4 /* Flags for tsx_set_state() */ enum @@ -1124,8 +1125,11 @@ static void tsx_timer_callback( pj_timer_heap_t *theap, pj_timer_entry *entry) return; } - if (entry->id == TRANSPORT_ERR_TIMER) { - /* Posted transport error event */ + if (entry->id == TRANSPORT_ERR_TIMER || entry->id == TRANSPORT_DISC_TIMER) + { + /* Posted transport error/disconnection event */ + pj_bool_t tp_disc = (entry->id == TRANSPORT_DISC_TIMER); + entry->id = 0; if (tsx->state < PJSIP_TSX_STATE_TERMINATED) { pjsip_tsx_state_e prev_state; @@ -1137,6 +1141,31 @@ static void tsx_timer_callback( pj_timer_heap_t *theap, pj_timer_entry *entry) /* Release transport as it's no longer working. */ tsx_update_transport(tsx, NULL); +#if PJSIP_TSX_UAS_CONTINUE_ON_TP_ERROR + if (tp_disc && tsx->method.id == PJSIP_INVITE_METHOD && + tsx->role == PJSIP_ROLE_UAS && tsx->status_code < 200 && + !(tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) && + !(tsx->transport_flag & TSX_HAS_PENDING_DESTROY)) +#else + PJ_UNUSED_ARG(tp_disc); + if (0) +#endif + { + /* Upon transport disconnection event, if we receive + * incoming INVITE and haven't responded with a final answer, + * just return here and don't terminate the transaction, + * in case that the library can switch to another working + * transport. + */ + tsx->transport_flag = 0; + tsx->addr_len = 0; + tsx->res_addr.transport = NULL; + tsx->res_addr.addr_len = 0; + + pj_grp_lock_release(tsx->grp_lock); + return; + } + if (tsx->status_code < 200) { pj_str_t err; char errmsg[PJ_ERR_MSG_SIZE]; @@ -2132,7 +2161,7 @@ static void tsx_tp_state_callback( pjsip_transport *tp, if (tsx->state < PJSIP_TSX_STATE_COMPLETED) { tsx_cancel_timer(tsx, &tsx->timeout_timer); tsx_schedule_timer(tsx, &tsx->timeout_timer, &delay, - TRANSPORT_ERR_TIMER); + TRANSPORT_DISC_TIMER); } unlock_timer(tsx); }