Revision
17474
Author
support
Date
2010-05-03 12:36:23 -0500 (Mon, 03 May 2010)

Log Message

fix race condition when hangup happends after answer indication but before the session thread is started

Modified Paths

Diff

Modified: freeswitch/trunk/src/include/private/switch_core_pvt.h (17473 => 17474)


--- freeswitch/trunk/src/include/private/switch_core_pvt.h	2010-05-03 17:02:26 UTC (rev 17473)
+++ freeswitch/trunk/src/include/private/switch_core_pvt.h	2010-05-03 17:36:23 UTC (rev 17474)
@@ -92,7 +92,9 @@
 	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 @@
 	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;

Modified: freeswitch/trunk/src/include/switch_core.h (17473 => 17474)


--- freeswitch/trunk/src/include/switch_core.h	2010-05-03 17:02:26 UTC (rev 17473)
+++ freeswitch/trunk/src/include/switch_core.h	2010-05-03 17:36:23 UTC (rev 17474)
@@ -479,6 +479,7 @@
   \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);
 

Modified: freeswitch/trunk/src/switch_channel.c (17473 => 17474)


--- freeswitch/trunk/src/switch_channel.c	2010-05-03 17:02:26 UTC (rev 17473)
+++ freeswitch/trunk/src/switch_channel.c	2010-05-03 17:36:23 UTC (rev 17474)
@@ -106,6 +106,10 @@
 	{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 @@
 	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(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);
 		}
 

Modified: freeswitch/trunk/src/switch_core_session.c (17473 => 17474)


--- freeswitch/trunk/src/switch_core_session.c	2010-05-03 17:02:26 UTC (rev 17473)
+++ freeswitch/trunk/src/switch_core_session.c	2010-05-03 17:36:23 UTC (rev 17474)
@@ -1024,9 +1024,14 @@
 
 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)
 {
 	switch_memory_pool_t *pool;
@@ -1197,17 +1202,22 @@
 
 	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);

Modified: freeswitch/trunk/src/switch_core_state_machine.c (17473 => 17474)


--- freeswitch/trunk/src/switch_core_state_machine.c	2010-05-03 17:02:26 UTC (rev 17473)
+++ freeswitch/trunk/src/switch_core_state_machine.c	2010-05-03 17:36:23 UTC (rev 17474)
@@ -291,7 +291,7 @@
 	 */
 	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 @@
   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_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_assert(session != NULL);
 
-	session->thread_running = 1;
 	endpoint_interface = session->endpoint_interface;
 	switch_assert(endpoint_interface != NULL);