]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
fix recursion error
authorAnthony Minessale <anthm@freeswitch.org>
Mon, 10 Dec 2012 16:56:07 +0000 (10:56 -0600)
committerAnthony Minessale <anthm@freeswitch.org>
Mon, 10 Dec 2012 16:56:07 +0000 (10:56 -0600)
src/include/switch_ivr.h
src/include/switch_types.h
src/switch_ivr.c
src/switch_ivr_async.c
src/switch_ivr_play_say.c
src/switch_ivr_say.c

index 06679f53d317e686db0cff04de7c8117bd113cf2..e4e8517781f6ea3f4f2e776939d0c835a1a04d03 100644 (file)
@@ -358,7 +358,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_stop_inband_dtmf_generate_session(swi
   \brief - NEEDDESC -
   \param session the session to act on
 */
-SWITCH_DECLARE(void) switch_ivr_session_echo(switch_core_session_t *session, switch_input_args_t *args);
+SWITCH_DECLARE(switch_status_t) switch_ivr_session_echo(switch_core_session_t *session, switch_input_args_t *args);
 
 /*!
   \brief Stop looking for TONES
index 20c83cd8986d0ac43953399fbdf5efbc71b298d4..c6dfb4376c19a2882aaf4a9a75349ceed3dc160b 100644 (file)
@@ -1972,6 +1972,19 @@ struct switch_ivr_dmachine_match {
 typedef struct switch_ivr_dmachine_match switch_ivr_dmachine_match_t;
 typedef switch_status_t (*switch_ivr_dmachine_callback_t) (switch_ivr_dmachine_match_t *match);
 
+#define MAX_ARG_RECURSION 25
+
+#define arg_recursion_check_start(_args) if (_args) {                                  \
+               if (_args->loops >= MAX_ARG_RECURSION) {                                                \
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,         \
+                                                         "RECURSION ERROR!  It's not the best idea to call things that collect input recursively from an input callback.\n"); \
+                       return SWITCH_STATUS_GENERR;                                                            \
+               } else {_args->loops++;}                                                                                \
+       }
+
+
+#define arg_recursion_check_stop(_args) if (_args) _args->loops--
+
 typedef struct {
        switch_input_callback_function_t input_callback;
        void *buf;
@@ -1979,6 +1992,7 @@ typedef struct {
        switch_read_frame_callback_function_t read_frame_callback;
        void *user_data;
        switch_ivr_dmachine_t *dmachine;
+       int loops;
 } switch_input_args_t;
 
 
index 6aa51666348af4fabb2e1243452c6602de9c2f5f..42bd11b80274456b0c8de0dc8d7a34f93dd59e30 100644 (file)
@@ -141,6 +141,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_sleep(switch_core_session_t *session,
        int sval = 0;
        const char *var;
 
+       arg_recursion_check_start(args);
+
        /*
           if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND && !switch_channel_test_flag(channel, CF_PROXY_MODE) && 
           !switch_channel_media_ready(channel) && !switch_channel_test_flag(channel, CF_SERVICE)) {
@@ -156,12 +158,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_sleep(switch_core_session_t *session,
                for (elapsed=0; switch_channel_up(channel) && elapsed<(ms/20); elapsed++) {
                        if (switch_channel_test_flag(channel, CF_BREAK)) {
                                switch_channel_clear_flag(channel, CF_BREAK);
-                               return SWITCH_STATUS_BREAK;
+                               switch_goto_status(SWITCH_STATUS_BREAK, end);
                        }
                
                        switch_yield(20 * 1000);
                }
-               return SWITCH_STATUS_SUCCESS;
+               switch_goto_status(SWITCH_STATUS_SUCCESS, end);
        }
 
        var = switch_channel_get_variable(channel, SWITCH_SEND_SILENCE_WHEN_IDLE_VARIABLE);
@@ -183,7 +185,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_sleep(switch_core_session_t *session,
                                                                   switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec Error L16@%uhz %u channels %dms\n",
                                                          imp.samples_per_second, imp.number_of_channels, imp.microseconds_per_packet / 1000);
-                       return SWITCH_STATUS_FALSE;
+                       switch_goto_status(SWITCH_STATUS_FALSE, end);
                }
 
 
@@ -213,7 +215,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_sleep(switch_core_session_t *session,
        }
 
        if (!ms) {
-               return SWITCH_STATUS_SUCCESS;
+               switch_goto_status(SWITCH_STATUS_SUCCESS, end);
        }
 
        for (;;) {
@@ -303,6 +305,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_sleep(switch_core_session_t *session,
                }
        }
 
+
+ end:
+
+       arg_recursion_check_stop(args);
+
        if (write_frame.codec) {
                switch_core_codec_destroy(&codec);
        }
@@ -874,6 +881,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session,
        unsigned char *abuf = NULL;
        switch_codec_implementation_t imp = { 0 };
 
+
+
        if (switch_channel_test_flag(channel, CF_RECOVERED) && switch_channel_test_flag(channel, CF_CONTROLLED)) {
                switch_channel_clear_flag(channel, CF_CONTROLLED);
        }
@@ -887,6 +896,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session,
                return SWITCH_STATUS_FALSE;
        }
 
+       arg_recursion_check_start(args);
+
        if ((to = switch_channel_get_variable(channel, "park_timeout"))) {
                char *cause_str;
 
@@ -931,7 +942,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session,
                                                                   switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
                                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec Error L16@%uhz %u channels %dms\n",
                                                                          imp.samples_per_second, imp.number_of_channels, imp.microseconds_per_packet / 1000);
-                                       return SWITCH_STATUS_FALSE;
+                                       switch_goto_status(SWITCH_STATUS_FALSE, end);
                                }
 
 
@@ -982,7 +993,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session,
                if (switch_channel_test_flag(channel, CF_UNICAST)) {
                        if (!switch_channel_media_ready(channel)) {
                                if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
-                                       return SWITCH_STATUS_FALSE;
+                                       switch_goto_status(SWITCH_STATUS_FALSE, end);
                                }
                        }
 
@@ -1100,6 +1111,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session,
 
        }
 
+ end:
+
+       arg_recursion_check_stop(args);
+
        if (write_frame.codec) {
                switch_core_codec_destroy(&codec);
        }
@@ -1133,12 +1148,15 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_collect_digits_callback(switch_core_s
                return SWITCH_STATUS_GENERR;
        }
 
+       arg_recursion_check_start(args);
+
        if (abs_timeout) {
                abs_started = switch_micro_time_now();
        }
        if (digit_timeout) {
                digit_started = switch_micro_time_now();
        }
+
        while (switch_channel_ready(channel)) {
                switch_frame_t *read_frame = NULL;
                switch_event_t *event;
@@ -1224,6 +1242,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_collect_digits_callback(switch_core_s
                }
        }
 
+       arg_recursion_check_stop(args);
+
        return status;
 }
 
@@ -2890,6 +2910,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_say(switch_core_session_t *session,
        channel = switch_core_session_get_channel(session);
        switch_assert(channel);
 
+       arg_recursion_check_start(args);
+
+
        if (zstr(module_name)) {
                module_name = "en";
        }
@@ -2971,6 +2994,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_say(switch_core_session_t *session,
 
   done:
 
+       arg_recursion_check_stop(args);
+
+
        if (hint_data) {
                switch_event_destroy(&hint_data);
        }
index f301b118878bbeded73a57170f236ceb349f3a06..80b7a3ae2587d7017e6593b311111910c0926a97 100644 (file)
@@ -616,7 +616,7 @@ static void *SWITCH_THREAD_FUNC echo_video_thread(switch_thread_t *thread, void
 }
 #endif
 
-SWITCH_DECLARE(void) switch_ivr_session_echo(switch_core_session_t *session, switch_input_args_t *args)
+SWITCH_DECLARE(switch_status_t) switch_ivr_session_echo(switch_core_session_t *session, switch_input_args_t *args)
 {
        switch_status_t status;
        switch_frame_t *read_frame;
@@ -630,9 +630,11 @@ SWITCH_DECLARE(void) switch_ivr_session_echo(switch_core_session_t *session, swi
 #endif
 
        if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
-               return;
+               return SWITCH_STATUS_FALSE;
        }
 
+       arg_recursion_check_start(args);
+
  restart:
 
 #ifdef SWITCH_VIDEO_IN_THREADS
@@ -725,6 +727,7 @@ SWITCH_DECLARE(void) switch_ivr_session_echo(switch_core_session_t *session, swi
        }
 #endif
 
+       return SWITCH_STATUS_SUCCESS;
 }
 
 typedef struct {
@@ -3413,6 +3416,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_and_detect_speech(switch_core_se
        play_and_detect_speech_state_t state = { 0, "" };
        switch_channel_t *channel = switch_core_session_get_channel(session);
 
+       arg_recursion_check_start(args);
+
        if (result == NULL) {
                goto done;
        }
@@ -3474,6 +3479,8 @@ done:
                status = SWITCH_STATUS_FALSE;
        }
 
+       arg_recursion_check_stop(args);
+
        return status;;
 }
 
index c15da6fb032063c099da7b1e86babd653f75d724..e7e2e4e22a952ec6b17cc59caf116b66fc5144e9 100644 (file)
@@ -54,11 +54,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_phrase_macro_event(switch_core_sessio
        switch_bool_t sound_prefix_enforced = switch_true(switch_channel_get_variable(channel, "sound_prefix_enforced"));
        switch_bool_t local_sound_prefix_enforced = SWITCH_FALSE;
 
+
        if (!macro_name) {
                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No phrase macro specified.\n");
                return status;
        }
 
+       arg_recursion_check_start(args);
+
        if (!lang) {
                chan_lang = switch_channel_get_variable(channel, "default_language");
                if (!chan_lang) {
@@ -331,6 +334,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_phrase_macro_event(switch_core_sessio
 
   done:
 
+       arg_recursion_check_stop(args);
+
        if (hint_data) {
                switch_event_destroy(&hint_data);
        }
@@ -379,6 +384,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se
        int restart_limit_on_dtmf = 0;
        const char *prefix, *var;
 
+
        prefix = switch_channel_get_variable(channel, "sound_prefix");
 
        if (!prefix) {
@@ -404,6 +410,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se
                return SWITCH_STATUS_FALSE;
        }
 
+       arg_recursion_check_start(args);
+
        if (!fh) {
                fh = &lfh;
        }
@@ -467,6 +475,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se
                        write_frame.samples = write_frame.datalen / 2;
                        write_frame.codec = &write_codec;
                } else {
+                       arg_recursion_check_stop(args);
                        return SWITCH_STATUS_FALSE;
                }
        }
@@ -519,6 +528,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se
        if (switch_core_file_open(fh, file, fh->channels, read_impl.actual_samples_per_second, file_flags, NULL) != SWITCH_STATUS_SUCCESS) {
                switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
                switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
+               arg_recursion_check_stop(args);
                return SWITCH_STATUS_GENERR;
        }
 
@@ -590,6 +600,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se
                                                          fh->channels, read_impl.microseconds_per_packet / 1000);
                        switch_core_file_close(fh);
                        switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
+                       arg_recursion_check_stop(args);
                        return SWITCH_STATUS_GENERR;
                }
        }
@@ -796,6 +807,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se
        }
 
        switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
+
+       arg_recursion_check_stop(args);
        return status;
 }
 
@@ -841,6 +854,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_gentones(switch_core_session_t *sessi
 
                return SWITCH_STATUS_FALSE;
        }
+
+       arg_recursion_check_start(args);
+
        memset(&ts, 0, sizeof(ts));
        write_frame.codec = &write_codec;
        write_frame.data = data;
@@ -946,6 +962,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_gentones(switch_core_session_t *sessi
        switch_buffer_destroy(&audio_buffer);
        teletone_destroy_session(&ts);
 
+       arg_recursion_check_stop(args);
+
        return SWITCH_STATUS_SUCCESS;
 }
 
@@ -1084,6 +1102,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
                return SWITCH_STATUS_FALSE;
        }
 
+       arg_recursion_check_start(args);
+
        if (!strcasecmp(read_impl.iananame, "l16")) {
                l16++;
        }
@@ -1136,6 +1156,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
                                                *arg++ = '\0';
                                        }
                                        if ((status = switch_ivr_phrase_macro(session, dup, arg, lang, args)) != SWITCH_STATUS_SUCCESS) {
+                                               arg_recursion_check_stop(args);
                                                return status;
                                        }
                                        continue;
@@ -1160,6 +1181,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
 
                                if (!zstr(engine) && !zstr(voice) && !zstr(text)) {
                                        if ((status = switch_ivr_speak_text(session, engine, voice, text, args)) != SWITCH_STATUS_SUCCESS) {
+                                               arg_recursion_check_stop(args);
                                                return status;
                                        }
                                } else {
@@ -1168,6 +1190,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
                                        voice = (char *) switch_channel_get_variable(channel, "tts_voice");
                                        if (engine && text) {
                                                if ((status = switch_ivr_speak_text(session, engine, voice, text, args)) != SWITCH_STATUS_SUCCESS) {
+                                                       arg_recursion_check_stop(args);
                                                        return status;
                                                }
                                        } else {
@@ -1727,6 +1750,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
        switch_safe_free(abuf);
 
        switch_core_session_reset(session, SWITCH_FALSE, SWITCH_FALSE);
+
+       arg_recursion_check_stop(args);
+
        return status;
 }
 
@@ -2119,6 +2145,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session
                return SWITCH_STATUS_FALSE;
        }
 
+       arg_recursion_check_start(args);
+
        write_frame.data = abuf;
        write_frame.buflen = sizeof(abuf);
 
@@ -2149,6 +2177,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session
                switch_size_t mylen = strlen(text) + extra + 1;
                tmp = malloc(mylen);
                if (!tmp) {
+                       arg_recursion_check_stop(args);
                        return SWITCH_STATUS_MEMERR;
                }
                memset(tmp, 0, mylen);
@@ -2369,6 +2398,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session
        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "done speaking text\n");
        flags = 0;
        switch_core_speech_flush_tts(sh);
+
+       arg_recursion_check_stop(args);
        return status;
 }
 
@@ -2426,6 +2457,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text(switch_core_session_t *ses
                return SWITCH_STATUS_FALSE;
        }
 
+       arg_recursion_check_start(args);
+
        sh = &lsh;
        codec = &lcodec;
        timer = &ltimer;
@@ -2466,6 +2499,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text(switch_core_session_t *ses
                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid TTS module!\n");
                        switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
                        switch_ivr_clear_speech_cache(session);
+                       arg_recursion_check_stop(args);
                        return status;
                }
        } else if (cache_obj && strcasecmp(cache_obj->voice_name, voice_name)) {
@@ -2476,6 +2510,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text(switch_core_session_t *ses
        if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
                flags = 0;
                switch_core_speech_close(sh, &flags);
+               arg_recursion_check_stop(args);
                return SWITCH_STATUS_FALSE;
        }
        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "OPEN TTS %s\n", tts_name);
@@ -2495,6 +2530,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text(switch_core_session_t *ses
                        switch_core_speech_close(sh, &flags);
                        switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
                        switch_ivr_clear_speech_cache(session);
+                       arg_recursion_check_stop(args);
                        return SWITCH_STATUS_GENERR;
                }
        }
@@ -2510,6 +2546,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text(switch_core_session_t *ses
                                switch_core_speech_close(sh, &flags);
                                switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
                                switch_ivr_clear_speech_cache(session);
+                               arg_recursion_check_stop(args);
                                return SWITCH_STATUS_GENERR;
                        }
                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Setup timer success %u bytes per %d ms!\n", sh->samples * 2,
@@ -2539,6 +2576,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text(switch_core_session_t *ses
        }
 
        switch_core_session_reset(session, SWITCH_FALSE, SWITCH_TRUE);
+       arg_recursion_check_stop(args);
+
        return status;
 }
 
index 0081ab16f51f8f2e1d5b74bd6d1e626a1ed60b4c..214931b1bd97dc20662d727ac8d956ed91764919 100644 (file)
@@ -133,6 +133,8 @@ SWITCH_DECLARE(switch_say_type_t) switch_ivr_get_say_type_by_name(const char *na
 SWITCH_DECLARE(switch_status_t) switch_ivr_say_spell(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args)
 {
        char *p;
+       
+       arg_recursion_check_start(args);
 
        for (p = tosay; p && *p; p++) {
                int a = tolower((int) *p);
@@ -147,6 +149,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_say_spell(switch_core_session_t *sess
                }
        }
 
+       arg_recursion_check_stop(args);
+
        return SWITCH_STATUS_SUCCESS;
 }
 
@@ -172,24 +176,28 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_say_ip(switch_core_session_t *session
                                                                                                  switch_input_args_t *args)
 {
        char *a, *b, *c, *d;
+       switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+       arg_recursion_check_start(args);
+
        if (!(a = switch_core_session_strdup(session, tosay))) {
-               return SWITCH_STATUS_FALSE;
+               switch_goto_status(SWITCH_STATUS_FALSE, end);
        }
 
        if (!(b = strchr(a, '.'))) {
-               return SWITCH_STATUS_FALSE;
+               switch_goto_status(SWITCH_STATUS_FALSE, end);
        }
 
        *b++ = '\0';
 
        if (!(c = strchr(b, '.'))) {
-               return SWITCH_STATUS_FALSE;
+               switch_goto_status(SWITCH_STATUS_FALSE, end);
        }
 
        *c++ = '\0';
 
        if (!(d = strchr(c, '.'))) {
-               return SWITCH_STATUS_FALSE;
+               switch_goto_status(SWITCH_STATUS_FALSE, end);
        }
 
        *d++ = '\0';
@@ -202,7 +210,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_say_ip(switch_core_session_t *session
        say_file("digits/dot.wav");
        say_num(atoi(d), say_args->method);
 
-       return SWITCH_STATUS_SUCCESS;
+ end:
+
+       arg_recursion_check_stop(args);
+
+       return status;
 }