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;
}
/* 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");
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));
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);
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;
-
- ftdm_channel_lock(ftdmchan);
+ 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 = ftdmchan->variable_hash == NULL ? NULL : hashtable_first(ftdmchan->variable_hash);
+ 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->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;
}
*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;
FT_DECLARE(ftdm_iterator_t *) ftdm_iterator_next(ftdm_iterator_t *iter)
{
+ 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;
+ }
+
+ 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 NULL;
+ return FTDM_SUCCESS;
}
- return hashtable_next(iter);
+
+ 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 {
} 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 {
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);
/*! \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);
/*! \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
*
#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)
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