Skip to content

Commit

Permalink
ENGDESK-27616: Support for sofia module to handle waiting for PRACK
Browse files Browse the repository at this point in the history
  • Loading branch information
dev-ryanc authored and minhtuan1407-telnyx committed Jan 30, 2024
1 parent beecace commit ade1129
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 0 deletions.
58 changes: 58 additions & 0 deletions src/mod/endpoints/mod_sofia/mod_sofia.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);


Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand Down
5 changes: 5 additions & 0 deletions src/mod/endpoints/mod_sofia/mod_sofia.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
};


Expand Down
38 changes: 38 additions & 0 deletions src/mod/endpoints/mod_sofia/sofia.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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");
Expand Down
4 changes: 4 additions & 0 deletions src/mod/endpoints/mod_sofia/sofia_glue.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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")));
Expand Down

0 comments on commit ade1129

Please sign in to comment.