diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 955729df36..b8124147e9 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -63,7 +63,7 @@ ftdm_time_t time_last_throttle_log = 0; ftdm_time_t time_current_throttle_log = 0; static ftdm_iterator_t *get_iterator(ftdm_iterator_type_t type, ftdm_iterator_t *iter); -static ftdm_status_t ftdm_call_set_call_id(ftdm_caller_data_t *caller_data); +static ftdm_status_t ftdm_call_set_call_id(ftdm_channel_t *fchan, ftdm_caller_data_t *caller_data); static ftdm_status_t ftdm_call_clear_call_id(ftdm_caller_data_t *caller_data); static ftdm_status_t ftdm_channel_clear_vars(ftdm_channel_t *ftdmchan); static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan); @@ -2522,7 +2522,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char if (status == FTDM_SUCCESS) { ftdm_set_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED); - ftdm_call_set_call_id(&ftdmchan->caller_data); + ftdm_call_set_call_id(ftdmchan, &ftdmchan->caller_data); ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 100); } @@ -2606,10 +2606,11 @@ FT_DECLARE(ftdm_status_t) ftdm_span_get_sig_status(ftdm_span_t *span, ftdm_signa } } +/* this function must be called with the channel lock */ static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan) { ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "Null channel can't be done!\n"); - ftdm_mutex_lock(ftdmchan->mutex); + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OPEN); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF); @@ -2694,7 +2695,6 @@ static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan) ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE); } ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "channel done\n"); - ftdm_mutex_unlock(ftdmchan->mutex); return FTDM_SUCCESS; } @@ -4397,6 +4397,16 @@ static void print_channels_by_state(ftdm_stream_handle_t *stream, ftdm_channel_s ftdm_mutex_unlock(globals.mutex); } +static void print_core_usage(ftdm_stream_handle_t *stream) +{ + stream->write_function(stream, + "--------------------------------------------------------------------------------\n" + "ftdm core state [!] - List all channels in or not in the given state\n" + "ftdm core flag - List all channels with the fiven flag value set\n" + "ftdm core calls - List all known calls to the FreeTDM core\n" + "--------------------------------------------------------------------------------\n"); +} + static char *handle_core_command(const char *cmd) { char *mycmd = NULL; @@ -4407,22 +4417,31 @@ static char *handle_core_command(const char *cmd) char *state = NULL; char *flag = NULL; uint32_t flagval = 0; + uint32_t current_call_id = 0; + ftdm_caller_data_t *calldata = NULL; + ftdm_channel_t *fchan = NULL; ftdm_channel_state_t i = FTDM_CHANNEL_STATE_INVALID; ftdm_stream_handle_t stream = { 0 }; FTDM_STANDARD_STREAM(stream); - if (cmd) { + if (cmd && strlen(cmd)) { mycmd = ftdm_strdup(cmd); argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); } else { - stream.write_function(&stream, "invalid core command\n"); + print_core_usage(&stream); + goto done; + } + + if (!argc) { + print_core_usage(&stream); goto done; } if (!strcasecmp(argv[0], "state")) { if (argc < 2) { stream.write_function(&stream, "core state command requires an argument\n"); + print_core_usage(&stream); goto done; } state = argv[1]; @@ -4443,7 +4462,8 @@ static char *handle_core_command(const char *cmd) stream.write_function(&stream, "\nTotal channels %s %s: %d\n", not ? "not in state" : "in state", ftdm_channel_state2str(i), count); } else if (!strcasecmp(argv[0], "flag")) { if (argc < 2) { - stream.write_function(&stream, "core state command requires an argument\n"); + stream.write_function(&stream, "core flag command requires an argument\n"); + print_core_usage(&stream); goto done; } flag = argv[1]; @@ -4454,8 +4474,28 @@ static char *handle_core_command(const char *cmd) flagval = atoi(flag); print_channels_by_flag(&stream, flagval, not, &count); stream.write_function(&stream, "\nTotal channels %s %d: %d\n", not ? "without flag" : "with flag", flagval, count); + } else if (!strcasecmp(argv[0], "calls")) { + ftdm_mutex_lock(globals.call_id_mutex); + current_call_id = globals.last_call_id; + for (current_call_id = 0; current_call_id <= MAX_CALLIDS; current_call_id++) { + if (!globals.call_ids[current_call_id]) { + continue; + } + calldata = globals.call_ids[current_call_id]; + fchan = calldata->fchan; + if (fchan) { + stream.write_function(&stream, "Call %d on channel %d:%d\n", current_call_id, + fchan->span_id, fchan->chan_id); + } else { + stream.write_function(&stream, "Call %d without a channel?\n", current_call_id); + } + count++; + } + ftdm_mutex_unlock(globals.call_id_mutex); + stream.write_function(&stream, "\nTotal calls: %d\n", count); } else { stream.write_function(&stream, "invalid core command %s\n", argv[0]); + print_core_usage(&stream); } done: @@ -4475,6 +4515,8 @@ FT_DECLARE(char *) ftdm_api_execute(const char *cmd) if ((p = strchr(dup, ' '))) { *p++ = '\0'; cmd = p; + } else { + cmd = ""; } type = dup; @@ -5447,7 +5489,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t case FTDM_SIGEVENT_START: { ftdm_set_flag(sigmsg->channel, FTDM_CHANNEL_CALL_STARTED); - ftdm_call_set_call_id(&sigmsg->channel->caller_data); + ftdm_call_set_call_id(sigmsg->channel, &sigmsg->channel->caller_data); ftdm_set_echocancel_call_begin(sigmsg->channel); if (sigmsg->channel->dtmfdbg.requested) { ftdm_channel_command(sigmsg->channel, FTDM_COMMAND_ENABLE_DEBUG_DTMF, NULL); @@ -6089,27 +6131,35 @@ FT_DECLARE(char *) ftdm_channel_get_history_str(const ftdm_channel_t *fchan) return stream.data; } -static ftdm_status_t ftdm_call_set_call_id(ftdm_caller_data_t *caller_data) +static ftdm_status_t ftdm_call_set_call_id(ftdm_channel_t *fchan, ftdm_caller_data_t *caller_data) { uint32_t current_call_id; - ftdm_assert_return(!caller_data->call_id, FTDM_FAIL, "Overwriting non-cleared call-id"); + + ftdm_assert_return(!caller_data->call_id, FTDM_FAIL, "Overwriting non-cleared call-id\n"); ftdm_mutex_lock(globals.call_id_mutex); + current_call_id = globals.last_call_id; - do { - if (++current_call_id > MAX_CALLIDS) { + for (current_call_id = globals.last_call_id + 1; + current_call_id != globals.last_call_id; + current_call_id++ ) { + if (current_call_id > MAX_CALLIDS) { current_call_id = 1; } - if (globals.call_ids[current_call_id] != NULL) { - continue; + if (globals.call_ids[current_call_id] == NULL) { + break; } - } while (0); + } + + ftdm_assert_return(globals.call_ids[current_call_id] == NULL, FTDM_FAIL, "We ran out of call ids\n"); globals.last_call_id = current_call_id; caller_data->call_id = current_call_id; globals.call_ids[current_call_id] = caller_data; + caller_data->fchan = fchan; + ftdm_mutex_unlock(globals.call_id_mutex); return FTDM_SUCCESS; } @@ -6126,8 +6176,8 @@ static ftdm_status_t ftdm_call_clear_call_id(ftdm_caller_data_t *caller_data) ftdm_mutex_lock(globals.call_id_mutex); if (globals.call_ids[caller_data->call_id]) { ftdm_log(FTDM_LOG_DEBUG, "Cleared call with id %u\n", caller_data->call_id); - caller_data->call_id = 0; globals.call_ids[caller_data->call_id] = NULL; + caller_data->call_id = 0; } else { ftdm_log(FTDM_LOG_CRIT, "call-id did not exist %u\n", caller_data->call_id); } diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index dfb3f1fc02..d27353ddb0 100644 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -320,6 +320,7 @@ typedef struct ftdm_caller_data { * that the user can use caller_data.call_id to obtain the call_id. The user * should use the call_id from sigmsg otherwise */ uint32_t call_id; /*!< Unique call ID for this call */ + ftdm_channel_t *fchan; /*!< FreeTDM channel associated (can be NULL) */ } ftdm_caller_data_t; /*! \brief Tone type */