From 85ad1f83303564466f1a5779cf32fed03d43175c Mon Sep 17 00:00:00 2001 From: Alfonso Pinto Date: Thu, 25 Jan 2024 15:35:42 +0100 Subject: [PATCH 1/3] TEL-5885: fix DE-REGISTER (#244) --- src/mod/endpoints/mod_sofia/mod_sofia.c | 2 +- src/mod/endpoints/mod_sofia/sofia.c | 9 ++++++++- src/mod/endpoints/mod_sofia/sofia_glue.c | 2 +- src/mod/endpoints/mod_sofia/sofia_reg.c | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index a47d97fe34b..2ddce7611d3 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -3908,7 +3908,7 @@ static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t } stream->write_function(stream, "+OK\n"); } else if ((gateway_ptr = sofia_reg_find_gateway(gname))) { - if (gateway_ptr->state != REG_STATE_NOREG) { + if (gateway_ptr->state != REG_STATE_NOREG && gateway_ptr->state != REG_STATE_DOWN) { gateway_ptr->retry = 0; gateway_ptr->state = REG_STATE_UNREGISTER; stream->write_function(stream, "+OK\n"); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 08680dd8111..1646047ebd4 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -1513,9 +1513,16 @@ static void our_sofia_event_callback(nua_event_t event, } } - if (sofia_private && sofia_private != &mod_sofia_globals.destroy_private && sofia_private != &mod_sofia_globals.keep_private) { if (!zstr(sofia_private->gateway_name)) { + if (event == nua_r_unregister && status != 401 && status != 407) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Destroy handle after unregister for gateway %s.\n", sofia_private->gateway_name); + sofia_private_free(sofia_private); + nua_handle_bind(nh, NULL); + nua_handle_destroy(nh); + nh = NULL; + return; + } if (!(gateway = sofia_reg_find_gateway(sofia_private->gateway_name))) { return; } diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 65f29aeac83..a167c0cbf2c 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -2175,7 +2175,7 @@ void sofia_glue_gateway_list(sofia_profile_t *profile, switch_stream_handle_t *s void sofia_glue_del_gateway(sofia_gateway_t *gp) { if (!gp->deleted) { - if (gp->state != REG_STATE_NOREG) { + if (gp->state != REG_STATE_NOREG && gp->state != REG_STATE_DOWN) { gp->retry = 0; gp->state = REG_STATE_UNREGISTER; } diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 0c0f83c87ac..b693321c425 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -139,6 +139,7 @@ static void sofia_reg_kill_reg(sofia_gateway_t *gateway_ptr) if (gateway_ptr->state == REG_STATE_REGED || gateway_ptr->state == REG_STATE_UNREGISTER) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "UN-Registering %s\n", gateway_ptr->name); nua_unregister(gateway_ptr->nh, NUTAG_URL(gateway_ptr->register_url), NUTAG_REGISTRAR(gateway_ptr->register_proxy), TAG_END()); + return; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Destroying registration handle for %s\n", gateway_ptr->name); } From 41e4cdd1c47580a186c040a9593319289a6e6cdc Mon Sep 17 00:00:00 2001 From: dev-ryanc <46878298+dev-ryanc@users.noreply.github.com> Date: Tue, 30 Jan 2024 20:32:27 +0800 Subject: [PATCH 2/3] ENGDESK-27616: Support for sofia module to handle waiting for PRACK --- src/mod/endpoints/mod_sofia/mod_sofia.c | 58 ++++++++++++++++++++++++ src/mod/endpoints/mod_sofia/mod_sofia.h | 5 ++ src/mod/endpoints/mod_sofia/sofia.c | 38 ++++++++++++++++ src/mod/endpoints/mod_sofia/sofia_glue.c | 4 ++ 4 files changed, 105 insertions(+) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 2ddce7611d3..6206d5bca2d 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -448,6 +448,18 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) return SWITCH_STATUS_SUCCESS; } + if (switch_channel_var_true(channel, "apply_100rel_sync")) { + private_object_t *tech_pvt = switch_core_session_get_private(session); + switch_mutex_lock(tech_pvt->prack_mutex); + if (sofia_test_flag(tech_pvt, TFLAG_PRACK_LOCK)) { + sofia_clear_flag(tech_pvt, TFLAG_PRACK_LOCK); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, + "%s Received Hangup while waiting PRACK: release PRACK lock\n", switch_channel_get_name(channel)); + switch_thread_cond_signal(tech_pvt->prack_cond); + } + switch_mutex_unlock(tech_pvt->prack_mutex); + } + switch_mutex_lock(tech_pvt->sofia_mutex); @@ -1462,6 +1474,8 @@ static switch_status_t sofia_send_dtmf(switch_core_session_t *session, const swi return SWITCH_STATUS_SUCCESS; } +#define SIP_100REL_MIN_DIFF_PROGRESS_TIME 300 + static switch_status_t sofia_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) { switch_channel_t *channel = switch_core_session_get_channel(session); @@ -1494,6 +1508,50 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi tech_pvt->reply_contact = switch_core_session_sprintf(session, "%s;isfocus", tech_pvt->reply_contact); } + // TODO + // Temporary solution until sofia-sip has been patch + // Possible race condition if 1xx and 200 OK is sent + // immediately that may cause crash or will not wait + // for the prack before sending the final response. + if (switch_channel_var_true(channel, "apply_100rel_sync")) { + const char* message_str = "N/A"; + switch (msg->message_id) { + case SWITCH_MESSAGE_INDICATE_RINGING: + message_str = "RINGING"; + case SWITCH_MESSAGE_INDICATE_PROGRESS: + message_str = "PROGRESS"; + case SWITCH_MESSAGE_INDICATE_ANSWER: + message_str = "ANSWER"; + { + // PRACK timeout is also based on timer t1x64 + // to prevent deadlock, will need to time the + // lock based on the value of t1x64 + uint32_t t1x64 = tech_pvt->profile->timer_t1x64 ? tech_pvt->profile->timer_t1x64 : 32000; + switch_mutex_lock(tech_pvt->prack_mutex); + if (sofia_test_flag(tech_pvt, TFLAG_PRACK_LOCK)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, + "%s Waiting for incoming PRACK! (Blocking %s message)\n", switch_channel_get_name(channel), message_str); + if (switch_thread_cond_timedwait(tech_pvt->prack_cond, tech_pvt->prack_mutex, t1x64 * 1000) == SWITCH_STATUS_TIMEOUT) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, + "%s Timeout on waiting for PRACK! (Unblock %s message)\n", switch_channel_get_name(channel), message_str); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, + "%s Received PRACK! (Unblock %s message)\n", switch_channel_get_name(channel), message_str); + } + } else { + if (msg->message_id != SWITCH_MESSAGE_INDICATE_ANSWER) { + sofia_set_flag(tech_pvt, TFLAG_PRACK_LOCK); + } + } + switch_mutex_unlock(tech_pvt->prack_mutex); + } + break; + default: + break; + } + } + + /* ones that do not need to lock sofia mutex */ switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_KEEPALIVE: diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 9367f8273e4..708770ce553 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -320,6 +320,7 @@ typedef enum { PFLAG_TAGGED_ON_PRACK, PFLAG_SDP_MEDIA_STRICT_FMT, PFLAG_ALWAYS_BRIDGE_EARLY_MEDIA, + PFLAG_ENABLE_100REL_SYNC, /* No new flags below this line */ PFLAG_MAX } PFLAGS; @@ -373,6 +374,7 @@ typedef enum { TFLAG_KEEPALIVE, TFLAG_SKIP_EARLY, TFLAG_100_UEPOCH_SET, + TFLAG_PRACK_LOCK, /* No new flags below this line */ TFLAG_MAX } TFLAGS; @@ -927,6 +929,9 @@ struct private_object { switch_time_t last_audio_activity_signal_write; switch_time_t last_audio_inactivity_signal_write; uint8_t recovered_call_route_fixed; + + switch_mutex_t *prack_mutex; + switch_thread_cond_t *prack_cond; }; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 1646047ebd4..6eea2e22700 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -2618,6 +2618,26 @@ void sofia_event_callback(nua_event_t event, break; + case nua_i_prack: + if (sofia_private) { + switch_core_session_t *session; + if ((session = switch_core_session_locate(sofia_private->uuid))) { + switch_channel_t *channel = switch_core_session_get_channel(session); + if (switch_channel_var_true(channel, "apply_100rel_sync")) { + private_object_t *tech_pvt = switch_core_session_get_private(session); + switch_mutex_lock(tech_pvt->prack_mutex); + if (sofia_test_flag(tech_pvt, TFLAG_PRACK_LOCK)) { + sofia_clear_flag(tech_pvt, TFLAG_PRACK_LOCK); + switch_thread_cond_signal(tech_pvt->prack_cond); + } + switch_mutex_unlock(tech_pvt->prack_mutex); + } + switch_core_session_rwunlock(session); + } + } + + break; + default: break; @@ -5899,6 +5919,12 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { sofia_set_pflag(profile, PFLAG_DISABLE_100REL); } + } else if (!strcasecmp(var, "enable-100rel-sync")) { + if (switch_true(val)) { + sofia_set_pflag(profile, PFLAG_ENABLE_100REL_SYNC); + } else { + sofia_clear_pflag(profile, PFLAG_ENABLE_100REL_SYNC); + } } else if (!strcasecmp(var, "enable-compact-headers")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_SIPCOMPACT); @@ -11266,6 +11292,18 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia } } + if (sip && sip->sip_supported && !sofia_test_pflag(profile, PFLAG_DISABLE_100REL)) { + int supported_100rel = sip_has_feature(sip->sip_supported, "100rel"); + if (supported_100rel) { + const char *sync = switch_channel_get_variable(channel, "apply_100rel_sync"); + if (sync) { + switch_channel_set_variable(channel, "apply_100rel_sync", switch_true(sync) ? "true" : "false"); + } else if (sofia_test_pflag(profile, PFLAG_ENABLE_100REL_SYNC)) { + switch_channel_set_variable(channel, "apply_100rel_sync", "true"); + } + } + } + if (sofia_test_media_flag(profile, SCMF_REJECT_IPV6) && sip->sip_payload && sip->sip_payload->pl_data && switch_stristr("c=IN IP6", sip->sip_payload->pl_data)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Reject IPv6 media address!\n"); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index a167c0cbf2c..3cdc3747c47 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -55,6 +55,8 @@ private_object_t *sofia_glue_new_pvt(switch_core_session_t *session) private_object_t *tech_pvt = (private_object_t *) switch_core_session_alloc(session, sizeof(private_object_t)); switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session)); switch_mutex_init(&tech_pvt->sofia_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session)); + switch_mutex_init(&tech_pvt->prack_mutex, SWITCH_MUTEX_DEFAULT, switch_core_session_get_pool(session)); + switch_thread_cond_create(&tech_pvt->prack_cond, switch_core_session_get_pool(session)); return tech_pvt; } @@ -2393,6 +2395,8 @@ int sofia_recover_callback(switch_core_session_t *session) switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session)); switch_mutex_init(&tech_pvt->sofia_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session)); + switch_mutex_init(&tech_pvt->prack_mutex, SWITCH_MUTEX_DEFAULT, switch_core_session_get_pool(session)); + switch_thread_cond_create(&tech_pvt->prack_cond, switch_core_session_get_pool(session)); tech_pvt->mparams.remote_ip = (char *) switch_channel_get_variable(channel, "sip_network_ip"); tech_pvt->mparams.remote_port = atoi(switch_str_nil(switch_channel_get_variable(channel, "sip_network_port"))); From dc460deaa295c31efaae9c485243a41776a85237 Mon Sep 17 00:00:00 2001 From: dev-ryanc <46878298+dev-ryanc@users.noreply.github.com> Date: Tue, 13 Feb 2024 00:12:28 +0800 Subject: [PATCH 3/3] ENGDESK-28798: Fix issue during waiting for PRACK - Handle already process state for RINGING, PROGRESS and ANSWER when waiting for PRACK --- src/mod/endpoints/mod_sofia/mod_sofia.c | 82 +++++++++++++++++-------- 1 file changed, 56 insertions(+), 26 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 6206d5bca2d..d1ffd7891a1 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1474,8 +1474,6 @@ static switch_status_t sofia_send_dtmf(switch_core_session_t *session, const swi return SWITCH_STATUS_SUCCESS; } -#define SIP_100REL_MIN_DIFF_PROGRESS_TIME 300 - static switch_status_t sofia_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) { switch_channel_t *channel = switch_core_session_get_channel(session); @@ -1515,40 +1513,72 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi // for the prack before sending the final response. if (switch_channel_var_true(channel, "apply_100rel_sync")) { const char* message_str = "N/A"; + uint32_t channel_flag = CF_FLAG_MAX; switch (msg->message_id) { - case SWITCH_MESSAGE_INDICATE_RINGING: - message_str = "RINGING"; + case SWITCH_MESSAGE_INDICATE_RINGING: + { + message_str = "RINGING"; + if (!sofia_test_flag(tech_pvt, TFLAG_BYE) && !switch_channel_test_flag(channel, CF_RING_READY) && + !switch_channel_test_flag(channel, CF_EARLY_MEDIA) && !switch_channel_test_flag(channel, CF_ANSWERED)) { + channel_flag = CF_RING_READY; + } + + } + break; case SWITCH_MESSAGE_INDICATE_PROGRESS: - message_str = "PROGRESS"; + { + message_str = "PROGRESS"; + if (!sofia_test_flag(tech_pvt, TFLAG_BYE) && !switch_channel_test_flag(channel, CF_EARLY_MEDIA) && !switch_channel_test_flag(channel, CF_ANSWERED)) { + channel_flag = CF_EARLY_MEDIA; + } + } case SWITCH_MESSAGE_INDICATE_ANSWER: - message_str = "ANSWER"; { - // PRACK timeout is also based on timer t1x64 - // to prevent deadlock, will need to time the - // lock based on the value of t1x64 - uint32_t t1x64 = tech_pvt->profile->timer_t1x64 ? tech_pvt->profile->timer_t1x64 : 32000; - switch_mutex_lock(tech_pvt->prack_mutex); - if (sofia_test_flag(tech_pvt, TFLAG_PRACK_LOCK)) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, - "%s Waiting for incoming PRACK! (Blocking %s message)\n", switch_channel_get_name(channel), message_str); - if (switch_thread_cond_timedwait(tech_pvt->prack_cond, tech_pvt->prack_mutex, t1x64 * 1000) == SWITCH_STATUS_TIMEOUT) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, - "%s Timeout on waiting for PRACK! (Unblock %s message)\n", switch_channel_get_name(channel), message_str); - } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, - "%s Received PRACK! (Unblock %s message)\n", switch_channel_get_name(channel), message_str); - } - } else { - if (msg->message_id != SWITCH_MESSAGE_INDICATE_ANSWER) { - sofia_set_flag(tech_pvt, TFLAG_PRACK_LOCK); - } + message_str = "ANSWER"; + if (!sofia_test_flag(tech_pvt, TFLAG_BYE) && !switch_channel_test_flag(channel, CF_ANSWERED)) { + channel_flag = CF_ANSWERED; } - switch_mutex_unlock(tech_pvt->prack_mutex); } break; default: break; } + + if (channel_flag != CF_FLAG_MAX) { + switch (msg->message_id) { + case SWITCH_MESSAGE_INDICATE_RINGING: + case SWITCH_MESSAGE_INDICATE_PROGRESS: + case SWITCH_MESSAGE_INDICATE_ANSWER: + { + // PRACK timeout is also based on timer t1x64 + // to prevent deadlock, will need to time the + // lock based on the value of t1x64 + uint32_t t1x64 = tech_pvt->profile->timer_t1x64 ? tech_pvt->profile->timer_t1x64 : 32000; + switch_mutex_lock(tech_pvt->prack_mutex); + if (sofia_test_flag(tech_pvt, TFLAG_PRACK_LOCK)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, + "%s Waiting for incoming PRACK! (Blocking %s message)\n", switch_channel_get_name(channel), message_str); + if (switch_thread_cond_timedwait(tech_pvt->prack_cond, tech_pvt->prack_mutex, t1x64 * 1000) == SWITCH_STATUS_TIMEOUT) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, + "%s Timeout on waiting for PRACK! (Unblock %s message)\n", switch_channel_get_name(channel), message_str); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, + "%s Received PRACK! (Unblock %s message)\n", switch_channel_get_name(channel), message_str); + } + } else { + if (msg->message_id != SWITCH_MESSAGE_INDICATE_ANSWER) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, + "%s Expecting incoming PRACK! (Trigger by %s message)\n", switch_channel_get_name(channel), message_str); + sofia_set_flag(tech_pvt, TFLAG_PRACK_LOCK); + } + } + switch_mutex_unlock(tech_pvt->prack_mutex); + } + break; + default: + break; + } + } }