From bc2638334bca11e79b24ad1e44df9af09acbd0f7 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 10 Sep 2010 14:01:52 -0400 Subject: [PATCH] freetdm: iterators refactoring add channel iterator --- libs/freetdm/mod_freetdm/mod_freetdm.c | 19 +-- libs/freetdm/src/ftdm_io.c | 116 ++++++++++++++++-- libs/freetdm/src/include/freetdm.h | 28 ++++- libs/freetdm/src/include/private/ftdm_core.h | 3 + libs/freetdm/src/include/private/ftdm_types.h | 17 +++ 5 files changed, 161 insertions(+), 22 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index b911155334..6b4fec6d87 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1404,6 +1404,7 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session private_t *tech_pvt = NULL; switch_channel_t *channel = NULL; ftdm_iterator_t *iter = NULL; + ftdm_iterator_t *curr = NULL; const char *var_name = NULL; const char *var_value = NULL; uint32_t spanid, chanid; @@ -1516,12 +1517,13 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session } /* Add any channel variable to the dial plan */ iter = ftdm_channel_get_var_iterator(sigmsg->channel); - for ( ; iter; iter = ftdm_iterator_next(iter)) { - ftdm_channel_get_current_var(iter, &var_name, &var_value); + for (curr = iter ; curr; curr = ftdm_iterator_next(curr)) { + ftdm_channel_get_current_var(curr, &var_name, &var_value); snprintf(name, sizeof(name), FREETDM_VAR_PREFIX "%s", var_name); switch_channel_set_variable_printf(channel, name, "%s", var_value); } - + ftdm_iterator_free(iter); + switch_channel_set_state(channel, CS_INIT); if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error spawning thread\n"); @@ -2496,7 +2498,8 @@ static switch_status_t load_config(void) unsigned boosti = 0; unsigned int i = 0; ftdm_channel_t *fchan = NULL; - unsigned int chancount = 0; + ftdm_iterator_t *chaniter = NULL; + ftdm_iterator_t *curr = NULL; memset(boost_spans, 0, sizeof(boost_spans)); memset(&globals, 0, sizeof(globals)); @@ -2780,11 +2783,13 @@ static switch_status_t load_config(void) switch_set_string(SPAN_CONFIG[span_id].dialplan, dialplan); SPAN_CONFIG[span_id].analog_options = analog_options | globals.analog_options; - chancount = ftdm_span_get_chan_count(span); - for (i = 1; i <= chancount; i++) { - fchan = ftdm_span_get_channel(span, i); + chaniter = ftdm_span_get_chan_iterator(span); + curr = chaniter + for (curr = chaniter ; curr; curr = ftdm_iterator_next(curr)) { + fchan = ftdm_iterator_current(curr); ftdm_channel_set_private(fchan, &SPAN_CONFIG[span_id].pvts[i]); } + ftdm_iterator_free(chaniter); if (dial_regex) { switch_set_string(SPAN_CONFIG[span_id].dial_regex, dial_regex); diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index b275403c85..b83f1b7e88 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -3524,16 +3524,48 @@ done: return var; } -FT_DECLARE(ftdm_iterator_t *) ftdm_channel_get_var_iterator(const ftdm_channel_t *ftdmchan) +static ftdm_iterator_t *get_iterator(ftdm_iterator_type_t type, ftdm_iterator_t *iter) { - ftdm_hash_iterator_t *iter = NULL; + int allocated = 0; + if (iter) { + if (iter->type != type) { + ftdm_log(FTDM_LOG_ERROR, "Cannot switch iterator types\n"); + return NULL; + } + allocated = iter->allocated; + memset(iter, 0, sizeof(*iter)); + iter->type = type; + iter->allocated = allocated; + return iter; + } + iter = ftdm_calloc(1, sizeof(*iter)); + if (!iter) { + return NULL; + } + iter->type = type; + iter->allocated = 1; + return iter; +} + +FT_DECLARE(ftdm_iterator_t *) ftdm_channel_get_var_iterator(const ftdm_channel_t *ftdmchan, ftdm_iterator_t *iter) +{ + if (!(iter = get_iterator(FTDM_ITERATOR_VARS, iter))) { + return NULL; + } ftdm_channel_lock(ftdmchan); - - iter = ftdmchan->variable_hash == NULL ? NULL : hashtable_first(ftdmchan->variable_hash); - + iter->pvt.hashiter = ftdmchan->variable_hash == NULL ? NULL : hashtable_first(ftdmchan->variable_hash); ftdm_channel_unlock(ftdmchan); + return iter; +} +FT_DECLARE(ftdm_iterator_t *) ftdm_span_get_chan_iterator(const ftdm_span_t *span, ftdm_iterator_t *iter) +{ + if (!(iter = get_iterator(FTDM_ITERATOR_CHANS, iter))) { + return NULL; + } + iter->pvt.chaniter.index = 1; + iter->pvt.chaniter.span = span; return iter; } @@ -3545,11 +3577,9 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_get_current_var(ftdm_iterator_t *iter, co *var_name = NULL; *var_val = NULL; - if (!iter) { - return FTDM_FAIL; - } + ftdm_assert_return(iter && (iter->type == FTDM_ITERATOR_CHANS) && iter->pvt.hashiter, FTDM_FAIL, "Cannot get variable from invalid iterator!\n"); - hashtable_this(iter, &key, NULL, &val); + hashtable_this(iter->pvt.hashiter, &key, NULL, &val); *var_name = key; *var_val = val; @@ -3559,10 +3589,72 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_get_current_var(ftdm_iterator_t *iter, co FT_DECLARE(ftdm_iterator_t *) ftdm_iterator_next(ftdm_iterator_t *iter) { - if (!iter) { - return NULL; + ftdm_assert_return(iter && iter->type, NULL, "Invalid iterator\n"); + + switch (iter->type) { + case FTDM_ITERATOR_VARS: + if (!iter->pvt.hashiter) { + return NULL; + } + iter->pvt.hashiter = hashtable_next(iter->pvt.hashiter); + if (!iter->pvt.hashiter) { + return NULL; + } + return iter; + case FTDM_ITERATOR_CHANS: + if (iter->pvt.chaniter.index == iter->pvt.chaniter.span->chan_count) { + return NULL; + } + iter->pvt.chaniter.index++; + return iter; + default: + break; } - return hashtable_next(iter); + + ftdm_assert_return(0, NULL, "Unknown iterator type\n"); + return NULL; +} + +FT_DECLARE(void *) ftdm_iterator_current(ftdm_iterator_t *iter) +{ + const void *key = NULL; + void *val = NULL; + + ftdm_assert_return(iter && iter->type, NULL, "Invalid iterator\n"); + + switch (iter->type) { + case FTDM_ITERATOR_VARS: + hashtable_this(iter->pvt.hashiter, &key, NULL, &val); + /* I decided to return the key instead of the value since the value can be retrieved using the key */ + return (void *)key; + case FTDM_ITERATOR_CHANS: + ftdm_assert_return(iter->pvt.chaniter.index, NULL, "channel iterator index cannot be zero!\n"); + ftdm_assert_return(iter->pvt.chaniter.index > iter->pvt.chaniter.span->chan_count, NULL, "channel iterator index bigger than span chan count!\n"); + return iter->pvt.chaniter.span->channels[iter->pvt.chaniter.index]; + default: + break; + } + + ftdm_assert_return(0, NULL, "Unknown iterator type\n"); + return NULL; +} + +FT_DECLARE(ftdm_status_t) ftdm_iterator_free(ftdm_iterator_t *iter) +{ + /* it's valid to pass a NULL iterator, do not return failure */ + if (!iter) { + return FTDM_SUCCESS; + } + + if (!iter->allocated) { + memset(iter, 0, sizeof(*iter)); + return FTDM_SUCCESS; + } + + ftdm_assert_return(iter->type, FTDM_FAIL, "Cannot free invalid iterator\n"); + ftdm_safe_free(iter); + + return FTDM_SUCCESS; } static struct { diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 0437e02e51..1f50a2ccaa 100644 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -386,7 +386,7 @@ typedef struct ftdm_conf_parameter { } ftdm_conf_parameter_t; /*! \brief Opaque general purpose iterator */ -typedef void ftdm_iterator_t; +typedef struct ftdm_iterator ftdm_iterator_t; /*! \brief Channel commands that can be executed through ftdm_channel_command() */ typedef enum { @@ -1032,8 +1032,19 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_add_var(ftdm_channel_t *ftdmchan, const c FT_DECLARE(const char *) ftdm_channel_get_var(ftdm_channel_t *ftdmchan, const char *var_name); /*! \brief Get an iterator to iterate over the channel variables - * \note The iterator pointer returned is only valid while the channel is open and it'll be destroyed when the channel is closed. */ -FT_DECLARE(ftdm_iterator_t *) ftdm_channel_get_var_iterator(const ftdm_channel_t *ftdmchan); + * \param ftdmchan The channel structure containing the variables + * \param iter Optional iterator. You can reuse an old iterator (not previously freed) to avoid the extra allocation of a new iterator. + * \note The iterator pointer returned is only valid while the channel is open and it'll be destroyed when the channel is closed. + * This iterator is completely non-thread safe, if you are adding variables or removing variables while iterating + * results are unpredictable + */ +FT_DECLARE(ftdm_iterator_t *) ftdm_channel_get_var_iterator(const ftdm_channel_t *ftdmchan, ftdm_iterator_t *iter); + +/*! \brief Get iterator current value (depends on the iterator type) + * \note Channel iterators return a pointer to ftdm_channel_t + * Variable iterators return a pointer to the variable name (not the variable value) + */ +FT_DECLARE(void *) ftdm_iterator_current(ftdm_iterator_t *iter); /*! \brief Get variable name and value for the current iterator position */ FT_DECLARE(ftdm_status_t) ftdm_channel_get_current_var(ftdm_iterator_t *iter, const char **var_name, const char **var_val); @@ -1041,6 +1052,11 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_get_current_var(ftdm_iterator_t *iter, co /*! \brief Advance iterator */ FT_DECLARE(ftdm_iterator_t *) ftdm_iterator_next(ftdm_iterator_t *iter); +/*! \brief Free iterator + * \note You must free an iterator after using it unless you plan to reuse it + */ +FT_DECLARE(ftdm_status_t) ftdm_iterator_free(ftdm_iterator_t *iter); + /*! \brief Get the span pointer associated to the channel */ FT_DECLARE(ftdm_span_t *) ftdm_channel_get_span(const ftdm_channel_t *ftdmchan); @@ -1144,6 +1160,12 @@ FT_DECLARE(uint32_t) ftdm_span_get_id(const ftdm_span_t *span); /*! \brief Get the span name */ FT_DECLARE(const char *) ftdm_span_get_name(const ftdm_span_t *span); +/*! \brief Get iterator for the span channels + * \param span The span containing the channels + * \param iter Optional iterator. You can reuse an old iterator (not previously freed) to avoid the extra allocation of a new iterator. + */ +FT_DECLARE(ftdm_iterator_t *) ftdm_span_get_chan_iterator(const ftdm_span_t *span, ftdm_iterator_t *iter); + /*! * \brief Execute a text command. The text command output will be returned and must be free'd * diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 74bea8148c..d8947f6de4 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -619,6 +619,9 @@ FT_DECLARE(ftdm_status_t) ftdm_span_trigger_signals(const ftdm_span_t *span); #define ftdm_log_chan(fchan, level, format, ...) ftdm_log(level, "[s%dc%d][%d:%d] " format, fchan->span_id, fchan->chan_id, fchan->physical_span_id, fchan->physical_chan_id, __VA_ARGS__) #define ftdm_log_chan_msg(fchan, level, msg) ftdm_log(level, "[s%dc%d][%d:%d] " msg, fchan->span_id, fchan->chan_id, fchan->physical_span_id, fchan->physical_chan_id) +#define ftdm_span_lock(span) ftdm_mutex_lock(span->mutex) +#define ftdm_span_unlock(span) ftdm_mutex_unlock(span->mutex) + FT_DECLARE_DATA extern const char *FTDM_LEVEL_NAMES[9]; static __inline__ void ftdm_abort(void) diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h index d8e8b5c2e6..ba6956344d 100644 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -366,6 +366,23 @@ typedef ftdm_status_t (*ftdm_span_start_t)(ftdm_span_t *span); typedef ftdm_status_t (*ftdm_span_stop_t)(ftdm_span_t *span); typedef ftdm_status_t (*ftdm_channel_sig_read_t)(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t size); +typedef enum { + FTDM_ITERATOR_VARS = 1, + FTDM_ITERATOR_CHANS, +} ftdm_iterator_type_t; + +struct ftdm_iterator { + ftdm_iterator_type_t type; + unsigned int allocated:1; + union { + struct { + int32_t index; + const ftdm_span_t *span; + } chaniter; + ftdm_hash_iterator_t *hashiter; + } pvt; +}; + #ifdef __cplusplus } #endif