From 4bcb352602eb2f22d65fd2e3898f54de91471a99 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Tue, 16 Feb 2010 00:07:50 +0000 Subject: [PATCH] MODSOFIA-57 fix edge case if a session is blocked during a sip profile shutdown git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@16654 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/mod/endpoints/mod_sofia/mod_sofia.c | 8 ++++++++ src/mod/endpoints/mod_sofia/mod_sofia.h | 8 ++++++++ src/mod/endpoints/mod_sofia/sofia.c | 24 ++++++++++++++++++----- src/mod/endpoints/mod_sofia/sofia_glue.c | 25 ++++++++++++++---------- src/mod/endpoints/mod_sofia/sofia_reg.c | 24 +++++++++++++++-------- 5 files changed, 66 insertions(+), 23 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 93e1a7be6c..f076bdf2cf 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -362,6 +362,10 @@ switch_status_t sofia_on_destroy(switch_core_session_t *session) switch_mutex_unlock(tech_pvt->profile->flag_mutex); sofia_glue_deactivate_rtp(tech_pvt); + + if (sofia_test_pflag(tech_pvt->profile, PFLAG_DESTROY) && !tech_pvt->profile->inuse) { + sofia_profile_destroy(tech_pvt->profile); + } } return SWITCH_STATUS_SUCCESS; @@ -376,6 +380,10 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) switch_call_cause_t cause = switch_channel_get_cause(channel); int sip_cause = hangup_cause_to_sip(cause); const char *ps_cause = NULL, *use_my_cause; + + if (sofia_test_pflag(tech_pvt->profile, PFLAG_DESTROY)) { + return SWITCH_STATUS_SUCCESS; + } switch_mutex_lock(tech_pvt->sofia_mutex); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 55c970ced9..7bb7c2d325 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -206,6 +206,7 @@ typedef enum { PFLAG_PASS_CALLEE_ID, PFLAG_LOG_AUTH_FAIL, PFLAG_TRACK_CALLS, + PFLAG_DESTROY, /* No new flags below this line */ PFLAG_MAX } PFLAGS; @@ -837,6 +838,9 @@ void sofia_glue_release_profile__(const char *file, const char *func, int line, sofia_profile_t *sofia_glue_find_profile__(const char *file, const char *func, int line, const char *key); #define sofia_glue_find_profile(x) sofia_glue_find_profile__(__FILE__, __SWITCH_FUNC__, __LINE__, x) +#define sofia_glue_profile_rdlock(x) sofia_glue_profile_rdlock__(__FILE__, __SWITCH_FUNC__, __LINE__, x) +switch_status_t sofia_glue_profile_rdlock__(const char *file, const char *func, int line, sofia_profile_t *profile); + switch_status_t sofia_reg_add_gateway(char *key, sofia_gateway_t *gateway); 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) @@ -846,6 +850,9 @@ sofia_gateway_t *sofia_reg_find_gateway_by_realm__(const char *file, const char sofia_gateway_subscription_t *sofia_find_gateway_subscription(sofia_gateway_t *gateway_ptr, const char *event); +#define sofia_reg_gateway_rdlock(x) sofia_reg_gateway_rdlock__(__FILE__, __SWITCH_FUNC__, __LINE__, x) +switch_status_t sofia_reg_gateway_rdlock__(const char *file, const char *func, int line, sofia_gateway_t *gateway); + void sofia_reg_release_gateway__(const char *file, const char *func, int line, sofia_gateway_t *gateway); #define sofia_reg_release_gateway(x) sofia_reg_release_gateway__(__FILE__, __SWITCH_FUNC__, __LINE__, x); @@ -964,3 +971,4 @@ int sofia_sla_supported(sip_t const *sip); void sofia_glue_tech_untrack(sofia_profile_t *profile, switch_core_session_t *session, switch_bool_t force); void sofia_glue_tech_track(sofia_profile_t *profile, switch_core_session_t *session); int sofia_glue_recover(switch_bool_t flush); +void sofia_profile_destroy(sofia_profile_t *profile); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 901c0afe6a..38846c0c48 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -682,6 +682,8 @@ void sofia_event_callback(nua_event_t event, int locked = 0; int check_destroy = 1; + /* sofia_private will be == &mod_sofia_globals.keep_private whenever a request is done with a new handle that has to be + freed whenever the request is done */ if (nh && sofia_private == &mod_sofia_globals.keep_private) { if (status >= 300) { nua_handle_bind(nh, NULL); @@ -689,11 +691,12 @@ void sofia_event_callback(nua_event_t event, return; } } + if (sofia_private && sofia_private != &mod_sofia_globals.destroy_private && sofia_private != &mod_sofia_globals.keep_private) { if ((gateway = sofia_private->gateway)) { - if (switch_thread_rwlock_tryrdlock(gateway->profile->rwlock) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile %s is locked\n", gateway->profile->name); + /* Released in sofia_reg_release_gateway() */ + if (sofia_reg_gateway_rdlock(gateway) != SWITCH_STATUS_SUCCESS) { return; } } else if (!zstr(sofia_private->uuid)) { @@ -733,7 +736,8 @@ void sofia_event_callback(nua_event_t event, } } } - + + if (sofia_test_pflag(profile, PFLAG_AUTH_ALL) && tech_pvt && tech_pvt->key && sip) { sip_authorization_t const *authorization = NULL; @@ -1527,8 +1531,8 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void if (sofia_test_pflag(profile, PFLAG_RESPAWN)) { config_sofia(1, profile->name); } - - switch_core_destroy_memory_pool(&pool); + + sofia_profile_destroy(profile); end: switch_mutex_lock(mod_sofia_globals.mutex); @@ -1538,6 +1542,16 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void return NULL; } +void sofia_profile_destroy(sofia_profile_t *profile) +{ + if (!profile->inuse) { + switch_memory_pool_t *pool = profile->pool; + switch_core_destroy_memory_pool(&pool); + } else { + sofia_set_pflag(profile, PFLAG_DESTROY); + } +} + void launch_sofia_profile_thread(sofia_profile_t *profile) { switch_thread_t *thread; diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index ea3725ead0..987e25cbf6 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -3776,6 +3776,19 @@ char *sofia_glue_get_url_from_contact(char *buf, uint8_t to_dup) return url; } +switch_status_t sofia_glue_profile_rdlock__(const char *file, const char *func, int line, sofia_profile_t *profile) +{ + switch_status_t status = switch_thread_rwlock_tryrdlock(profile->rwlock); + if (status != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "Profile %s is locked\n", profile->name); + return status; + } +#ifdef SOFIA_DEBUG_RWLOCKS + switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "XXXXXXXXXXXXXX LOCK %s\n", profile->name); +#endif + return status; +} + sofia_profile_t *sofia_glue_find_profile__(const char *file, const char *func, int line, const char *key) { sofia_profile_t *profile; @@ -3789,10 +3802,7 @@ sofia_profile_t *sofia_glue_find_profile__(const char *file, const char *func, i profile = NULL; goto done; } - if (switch_thread_rwlock_tryrdlock(profile->rwlock) != SWITCH_STATUS_SUCCESS) { -#ifdef SOFIA_DEBUG_RWLOCKS - switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "Profile %s is locked\n", profile->name); -#endif + if (sofia_glue_profile_rdlock__(file, func, line, profile) != SWITCH_STATUS_SUCCESS) { profile = NULL; } } else { @@ -3800,13 +3810,8 @@ sofia_profile_t *sofia_glue_find_profile__(const char *file, const char *func, i switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "Profile %s is not in the hash\n", key); #endif } -#ifdef SOFIA_DEBUG_RWLOCKS - if (profile) { - switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "XXXXXXXXXXXXXX LOCK %s\n", profile->name); - } -#endif - done: +done: switch_mutex_unlock(mod_sofia_globals.hash_mutex); return profile; diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 0ff4fcf9c9..5248ad840b 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -320,8 +320,9 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now) gateway_ptr->status = SOFIA_GATEWAY_DOWN; gateway_ptr->retry = 0; - if (!gateway_ptr->nh) + if (!gateway_ptr->nh) { sofia_reg_new_handle(gateway_ptr, now ? 1 : 0); + } if (sofia_glue_check_nat(gateway_ptr->profile, gateway_ptr->register_proxy)) { user_via = sofia_glue_create_external_via(NULL, gateway_ptr->profile, gateway_ptr->register_transport); @@ -2340,16 +2341,10 @@ sofia_gateway_t *sofia_reg_find_gateway__(const char *file, const char *func, in gateway = NULL; goto done; } - if (switch_thread_rwlock_tryrdlock(gateway->profile->rwlock) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "Profile %s is locked\n", gateway->profile->name); + if (sofia_reg_gateway_rdlock__(file, func, line, gateway) != SWITCH_STATUS_SUCCESS) { gateway = NULL; } } - if (gateway) { -#ifdef SOFIA_DEBUG_RWLOCKS - switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, SWITCH_LOG_ERROR, "XXXXXXXXXXXXXX GW LOCK %s\n", gateway->profile->name); -#endif - } done: switch_mutex_unlock(mod_sofia_globals.hash_mutex); @@ -2397,6 +2392,19 @@ sofia_gateway_t *sofia_reg_find_gateway_by_realm__(const char *file, const char return gateway; } +switch_status_t sofia_reg_gateway_rdlock__(const char *file, const char *func, int line, sofia_gateway_t *gateway) +{ + switch_status_t status = sofia_glue_profile_rdlock__(file, func, line, gateway->profile); + +#ifdef SOFIA_DEBUG_RWLOCKS + if (status != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, SWITCH_LOG_ERROR, "XXXXXXXXXXXXXX GW LOCK %s\n", gateway->profile->name); + } +#endif + + return status; +} + void sofia_reg_release_gateway__(const char *file, const char *func, int line, sofia_gateway_t *gateway) {