From 6e7d44af425b7b849715287655abe42eecde891c Mon Sep 17 00:00:00 2001
From: Anthony Minessale <anthm@freeswitch.org>
Date: Wed, 14 Dec 2011 13:23:54 -0600
Subject: [PATCH] FS-3764 --resolve

---
 src/include/switch_core.h                     | 14 +++++-
 src/include/switch_types.h                    | 45 +++++++++++--------
 .../applications/mod_commands/mod_commands.c  | 39 ++++++++++++++--
 src/mod/endpoints/mod_sofia/sofia.c           |  5 ++-
 src/switch_core.c                             | 37 +++++++++++++--
 src/switch_core_session.c                     | 11 +++++
 6 files changed, 122 insertions(+), 29 deletions(-)

diff --git a/src/include/switch_core.h b/src/include/switch_core.h
index e38d4aba7c..9d0893565f 100644
--- a/src/include/switch_core.h
+++ b/src/include/switch_core.h
@@ -25,7 +25,7 @@
  * 
  * Anthony Minessale II <anthm@freeswitch.org>
  * Luke Dashjr <luke@openmethods.com> (OpenMethods, LLC)
- *
+ * Joseph Sullivan <jossulli@amazon.com>
  *
  * switch_core.h -- Core Library
  *
@@ -1955,6 +1955,18 @@ SWITCH_DECLARE(FILE *) switch_core_data_channel(switch_text_channel_t channel);
 */
 SWITCH_DECLARE(switch_bool_t) switch_core_ready(void);
 
