From fcaaf20c7dd8ac946dc0dda314e2c77f672f98e9 Mon Sep 17 00:00:00 2001 From: Andrey Volk Date: Thu, 12 Aug 2021 18:02:41 +0300 Subject: [PATCH] [Core] switch_ivr: Restrict the misuse of uuid_hold API. Add switch_hold unit-test. --- .../applications/mod_commands/mod_commands.c | 2 + src/switch_ivr.c | 39 ++++- tests/unit/.gitignore | 1 + tests/unit/Makefile.am | 1 + tests/unit/conf_hold/freeswitch.xml | 157 ++++++++++++++++++ tests/unit/conf_hold/gw/holdtest.xml | 14 ++ tests/unit/switch_hold.c | 105 ++++++++++++ 7 files changed, 311 insertions(+), 8 deletions(-) create mode 100644 tests/unit/conf_hold/freeswitch.xml create mode 100644 tests/unit/conf_hold/gw/holdtest.xml create mode 100644 tests/unit/switch_hold.c diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 955f80ae33..b5f7f5ff8e 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -7896,6 +7896,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) switch_console_set_complete("add uuid_flush_dtmf ::console::list_uuid"); switch_console_set_complete("add uuid_getvar ::console::list_uuid"); switch_console_set_complete("add uuid_hold ::console::list_uuid"); + switch_console_set_complete("add uuid_hold off ::console::list_uuid"); + switch_console_set_complete("add uuid_hold toggle ::console::list_uuid"); switch_console_set_complete("add uuid_send_info ::console::list_uuid"); switch_console_set_complete("add uuid_jitterbuffer ::console::list_uuid"); switch_console_set_complete("add uuid_kill ::console::list_uuid"); diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 4f9d2d0cbd..ddd3a8e529 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -1530,6 +1530,16 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_hold(switch_core_session_t *session, const char *other_uuid; switch_event_t *event; + if (channel) { + switch_channel_callstate_t callstate; + + callstate = switch_channel_get_callstate(channel); + if (callstate == CCS_HELD) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Call is already on hold. No need to hold again.\n"); + return SWITCH_STATUS_FALSE; + } + } + msg.message_id = SWITCH_MESSAGE_INDICATE_HOLD; msg.string_arg = message; msg.from = __FILE__; @@ -1557,13 +1567,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_hold(switch_core_session_t *session, SWITCH_DECLARE(switch_status_t) switch_ivr_hold_uuid(const char *uuid, const char *message, switch_bool_t moh) { switch_core_session_t *session; + switch_status_t status = SWITCH_STATUS_SUCCESS; if ((session = switch_core_session_locate(uuid))) { - switch_ivr_hold(session, message, moh); + status = switch_ivr_hold(session, message, moh); switch_core_session_rwunlock(session); } - return SWITCH_STATUS_SUCCESS; + return status; } SWITCH_DECLARE(switch_status_t) switch_ivr_hold_toggle_uuid(const char *uuid, const char *message, switch_bool_t moh) @@ -1571,21 +1582,22 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_hold_toggle_uuid(const char *uuid, co switch_core_session_t *session; switch_channel_t *channel; switch_channel_callstate_t callstate; + switch_status_t status = SWITCH_STATUS_SUCCESS; if ((session = switch_core_session_locate(uuid))) { if ((channel = switch_core_session_get_channel(session))) { callstate = switch_channel_get_callstate(channel); - if (callstate == CCS_ACTIVE) { - switch_ivr_hold(session, message, moh); + if (callstate == CCS_ACTIVE || callstate == CCS_UNHELD) { + status = switch_ivr_hold(session, message, moh); } else if (callstate == CCS_HELD) { - switch_ivr_unhold(session); + status = switch_ivr_unhold(session); } } switch_core_session_rwunlock(session); } - return SWITCH_STATUS_SUCCESS; + return status; } SWITCH_DECLARE(switch_status_t) switch_ivr_unhold(switch_core_session_t *session) @@ -1596,6 +1608,16 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_unhold(switch_core_session_t *session switch_core_session_t *b_session; switch_event_t *event; + if (channel) { + switch_channel_callstate_t callstate; + + callstate = switch_channel_get_callstate(channel); + if (callstate != CCS_HELD) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Call is not on hold. No need to unhold.\n"); + return SWITCH_STATUS_FALSE; + } + } + msg.message_id = SWITCH_MESSAGE_INDICATE_UNHOLD; msg.from = __FILE__; @@ -1624,13 +1646,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_unhold(switch_core_session_t *session SWITCH_DECLARE(switch_status_t) switch_ivr_unhold_uuid(const char *uuid) { switch_core_session_t *session; + switch_status_t status = SWITCH_STATUS_SUCCESS; if ((session = switch_core_session_locate(uuid))) { - switch_ivr_unhold(session); + status = switch_ivr_unhold(session); switch_core_session_rwunlock(session); } - return SWITCH_STATUS_SUCCESS; + return status; } diff --git a/tests/unit/.gitignore b/tests/unit/.gitignore index 66ea66aa06..4c7b7466c4 100644 --- a/tests/unit/.gitignore +++ b/tests/unit/.gitignore @@ -22,6 +22,7 @@ switch_core_video switch_eavesdrop switch_event switch_hash +switch_hold switch_ivr_async switch_ivr_originate switch_ivr_play_say diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index ee2e92b175..3f41d71dda 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -4,6 +4,7 @@ noinst_PROGRAMS = switch_event switch_hash switch_ivr_originate switch_utils swi switch_ivr_play_say switch_core_codec switch_rtp switch_xml noinst_PROGRAMS += switch_core_video switch_core_db switch_vad switch_packetizer switch_core_session test_sofia switch_ivr_async switch_core_asr switch_log +noinst_PROGRAMS+= switch_hold AM_LDFLAGS += -avoid-version -no-undefined $(SWITCH_AM_LDFLAGS) $(openssl_LIBS) AM_LDFLAGS += $(FREESWITCH_LIBS) $(switch_builddir)/libfreeswitch.la $(CORE_LIBS) $(APR_LIBS) diff --git a/tests/unit/conf_hold/freeswitch.xml b/tests/unit/conf_hold/freeswitch.xml new file mode 100644 index 0000000000..883e3846e1 --- /dev/null +++ b/tests/unit/conf_hold/freeswitch.xml @@ -0,0 +1,157 @@ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + +
+
diff --git a/tests/unit/conf_hold/gw/holdtest.xml b/tests/unit/conf_hold/gw/holdtest.xml new file mode 100644 index 0000000000..d919ddb2d4 --- /dev/null +++ b/tests/unit/conf_hold/gw/holdtest.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/tests/unit/switch_hold.c b/tests/unit/switch_hold.c new file mode 100644 index 0000000000..9da8ccfc94 --- /dev/null +++ b/tests/unit/switch_hold.c @@ -0,0 +1,105 @@ +#include +#include + +FST_CORE_DB_BEGIN("./conf_hold") +{ +FST_SUITE_BEGIN(switch_hold) +{ + FST_SETUP_BEGIN() + { + fst_requires_module("mod_sofia"); + fst_requires_module("mod_commands"); + } + FST_SETUP_END() + + FST_TEARDOWN_BEGIN() + { + } + FST_TEARDOWN_END() + + FST_TEST_BEGIN(hold_unhold_restriction) + { + switch_core_session_t *session = NULL; + switch_status_t status; + switch_call_cause_t cause; + + status = switch_ivr_originate(NULL, &session, &cause, "{ignore_early_media=true}sofia/gateway/hold_unhold_test/+15553332900", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL); + fst_requires(session); + fst_check(status == SWITCH_STATUS_SUCCESS); + + if (session) { + const char *uuid = switch_core_session_get_uuid(session); + switch_channel_t *channel = NULL; + + channel = switch_core_session_get_channel(session); + fst_requires(channel); + + if (uuid) { + char *off_uuid = switch_mprintf("off %s", uuid); + char *toggle_uuid = switch_mprintf("toggle %s", uuid); + + switch_stream_handle_t stream = { 0 }; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "firing the api.\n"); + + SWITCH_STANDARD_STREAM(stream); + switch_api_execute("uuid_hold", off_uuid, NULL, &stream); + fst_check_string_equals(stream.data, "-ERR Operation failed\n"); + switch_safe_free(stream.data); + switch_sleep(200000); + + SWITCH_STANDARD_STREAM(stream); + switch_api_execute("uuid_hold", uuid, NULL, &stream); + fst_check_string_equals(stream.data, "+OK Success\n"); + switch_safe_free(stream.data); + switch_sleep(200000); + + SWITCH_STANDARD_STREAM(stream); + switch_api_execute("uuid_hold", uuid, NULL, &stream); + fst_check_string_equals(stream.data, "-ERR Operation failed\n"); + switch_safe_free(stream.data); + switch_sleep(200000); + + SWITCH_STANDARD_STREAM(stream); + switch_api_execute("uuid_hold", uuid, NULL, &stream); + fst_check_string_equals(stream.data, "-ERR Operation failed\n"); + switch_safe_free(stream.data); + switch_sleep(200000); + + SWITCH_STANDARD_STREAM(stream); + switch_api_execute("uuid_hold", toggle_uuid, NULL, &stream); + fst_check_string_equals(stream.data, "+OK Success\n"); + switch_safe_free(stream.data); + switch_sleep(200000); + + SWITCH_STANDARD_STREAM(stream); + switch_api_execute("uuid_hold", off_uuid, NULL, &stream); + fst_check_string_equals(stream.data, "-ERR Operation failed\n"); + switch_safe_free(stream.data); + switch_sleep(200000); + + SWITCH_STANDARD_STREAM(stream); + switch_api_execute("uuid_hold", toggle_uuid, NULL, &stream); + fst_check_string_equals(stream.data, "+OK Success\n"); + switch_safe_free(stream.data); + switch_sleep(200000); + + SWITCH_STANDARD_STREAM(stream); + switch_api_execute("uuid_hold", uuid, NULL, &stream); + fst_check_string_equals(stream.data, "-ERR Operation failed\n"); + switch_safe_free(stream.data); + switch_sleep(200000); + + switch_safe_free(off_uuid); + switch_safe_free(toggle_uuid); + } + + switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + switch_core_session_rwunlock(session); + } + } + FST_TEST_END() +} +FST_SUITE_END() +} +FST_CORE_END() +