diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 983f04177a..dfdde83db0 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -244,6 +244,10 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) switch_clear_flag_locked(tech_pvt, TFLAG_IO); + switch_mutex_lock(tech_pvt->profile->flag_mutex); + tech_pvt->profile->inuse--; + switch_mutex_unlock(tech_pvt->profile->flag_mutex); + if (tech_pvt->sofia_private) { *tech_pvt->sofia_private->uuid = '\0'; } @@ -275,7 +279,6 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) assert(channel != NULL); tech_pvt = (private_object_t *) switch_core_session_get_private(session); - assert(tech_pvt != NULL); if (!switch_test_flag(tech_pvt, TFLAG_ANS) && !switch_channel_test_flag(channel, CF_OUTBOUND)) { switch_set_flag_locked(tech_pvt, TFLAG_ANS); @@ -314,9 +317,11 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) } } } + nua_respond(tech_pvt->nh, SIP_200_OK, SIPTAG_CONTACT_STR(tech_pvt->profile->url), SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_END()); + } return SWITCH_STATUS_SUCCESS; @@ -336,7 +341,7 @@ static switch_status_t sofia_read_video_frame(switch_core_session_t *session, sw tech_pvt = (private_object_t *) switch_core_session_get_private(session); assert(tech_pvt != NULL); - if (switch_test_flag(tech_pvt, TFLAG_HUP)) { + if (switch_test_flag(tech_pvt, TFLAG_HUP) || !sofia_test_pflag(tech_pvt->profile, PFLAG_RUNNING)) { return SWITCH_STATUS_FALSE; } @@ -408,7 +413,7 @@ static switch_status_t sofia_write_video_frame(switch_core_session_t *session, s } } - if (switch_test_flag(tech_pvt, TFLAG_HUP)) { + if (switch_test_flag(tech_pvt, TFLAG_HUP) || !sofia_test_pflag(tech_pvt->profile, PFLAG_RUNNING)) { return SWITCH_STATUS_FALSE; } @@ -440,7 +445,7 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f tech_pvt = (private_object_t *) switch_core_session_get_private(session); assert(tech_pvt != NULL); - if (switch_test_flag(tech_pvt, TFLAG_HUP)) { + if (switch_test_flag(tech_pvt, TFLAG_HUP) || !sofia_test_pflag(tech_pvt->profile, PFLAG_RUNNING)) { return SWITCH_STATUS_FALSE; } @@ -535,7 +540,7 @@ static switch_status_t sofia_write_frame(switch_core_session_t *session, switch_ } } - if (switch_test_flag(tech_pvt, TFLAG_HUP)) { + if (switch_test_flag(tech_pvt, TFLAG_HUP) || !sofia_test_pflag(tech_pvt->profile, PFLAG_RUNNING)) { return SWITCH_STATUS_FALSE; } @@ -880,6 +885,126 @@ static switch_status_t sofia_receive_event(switch_core_session_t *session, switc return SWITCH_STATUS_SUCCESS; } +typedef switch_status_t (*sofia_command_t) (char **argv, int argc, switch_stream_handle_t *stream); + + +static switch_status_t cmd_status(char **argv, int argc, switch_stream_handle_t *stream) +{ + sofia_profile_t *profile = NULL; + switch_hash_index_t *hi; + void *val; + int c = 0; + + switch_mutex_lock(mod_sofia_globals.hash_mutex); + for (hi = switch_hash_first(switch_hash_pool_get(mod_sofia_globals.profile_hash), mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) { + switch_hash_this(hi, NULL, NULL, &val); + profile = (sofia_profile_t *) val; + if (sofia_test_pflag(profile, PFLAG_RUNNING)) { + stream->write_function(stream, "Profile %s\n", profile->name); + c++; + } + } + switch_mutex_unlock(mod_sofia_globals.hash_mutex); + stream->write_function(stream, "%d profiles\n", c); + return SWITCH_STATUS_SUCCESS; + +} + +static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t *stream) +{ + sofia_profile_t *profile = NULL; + char *profile_name = argv[0]; + + if (argc < 2) { + stream->write_function(stream, "Invalid Args!\n"); + return SWITCH_STATUS_SUCCESS; + } + + if (!strcasecmp(argv[1], "start")) { + if (config_sofia(1, argv[0]) == SWITCH_STATUS_SUCCESS) { + stream->write_function(stream, "%s started successfully\n", argv[0]); + } else { + stream->write_function(stream, "Failure starting %s\n", argv[0]); + } + return SWITCH_STATUS_SUCCESS; + } + + if (switch_strlen_zero(profile_name) || !(profile = sofia_glue_find_profile(profile_name))) { + stream->write_function(stream, "Invalid Profile [%s]", switch_str_nil(profile_name)); + return SWITCH_STATUS_SUCCESS; + } + + if (!strcasecmp(argv[1], "stop")) { + sofia_clear_pflag_locked(profile, PFLAG_RUNNING); + stream->write_function(stream, "stopping: %s", profile->name); + } + + if (profile) { + switch_thread_rwlock_unlock(profile->rwlock); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t sofia_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +{ + char *argv[1024] = { 0 }; + int argc = 0; + char *mycmd = NULL; + switch_status_t status = SWITCH_STATUS_SUCCESS; + sofia_command_t func = NULL; + int lead = 1; + const char *usage_string = "USAGE:\n" + "--------------------------------------------------------------------------------\n" + "sofia help\n" + "sofia profile \n" + "sofia status\n" + "--------------------------------------------------------------------------------\n"; + + if (isession) { + return SWITCH_STATUS_FALSE; + } + + if (switch_strlen_zero(cmd)) { + stream->write_function(stream, "%s", usage_string); + goto done; + } + + if (!(mycmd = strdup(cmd))) { + status = SWITCH_STATUS_MEMERR; + goto done; + } + + if (!(argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) { + stream->write_function(stream, "%s", usage_string); + goto done; + } + + if (!strcasecmp(argv[0], "profile")) { + func = cmd_profile; + } else if (!strcasecmp(argv[0], "status")) { + func = cmd_status; + } else if (!strcasecmp(argv[0], "help")) { + stream->write_function(stream, "%s", usage_string); + goto done; + } + + if (func) { + status = func(&argv[lead], argc - lead, stream); + } else { + stream->write_function(stream, "Unknown Command [%s]\n", argv[0]); + } + + + done: + + switch_safe_free(mycmd); + + return status; + + +} + static const switch_io_routines_t sofia_io_routines = { /*.outgoing_channel */ sofia_outgoing_channel, /*.read_frame */ sofia_read_frame, @@ -928,6 +1053,14 @@ static const switch_management_interface_t sofia_management_interface = { /*.management_function */ sofia_manage }; +static switch_api_interface_t sofia_api_interface = { + /*.interface_name */ "sofia", + /*.desc */ "Sofia Controls", + /*.function */ sofia_function, + /*.syntax */ " ", + /*.next */ NULL +}; + static const switch_loadable_module_interface_t sofia_module_interface = { /*.module_name */ modname, /*.endpoint_interface */ &sofia_endpoint_interface, @@ -935,7 +1068,7 @@ static const switch_loadable_module_interface_t sofia_module_interface = { /*.dialplan_interface */ NULL, /*.codec_interface */ NULL, /*.application_interface */ NULL, - /*.api_interface */ NULL, + /*.api_interface */ &sofia_api_interface, /*.file_interface */ NULL, /*.speech_interface */ NULL, /*.directory_interface */ NULL, @@ -954,7 +1087,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; switch_core_session_t *nsession; char *data, *profile_name, *dest; - sofia_profile_t *profile; + sofia_profile_t *profile = NULL; switch_caller_profile_t *caller_profile = NULL; private_object_t *tech_pvt = NULL; switch_channel_t *nchannel; @@ -979,7 +1112,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session if (!strncasecmp(profile_name, "gateway", 7)) { char *gw; - outbound_reg_t *gateway_ptr; + sofia_gateway_t *gateway_ptr = NULL; if (!(gw = strchr(profile_name, '/'))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL\n"); @@ -1016,6 +1149,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session tech_pvt->dest = switch_core_session_sprintf(nsession, "sip:%s", dest); } tech_pvt->invite_contact = switch_core_session_strdup(nsession, gateway_ptr->register_contact); + sofia_reg_release_gateway(gateway_ptr); } else { if (!(dest = strchr(profile_name, '/'))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL\n"); @@ -1102,6 +1236,10 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session } done: + if (profile) { + switch_thread_rwlock_unlock(profile->rwlock); + } + return cause; } @@ -1133,7 +1271,7 @@ SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_mod switch_core_hash_init(&mod_sofia_globals.gateway_hash, module_pool); switch_mutex_init(&mod_sofia_globals.hash_mutex, SWITCH_MUTEX_NESTED, module_pool); - if (config_sofia(0) != SWITCH_STATUS_SUCCESS) { + if (config_sofia(0, NULL) != SWITCH_STATUS_SUCCESS) { return SWITCH_STATUS_GENERR; } diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 10c07a80b0..327d5041cb 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -47,8 +47,8 @@ static const char modname[] = "mod_sofia"; static const switch_state_handler_table_t noop_state_handler = { 0 }; -struct outbound_reg; -typedef struct outbound_reg outbound_reg_t; +struct sofia_gateway; +typedef struct sofia_gateway sofia_gateway_t; struct sofia_profile; typedef struct sofia_profile sofia_profile_t; @@ -82,7 +82,7 @@ typedef struct private_object private_object_t; struct sofia_private { char uuid[SWITCH_UUID_FORMATTED_LENGTH + 1]; - outbound_reg_t *gateway; + sofia_gateway_t *gateway; su_home_t *home; }; @@ -109,7 +109,8 @@ typedef enum { PFLAG_PRESENCE = (1 << 4), PFLAG_PASS_RFC2833 = (1 << 5), PFLAG_DISABLE_TRANSCODING = (1 << 6), - PFLAG_REWRITE_TIMESTAMPS = (1 << 7) + PFLAG_REWRITE_TIMESTAMPS = (1 << 7), + PFLAG_RUNNING = (1 << 8) } PFLAGS; typedef enum { @@ -170,7 +171,7 @@ typedef enum { REG_STATE_NOREG } reg_state_t; -struct outbound_reg { +struct sofia_gateway { sofia_private_t *sofia_private; nua_handle_t *nh; sofia_profile_t *profile; @@ -191,7 +192,7 @@ struct outbound_reg { uint32_t flags; reg_state_t state; switch_memory_pool_t *pool; - struct outbound_reg *next; + struct sofia_gateway *next; }; @@ -229,11 +230,14 @@ struct sofia_profile { uint32_t codec_flags; switch_mutex_t *ireg_mutex; switch_mutex_t *gateway_mutex; - outbound_reg_t *gateways; + sofia_gateway_t *gateways; su_home_t *home; switch_hash_t *profile_hash; switch_hash_t *chat_hash; switch_core_db_t *master_db; + switch_thread_rwlock_t *rwlock; + switch_mutex_t *flag_mutex; + uint32_t inuse; #ifdef SWITCH_HAVE_ODBC char *odbc_dsn; char *odbc_user; @@ -350,6 +354,17 @@ typedef enum { AUTH_STALE, } auth_res_t; + +#define sofia_test_pflag(obj, flag) ((obj)->pflags & flag) +#define sofia_set_pflag(obj, flag) (obj)->pflags |= (flag) +#define sofia_set_pflag_locked(obj, flag) assert(obj->flag_mutex != NULL);\ +switch_mutex_lock(obj->flag_mutex);\ +(obj)->pflags |= (flag);\ +switch_mutex_unlock(obj->flag_mutex); +#define sofia_clear_pflag_locked(obj, flag) switch_mutex_lock(obj->flag_mutex); (obj)->pflags &= ~(flag); switch_mutex_unlock(obj->flag_mutex); +#define sofia_clear_pflag(obj, flag) (obj)->pflags &= ~(flag) +#define sofia_copy_pflags(dest, src, flags) (dest)->pflags &= ~(flags); (dest)->pflags |= ((src)->pflags & (flags)) + /* Function Prototypes */ /*************************************************************************************************************************************************************/ @@ -398,7 +413,7 @@ void event_handler(switch_event_t *event); void sofia_presence_event_handler(switch_event_t *event); void sofia_presence_mwi_event_handler(switch_event_t *event); void sofia_presence_cancel(void); -switch_status_t config_sofia(int reload); +switch_status_t config_sofia(int reload, char *profile_name); auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile, sip_authorization_t const *authorization, const char *regstr, char *np, size_t nplen, char *ip); void sofia_reg_handle_sip_r_challenge(int status, char const *phrase, @@ -427,8 +442,8 @@ void sofia_reg_check_expire(sofia_profile_t *profile, time_t now); void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now); void sofia_reg_unregister(sofia_profile_t *profile); switch_status_t sofia_glue_ext_address_lookup(char **ip, switch_port_t *port, char *sourceip, switch_memory_pool_t *pool); -outbound_reg_t *sofia_reg_find_gateway(char *key); -void sofia_reg_add_gateway(char *key, outbound_reg_t *gateway); +sofia_gateway_t *sofia_reg_find_gateway(char *key); +void sofia_reg_add_gateway(char *key, sofia_gateway_t *gateway); void sofia_glue_pass_sdp(private_object_t *tech_pvt, char *sdp); int sofia_glue_get_user_host(char *in, char **user, char **host); switch_call_cause_t sofia_glue_sip_cause_to_freeswitch(int status); @@ -449,3 +464,4 @@ switch_bool_t sofia_glue_execute_sql_callback(sofia_profile_t *profile, void *pdata); char *sofia_glue_execute_sql2str(sofia_profile_t *profile, switch_mutex_t *mutex, char *sql, char *resbuf, size_t len); void sofia_glue_check_video_codecs(private_object_t *tech_pvt); +void sofia_reg_release_gateway(sofia_gateway_t *gateway); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 8bb8f785b8..0499a7ca78 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -70,7 +70,7 @@ void sofia_event_callback(nua_event_t event, } } - + if (status != 100 && status != 200) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "event [%s] status [%d][%s] session: %s\n", nua_event_name(event), status, phrase, session ? switch_channel_get_name(channel) : "n/a"); @@ -110,6 +110,10 @@ void sofia_event_callback(nua_event_t event, switch (event) { case nua_r_shutdown: + if (status >= 200) { + su_root_break(profile->s_root); + } + break; case nua_r_get_params: case nua_r_invite: case nua_r_unregister: @@ -201,7 +205,7 @@ void event_handler(switch_event_t *event) char *rpid = switch_event_get_header(event, "orig-rpid"); long expires = (long) time(NULL) + atol(exp_str); char *profile_name = switch_event_get_header(event, "orig-profile-name"); - sofia_profile_t *profile; + sofia_profile_t *profile = NULL; char buf[512]; if (!rpid) { @@ -233,6 +237,9 @@ void event_handler(switch_event_t *event) } + if (profile) { + switch_thread_rwlock_unlock(profile->rwlock); + } } } @@ -340,7 +347,9 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Starting thread for %s\n", profile->name); - while (mod_sofia_globals.running == 1) { + + sofia_set_pflag_locked(profile, PFLAG_RUNNING); + while (mod_sofia_globals.running == 1 && sofia_test_pflag(profile, PFLAG_RUNNING)) { if (++ireg_loops >= IREG_SECONDS) { sofia_reg_check_expire(profile, time(NULL)); ireg_loops = 0; @@ -353,23 +362,40 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void su_root_step(profile->s_root, 1000); } - - sofia_glue_sql_close(profile); + //sofia_reg_check_expire(profile, 0); + //sofia_reg_check_gateway(profile, 0); + switch_thread_rwlock_wrlock(profile->rwlock); sofia_reg_unregister(profile); - su_home_unref(profile->home); + nua_shutdown(profile->nua); + su_root_run(profile->s_root); + nua_destroy(profile->nua); + while(0 && profile->inuse) { + switch_yield(1000000); + } + if (switch_event_create(&s_event, SWITCH_EVENT_UNPUBLISH) == SWITCH_STATUS_SUCCESS) { switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._udp"); switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port); switch_event_fire(&s_event); } + sofia_glue_sql_close(profile); + su_home_unref(profile->home); su_root_destroy(profile->s_root); pool = profile->pool; + + switch_mutex_lock(mod_sofia_globals.hash_mutex); + switch_core_hash_delete(mod_sofia_globals.profile_hash, profile->name); + switch_mutex_unlock(mod_sofia_globals.hash_mutex); + + switch_thread_rwlock_unlock(profile->rwlock); + switch_core_destroy_memory_pool(&pool); + end: switch_mutex_lock(mod_sofia_globals.mutex); @@ -417,14 +443,15 @@ static void logger(void *logarg, char const *fmt, va_list ap) } -switch_status_t config_sofia(int reload) +switch_status_t config_sofia(int reload, char *profile_name) { char *cf = "sofia.conf"; switch_xml_t cfg, xml = NULL, xprofile, param, settings, profiles, gateway_tag, gateways_tag; switch_status_t status = SWITCH_STATUS_SUCCESS; sofia_profile_t *profile = NULL; char url[512] = ""; - + sofia_gateway_t *gp; + int profile_found = 0; if (!reload) { su_init(); @@ -432,6 +459,14 @@ switch_status_t config_sofia(int reload) su_log_redirect(tport_log, logger, NULL); } + + if (!switch_strlen_zero(profile_name) && (profile = sofia_glue_find_profile(profile_name))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile [%s] Already exists.\n", switch_str_nil(profile_name)); + status = SWITCH_STATUS_FALSE; + switch_thread_rwlock_unlock(profile->rwlock); + return status; + } + if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf); status = SWITCH_STATUS_FALSE; @@ -458,7 +493,18 @@ switch_status_t config_sofia(int reload) char *xprofilename = (char *) switch_xml_attr_soft(xprofile, "name"); switch_memory_pool_t *pool = NULL; - + if (!xprofilename) { + xprofilename = "unnamed"; + } + + if (profile_name) { + if (strcasecmp(profile_name, xprofilename)) { + continue; + } else { + profile_found = 1; + } + } + /* Setup the pool */ if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); @@ -470,9 +516,7 @@ switch_status_t config_sofia(int reload) goto done; } - if (!xprofilename) { - xprofilename = "unnamed"; - } + profile->pool = pool; @@ -481,7 +525,8 @@ switch_status_t config_sofia(int reload) profile->dbname = switch_core_strdup(profile->pool, url); switch_core_hash_init(&profile->chat_hash, profile->pool); - + switch_thread_rwlock_create(&profile->rwlock, profile->pool); + switch_mutex_init(&profile->flag_mutex, SWITCH_MUTEX_NESTED, profile->pool); profile->dtmf_duration = 100; profile->codec_ms = 20; @@ -503,7 +548,6 @@ switch_status_t config_sofia(int reload) if ((profile->odbc_pass = strchr(profile->odbc_user, ':'))) { *profile->odbc_pass++ = '\0'; } - #else switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC IS NOT AVAILABLE!\n"); @@ -682,7 +726,7 @@ switch_status_t config_sofia(int reload) if ((gateways_tag = switch_xml_child(xprofile, "gateways"))) { for (gateway_tag = switch_xml_child(gateways_tag, "gateway"); gateway_tag; gateway_tag = gateway_tag->next) { char *name = (char *) switch_xml_attr_soft(gateway_tag, "name"); - outbound_reg_t *gateway; + sofia_gateway_t *gateway; if (switch_strlen_zero(name)) { name = "anonymous"; @@ -790,12 +834,15 @@ switch_status_t config_sofia(int reload) gateway->next = profile->gateways; profile->gateways = gateway; - if (sofia_reg_find_gateway(gateway->name)) { + if ((gp = sofia_reg_find_gateway(gateway->name))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate gateway '%s'\n", gateway->name); - } else if (sofia_reg_find_gateway(gateway->register_from)) { + sofia_reg_release_gateway(gp); + } else if ((gp=sofia_reg_find_gateway(gateway->register_from))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate uri '%s'\n", gateway->register_from); - } else if (sofia_reg_find_gateway(gateway->register_contact)) { + sofia_reg_release_gateway(gp); + } else if ((gp=sofia_reg_find_gateway(gateway->register_contact))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate contact '%s'\n", gateway->register_from); + sofia_reg_release_gateway(gp); } else { sofia_reg_add_gateway(gateway->name, gateway); sofia_reg_add_gateway(gateway->register_from, gateway); @@ -816,6 +863,9 @@ switch_status_t config_sofia(int reload) } profile = NULL; } + if (profile_found) { + break; + } } } done: @@ -823,6 +873,11 @@ switch_status_t config_sofia(int reload) switch_xml_free(xml); } + if (profile_name && !profile_found) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No Such Profile '%s'\n", profile_name); + status = SWITCH_STATUS_FALSE; + } + return status; } @@ -1169,6 +1224,10 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, tech_pvt->nh = NULL; + switch_mutex_lock(profile->flag_mutex); + profile->inuse--; + switch_mutex_unlock(profile->flag_mutex); + } else if (sofia_private) { if (sofia_private->home) { su_home_unref(sofia_private->home); @@ -1706,7 +1765,7 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ if (sip->sip_request->rq_url) { - outbound_reg_t *gateway; + sofia_gateway_t *gateway; char *from_key = switch_core_session_sprintf(session, "sip:%s@%s", (char *) sip->sip_request->rq_url->url_user, (char *) sip->sip_request->rq_url->url_host); @@ -1714,6 +1773,7 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ if ((gateway = sofia_reg_find_gateway(from_key))) { context = gateway->register_context; switch_channel_set_variable(channel, "sip_gateway", gateway->name); + sofia_reg_release_gateway(gateway); } } diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 68a0548c82..dd8c58ec7a 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -315,9 +315,13 @@ void sofia_glue_attach_private(switch_core_session_t *session, sofia_profile_t * switch_mutex_lock(tech_pvt->flag_mutex); + switch_mutex_lock(profile->flag_mutex); tech_pvt->flags = profile->flags; - switch_mutex_unlock(tech_pvt->flag_mutex); tech_pvt->profile = profile; + profile->inuse++; + switch_mutex_unlock(profile->flag_mutex); + switch_mutex_unlock(tech_pvt->flag_mutex); + if (tech_pvt->bte) { tech_pvt->te = tech_pvt->bte; } else if (!tech_pvt->te) { @@ -1420,7 +1424,14 @@ sofia_profile_t *sofia_glue_find_profile(char *key) sofia_profile_t *profile; switch_mutex_lock(mod_sofia_globals.hash_mutex); - profile = (sofia_profile_t *) switch_core_hash_find(mod_sofia_globals.profile_hash, key); + if ((profile = (sofia_profile_t *) switch_core_hash_find(mod_sofia_globals.profile_hash, key))) { + if (!sofia_test_pflag(profile, PFLAG_RUNNING)) { + profile = NULL; + } else if (switch_thread_rwlock_tryrdlock(profile->rwlock) != SWITCH_STATUS_SUCCESS) { + profile = NULL; + } + } + switch_mutex_unlock(mod_sofia_globals.hash_mutex); return profile; @@ -1508,6 +1519,7 @@ void sofia_glue_sql_close(sofia_profile_t *profile) } else { #endif switch_core_db_close(profile->master_db); + profile->master_db = NULL; #ifdef SWITCH_HAVE_ODBC } #endif diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index 46227a9499..e89cd3c8b9 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -43,7 +43,7 @@ switch_status_t sofia_presence_chat_send(char *proto, char *from, char *to, char { char buf[256]; char *user, *host; - sofia_profile_t *profile; + sofia_profile_t *profile = NULL; char *ffrom = NULL; nua_handle_t *msg_nh; char *contact; @@ -98,6 +98,10 @@ switch_status_t sofia_presence_chat_send(char *proto, char *from, char *to, char switch_safe_free(ffrom); free(user); + + if (profile) { + switch_thread_rwlock_unlock(profile->rwlock); + } } return SWITCH_STATUS_SUCCESS; @@ -178,7 +182,7 @@ void sofia_presence_mwi_event_handler(switch_event_t *event) { char *account, *dup_account, *yn, *host, *user; char *sql; - sofia_profile_t *profile; + sofia_profile_t *profile = NULL; switch_stream_handle_t stream = { 0 }; switch_event_header_t *hp; @@ -230,11 +234,16 @@ void sofia_presence_mwi_event_handler(switch_event_t *event) switch_safe_free(sql); switch_safe_free(dup_account); + + if (profile) { + switch_thread_rwlock_unlock(profile->rwlock); + } + } void sofia_presence_event_handler(switch_event_t *event) { - sofia_profile_t *profile; + sofia_profile_t *profile = NULL; switch_hash_index_t *hi; void *val; char *from = switch_event_get_header(event, "from"); @@ -364,6 +373,9 @@ void sofia_presence_event_handler(switch_event_t *event) sofia_presence_resub_callback, profile); + + switch_thread_rwlock_unlock(profile->rwlock); + switch_safe_free(sql); } switch_safe_free(user); @@ -569,7 +581,7 @@ static int sofia_presence_mwi_callback(void *pArg, int argc, char **argv, char * char *expires = argv[10]; char *body = argv[11]; char *exp; - sofia_profile_t *profile; + sofia_profile_t *profile = NULL; char *tmp, *id = NULL; nua_handle_t *nh; int expire_sec = atoi(expires); @@ -606,6 +618,11 @@ static int sofia_presence_mwi_callback(void *pArg, int argc, char **argv, char * switch_safe_free(id); switch_safe_free(exp); + + if (profile) { + switch_thread_rwlock_unlock(profile->rwlock); + } + return 0; } diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 9c6fb59b69..679a8c017e 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -39,7 +39,7 @@ void sofia_reg_unregister(sofia_profile_t *profile) { - outbound_reg_t *gateway_ptr; + sofia_gateway_t *gateway_ptr; for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) { if (gateway_ptr->sofia_private) { free(gateway_ptr->sofia_private); @@ -52,11 +52,16 @@ void sofia_reg_unregister(sofia_profile_t *profile) void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now) { - outbound_reg_t *gateway_ptr; + sofia_gateway_t *gateway_ptr; for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) { int ss_state = nua_callstate_authenticating; reg_state_t ostate = gateway_ptr->state; + if (!now) { + gateway_ptr->state = ostate = REG_STATE_UNREGED; + gateway_ptr->expires_str = "0"; + } + switch (ostate) { case REG_STATE_NOREG: break; @@ -80,14 +85,26 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now) gateway_ptr->sofia_private->gateway = gateway_ptr; nua_handle_bind(gateway_ptr->nh, gateway_ptr->sofia_private); - nua_register(gateway_ptr->nh, - SIPTAG_FROM_STR(gateway_ptr->register_from), - SIPTAG_CONTACT_STR(gateway_ptr->register_contact), - SIPTAG_EXPIRES_STR(gateway_ptr->expires_str), - NUTAG_REGISTRAR(gateway_ptr->register_proxy), - NUTAG_OUTBOUND("no-options-keepalive"), NUTAG_OUTBOUND("no-validate"), NUTAG_KEEPALIVE(0), TAG_NULL()); - gateway_ptr->retry = now + 10; + if (now) { + nua_register(gateway_ptr->nh, + SIPTAG_FROM_STR(gateway_ptr->register_from), + SIPTAG_CONTACT_STR(gateway_ptr->register_contact), + SIPTAG_EXPIRES_STR(gateway_ptr->expires_str), + NUTAG_REGISTRAR(gateway_ptr->register_proxy), + NUTAG_OUTBOUND("no-options-keepalive"), NUTAG_OUTBOUND("no-validate"), NUTAG_KEEPALIVE(0), TAG_NULL()); + gateway_ptr->retry = now + 10; + } else { + nua_unregister(gateway_ptr->nh, + SIPTAG_FROM_STR(gateway_ptr->register_from), + SIPTAG_CONTACT_STR(gateway_ptr->register_contact), + SIPTAG_EXPIRES_STR(gateway_ptr->expires_str), + NUTAG_REGISTRAR(gateway_ptr->register_proxy), + NUTAG_OUTBOUND("no-options-keepalive"), NUTAG_OUTBOUND("no-validate"), NUTAG_KEEPALIVE(0), TAG_NULL()); + } + + gateway_ptr->retry = now + time(NULL); gateway_ptr->state = REG_STATE_TRYING; + } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error registering %s\n", gateway_ptr->name); gateway_ptr->state = REG_STATE_FAILED; @@ -107,7 +124,6 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now) break; } } - } @@ -157,7 +173,11 @@ void sofia_reg_check_expire(sofia_profile_t *profile, time_t now) } #endif - snprintf(sql, sizeof(sql), "select '%s',* from sip_registrations where expires > 0 and expires <= %ld", profile->name, (long) now); + if (now) { + snprintf(sql, sizeof(sql), "select '%s',* from sip_registrations where expires > 0 and expires <= %ld", profile->name, (long) now); + } else { + snprintf(sql, sizeof(sql), "select '%s',* from sip_registrations where expires > 0", profile->name); + } switch_mutex_lock(profile->ireg_mutex); sofia_glue_execute_sql_callback(profile, @@ -166,12 +186,23 @@ void sofia_reg_check_expire(sofia_profile_t *profile, time_t now) sql, sofia_reg_del_callback, NULL); - - snprintf(sql, sizeof(sql), "delete from sip_registrations where expires > 0 and expires <= %ld", (long) now); + if (now) { + snprintf(sql, sizeof(sql), "delete from sip_registrations where expires > 0 and expires <= %ld", (long) now); + } else { + snprintf(sql, sizeof(sql), "delete from sip_registrations where expires > 0"); + } sofia_glue_execute_sql(profile, SWITCH_TRUE, sql, NULL); - snprintf(sql, sizeof(sql), "delete from sip_authentication where expires > 0 and expires <= %ld", (long) now); + if (now) { + snprintf(sql, sizeof(sql), "delete from sip_authentication where expires > 0 and expires <= %ld", (long) now); + } else { + snprintf(sql, sizeof(sql), "delete from sip_authentication where expires > 0"); + } sofia_glue_execute_sql(profile, SWITCH_TRUE, sql, NULL); - snprintf(sql, sizeof(sql), "delete from sip_subscriptions where expires > 0 and expires <= %ld", (long) now); + if (now) { + snprintf(sql, sizeof(sql), "delete from sip_subscriptions where expires > 0 and expires <= %ld", (long) now); + } else { + snprintf(sql, sizeof(sql), "delete from sip_subscriptions where expires > 0"); + } sofia_glue_execute_sql(profile, SWITCH_TRUE, sql, NULL); switch_mutex_unlock(profile->ireg_mutex); @@ -479,7 +510,7 @@ void sofia_reg_handle_sip_r_challenge(int status, char const *phrase, nua_t * nua, sofia_profile_t *profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[]) { - outbound_reg_t *gateway = NULL; + sofia_gateway_t *gateway = NULL; sip_www_authenticate_t const *authenticate = NULL; char const *realm = NULL; char *p = NULL, *duprealm = NULL, *qrealm = NULL; @@ -522,7 +553,7 @@ void sofia_reg_handle_sip_r_challenge(int status, } if (profile) { - outbound_reg_t *gateway_ptr; + sofia_gateway_t *gateway_ptr; if ((duprealm = strdup(realm))) { qrealm = duprealm; @@ -548,13 +579,21 @@ void sofia_reg_handle_sip_r_challenge(int status, } if (!gateway) { + switch_mutex_lock(mod_sofia_globals.hash_mutex); for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) { if (scheme && qrealm && !strcasecmp(gateway_ptr->register_scheme, scheme) && !strcasecmp(gateway_ptr->register_realm, qrealm)) { gateway = gateway_ptr; + + if (!switch_test_flag(gateway->profile, PFLAG_RUNNING)) { + gateway = NULL; + } else if (switch_thread_rwlock_tryrdlock(gateway->profile->rwlock) != SWITCH_STATUS_SUCCESS) { + gateway = NULL; + } break; } } + switch_mutex_unlock(mod_sofia_globals.hash_mutex); } if (!gateway) { @@ -578,7 +617,7 @@ void sofia_reg_handle_sip_r_challenge(int status, tl_gets(tags, NUTAG_CALLSTATE_REF(ss_state), SIPTAG_WWW_AUTHENTICATE_REF(authenticate), TAG_END()); nua_authenticate(nh, SIPTAG_EXPIRES_STR(gateway->expires_str), NUTAG_AUTH(authentication), TAG_END()); - + sofia_reg_release_gateway(gateway); return; cancel: @@ -761,18 +800,29 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile, sip_authorization_t co } -outbound_reg_t *sofia_reg_find_gateway(char *key) +sofia_gateway_t *sofia_reg_find_gateway(char *key) { - outbound_reg_t *gateway; + sofia_gateway_t *gateway = NULL; switch_mutex_lock(mod_sofia_globals.hash_mutex); - gateway = (outbound_reg_t *) switch_core_hash_find(mod_sofia_globals.gateway_hash, key); - switch_mutex_unlock(mod_sofia_globals.hash_mutex); + if ((gateway = (sofia_gateway_t *) switch_core_hash_find(mod_sofia_globals.gateway_hash, key))) { + if (!sofia_test_pflag(gateway->profile, PFLAG_RUNNING)) { + gateway = NULL; + } else if (switch_thread_rwlock_tryrdlock(gateway->profile->rwlock) != SWITCH_STATUS_SUCCESS) { + gateway = NULL; + } + } + switch_mutex_unlock(mod_sofia_globals.hash_mutex); return gateway; } -void sofia_reg_add_gateway(char *key, outbound_reg_t * gateway) +void sofia_reg_release_gateway(sofia_gateway_t *gateway) +{ + switch_thread_rwlock_unlock(gateway->profile->rwlock); +} + +void sofia_reg_add_gateway(char *key, sofia_gateway_t * gateway) { switch_mutex_lock(mod_sofia_globals.hash_mutex); switch_core_hash_insert(mod_sofia_globals.gateway_hash, key, gateway); diff --git a/src/switch_odbc.c b/src/switch_odbc.c index 85245bb13e..58d84e4b95 100644 --- a/src/switch_odbc.c +++ b/src/switch_odbc.c @@ -372,6 +372,7 @@ SWITCH_DECLARE(void) switch_odbc_handle_destroy(switch_odbc_handle_t **handlep) switch_safe_free(handle->password); free(handle); } + *handlep = NULL; } SWITCH_DECLARE(switch_odbc_state_t) switch_odbc_handle_get_state(switch_odbc_handle_t *handle)