diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index e5311468e3..8ec44ef60c 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -3660,7 +3660,12 @@ SWITCH_STANDARD_API(ft_function) if(chan_id > ftdm_span_get_chan_count(span)) { stream->write_function(stream, "-ERR invalid channel\n"); } else { + char *dbgstr = NULL; + ftdm_channel_t *fchan = ftdm_span_get_channel(span, chan_id); dump_chan(span, chan_id, stream); + dbgstr = ftdm_channel_get_history_str(fchan); + stream->write_function(stream, "%s\n", dbgstr); + ftdm_free(dbgstr); } } else { stream->write_function(stream, "+OK\n"); @@ -3989,7 +3994,7 @@ SWITCH_STANDARD_API(ft_function) if (rply) { stream->write_function(stream, "%s", rply); - free(rply); + ftdm_free(rply); } else { stream->write_function(stream, "-ERR Usage: %s\n", FT_SYNTAX); } diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index bb46e798b2..0cb217065a 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -1293,6 +1293,16 @@ end: ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_DEBUG, "Changed state from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state)); ftdmchan->last_state = ftdmchan->state; ftdmchan->state = state; + ftdmchan->history[ftdmchan->hindex].file = file; + ftdmchan->history[ftdmchan->hindex].func = func; + ftdmchan->history[ftdmchan->hindex].line = line; + ftdmchan->history[ftdmchan->hindex].state = ftdmchan->state; + ftdmchan->history[ftdmchan->hindex].last_state = ftdmchan->last_state; + ftdmchan->history[ftdmchan->hindex].time = ftdm_current_time_in_ms(); + ftdmchan->hindex++; + if (ftdmchan->hindex == ftdm_array_len(ftdmchan->history)) { + ftdmchan->hindex = 0; + } ftdm_set_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); ftdm_mutex_lock(ftdmchan->span->mutex); @@ -5192,6 +5202,63 @@ FT_DECLARE(char *) ftdm_strndup(const char *str, ftdm_size_t inlen) return new; } +#define FTDM_DEBUG_LINE_LEN 255 +#define handle_snprintf_result(buff, written, len, debugstr) \ + if (written >= len) { \ + ftdm_free(debugstr); \ + return NULL; \ + } \ + len -= written; \ + buff += written; + +FT_DECLARE(char *) ftdm_channel_get_history_str(const ftdm_channel_t *fchan) +{ + char func[255]; + char line[255]; + char states[255]; + int written = 0; + char *buff = NULL; + uint8_t i = 0; + int dbglen = ftdm_array_len(fchan->history) * FTDM_DEBUG_LINE_LEN; + int len = dbglen; + + if (!fchan->history[0].file) { + return ftdm_strdup("-- No state history --\n"); + } + + char *debugstr = ftdm_calloc(1, dbglen); + if (!debugstr) { + return NULL; + } + buff = debugstr; + + written = snprintf(buff, len, "%-30.30s %-30.30s %s", "-- States --", "-- Function --", "-- Location --\n"); + handle_snprintf_result(buff, written, len, debugstr); + + for (i = fchan->hindex; i < ftdm_array_len(fchan->history); i++) { + if (!fchan->history[i].file) { + break; + } + snprintf(states, sizeof(states), "%-5.15s => %-5.15s", ftdm_channel_state2str(fchan->history[i].last_state), ftdm_channel_state2str(fchan->history[i].state)); + snprintf(func, sizeof(func), "[%s]", fchan->history[i].func); + snprintf(line, sizeof(func), "[%s:%d]", fchan->history[i].file, fchan->history[i].line); + written = snprintf(buff, len, "%-30.30s %-30.30s %s\n", states, func, line); + handle_snprintf_result(buff, written, len, debugstr); + } + + for (i = 0; i < fchan->hindex; i++) { + snprintf(states, sizeof(states), "%-5.15s => %-5.15s", ftdm_channel_state2str(fchan->history[i].last_state), ftdm_channel_state2str(fchan->history[i].state)); + snprintf(func, sizeof(func), "[%s]", fchan->history[i].func); + snprintf(line, sizeof(func), "[%s:%d]", fchan->history[i].file, fchan->history[i].line); + written = snprintf(buff, len, "%-30.30s %-30.30s %s\n", states, func, line); + handle_snprintf_result(buff, written, len, debugstr); + } + + debugstr[dbglen-1] = 0; + + return debugstr; +} + /* For Emacs: * Local Variables: diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 3b847f821e..078875b09c 100644 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -1277,7 +1277,13 @@ FT_DECLARE(const char *) ftdm_channel_get_state_str(const ftdm_channel_t *channe /*! \brief For display debugging purposes you can display this string which describes the last channel internal state */ FT_DECLARE(const char *) ftdm_channel_get_last_state_str(const ftdm_channel_t *channel); -/*! \brief For display debugging purposes you can display this string which describes the last channel internal state */ +/*! \brief For display debugging purposes you can display this string which describes the history of the channel + * \param The channel + * \return History string for the channel. You must free the string with ftdm_free + */ +FT_DECLARE(char *) ftdm_channel_get_history_str(const ftdm_channel_t *channel); + +/*! \brief Initialize channel state for an outgoing call */ FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *ftdmchan); /*! \brief Initialize the library */ diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index a701c1383d..beee868633 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -356,6 +356,15 @@ typedef struct { } ftdm_dtmf_debug_t; #endif +typedef struct { + const char *file; + const char *func; + int line; + ftdm_channel_state_t state; + ftdm_channel_state_t last_state; + ftdm_time_t time; +} ftdm_channel_history_entry_t; + /* 2^8 table size, one for each byte (sample) value */ #define FTDM_GAINS_TABLE_SIZE 256 struct ftdm_channel { @@ -381,6 +390,8 @@ struct ftdm_channel { ftdm_channel_state_t state; ftdm_channel_state_t last_state; ftdm_channel_state_t init_state; + ftdm_channel_history_entry_t history[10]; + uint8_t hindex; ftdm_mutex_t *mutex; teletone_dtmf_detect_state_t dtmf_detect; uint32_t buffer_delay;