]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
fix race condition when hangup happends after answer indication but before the sessio...
authorAnthony Minessale <anthm@freeswitch.org>
Mon, 3 May 2010 17:29:56 +0000 (13:29 -0400)
committerSangoma Dev Box <support@sangoma.com>
Mon, 3 May 2010 17:36:23 +0000 (13:36 -0400)
src/include/private/switch_core_pvt.h
src/include/switch_core.h
src/switch_channel.c
src/switch_core_session.c
src/switch_core_state_machine.c

index ef1fe80fed0ca3d6ee0370b2d0858bb36654146c..12fd3209c6424c49528ea88bb32c006d1c0abae1 100644 (file)
@@ -92,7 +92,9 @@ typedef enum {
        SSF_NONE = 0,
        SSF_DESTROYED = (1 << 0),
        SSF_WARN_TRANSCODE = (1 << 1),
-       SSF_HANGUP = (1 << 2)
+       SSF_HANGUP = (1 << 2),
+       SSF_THREAD_STARTED = (1 << 3),
+       SSF_THREAD_RUNNING = (1 << 4)
 } switch_session_flag_t;
 
 
@@ -103,7 +105,6 @@ struct switch_core_session {
        switch_endpoint_interface_t *endpoint_interface;
        switch_size_t id;
        switch_session_flag_t flags;
-       int thread_running;
        switch_channel_t *channel;
 
        switch_io_event_hooks_t event_hooks;
index 7fb24783e987fb8dba126e2485bf0d295cc0ba20..7cfc102dad2a3ff7336e1cf10271667834c39000 100644 (file)
@@ -479,6 +479,7 @@ SWITCH_DECLARE(void) switch_core_session_run(_In_ switch_core_session_t *session
   \param session the session on which to check
 */
 SWITCH_DECLARE(unsigned int) switch_core_session_running(_In_ switch_core_session_t *session);
+SWITCH_DECLARE(unsigned int) switch_core_session_started(_In_ switch_core_session_t *session);
 
 SWITCH_DECLARE(void *) switch_core_perform_permanent_alloc(_In_ switch_size_t memory, _In_z_ const char *file, _In_z_ const char *func, _In_ int line);
 
index b826da45d5575b1963957509b5b093ae17511197..77838a8ca69969ea9083fbd7bd487108a33130d2 100644 (file)
@@ -106,6 +106,10 @@ static struct switch_cause_table CAUSE_CHART[] = {
        {NULL, 0}
 };
 
+typedef enum {
+       OCF_HANGUP = (1 << 0)
+} opaque_channel_flag_t;
+
 struct switch_channel {
        char *name;
        switch_call_direction_t direction;
@@ -132,6 +136,7 @@ struct switch_channel {
        int vi;
        int event_count;
        int profile_index;
+       opaque_channel_flag_t opaque_flags;
 };
 
 SWITCH_DECLARE(const char *) switch_channel_cause2str(switch_call_cause_t cause)
@@ -2090,29 +2095,44 @@ SWITCH_DECLARE(void) switch_channel_set_hangup_time(switch_channel_t *channel)
 SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_hangup(switch_channel_t *channel,
                                                                                                                                         const char *file, const char *func, int line, switch_call_cause_t hangup_cause)
 {
+       int ok = 0;
+
        switch_assert(channel != NULL);
 
+       /* one per customer */
+       switch_mutex_lock(channel->state_mutex);
+       if (!(channel->opaque_flags & OCF_HANGUP)) {
+               channel->opaque_flags |= OCF_HANGUP;
+               ok = 1;
+       }
+       switch_mutex_unlock(channel->state_mutex);
+
+       if (!ok) {
+               return channel->state;
+       }
+
        switch_channel_clear_flag(channel, CF_BLOCK_STATE);
 
        if (channel->state < CS_HANGUP) {
                switch_channel_state_t last_state;
                switch_event_t *event;
 
-               if (hangup_cause == SWITCH_CAUSE_LOSE_RACE) {
-                       switch_channel_set_variable(channel, "presence_call_info", NULL);
-               }
-
                switch_mutex_lock(channel->state_mutex);
                last_state = channel->state;
                channel->state = CS_HANGUP;
                switch_mutex_unlock(channel->state_mutex);
 
+
+               if (hangup_cause == SWITCH_CAUSE_LOSE_RACE) {
+                       switch_channel_set_variable(channel, "presence_call_info", NULL);
+               }
+
                channel->hangup_cause = hangup_cause;
                switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_channel_get_uuid(channel), SWITCH_LOG_NOTICE, "Hangup %s [%s] [%s]\n",
                                                  channel->name, state_names[last_state], switch_channel_cause2str(channel->hangup_cause));
 
 
-               if (!switch_core_session_running(channel->session)) {
+               if (!switch_core_session_running(channel->session) && !switch_core_session_started(channel->session)) {
                        switch_core_session_thread_launch(channel->session);
                }
 
index 69f2492a933aa3ee708146fc66b14e43a97ff5d6..1de6ea02d698d6c381e85b15dd1670c733552cc8 100644 (file)
@@ -1024,7 +1024,12 @@ SWITCH_DECLARE(void) switch_core_session_signal_state_change(switch_core_session
 
 SWITCH_DECLARE(unsigned int) switch_core_session_running(switch_core_session_t *session)
 {
-       return session->thread_running;
+       return switch_test_flag(session, SSF_THREAD_RUNNING) ? 1 : 0;
+}
+
+SWITCH_DECLARE(unsigned int) switch_core_session_started(switch_core_session_t *session)
+{
+       return switch_test_flag(session, SSF_THREAD_STARTED) ? 1 : 0;
 }
 
 SWITCH_DECLARE(void) switch_core_session_perform_destroy(switch_core_session_t **session, const char *file, const char *func, int line)
@@ -1197,17 +1202,22 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_thread_launch(switch_core_se
 
        switch_mutex_lock(session->mutex);
 
-       if (!session->thread_running) {
-               session->thread_running = 1;
+       if (switch_test_flag(session, SSF_THREAD_RUNNING)) {
+               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Cannot double-launch thread!\n");
+       } else if (switch_test_flag(session, SSF_THREAD_STARTED)) {
+               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Cannot launch thread again after it has already been run!\n");
+       } else {
+               switch_set_flag(session, SSF_THREAD_RUNNING);
+               switch_set_flag(session, SSF_THREAD_STARTED);
                switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
                if (switch_thread_create(&thread, thd_attr, switch_core_session_thread, session, session->pool) == SWITCH_STATUS_SUCCESS) {
+                       switch_set_flag(session, SSF_THREAD_STARTED);
                        status = SWITCH_STATUS_SUCCESS;
                } else {
-                       session->thread_running = 0;
+                       switch_clear_flag(session, SSF_THREAD_RUNNING);
+                       switch_clear_flag(session, SSF_THREAD_STARTED); 
                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Cannot create thread!\n");
                }
-       } else {
-               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Cannot double-launch thread!\n");
        }
 
        switch_mutex_unlock(session->mutex);
index ec9c190e708a2b9ab08527b494caa65dc36157d5..43315705ce1219ae6b8da0fc7c741fe3c14d0ae2 100644 (file)
@@ -291,7 +291,7 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session_t *session)
         */
        switch_assert(session != NULL);
 
-       session->thread_running = 1;
+       switch_set_flag(session, SSF_THREAD_RUNNING);
        endpoint_interface = session->endpoint_interface;
        switch_assert(endpoint_interface != NULL);
 
@@ -409,7 +409,7 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session_t *session)
   done:
        switch_mutex_unlock(session->mutex);
 
-       session->thread_running = 0;
+       switch_clear_flag(session, SSF_THREAD_RUNNING);
 }
 
 SWITCH_DECLARE(void) switch_core_session_destroy_state(switch_core_session_t *session)
@@ -429,7 +429,6 @@ SWITCH_DECLARE(void) switch_core_session_destroy_state(switch_core_session_t *se
        switch_channel_clear_flag(session->channel, CF_TRANSFER);
        switch_channel_clear_flag(session->channel, CF_REDIRECT);
 
-       session->thread_running = 1;
        endpoint_interface = session->endpoint_interface;
        switch_assert(endpoint_interface != NULL);
 
@@ -567,7 +566,6 @@ SWITCH_DECLARE(void) switch_core_session_reporting_state(switch_core_session_t *
 
        switch_assert(session != NULL);
 
-       session->thread_running = 1;
        endpoint_interface = session->endpoint_interface;
        switch_assert(endpoint_interface != NULL);