diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index c41ed9b2e3..25ec1276fe 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -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; diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 8e2b1b483c..9121c53a55 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -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) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index a370b52442..c00d1aae1c 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -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; } } diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 1452a7cf0f..e3d287ddcd 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -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); } diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index 48ad579411..e567b615a9 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -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; } diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index d9e04528a8..5c5ee92218 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -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);