When using multiple profiles and with the same gateway name on both, freeswitch mixes up the two gateways and is unable to restart any of them unless restarting the profile.

This also effects when moving a gateway from one profile to the other.

What this changes

- Do not remove a gateway from the hash unless it matches the profile.
- Fix `sofia profile <ProfileName> killgw <GatewayName>` to delete the gateway by using the qualified name `ProfileName::GatewayName` so we only delete a gateway on profile `ProfileName`.
- When loading/reloading a gateway, add it with the unqualified name to the hash if there is no other gateway with that name on another profile. (for example when `profileA` and `profileB` have a gateway `gw1`, `profileA` is first in the list, so we add `gw1` from `profileA` to the hash qualified and unqualified. for `profileB` it is added only qualified. Now, `sofia profile profileA killgw gw1` removes the gateway from `profileA`, so executing `sofia profile profileB startgw gw1` will now add `gw1` from `profileB` to the hash using the unqualified name).
- Fix `sofia profile ProfileName register|unregister GatewayName` to be profile specific.

- Ensure throughout sofia whenever we lookup a gateway related to an ongoing call, to also check the profile that it matches.
This commit is contained in:
Aron Podrigal 2021-05-10 18:27:22 -05:00
parent 53abb53f2b
commit ca017c8f73
6 changed files with 112 additions and 53 deletions

View File

