diff --git a/conf/freeswitch.xml b/conf/freeswitch.xml index 43d7e89028..48f23b2d19 100644 --- a/conf/freeswitch.xml +++ b/conf/freeswitch.xml @@ -1,6 +1,12 @@
+ + + + + + diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 95ef2073b6..e4c6b79ca7 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -116,6 +116,13 @@ struct switch_core_runtime; */ SWITCH_DECLARE(switch_status_t) switch_core_init(char *console, const char **err); +/*! + \brief Set/Get Session Limit + \param new new value (if > 0) + \return the current session limit +*/ +SWITCH_DECLARE(uint32_t) switch_core_session_limit(uint32_t new); + /*! \brief Destroy the core \note to be called at application shutdown @@ -309,6 +316,11 @@ SWITCH_DECLARE(char *) switch_core_session_get_uuid(switch_core_session_t *sessi */ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_locate(char *uuid_str); +/*! + \brief Hangup All Sessions +*/ +SWITCH_DECLARE(void) switch_core_session_hupall(void); + /*! \brief Send a message to another session using it's uuid \param uuid_str the unique id of the session you want to send a message to diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 072812a13a..0db6c0fd41 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -619,7 +619,8 @@ typedef enum { SWITCH_CAUSE_MANDATORY_IE_LENGTH_ERROR = 103, SWITCH_CAUSE_PROTOCOL_ERROR = 111, SWITCH_CAUSE_INTERWORKING = 127, - SWITCH_CAUSE_CRASH = 500 + SWITCH_CAUSE_CRASH = 500, + SWITCH_CAUSE_SYSTEM_SHUTDOWN = 501 } switch_call_cause_t; diff --git a/src/switch.c b/src/switch.c index 41b0d170c8..0048050766 100644 --- a/src/switch.c +++ b/src/switch.c @@ -188,7 +188,7 @@ int main(int argc, char *argv[]) #define __CP "DISABLED" #endif - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "freeswitch Version %s Started. Crash Protection [%s]\n\n", SWITCH_VERSION_FULL, __CP); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "freeswitch Version %s Started. Crash Protection [%s] Max Sessions[%u]\n\n", SWITCH_VERSION_FULL, __CP, switch_core_session_limit(0)); snprintf(path, sizeof(path), "%s%s%s", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, pfile); if (bg) { @@ -217,6 +217,8 @@ int main(int argc, char *argv[]) switch_event_fire(&event); } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "End existing sessions\n"); + switch_core_session_hupall(); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Clean up modules.\n"); switch_loadable_module_shutdown(); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Tearing down environment.\n"); diff --git a/src/switch_channel.c b/src/switch_channel.c index e3189822f1..599dfca64e 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -83,6 +83,7 @@ static struct switch_cause_table CAUSE_CHART[] = { { "PROTOCOL_ERROR", SWITCH_CAUSE_PROTOCOL_ERROR }, { "INTERWORKING", SWITCH_CAUSE_INTERWORKING }, { "CRASH", SWITCH_CAUSE_CRASH }, + { "SYSTEM_SHUTDOWN", SWITCH_CAUSE_SYSTEM_SHUTDOWN }, { NULL, 0 } }; diff --git a/src/switch_core.c b/src/switch_core.c index 4fce252747..f77a8d72f0 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -85,6 +85,7 @@ struct switch_core_runtime { uint32_t session_id; apr_pool_t *memory_pool; switch_hash_t *session_table; + switch_mutex_t *session_table_mutex; #ifdef CRASH_PROT switch_hash_t *stack_table; #endif @@ -93,6 +94,8 @@ struct switch_core_runtime { const switch_state_handler_table_t *state_handlers[SWITCH_MAX_STATE_HANDLERS]; int state_handler_index; FILE *console; + uint32_t session_count; + uint32_t session_limit; switch_queue_t *sql_queue; }; @@ -246,6 +249,8 @@ SWITCH_DECLARE(void) switch_core_session_rwunlock(switch_core_session_t *session SWITCH_DECLARE(switch_core_session_t *) switch_core_session_locate(char *uuid_str) { switch_core_session_t *session; + + switch_mutex_lock(runtime.session_table_mutex); if ((session = switch_core_hash_find(runtime.session_table, uuid_str))) { /* Acquire a read lock on the session */ if (switch_thread_rwlock_tryrdlock(session->rwlock) != SWITCH_STATUS_SUCCESS) { @@ -253,16 +258,41 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_locate(char *uuid_st session = NULL; } } + switch_mutex_unlock(runtime.session_table_mutex); /* if its not NULL, now it's up to you to rwunlock this */ return session; } +SWITCH_DECLARE(void) switch_core_session_hupall(void) +{ + switch_hash_index_t *hi; + void *val; + switch_core_session_t *session; + switch_channel_t *channel; + + switch_mutex_lock(runtime.session_table_mutex); + for (hi = switch_hash_first(runtime.memory_pool, runtime.session_table); hi; hi = switch_hash_next(hi)) { + switch_hash_this(hi, NULL, NULL, &val); + if (val) { + session = (switch_core_session_t *) val; + channel = switch_core_session_get_channel(session); + switch_channel_hangup(channel, SWITCH_CAUSE_SYSTEM_SHUTDOWN); + } + } + switch_mutex_unlock(runtime.session_table_mutex); + + while(runtime.session_count) { + switch_yield(1000); + } +} + SWITCH_DECLARE(switch_status_t) switch_core_session_message_send(char *uuid_str, switch_core_session_message_t *message) { switch_core_session_t *session = NULL; switch_status_t status = SWITCH_STATUS_FALSE; + switch_mutex_lock(runtime.session_table_mutex); if ((session = switch_core_hash_find(runtime.session_table, uuid_str)) != 0) { /* Acquire a read lock on the session or forget it the channel is dead */ if (switch_thread_rwlock_tryrdlock(session->rwlock) == SWITCH_STATUS_SUCCESS) { @@ -272,6 +302,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_message_send(char *uuid_str, switch_thread_rwlock_unlock(session->rwlock); } } + switch_mutex_unlock(runtime.session_table_mutex); return status; } @@ -281,6 +312,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_event_send(char *uuid_str, s switch_core_session_t *session = NULL; switch_status_t status = SWITCH_STATUS_FALSE; + switch_mutex_lock(runtime.session_table_mutex); if ((session = switch_core_hash_find(runtime.session_table, uuid_str)) != 0) { /* Acquire a read lock on the session or forget it the channel is dead */ if (switch_thread_rwlock_tryrdlock(session->rwlock) == SWITCH_STATUS_SUCCESS) { @@ -290,6 +322,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_event_send(char *uuid_str, s switch_thread_rwlock_unlock(session->rwlock); } } + switch_mutex_unlock(runtime.session_table_mutex); return status; } @@ -2344,6 +2377,9 @@ SWITCH_DECLARE(void) switch_core_session_destroy(switch_core_session_t **session apr_pool_destroy(pool); pool = NULL; + switch_mutex_lock(runtime.session_table_mutex); + runtime.session_count--; + switch_mutex_unlock(runtime.session_table_mutex); } SWITCH_DECLARE(switch_status_t) switch_core_hash_init(switch_hash_t **hash, switch_memory_pool_t *pool) @@ -2434,18 +2470,21 @@ static void *SWITCH_THREAD_FUNC switch_core_session_thread(switch_thread_t *thre { switch_core_session_t *session = obj; session->thread = thread; - session->id = runtime.session_id++; - snprintf(session->name, sizeof(session->name), "%u", session->id); - + switch_mutex_lock(runtime.session_table_mutex); + session->id = runtime.session_id++; switch_core_hash_insert(runtime.session_table, session->uuid_str, session); + switch_mutex_unlock(runtime.session_table_mutex); + switch_core_session_run(session); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Session %u (%s) Locked, Waiting on external entities\n", session->id, switch_channel_get_name(session->channel)); switch_core_session_write_lock(session); switch_core_session_rwunlock(session); + switch_mutex_lock(runtime.session_table_mutex); switch_core_hash_delete(runtime.session_table, session->uuid_str); + switch_mutex_unlock(runtime.session_table_mutex); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Session %u (%s) Ended\n", session->id, switch_channel_get_name(session->channel)); switch_core_session_destroy(&session); return NULL; @@ -2503,9 +2542,19 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request(const switch switch_memory_pool_t *usepool; switch_core_session_t *session; switch_uuid_t uuid; + uint32_t count = 0; assert(endpoint_interface != NULL); + switch_mutex_lock(runtime.session_table_mutex); + count = runtime.session_count; + switch_mutex_unlock(runtime.session_table_mutex); + + if ((count + 1) > runtime.session_limit) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Over Session Limit!\n"); + return NULL; + } + if (pool) { usepool = pool; } else if (switch_core_new_memory_pool(&usepool) != SWITCH_STATUS_SUCCESS) { @@ -2551,6 +2600,9 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request(const switch switch_thread_cond_create(&session->cond, session->pool); switch_thread_rwlock_create(&session->rwlock, session->pool); + switch_mutex_lock(runtime.session_table_mutex); + runtime.session_count++; + switch_mutex_unlock(runtime.session_table_mutex); return session; } @@ -2806,10 +2858,22 @@ SWITCH_DECLARE(void) switch_core_set_globals(void) #endif } + +SWITCH_DECLARE(uint32_t) switch_core_session_limit(uint32_t new) +{ + if (new) { + runtime.session_limit = new; + } + + return runtime.session_limit; +} + SWITCH_DECLARE(switch_status_t) switch_core_init(char *console, const char **err) { memset(&runtime, 0, sizeof(runtime)); - + runtime.session_limit = 1000; + switch_xml_t xml = NULL, cfg = NULL; + switch_core_set_globals(); /* INIT APR and Create the pool context */ @@ -2830,6 +2894,23 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(char *console, const char **err return SWITCH_STATUS_MEMERR; } + + if ((xml = switch_xml_open_cfg("switch.conf", &cfg, NULL))) { + switch_xml_t settings, param; + + if ((settings = switch_xml_child(cfg, "settings"))) { + for (param = switch_xml_child(settings, "param"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + + if (!strcasecmp(var, "max-sessions")) { + runtime.session_limit = atoi(val); + } + } + } + switch_xml_free(xml); + } + *err = NULL; if(console) { @@ -2909,6 +2990,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(char *console, const char **err runtime.session_id = 1; switch_core_hash_init(&runtime.session_table, runtime.memory_pool); + switch_mutex_init(&runtime.session_table_mutex, SWITCH_MUTEX_NESTED, runtime.memory_pool); #ifdef CRASH_PROT switch_core_hash_init(&runtime.stack_table, runtime.memory_pool); #endif