+/*! 
+  \brief Determines if the core is ready to take inbound calls
+  \return SWITCH_TRUE or SWITCH_FALSE
+*/
+SWITCH_DECLARE(switch_bool_t) switch_core_ready_inbound(void);
+
+/*! 
+  \brief Determines if the core is ready to place outbound calls
+  \return SWITCH_TRUE or SWITCH_FALSE
+*/
+SWITCH_DECLARE(switch_bool_t) switch_core_ready_outbound(void);
+
 /*! 
   \brief return core flags
   \return core flags
diff --git a/src/include/switch_types.h b/src/include/switch_types.h
index 351de2213f..2ab4c07984 100644
--- a/src/include/switch_types.h
+++ b/src/include/switch_types.h
@@ -25,6 +25,7 @@
  * 
  * Anthony Minessale II <anthm@freeswitch.org>
  * Bret McDanel <trixter AT 0xdecafbad dot com>
+ * Joseph Sullivan <jossulli@amazon.com>
  *
  * switch_types.h -- Data Types
  *
@@ -293,25 +294,27 @@ typedef uint32_t switch_eavesdrop_flag_t;
 typedef enum {
 	SCF_NONE = 0,
 	SCF_USE_SQL = (1 << 0),
-	SCF_NO_NEW_SESSIONS = (1 << 1),
-	SCF_SHUTTING_DOWN = (1 << 2),
-	SCF_VG = (1 << 3),
-	SCF_RESTART = (1 << 4),
-	SCF_SHUTDOWN_REQUESTED = (1 << 5),
-	SCF_USE_AUTO_NAT = (1 << 6),
-	SCF_EARLY_HANGUP = (1 << 7),
-	SCF_CALIBRATE_CLOCK = (1 << 8),
-	SCF_USE_HEAVY_TIMING = (1 << 9),
-	SCF_USE_CLOCK_RT = (1 << 10),
-	SCF_VERBOSE_EVENTS = (1 << 11),
-	SCF_USE_WIN32_MONOTONIC = (1 << 12),
-	SCF_AUTO_SCHEMAS = (1 << 13),
-	SCF_MINIMAL = (1 << 14),
-	SCF_USE_NAT_MAPPING = (1 << 15),
-	SCF_CLEAR_SQL = (1 << 16),
-	SCF_THREADED_SYSTEM_EXEC = (1 << 17),
-	SCF_SYNC_CLOCK_REQUESTED = (1 << 18),
-	SCF_CORE_ODBC_REQ = (1 << 19)
+	SCF_NO_NEW_OUTBOUND_SESSIONS = (1 << 1),
+	SCF_NO_NEW_INBOUND_SESSIONS = (1 << 2),
+	SCF_NO_NEW_SESSIONS = (SCF_NO_NEW_OUTBOUND_SESSIONS | SCF_NO_NEW_INBOUND_SESSIONS),
+	SCF_SHUTTING_DOWN = (1 << 3),
+	SCF_VG = (1 << 4),
+	SCF_RESTART = (1 << 5),
+	SCF_SHUTDOWN_REQUESTED = (1 << 6),
+	SCF_USE_AUTO_NAT = (1 << 7),
+	SCF_EARLY_HANGUP = (1 << 8),
+	SCF_CALIBRATE_CLOCK = (1 << 9),
+	SCF_USE_HEAVY_TIMING = (1 << 10),
+	SCF_USE_CLOCK_RT = (1 << 11),
+	SCF_VERBOSE_EVENTS = (1 << 12),
+	SCF_USE_WIN32_MONOTONIC = (1 << 13),
+	SCF_AUTO_SCHEMAS = (1 << 14),
+	SCF_MINIMAL = (1 << 15),
+	SCF_USE_NAT_MAPPING = (1 << 16),
+	SCF_CLEAR_SQL = (1 << 17),
+	SCF_THREADED_SYSTEM_EXEC = (1 << 18),
+	SCF_SYNC_CLOCK_REQUESTED = (1 << 19),
+	SCF_CORE_ODBC_REQ = (1 << 20)
 } switch_core_flag_enum_t;
 typedef uint32_t switch_core_flag_t;
 
@@ -1689,6 +1692,8 @@ typedef enum {
 
 typedef enum {
 	SCSC_PAUSE_INBOUND,
+	SCSC_PAUSE_OUTBOUND,
+	SCSC_PAUSE_ALL,
 	SCSC_HUPALL,
 	SCSC_SHUTDOWN,
 	SCSC_CHECK_RUNNING,
@@ -1714,6 +1719,8 @@ typedef enum {
 	SCSC_MIN_IDLE_CPU,
 	SCSC_VERBOSE_EVENTS,
 	SCSC_SHUTDOWN_CHECK,
+	SCSC_PAUSE_INBOUND_CHECK,
+	SCSC_PAUSE_OUTBOUND_CHECK,
 	SCSC_PAUSE_CHECK,
 	SCSC_READY_CHECK,
 	SCSC_THREADED_SYSTEM_EXEC,
diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c
index cffe756ad2..dac0de9a55 100644
--- a/src/mod/applications/mod_commands/mod_commands.c
+++ b/src/mod/applications/mod_commands/mod_commands.c
@@ -32,6 +32,7 @@
  * Cesar Cepeda <cesar@auronix.com>
  * Massimo Cetra <devel@navynet.it>
  * Rupa Schomaker <rupa@rupa.com>
+ * Joseph Sullivan <jossulli@amazon.com>
  *
  * 
  * mod_commands.c -- Misc. Command Module
@@ -1792,7 +1793,7 @@ SWITCH_STANDARD_API(status_function)
 	return SWITCH_STATUS_SUCCESS;
 }
 
-#define CTL_SYNTAX "[send_sighup|hupall|pause|resume|shutdown [cancel|elegant|asap|now|restart]|sps|sync_clock|sync_clock_when_idle|reclaim_mem|max_sessions|min_dtmf_duration [num]|max_dtmf_duration [num]|default_dtmf_duration [num]|min_idle_cpu|loglevel [level]|debug_level [level]]"
+#define CTL_SYNTAX "[send_sighup|hupall|pause [inbound|outbound]|resume [inbound|outbound]|shutdown [cancel|elegant|asap|now|restart]|sps|sync_clock|sync_clock_when_idle|reclaim_mem|max_sessions|min_dtmf_duration [num]|max_dtmf_duration [num]|default_dtmf_duration [num]|min_idle_cpu|loglevel [level]|debug_level [level]]"
 SWITCH_STANDARD_API(ctl_function)
 {
 	int argc;
@@ -1815,16 +1816,32 @@ SWITCH_STANDARD_API(ctl_function)
 			switch_core_session_ctl(SCSC_FLUSH_DB_HANDLES, NULL);
 			stream->write_function(stream, "+OK\n");
 		} else if (!strcasecmp(argv[0], "pause")) {
+			switch_session_ctl_t command = SCSC_PAUSE_ALL;
 			arg = 1;
-			switch_core_session_ctl(SCSC_PAUSE_INBOUND, &arg);
+			if (argv[1]) {
+				if (!strcasecmp(argv[1], "inbound")) {
+					command = SCSC_PAUSE_INBOUND;
+				} else if (!strcasecmp(argv[1], "outbound")) {
+					command = SCSC_PAUSE_OUTBOUND;
+				}
+			}
+			switch_core_session_ctl(command, &arg);
 			stream->write_function(stream, "+OK\n");
 		} else if (!strcasecmp(argv[0], "send_sighup")) {
 			arg = 1;
 			switch_core_session_ctl(SCSC_SEND_SIGHUP, &arg);
 			stream->write_function(stream, "+OK\n");
 		} else if (!strcasecmp(argv[0], "resume")) {
+			switch_session_ctl_t command = SCSC_PAUSE_ALL;
 			arg = 0;
-			switch_core_session_ctl(SCSC_PAUSE_INBOUND, &arg);
+			if (argv[1]) {
+				if (!strcasecmp(argv[1], "inbound")) {
+					command = SCSC_PAUSE_INBOUND;
+				} else if (!strcasecmp(argv[1], "outbound")) {
+					command = SCSC_PAUSE_OUTBOUND;
+				}
+			}
+			switch_core_session_ctl(command, &arg);
 			stream->write_function(stream, "+OK\n");
 		} else if (!strcasecmp(argv[0], "calibrate_clock")) {
 			switch_core_session_ctl(SCSC_CALIBRATE_CLOCK, NULL);
@@ -1855,7 +1872,15 @@ SWITCH_STANDARD_API(ctl_function)
 			switch_core_session_ctl(SCSC_SAVE_HISTORY, NULL);
 			stream->write_function(stream, "+OK\n");
 		} else if (!strcasecmp(argv[0], "pause_check")) {
-			switch_core_session_ctl(SCSC_PAUSE_CHECK, &arg);
+			switch_session_ctl_t command = SCSC_PAUSE_CHECK;
+			if (argv[1]) {
+				if (!strcasecmp(argv[1], "inbound")) {
+					command = SCSC_PAUSE_INBOUND_CHECK;
+				} else if (!strcasecmp(argv[1], "outbound")) {
+					command = SCSC_PAUSE_OUTBOUND_CHECK;
+				}
+			}
+			switch_core_session_ctl(command, &arg);
 			stream->write_function(stream, arg ? "true" : "false");
 		} else if (!strcasecmp(argv[0], "ready_check")) {
 			switch_core_session_ctl(SCSC_READY_CHECK, &arg);
@@ -5431,13 +5456,19 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
 	switch_console_set_complete("add fsctl max_sessions");
 	switch_console_set_complete("add fsctl min_dtmf_duration");
 	switch_console_set_complete("add fsctl pause");
+	switch_console_set_complete("add fsctl pause inbound");
+	switch_console_set_complete("add fsctl pause outbound");
 	switch_console_set_complete("add fsctl reclaim_mem");
 	switch_console_set_complete("add fsctl resume");
+	switch_console_set_complete("add fsctl resume inbound");
+	switch_console_set_complete("add fsctl resume outbound");
 	switch_console_set_complete("add fsctl calibrate_clock");
 	switch_console_set_complete("add fsctl crash");
 	switch_console_set_complete("add fsctl verbose_events");
 	switch_console_set_complete("add fsctl save_history");
 	switch_console_set_complete("add fsctl pause_check");
+	switch_console_set_complete("add fsctl pause_check inbound");
+	switch_console_set_complete("add fsctl pause_check outbound");
 	switch_console_set_complete("add fsctl ready_check");
 	switch_console_set_complete("add fsctl shutdown_check");
 	switch_console_set_complete("add fsctl shutdown");
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index 9208e3a625..f934c4eea4 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -31,6 +31,7 @@
  * Norman Brandinger
  * Raymond Chandler <intralanman@gmail.com>
  * Nathan Patrick <npatrick at corp.sonic.net>
+ * Joseph Sullivan <jossulli@amazon.com>
  *
  *
  * sofia.c -- SOFIA SIP Endpoint (sofia code)
@@ -936,7 +937,7 @@ static void our_sofia_event_callback(nua_event_t event,
 		uint32_t sess_count = switch_core_session_count();
 		uint32_t sess_max = switch_core_session_limit(0);
 		
-		if (sess_count >= sess_max || !sofia_test_pflag(profile, PFLAG_RUNNING) || !switch_core_ready()) {
+		if (sess_count >= sess_max || !sofia_test_pflag(profile, PFLAG_RUNNING) || !switch_core_ready_inbound()) {
 			nua_respond(nh, 503, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), TAG_END());
 
 			//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "No more sessions allowed at this time.\n");
@@ -8351,7 +8352,7 @@ void sofia_handle_sip_i_options(int status,
 	uint32_t sess_max = switch_core_session_limit(0);
 
 	if (sofia_test_pflag(profile, PFLAG_OPTIONS_RESPOND_503_ON_BUSY) &&
-			(sess_count >= sess_max || !sofia_test_pflag(profile, PFLAG_RUNNING) || !switch_core_ready())) {
+			(sess_count >= sess_max || !sofia_test_pflag(profile, PFLAG_RUNNING) || !switch_core_ready_inbound())) {
 		nua_respond(nh, 503, "Maximum Calls In Progress", NUTAG_WITH_THIS_MSG(de->data->e_msg), SIPTAG_RETRY_AFTER_STR("300"), TAG_END());
 	} else {
 		nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
diff --git a/src/switch_core.c b/src/switch_core.c
index 4d00122b37..e07616d132 100644
--- a/src/switch_core.c
+++ b/src/switch_core.c
@@ -27,6 +27,7 @@
  * Michael Jerris <mike@jerris.com>
  * Paul D. Tinsley <pdt at jackhammer.org>
  * Marcel Barbulescu <marcelbarbulescu@gmail.com>
+ * Joseph Sullivan <jossulli@amazon.com>
  *
  *
  * switch_core.c -- Main Core Library
@@ -2000,13 +2001,27 @@ SWITCH_DECLARE(int32_t) switch_core_session_ctl(switch_session_ctl_t cmd, void *
 	case SCSC_SYNC_CLOCK_WHEN_IDLE:
 		newintval = switch_core_session_sync_clock();
 		break;
-	case SCSC_PAUSE_INBOUND:
+	case SCSC_PAUSE_ALL:
 		if (oldintval) {
 			switch_set_flag((&runtime), SCF_NO_NEW_SESSIONS);
 		} else {
 			switch_clear_flag((&runtime), SCF_NO_NEW_SESSIONS);
 		}
 		break;
+	case SCSC_PAUSE_INBOUND:
+		if (oldintval) {
+			switch_set_flag((&runtime), SCF_NO_NEW_INBOUND_SESSIONS);
+		} else {
+			switch_clear_flag((&runtime), SCF_NO_NEW_INBOUND_SESSIONS);
+		}
+		break;
+	case SCSC_PAUSE_OUTBOUND:
+		if (oldintval) {
+			switch_set_flag((&runtime), SCF_NO_NEW_OUTBOUND_SESSIONS);
+		} else {
+			switch_clear_flag((&runtime), SCF_NO_NEW_OUTBOUND_SESSIONS);
+		}
+		break;
 	case SCSC_HUPALL:
 		switch_core_session_hupall(SWITCH_CAUSE_MANAGER_REQUEST);
 		break;
@@ -2069,7 +2084,13 @@ SWITCH_DECLARE(int32_t) switch_core_session_ctl(switch_session_ctl_t cmd, void *
 		}
 		break;
 	case SCSC_PAUSE_CHECK:
-		newintval = !!switch_test_flag((&runtime), SCF_NO_NEW_SESSIONS);
+		newintval = !!(switch_test_flag((&runtime), SCF_NO_NEW_SESSIONS) == SCF_NO_NEW_SESSIONS);
+		break;
+	case SCSC_PAUSE_INBOUND_CHECK:
+		newintval = !!switch_test_flag((&runtime), SCF_NO_NEW_INBOUND_SESSIONS);
+		break;
+	case SCSC_PAUSE_OUTBOUND_CHECK:
+		newintval = !!switch_test_flag((&runtime), SCF_NO_NEW_OUTBOUND_SESSIONS);
 		break;
 	case SCSC_READY_CHECK:
 		newintval = switch_core_ready();
@@ -2169,7 +2190,17 @@ SWITCH_DECLARE(switch_core_flag_t) switch_core_flags(void)
 
 SWITCH_DECLARE(switch_bool_t) switch_core_ready(void)
 {
-	return (switch_test_flag((&runtime), SCF_SHUTTING_DOWN) || switch_test_flag((&runtime), SCF_NO_NEW_SESSIONS)) ? SWITCH_FALSE : SWITCH_TRUE;
+	return (switch_test_flag((&runtime), SCF_SHUTTING_DOWN) || switch_test_flag((&runtime), SCF_NO_NEW_SESSIONS) == SCF_NO_NEW_SESSIONS) ? SWITCH_FALSE : SWITCH_TRUE;
+}
+
+SWITCH_DECLARE(switch_bool_t) switch_core_ready_inbound(void)
+{
+	return (switch_test_flag((&runtime), SCF_SHUTTING_DOWN) || switch_test_flag((&runtime), SCF_NO_NEW_INBOUND_SESSIONS)) ? SWITCH_FALSE : SWITCH_TRUE;
+}
+
+SWITCH_DECLARE(switch_bool_t) switch_core_ready_outbound(void)
+{
+	return (switch_test_flag((&runtime), SCF_SHUTTING_DOWN) || switch_test_flag((&runtime), SCF_NO_NEW_OUTBOUND_SESSIONS)) ? SWITCH_FALSE : SWITCH_TRUE;
 }
 
 SWITCH_DECLARE(switch_status_t) switch_core_destroy(void)
diff --git a/src/switch_core_session.c b/src/switch_core_session.c
index 1b27ad5e12..8f72afc893 100644
--- a/src/switch_core_session.c
+++ b/src/switch_core_session.c
@@ -26,6 +26,7 @@
  * Anthony Minessale II <anthm@freeswitch.org>
  * Michael Jerris <mike@jerris.com>
  * Paul D. Tinsley <pdt at jackhammer.org>
+ * Joseph Sullivan <jossulli@amazon.com>
  *
  *
  * switch_core_session.c -- Main Core Library (session routines)
@@ -1781,6 +1782,16 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request_uuid(switch_
 		return NULL;
 	}
 
+	if (direction == SWITCH_CALL_DIRECTION_INBOUND && !switch_core_ready_inbound()) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "The system cannot create any inbound sessions at this time.\n");
+		return NULL;
+	}
+
+	if (direction == SWITCH_CALL_DIRECTION_OUTBOUND && !switch_core_ready_outbound()) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "The system cannot create any outbound sessions at this time.\n");
+		return NULL;
+	}
+
 	if (!switch_core_ready() || endpoint_interface == NULL) {
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "The system cannot create any sessions at this time.\n");
 		return NULL;