@ -422,16 +422,17 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session)
const char *gateway_name = NULL;
sofia_gateway_t *gateway_ptr = NULL;
if ((gateway_name = switch_channel_get_variable(channel, "sip_gateway_name"))) {
gateway_ptr = sofia_reg_find_gateway(gateway_name);
}
if (!tech_pvt) {
return SWITCH_STATUS_SUCCESS;
}
switch_mutex_lock(tech_pvt->sofia_mutex);
if (tech_pvt->gateway_name && tech_pvt->profile) {
gateway_name = tech_pvt->gateway_name;
gateway_ptr = sofia_reg_find_profile_gateway(tech_pvt->profile, gateway_name);
}
if (!switch_channel_test_flag(channel, CF_ANSWERED)) {
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
@ -3567,7 +3568,7 @@ static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t
sofia_glue_del_every_gateway(profile);
stream->write_function(stream, "+OK every gateway marked for deletion.\n");
} else {
if ((gateway_ptr = sofia_reg_find_gateway(argv[2]))) {
if ((gateway_ptr = sofia_reg_find_profile_gateway(profile, argv[2]))) {
sofia_glue_del_gateway(gateway_ptr);
sofia_reg_release_gateway(gateway_ptr);
stream->write_function(stream, "+OK gateway marked for deletion.\n");
@ -3680,7 +3681,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))) {
} else if ((gateway_ptr = sofia_reg_find_profile_gateway(profile, gname))) {
if (gateway_ptr->state != REG_STATE_NOREG) {
gateway_ptr->retry = 0;
gateway_ptr->state = REG_STATE_UNREGED;
@ -3713,7 +3714,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))) {
} else if ((gateway_ptr = sofia_reg_find_profile_gateway(profile, gname))) {
if (gateway_ptr->state != REG_STATE_NOREG) {
gateway_ptr->retry = 0;
gateway_ptr->state = REG_STATE_UNREGISTER;

View File

@ -1121,6 +1121,9 @@ switch_status_t sofia_reg_add_gateway(sofia_profile_t *profile, const char *key,
sofia_gateway_t *sofia_reg_find_gateway__(const char *file, const char *func, int line, const char *key);
#define sofia_reg_find_gateway(x) sofia_reg_find_gateway__(__FILE__, __SWITCH_FUNC__, __LINE__, x)
sofia_gateway_t *sofia_reg_find_profile_gateway__(const char *file, const char *func, int line, sofia_profile_t *profile, const char *key);
#define sofia_reg_find_profile_gateway(p, x) sofia_reg_find_profile_gateway__(__FILE__, __SWITCH_FUNC__, __LINE__, p, x)
sofia_gateway_t *sofia_reg_find_gateway_by_realm__(const char *file, const char *func, int line, const char *key);
#define sofia_reg_find_gateway_by_realm(x) sofia_reg_find_gateway_by_realm__(__FILE__, __SWITCH_FUNC__, __LINE__, x)

View File

@ -747,7 +747,7 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status,
}
if (!(gateway = sofia_reg_find_gateway(sofia_private->gateway_name))) {
if (!(gateway = sofia_reg_find_profile_gateway(profile, sofia_private->gateway_name))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Gateway information missing\n");
goto error;
}
@ -1491,7 +1491,7 @@ 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 (!(gateway = sofia_reg_find_gateway(sofia_private->gateway_name))) {
if (!(gateway = sofia_reg_find_profile_gateway(profile,sofia_private->gateway_name))) {
return;
}
} else if (!zstr(sofia_private->uuid)) {
@ -1520,7 +1520,7 @@ static void our_sofia_event_callback(nua_event_t event,
}
if (tech_pvt->gateway_name) {
gateway = sofia_reg_find_gateway(tech_pvt->gateway_name);
gateway = sofia_reg_find_profile_gateway(profile,tech_pvt->gateway_name);
}
if (channel && switch_channel_down(channel)) {
@ -2099,7 +2099,7 @@ static void our_sofia_event_callback(nua_event_t event,
if (sofia_private && !zstr(sofia_private->gateway_name)) {
sofia_gateway_t *gateway = NULL;
if ((gateway = sofia_reg_find_gateway(sofia_private->gateway_name))) {
if ((gateway = sofia_reg_find_profile_gateway(profile,sofia_private->gateway_name))) {
gateway->state = REG_STATE_FAILED;
gateway->failure_status = status;
sofia_reg_release_gateway(gateway);
@ -3790,8 +3790,12 @@ static void parse_gateways(sofia_profile_t *profile, switch_xml_t gateways_tag,
}
switch_mutex_lock(mod_sofia_globals.hash_mutex);
if (switch_core_hash_find(mod_sofia_globals.gateway_hash, name) && (gp = switch_core_hash_find(mod_sofia_globals.gateway_hash, pkey)) && !gp->deleted) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate gateway '%s'\n", name);
if ((gp = switch_core_hash_find(mod_sofia_globals.gateway_hash, pkey)) && !gp->deleted) {
if (sofia_reg_add_gateway(profile, name, gp) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Added gateway to hash '%s'\n", name);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate gateway '%s'\n", name);
}
switch_mutex_unlock(mod_sofia_globals.hash_mutex);
free(pkey);
goto skip;
@ -4219,7 +4223,9 @@ static void parse_gateways(sofia_profile_t *profile, switch_xml_t gateways_tag,
parse_gateway_subscriptions(profile, gateway, gw_subs_tag);
}
sofia_reg_add_gateway(profile, gateway->name, gateway);
if (sofia_reg_add_gateway(profile, gateway->name, gateway) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Skipped gateway '%s' on profile '%s'\n", gateway->name, profile->name);
}
}
@ -6446,7 +6452,7 @@ static void sofia_handle_sip_r_options(switch_core_session_t *session, int statu
switch_bool_t do_fire_gateway_state_event = SWITCH_FALSE;
if (sofia_private && !zstr(sofia_private->gateway_name)) {
gateway = sofia_reg_find_gateway(sofia_private->gateway_name);
gateway = sofia_reg_find_profile_gateway(profile,sofia_private->gateway_name);
sofia_private->destroy_me = 1;
}
@ -11309,13 +11315,13 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia
sofia_gateway_t *gateway = NULL;
char *extension = NULL;
if (gw_name && ((gateway = sofia_reg_find_gateway(gw_name)))) {
if (gw_name && ((gateway = sofia_reg_find_profile_gateway(profile, gw_name)))) {
gw_param_name = NULL;
extension = gateway->extension;
}
if (!gateway && gw_param_name) {
if ((gateway = sofia_reg_find_gateway(gw_param_name))) {
if ((gateway = sofia_reg_find_profile_gateway(profile, gw_param_name))) {
extension = gateway->real_extension;
}
}

View File

@ -2265,9 +2265,16 @@ void sofia_glue_del_profile(sofia_profile_t *profile)
for (gp = profile->gateways; gp; gp = gp->next) {
char *pkey = switch_mprintf("%s::%s", profile->name, gp->name);
// Only delete from hash if this gateway matches ours.
if (switch_core_hash_find(mod_sofia_globals.gateway_hash, gp->name) == gp) {
switch_core_hash_delete(mod_sofia_globals.gateway_hash, gp->name);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removing gateway on profile %s from hash %s.\n", profile->name, gp->name);
}
if (switch_core_hash_find(mod_sofia_globals.gateway_hash, pkey) == gp) {
switch_core_hash_delete(mod_sofia_globals.gateway_hash, pkey);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removing gateway on profile %s from hash %s.\n", profile->name, pkey);
}
switch_core_hash_delete(mod_sofia_globals.gateway_hash, gp->name);
switch_core_hash_delete(mod_sofia_globals.gateway_hash, pkey);
switch_safe_free(pkey);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "deleted gateway %s from profile %s\n", gp->name, profile->name);
}

View File

@ -4478,7 +4478,7 @@ void sofia_presence_handle_sip_r_subscribe(int status,
}
if (!(gateway = sofia_reg_find_gateway(sofia_private->gateway_name))) {
if (!(gateway = sofia_reg_find_profile_gateway(profile,sofia_private->gateway_name))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Gateway information missing\n");
return;
}

View File

@ -322,13 +322,15 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now)
switch_mutex_lock(profile->gw_mutex);
for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
if (gateway_ptr->deleted) {
char *pkey = switch_mprintf("%s::%s", profile->name, gateway_ptr->name);
switch_assert(pkey);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removing gateway on profile %s from hash %s.\n", profile->name, pkey);
switch_core_hash_delete(mod_sofia_globals.gateway_hash, pkey);
free(pkey);
if ((check = switch_core_hash_find(mod_sofia_globals.gateway_hash, gateway_ptr->name)) && check == gateway_ptr) {
char *pkey = switch_mprintf("%s::%s", profile->name, gateway_ptr->name);
switch_assert(pkey);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removing gateway %s from hash.\n", pkey);
switch_core_hash_delete(mod_sofia_globals.gateway_hash, pkey);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removing gateway on profile %s from hash %s.\n", profile->name, gateway_ptr->name);
switch_core_hash_delete(mod_sofia_globals.gateway_hash, gateway_ptr->name);
free(pkey);
}
if (gateway_ptr->state == REG_STATE_NOREG || gateway_ptr->state == REG_STATE_DOWN) {
@ -2581,14 +2583,13 @@ void sofia_reg_handle_sip_r_register(int status,
{
sofia_gateway_t *gateway = NULL;
if (!sofia_private) {
if (!profile || !sofia_private) {
nua_handle_destroy(nh);
return;
}
if (!zstr(sofia_private->gateway_name)) {
gateway = sofia_reg_find_gateway(sofia_private->gateway_name);
gateway = sofia_reg_find_profile_gateway(profile, sofia_private->gateway_name);
}
if (gateway) {
@ -2760,7 +2761,7 @@ void sofia_reg_handle_sip_r_challenge(int status,
if (!gateway) {
if (gw_name) {
var_gateway = sofia_reg_find_gateway((char *) gw_name);
var_gateway = sofia_reg_find_profile_gateway(profile,(char *) gw_name);
}
@ -2774,13 +2775,17 @@ void sofia_reg_handle_sip_r_challenge(int status,
if ((p = strchr(rb, '"'))) {
*p = '\0';
}
if (!(var_gateway = sofia_reg_find_gateway(rb))) {
if (!(var_gateway = sofia_reg_find_profile_gateway(profile, rb))) {
var_gateway = sofia_reg_find_gateway_by_realm(rb);
if(var_gateway && var_gateway->profile != profile) {
sofia_reg_release_gateway(var_gateway);
var_gateway = NULL;
}
}
}
if (!var_gateway && sip && sip->sip_to) {
var_gateway = sofia_reg_find_gateway(sip->sip_to->a_url->url_host);
var_gateway = sofia_reg_find_profile_gateway(profile,sip->sip_to->a_url->url_host);
}
if (var_gateway) {
@ -3490,7 +3495,7 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile,
name = "anonymous";
}
if ((gateway_ptr = sofia_reg_find_gateway(name))) {
if ((gateway_ptr = sofia_reg_find_profile_gateway(profile, name))) {
reg_state_t ostate = gateway_ptr->state;
gateway_ptr->retry = 0;
if (exptime) {
@ -3516,7 +3521,7 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile,
argc = switch_separate_string(mydata, ',', argv, (sizeof(argv) / sizeof(argv[0])));
for (x = 0; x < argc; x++) {
if ((gateway_ptr = sofia_reg_find_gateway((char *) argv[x]))) {
if ((gateway_ptr = sofia_reg_find_profile_gateway(profile,(char *) argv[x]))) {
reg_state_t ostate = gateway_ptr->state;
gateway_ptr->retry = 0;
if (exptime) {
@ -3619,6 +3624,26 @@ sofia_gateway_t *sofia_reg_find_gateway__(const char *file, const char *func, in
}
sofia_gateway_t *sofia_reg_find_profile_gateway__(const char *file, const char *func, int line, sofia_profile_t *profile, const char *key) {
char *pkey = NULL;
sofia_gateway_t *gw = NULL;
if (!strstr(key, "::")) {
pkey = switch_mprintf("%s::%s", profile->name, key);
key = pkey;
}
gw = sofia_reg_find_gateway__(file, func, line, key);
switch_safe_free(pkey);
if (gw) {
if (gw->profile != profile) {
sofia_reg_release_gateway__(file, func, line, gw);
gw = NULL;
}
}
return gw;
}
sofia_gateway_t *sofia_reg_find_gateway_by_realm__(const char *file, const char *func, int line, const char *key)
{
sofia_gateway_t *gateway = NULL;
@ -3684,42 +3709,59 @@ switch_status_t sofia_reg_add_gateway(sofia_profile_t *profile, const char *key,
{
switch_status_t status = SWITCH_STATUS_FALSE;
char *pkey = switch_mprintf("%s::%s", profile->name, key);
sofia_gateway_t *gp;
switch_mutex_lock(profile->gw_mutex);
gateway->next = profile->gateways;
profile->gateways = gateway;
switch_mutex_unlock(profile->gw_mutex);
sofia_gateway_t *unqualified_gw;
sofia_gateway_t *qualified_gw;
switch_mutex_lock(mod_sofia_globals.hash_mutex);
if ((gp = switch_core_hash_find(mod_sofia_globals.gateway_hash, key))) {
if (gp->deleted) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removing deleted gateway from hash.\n");
switch_core_hash_delete(mod_sofia_globals.gateway_hash, gp->name);
switch_core_hash_delete(mod_sofia_globals.gateway_hash, pkey);
if ((unqualified_gw = switch_core_hash_find(mod_sofia_globals.gateway_hash, key))) {
// regardless of the profile this belongs to, if it has been deleted, we remove it so we can add ours.
if (unqualified_gw->deleted) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removing deleted gateway from hash %s.\n", key);
switch_core_hash_delete(mod_sofia_globals.gateway_hash, key);
unqualified_gw = NULL;
}
}
if (!switch_core_hash_find(mod_sofia_globals.gateway_hash, key) && !switch_core_hash_find(mod_sofia_globals.gateway_hash, pkey)) {
status = switch_core_hash_insert(mod_sofia_globals.gateway_hash, key, gateway);
status |= switch_core_hash_insert(mod_sofia_globals.gateway_hash, pkey, gateway);
if (status != SWITCH_STATUS_SUCCESS) {
status = SWITCH_STATUS_FALSE;
if ((qualified_gw = switch_core_hash_find(mod_sofia_globals.gateway_hash, pkey))) {
if (qualified_gw->profile == profile) {
if (qualified_gw->deleted) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Re-adding gateway into hash %s.\n", pkey);
status = switch_core_hash_insert(mod_sofia_globals.gateway_hash, pkey, gateway);
}
} else {
qualified_gw = NULL;
}
} else {
status = SWITCH_STATUS_FALSE;
status = switch_core_hash_insert(mod_sofia_globals.gateway_hash, pkey, gateway);
qualified_gw = gateway;
}
if (status == SWITCH_STATUS_SUCCESS) {
switch_mutex_lock(profile->gw_mutex);
gateway->next = profile->gateways;
profile->gateways = gateway;
switch_mutex_unlock(profile->gw_mutex);
}
// insert namespaced version profile::gateway
if (qualified_gw) {
// insert un-namespaced name if it does not exist
if (!unqualified_gw) {
status = switch_core_hash_insert(mod_sofia_globals.gateway_hash, key, gateway);
} else {
status = SWITCH_STATUS_INUSE;
}
}
switch_mutex_unlock(mod_sofia_globals.hash_mutex);
free(pkey);
if (status == SWITCH_STATUS_SUCCESS) {
switch_event_t *s_event;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Added gateway '%s' to profile '%s'\n", gateway->name, gateway->profile->name);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Added gateway '%s' for profile '%s'\n", gateway->name, gateway->profile->name);
if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_GATEWAY_ADD) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "Gateway", gateway->name);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile-name", gateway->profile->name);