From 4a6b4e86f16a25074cc0f77fc7ddbda36f5cbfc4 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 4 Jan 2011 09:30:49 -0500 Subject: [PATCH] freetdm: add non-locking answer function to handle answer indication export ftdm_current_time_in_ms to users update testr2 to test non-blocking API (no waiting on indications) --- libs/freetdm/src/ftdm_io.c | 49 +++--- libs/freetdm/src/include/ftdm_os.h | 5 + libs/freetdm/src/include/private/ftdm_core.h | 1 - libs/freetdm/src/include/private/ftdm_types.h | 2 - libs/freetdm/src/testr2.c | 144 ++++++++++++++---- 5 files changed, 147 insertions(+), 54 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index e55839a784..b60e72f605 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -2032,22 +2032,22 @@ FT_DECLARE(void) ftdm_ack_indication(ftdm_channel_t *fchan, ftdm_channel_indicat ftdm_span_send_signal(fchan->span, &msg); } -FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan) +/*! \brief Answer call without locking the channel. The caller must have locked first + * \note This function was added because ftdm_channel_call_indicate needs to answer the call + * when its already locking the channel, ftdm_channel_set_state cannot be called with the same + * lock locked once or more (recursive lock) and wait for the result */ +static ftdm_status_t _ftdm_channel_call_answer_nl(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan) { ftdm_status_t status = FTDM_SUCCESS; - ftdm_channel_lock(ftdmchan); + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + status = FTDM_EINVAL; + goto done; + } if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call is already TERMINATING\n"); status = FTDM_ECANCELED; - ftdm_ack_indication(ftdmchan, FTDM_CHANNEL_INDICATE_ANSWER, status); - goto done; - } - - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { - status = FTDM_EINVAL; - ftdm_ack_indication(ftdmchan, FTDM_CHANNEL_INDICATE_ANSWER, status); goto done; } @@ -2059,7 +2059,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) { status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1); if (status != FTDM_SUCCESS) { - ftdm_ack_indication(ftdmchan, FTDM_CHANNEL_INDICATE_ANSWER, status); + status = FTDM_ECANCELED; goto done; } } @@ -2068,14 +2068,13 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n"); status = FTDM_ECANCELED; - ftdm_ack_indication(ftdmchan, FTDM_CHANNEL_INDICATE_ANSWER, status); goto done; } if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS_MEDIA) { status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1); if (status != FTDM_SUCCESS) { - ftdm_ack_indication(ftdmchan, FTDM_CHANNEL_INDICATE_ANSWER, status); + status = FTDM_ECANCELED; goto done; } } @@ -2084,23 +2083,35 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to UP\n"); status = FTDM_ECANCELED; - ftdm_ack_indication(ftdmchan, FTDM_CHANNEL_INDICATE_ANSWER, status); goto done; } } status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 1); if (status != FTDM_SUCCESS) { - ftdm_ack_indication(ftdmchan, FTDM_CHANNEL_INDICATE_ANSWER, status); + status = FTDM_ECANCELED; + goto done; } done: + + return status; +} + +FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan) +{ + ftdm_status_t status = FTDM_SUCCESS; + + ftdm_channel_lock(ftdmchan); + + status = _ftdm_channel_call_answer_nl(file, func, line, ftdmchan); + ftdm_channel_unlock(ftdmchan); return status; } /* lock must be acquired by the caller! */ -static ftdm_status_t call_hangup(ftdm_channel_t *chan, const char *file, const char *func, int line) +static ftdm_status_t _ftdm_channel_call_hangup_nl(ftdm_channel_t *chan, const char *file, const char *func, int line) { ftdm_status_t status = FTDM_SUCCESS; @@ -2139,7 +2150,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup_with_cause(const char *file, ftdmchan->caller_data.hangup_cause = cause; - status = call_hangup(ftdmchan, file, func, line); + status = _ftdm_channel_call_hangup_nl(ftdmchan, file, func, line); ftdm_channel_unlock(ftdmchan); return status; @@ -2153,7 +2164,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup(const char *file, const char ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING; - status = call_hangup(ftdmchan, file, func, line); + status = _ftdm_channel_call_hangup_nl(ftdmchan, file, func, line); ftdm_channel_unlock(ftdmchan); return status; @@ -2288,7 +2299,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch break; case FTDM_CHANNEL_INDICATE_ANSWER: /* _ftdm_channel_call_answer takes care of the indication ack */ - status = _ftdm_channel_call_answer(file, func, line, ftdmchan); + status = _ftdm_channel_call_answer_nl(file, func, line, ftdmchan); break; default: ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "Do not know how to indicate %d\n", indication); @@ -5292,7 +5303,7 @@ static void execute_safety_hangup(void *data) fchan->hangup_timer = 0; if (fchan->state == FTDM_CHANNEL_STATE_TERMINATING) { ftdm_log_chan(fchan, FTDM_LOG_CRIT, "Forcing hangup since the user did not confirmed our hangup after %dms\n", FORCE_HANGUP_TIMER); - call_hangup(fchan, __FILE__, __FUNCTION__, __LINE__); + _ftdm_channel_call_hangup_nl(fchan, __FILE__, __FUNCTION__, __LINE__); } else { ftdm_log_chan(fchan, FTDM_LOG_CRIT, "Not performing safety hangup, channel state is %s\n", ftdm_channel_state2str(fchan->state)); } diff --git a/libs/freetdm/src/include/ftdm_os.h b/libs/freetdm/src/include/ftdm_os.h index f3ebee9ea2..a4605c3371 100644 --- a/libs/freetdm/src/include/ftdm_os.h +++ b/libs/freetdm/src/include/ftdm_os.h @@ -51,6 +51,9 @@ extern "C" { #include #endif +/*! \brief time data type */ +typedef uint64_t ftdm_time_t; + /*! \brief sleep x amount of milliseconds */ #ifdef __WINDOWS__ #define ftdm_sleep(x) Sleep(x) @@ -114,6 +117,8 @@ FT_DECLARE(char *) ftdm_strdup(const char *str); /*! \brief Duplicate string with limit */ FT_DECLARE(char *) ftdm_strndup(const char *str, ftdm_size_t inlen); +/*! \brief Get the current time in milliseconds */ +FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void); #ifdef __cplusplus } /* extern C */ diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 55fb8ba032..a5862e5d15 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -556,7 +556,6 @@ FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_sdmf(ftdm_fsk_data_state_t *state, c FT_DECLARE(ftdm_status_t) ftdm_channel_send_fsk_data(ftdm_channel_t *ftdmchan, ftdm_fsk_data_state_t *fsk_data, float db_level); FT_DECLARE(ftdm_status_t) ftdm_span_load_tones(ftdm_span_t *span, const char *mapname); -FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void); FT_DECLARE(ftdm_status_t) ftdm_channel_use(ftdm_channel_t *ftdmchan); diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h index 41711f743d..2d683e3098 100644 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -69,8 +69,6 @@ extern "C" { #define FTDM_END -1 #define FTDM_ANY_STATE -1 -typedef uint64_t ftdm_time_t; - typedef enum { FTDM_ENDIAN_BIG = 1, FTDM_ENDIAN_LITTLE = -1 diff --git a/libs/freetdm/src/testr2.c b/libs/freetdm/src/testr2.c index 8ac90c59fd..72d98020bc 100644 --- a/libs/freetdm/src/testr2.c +++ b/libs/freetdm/src/testr2.c @@ -2,78 +2,158 @@ #include #include -static int R = 0; -static ftdm_mutex_t *mutex = NULL; +static volatile int running = 0; +static ftdm_mutex_t *the_mutex = NULL; +static ftdm_channel_t *fchan = NULL; +static ftdm_channel_indication_t indication = FTDM_CHANNEL_INDICATE_NONE; static FIO_SIGNAL_CB_FUNCTION(on_r2_signal) { int chanid = ftdm_channel_get_ph_id(sigmsg->channel); - ftdm_log(FTDM_LOG_DEBUG, "Got R2 channel sig [%s] in channel\n", ftdm_signal_event2str(sigmsg->event_id), chanid); - return FTDM_SUCCESS; + ftdm_log(FTDM_LOG_DEBUG, "Got R2 channel sig [%s] in channel\n", ftdm_signal_event2str(sigmsg->event_id), chanid); + switch (sigmsg->event_id) { + case FTDM_SIGEVENT_START: + { + ftdm_mutex_lock(the_mutex); + if (!fchan) { + fchan = sigmsg->channel; + indication = FTDM_CHANNEL_INDICATE_PROCEED; + } + ftdm_mutex_unlock(the_mutex); + } + break; + case FTDM_SIGEVENT_INDICATION_COMPLETED: + { + ftdm_channel_indication_t ind = FTDM_CHANNEL_INDICATE_NONE; + if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_PROCEED) { + ftdm_log(FTDM_LOG_DEBUG, "Proceed indication result = %d\n", sigmsg->ev_data.indication_completed.status); + ind = FTDM_CHANNEL_INDICATE_PROGRESS; + } else if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_PROGRESS) { + ftdm_log(FTDM_LOG_DEBUG, "Progress indication result = %d\n", sigmsg->ev_data.indication_completed.status); + ind = FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA; + } else if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA) { + ftdm_log(FTDM_LOG_DEBUG, "Progress media indication result = %d\n", sigmsg->ev_data.indication_completed.status); + ind = FTDM_CHANNEL_INDICATE_ANSWER; + } else if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_ANSWER) { + ftdm_log(FTDM_LOG_DEBUG, "Answer indication result = %d\n", sigmsg->ev_data.indication_completed.status); + } else { + ftdm_log(FTDM_LOG_DEBUG, "Unexpected indication, result = %d\n", sigmsg->ev_data.indication_completed.status); + exit(1); + } + ftdm_mutex_lock(the_mutex); + if (fchan) { + indication = ind; + } + ftdm_mutex_unlock(the_mutex); + } + break; + case FTDM_SIGEVENT_STOP: + { + ftdm_channel_call_hangup(sigmsg->channel); + } + break; + case FTDM_SIGEVENT_RELEASED: + { + ftdm_mutex_lock(the_mutex); + if (fchan && fchan == sigmsg->channel) { + fchan = NULL; + } + ftdm_mutex_unlock(the_mutex); + } + break; + default: + break; + } + return FTDM_SUCCESS; } -static void handle_SIGINT(int sig) +static void stop_test(int sig) { - ftdm_mutex_lock(mutex); - R = 0; - ftdm_mutex_unlock(mutex); - return; + running = 0; } int main(int argc, char *argv[]) { ftdm_span_t *span; - ftdm_mutex_create(&mutex); - - ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG); + ftdm_conf_parameter_t parameters[20]; + + ftdm_mutex_create(&the_mutex); if (argc < 2) { printf("umm no\n"); - exit(-1); + exit(1); } + ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG); + if (ftdm_global_init() != FTDM_SUCCESS) { fprintf(stderr, "Error loading FreeTDM\n"); - exit(-1); + exit(1); } + ftdm_global_configuration(); + printf("FreeTDM loaded\n"); - if (ftdm_span_find(atoi(argv[1]), &span) != FTDM_SUCCESS) { - fprintf(stderr, "Error finding FreeTDM span\n"); + if (ftdm_span_find_by_name(argv[1], &span) != FTDM_SUCCESS) { + fprintf(stderr, "Error finding FreeTDM span %s\n", argv[1]); goto done; } + /* testing non-blocking operation */ + //ftdm_span_set_blocking_mode(span, FTDM_FALSE); + parameters[0].var = "variant"; + parameters[0].val = "br"; - if (ftdm_configure_span(span, "r2", on_r2_signal, - "variant", "mx", - "max_ani", 10, - "max_dnis", 4, - "logging", "all", - FTDM_TAG_END) == FTDM_SUCCESS) { - + parameters[1].var = "max_ani"; + parameters[1].val = "4"; + parameters[2].var = "max_dnis"; + parameters[2].val = "4"; + + parameters[3].var = "logging"; + parameters[3].val = "all"; + + parameters[4].var = NULL; + parameters[4].val = NULL; + + if (ftdm_configure_span_signaling(span, "r2", on_r2_signal, parameters) == FTDM_SUCCESS) { ftdm_span_start(span); } else { fprintf(stderr, "Error starting R2 span\n"); goto done; } - signal(SIGINT, handle_SIGINT); - ftdm_mutex_lock(mutex); - R = 1; - ftdm_mutex_unlock(mutex); - while(R) { - ftdm_sleep(1 * 1000); + running = 1; + signal(SIGINT, stop_test); + while(running) { + ftdm_sleep(20); + if (fchan && indication != FTDM_CHANNEL_INDICATE_NONE) { + ftdm_channel_t *lchan = NULL; + ftdm_channel_indication_t ind = FTDM_CHANNEL_INDICATE_NONE; + ftdm_time_t start, stop, diff; + + ftdm_mutex_lock(the_mutex); + ind = indication; + indication = FTDM_CHANNEL_INDICATE_NONE; + lchan = fchan; + ftdm_mutex_unlock(the_mutex); + + start = ftdm_current_time_in_ms(); + ftdm_channel_call_indicate(lchan, ind); + stop = ftdm_current_time_in_ms(); + diff = stop - start; + ftdm_log(FTDM_LOG_DEBUG, "Setting indication %s took %llums\n", + ftdm_channel_indication2str(ind), diff); + } } - done: +done: ftdm_global_destroy(); - return 1; - + return 0; } /* For Emacs: