From a611a7e9441a0d5ea609d6a86f5db2080bae4555 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 11 May 2010 10:42:08 -0400 Subject: [PATCH 1/5] freetdm: shutdown boost events thread on unload --- .../ftmod_sangoma_boost/ftdm_sangoma_boost.h | 3 +- .../ftmod_sangoma_boost/ftmod_sangoma_boost.c | 36 +++++++++++++++---- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftdm_sangoma_boost.h b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftdm_sangoma_boost.h index 31a231f309..5a3ca76c56 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftdm_sangoma_boost.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftdm_sangoma_boost.h @@ -40,7 +40,8 @@ typedef enum { FTDM_SANGOMA_BOOST_RUNNING = (1 << 0), - FTDM_SANGOMA_BOOST_RESTARTING = (1 << 1) + FTDM_SANGOMA_BOOST_RESTARTING = (1 << 1), + FTDM_SANGOMA_BOOST_EVENTS_RUNNING = (1 << 2), } ftdm_sangoma_boost_flag_t; typedef struct ftdm_sangoma_boost_data { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c index bc0df8d4a8..e7a0dd18d1 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c @@ -1721,18 +1721,22 @@ static __inline__ ftdm_status_t check_events(ftdm_span_t *span, int ms_timeout) */ static void *ftdm_sangoma_events_run(ftdm_thread_t *me, void *obj) { - ftdm_span_t *span = (ftdm_span_t *) obj; + ftdm_span_t *span = (ftdm_span_t *) obj; ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data; unsigned errs = 0; - while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING) && ftdm_running()) { - if (check_events(span,100) != FTDM_SUCCESS) { + while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING) && ftdm_running()) { + if (check_events(span, 100) != FTDM_SUCCESS) { if (errs++ > 50) { ftdm_log(FTDM_LOG_ERROR, "Too many event errors, quitting sangoma events thread\n"); return NULL; } } } + + ftdm_log(FTDM_LOG_DEBUG, "Sangoma Boost Events thread ended.\n"); + + ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING); return NULL; } @@ -2159,18 +2163,23 @@ static ftdm_status_t ftdm_sangoma_boost_start(ftdm_span_t *span) int err; ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data; + ftdm_set_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING); - err=ftdm_thread_create_detached(ftdm_sangoma_boost_run, span); + err = ftdm_thread_create_detached(ftdm_sangoma_boost_run, span); if (err) { ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING); return err; } + // launch the events thread to handle HW DTMF and possibly // other events in the future - err=ftdm_thread_create_detached(ftdm_sangoma_events_run, span); + ftdm_set_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING); + err = ftdm_thread_create_detached(ftdm_sangoma_events_run, span); if (err) { + ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING); ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING); } + return err; } @@ -2179,12 +2188,16 @@ static ftdm_status_t ftdm_sangoma_boost_stop(ftdm_span_t *span) int cnt = 50; ftdm_status_t status = FTDM_SUCCESS; ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data; + if (sangoma_boost_data->sigmod) { /* I think stopping the span before destroying the queue makes sense otherwise may be boost events would still arrive when the queue is already destroyed! */ status = sangoma_boost_data->sigmod->stop_span(span); + if (status != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_CRIT, "Failed to stop span %s boost signaling\n", span->name); + return FTDM_FAIL; + } ftdm_queue_enqueue(sangoma_boost_data->boost_queue, NULL); - return status; } while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING) && cnt-- > 0) { @@ -2197,6 +2210,17 @@ static ftdm_status_t ftdm_sangoma_boost_stop(ftdm_span_t *span) return FTDM_FAIL; } + cnt = 50; + while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING) && cnt-- > 0) { + ftdm_log(FTDM_LOG_DEBUG, "Waiting for boost events thread\n"); + ftdm_sleep(100); + } + + if (!cnt) { + ftdm_log(FTDM_LOG_CRIT, "it seems boost events thread in span %s may be stuck, we may segfault :-(\n", span->name); + return FTDM_FAIL; + } + if (sangoma_boost_data->sigmod) { ftdm_queue_destroy(&sangoma_boost_data->boost_queue); } From f04bff40fa1197681a5560522217e7061ee4d142 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 11 May 2010 12:51:28 -0400 Subject: [PATCH 2/5] freetdm: return error when dlclose fails --- libs/freetdm/src/ftdm_dso.c | 18 ++++++++++++++---- .../ftmod_sangoma_boost/ftmod_sangoma_boost.c | 3 ++- libs/freetdm/src/include/private/ftdm_dso.h | 3 ++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/libs/freetdm/src/ftdm_dso.c b/libs/freetdm/src/ftdm_dso.c index ea5056130a..6e7403165d 100644 --- a/libs/freetdm/src/ftdm_dso.c +++ b/libs/freetdm/src/ftdm_dso.c @@ -27,11 +27,12 @@ #include -FT_DECLARE(void) ftdm_dso_destroy(ftdm_dso_lib_t *lib) { +FT_DECLARE(ftdm_status_t) ftdm_dso_destroy(ftdm_dso_lib_t *lib) { if (lib && *lib) { FreeLibrary(*lib); *lib = NULL; } + return FTDM_SUCCESS; } FT_DECLARE(ftdm_dso_lib_t) ftdm_dso_open(const char *path, char **err) { @@ -78,11 +79,20 @@ FT_DECLARE(void*) ftdm_dso_func_sym(ftdm_dso_lib_t lib, const char *sym, char ** #include -FT_DECLARE(void) ftdm_dso_destroy(ftdm_dso_lib_t *lib) { +FT_DECLARE(ftdm_status_t) ftdm_dso_destroy(ftdm_dso_lib_t *lib) { + int rc; if (lib && *lib) { - dlclose(*lib); + rc = dlclose(*lib); + if (rc) { + ftdm_log(FTDM_LOG_ERROR, "Failed to close lib %p: %s\n", *lib, dlerror()); + return FTDM_FAIL; + } + ftdm_log(FTDM_LOG_DEBUG, "lib %p was closed with success\n", *lib); *lib = NULL; + return FTDM_SUCCESS; } + ftdm_log(FTDM_LOG_ERROR, "Invalid pointer provided to ftdm_dso_destroy\n"); + return FTDM_FAIL; } FT_DECLARE(ftdm_dso_lib_t) ftdm_dso_open(const char *path, char **err) { @@ -93,7 +103,7 @@ FT_DECLARE(ftdm_dso_lib_t) ftdm_dso_open(const char *path, char **err) { return lib; } -FT_DECLARE(void*) ftdm_dso_func_sym(ftdm_dso_lib_t lib, const char *sym, char **err) { +FT_DECLARE(void *) ftdm_dso_func_sym(ftdm_dso_lib_t lib, const char *sym, char **err) { void *func = dlsym(lib, sym); if (!func) { *err = ftdm_strdup(dlerror()); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c index e7a0dd18d1..ab7f734c96 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c @@ -2142,12 +2142,13 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_sangoma_boost_destroy) const void *key = NULL; void *val = NULL; ftdm_dso_lib_t lib; - + ftdm_log(FTDM_LOG_DEBUG, "Destroying sangoma boost module\n"); for (i = hashtable_first(g_boost_modules_hash); i; i = hashtable_next(i)) { hashtable_this(i, &key, NULL, &val); if (key && val) { sigmod = val; lib = sigmod->pvt; + ftdm_log(FTDM_LOG_DEBUG, "destroying sigmod %s\n", sigmod->name); ftdm_dso_destroy(&lib); } } diff --git a/libs/freetdm/src/include/private/ftdm_dso.h b/libs/freetdm/src/include/private/ftdm_dso.h index c4c4b705d1..7e9d6d6be9 100644 --- a/libs/freetdm/src/include/private/ftdm_dso.h +++ b/libs/freetdm/src/include/private/ftdm_dso.h @@ -17,6 +17,7 @@ * */ +#include "freetdm.h" #ifndef _FTDM_DSO_H #define _FTDM_DSO_H @@ -28,7 +29,7 @@ extern "C" { typedef void (*ftdm_func_ptr_t) (void); typedef void * ftdm_dso_lib_t; -FT_DECLARE(void) ftdm_dso_destroy(ftdm_dso_lib_t *lib); +FT_DECLARE(ftdm_status_t) ftdm_dso_destroy(ftdm_dso_lib_t *lib); FT_DECLARE(ftdm_dso_lib_t) ftdm_dso_open(const char *path, char **err); FT_DECLARE(void *) ftdm_dso_func_sym(ftdm_dso_lib_t lib, const char *sym, char **err); From 5d15dc10975a65da2406aa14c4fdc665dbb64662 Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Tue, 11 May 2010 13:07:13 -0400 Subject: [PATCH 3/5] fix windows missing inet_ntop missing symbol when built on >= vista but run on < vista --- src/switch_utils.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/switch_utils.c b/src/switch_utils.c index e059d6ca08..842977acf9 100644 --- a/src/switch_utils.c +++ b/src/switch_utils.c @@ -1331,7 +1331,7 @@ static const char *switch_inet_ntop4(const unsigned char *src, char *dst, size_t return strcpy(dst, tmp); } -#if HAVE_SIN6 || (defined(NTDDI_VERSION) && (NTDDI_VERSION < NTDDI_VISTA)) +#if HAVE_SIN6 || defined(NTDDI_VERSION) /* const char * * inet_ntop6(src, dst, size) * convert IPv6 binary address into presentation (printable) format @@ -1488,7 +1488,7 @@ SWITCH_DECLARE(char *) get_addr6(char *buf, switch_size_t len, struct sockaddr_i *buf = '\0'; if (sa) { -#if defined(NTDDI_VERSION) && (NTDDI_VERSION < NTDDI_VISTA) +#if defined(NTDDI_VERSION) switch_inet_ntop6((unsigned char*)sa, buf, len); #else inet_ntop(AF_INET6, sa, buf, len); From b2d8e055bbd2cc56016fd4f70c0538e84ea086e0 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 11 May 2010 15:09:22 -0400 Subject: [PATCH 4/5] freetdm: modify prototype for ftdm_span_create to accept I/O module name instead of pointer --- libs/freetdm/src/ftdm_io.c | 108 +++++++++++------- libs/freetdm/src/include/freetdm.h | 61 +++++++++- libs/freetdm/src/include/private/ftdm_types.h | 14 --- 3 files changed, 123 insertions(+), 60 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index d39c26ed65..c709bced5d 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -522,17 +522,41 @@ FT_DECLARE(ftdm_status_t) ftdm_span_stop(ftdm_span_t *span) return FTDM_FAIL; } -FT_DECLARE(ftdm_status_t) ftdm_span_create(ftdm_io_interface_t *fio, ftdm_span_t **span, const char *name) +FT_DECLARE(ftdm_status_t) ftdm_span_create(const char *iotype, const char *name, ftdm_span_t **span) { ftdm_span_t *new_span = NULL; + ftdm_io_interface_t *fio = NULL; ftdm_status_t status = FTDM_FAIL; + char buf[128] = ""; - ftdm_assert(fio != NULL, "No IO provided\n"); + ftdm_assert_return(iotype != NULL, FTDM_FAIL, "No IO type provided\n"); + ftdm_assert_return(name != NULL, FTDM_FAIL, "No span name provided\n"); + + *span = NULL; ftdm_mutex_lock(globals.mutex); + if (!(fio = (ftdm_io_interface_t *) hashtable_search(globals.interface_hash, (void *)iotype))) { + ftdm_load_module_assume(iotype); + if ((fio = (ftdm_io_interface_t *) hashtable_search(globals.interface_hash, (void *)iotype))) { + ftdm_log(FTDM_LOG_INFO, "Auto-loaded I/O module '%s'\n", iotype); + } + } + ftdm_mutex_unlock(globals.mutex); + if (!fio) { + ftdm_log(FTDM_LOG_CRIT, "failure creating span, no such I/O type '%s'\n", iotype); + return FTDM_FAIL; + } + + if (!fio->configure_span) { + ftdm_log(FTDM_LOG_CRIT, "failure creating span, no configure_span method for I/O type '%s'\n", iotype); + return FTDM_FAIL; + } + + ftdm_mutex_lock(globals.mutex); if (globals.span_index < FTDM_MAX_SPANS_INTERFACE) { new_span = ftdm_calloc(sizeof(*new_span), 1); + ftdm_assert(new_span, "allocating span failed\n"); status = ftdm_mutex_create(&new_span->mutex); @@ -556,11 +580,11 @@ FT_DECLARE(ftdm_status_t) ftdm_span_create(ftdm_io_interface_t *fio, ftdm_span_t ftdm_mutex_unlock(globals.span_mutex); if (!name) { - char buf[128] = ""; snprintf(buf, sizeof(buf), "span%d", new_span->span_id); name = buf; } new_span->name = ftdm_strdup(name); + new_span->type = ftdm_strdup(iotype); ftdm_span_add(new_span); *span = new_span; status = FTDM_SUCCESS; @@ -1657,6 +1681,16 @@ FT_DECLARE(const char *) ftdm_channel_get_span_name(const ftdm_channel_t *ftdmch return ftdmchan->span->name; } +FT_DECLARE(void) ftdm_span_set_trunk_type(ftdm_span_t *span, ftdm_trunk_type_t type) +{ + span->trunk_type = type; +} + +FT_DECLARE(ftdm_trunk_type_t) ftdm_span_get_trunk_type(const ftdm_span_t *span) +{ + return span->trunk_type; +} + FT_DECLARE(uint32_t) ftdm_span_get_id(const ftdm_span_t *span) { return span->span_id; @@ -3227,7 +3261,15 @@ static ftdm_status_t ftdm_set_channels_alarms(ftdm_span_t *span, int currindex) FT_DECLARE(ftdm_status_t) ftdm_configure_span_channels(ftdm_span_t *span, const char* str, ftdm_channel_config_t *chan_config, unsigned *configured) { - int currindex = span->chan_count; + int currindex; + + ftdm_assert_return(span != NULL, FTDM_EINVAL, "span is null\n"); + ftdm_assert_return(chan_config != NULL, FTDM_EINVAL, "config is null\n"); + ftdm_assert_return(configured != NULL, FTDM_EINVAL, "configured pointer is null\n"); + ftdm_assert_return(span->fio != NULL, FTDM_EINVAL, "span with no I/O configured\n"); + ftdm_assert_return(span->fio->configure_span != NULL, FTDM_NOTIMPL, "span I/O with no channel configuration implemented\n"); + + currindex = span->chan_count; *configured = 0; *configured = span->fio->configure_span(span, str, chan_config->type, chan_config->name, chan_config->number); if (!*configured) { @@ -3235,18 +3277,24 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_channels(ftdm_span_t *span, const return FTDM_FAIL; } - if (ftdm_group_add_channels(span, currindex, chan_config->group_name) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "%d:Failed to add channels to group %s\n", span->span_id, chan_config->group_name); - return FTDM_FAIL; - } - if (ftdm_set_channels_alarms(span, currindex) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "%d:Failed to set channel alarms\n", span->span_id); - return FTDM_FAIL; + if (chan_config->group_name[0]) { + if (ftdm_group_add_channels(span, currindex, chan_config->group_name) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "%d:Failed to add channels to group %s\n", span->span_id, chan_config->group_name); + return FTDM_FAIL; + } } + if (ftdm_set_channels_gains(span, currindex, chan_config->rxgain, chan_config->txgain) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_ERROR, "%d:Failed to set channel gains\n", span->span_id); return FTDM_FAIL; } + + + if (ftdm_set_channels_alarms(span, currindex) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "%d:Failed to set channel alarms\n", span->span_id); + return FTDM_FAIL; + } + return FTDM_SUCCESS; } @@ -3260,7 +3308,6 @@ static ftdm_status_t load_config(void) int intparam = 0; ftdm_span_t *span = NULL; unsigned configured = 0, d = 0; - ftdm_io_interface_t *fio = NULL; ftdm_analog_start_type_t tmp; ftdm_size_t len = 0; ftdm_channel_config_t chan_config; @@ -3271,7 +3318,7 @@ static ftdm_status_t load_config(void) if (!ftdm_config_open_file(&cfg, cfg_name)) { return FTDM_FAIL; } - + ftdm_log(FTDM_LOG_DEBUG, "Reading FreeTDM configuration file\n"); while (ftdm_config_next_pair(&cfg, &var, &val)) { if (*cfg.category == '#') { if (cfg.catno != catno) { @@ -3300,33 +3347,9 @@ static ftdm_status_t load_config(void) *name++ = '\0'; } - ftdm_mutex_lock(globals.mutex); - if (!(fio = (ftdm_io_interface_t *) hashtable_search(globals.interface_hash, type))) { - ftdm_load_module_assume(type); - if ((fio = (ftdm_io_interface_t *) hashtable_search(globals.interface_hash, type))) { - ftdm_log(FTDM_LOG_INFO, "auto-loaded '%s'\n", type); - } - } - ftdm_mutex_unlock(globals.mutex); - - if (!fio) { - ftdm_log(FTDM_LOG_CRIT, "failure creating span, no such type '%s'\n", type); - span = NULL; - continue; - } - - if (!fio->configure_span) { - ftdm_log(FTDM_LOG_CRIT, "failure creating span, no configure_span method for '%s'\n", type); - span = NULL; - continue; - } - - if (ftdm_span_create(fio, &span, name) == FTDM_SUCCESS) { - span->type = ftdm_strdup(type); - d = 0; - + if (ftdm_span_create(type, name, &span) == FTDM_SUCCESS) { ftdm_log(FTDM_LOG_DEBUG, "created span %d (%s) of type %s\n", span->span_id, span->name, type); - + d = 0; } else { ftdm_log(FTDM_LOG_CRIT, "failure creating span of type %s\n", type); span = NULL; @@ -3341,8 +3364,9 @@ static ftdm_status_t load_config(void) ftdm_log(FTDM_LOG_DEBUG, "span %d [%s]=[%s]\n", span->span_id, var, val); if (!strcasecmp(var, "trunk_type")) { - span->trunk_type = ftdm_str2ftdm_trunk_type(val); - ftdm_log(FTDM_LOG_DEBUG, "setting trunk type to '%s'\n", ftdm_trunk_type2str(span->trunk_type)); + ftdm_trunk_type_t trtype = ftdm_str2ftdm_trunk_type(val); + ftdm_span_set_trunk_type(span, trtype); + ftdm_log(FTDM_LOG_DEBUG, "setting trunk type to '%s'\n", ftdm_trunk_type2str(trtype)); } else if (!strcasecmp(var, "name")) { if (!strcasecmp(val, "undef")) { chan_config.name[0] = '\0'; @@ -3371,7 +3395,7 @@ static ftdm_status_t load_config(void) ftdm_analog_start_type2str(span->start_type)); } if (span->trunk_type == FTDM_TRUNK_FXO) { - unsigned chans_configured = 0; + unsigned chans_configured = 0; chan_config.type = FTDM_CHAN_TYPE_FXO; if (ftdm_configure_span_channels(span, val, &chan_config, &chans_configured) == FTDM_SUCCESS) { configured += chans_configured; diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 6a1357f92b..4754edc946 100644 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -67,7 +67,8 @@ typedef enum { FTDM_MEMERR, /*!< Memory error, most likely allocation failure */ FTDM_TIMEOUT, /*!< Operation timed out (ie: polling on a device)*/ FTDM_NOTIMPL, /*!< Operation not implemented */ - FTDM_BREAK /*!< Request the caller to perform a break (context-dependant, ie: stop getting DNIS/ANI) */ + FTDM_BREAK, /*!< Request the caller to perform a break (context-dependant, ie: stop getting DNIS/ANI) */ + FTDM_EINVAL /*!< Invalid argument */ } ftdm_status_t; /*! \brief FreeTDM bool type. */ @@ -299,6 +300,23 @@ typedef enum { /*! \brief Move from string to ftdm_signal_event_t and viceversa */ FTDM_STR2ENUM_P(ftdm_str2ftdm_signal_event, ftdm_signal_event2str, ftdm_signal_event_t) +/*! \brief Span trunk types */ +typedef enum { + FTDM_TRUNK_E1, + FTDM_TRUNK_T1, + FTDM_TRUNK_J1, + FTDM_TRUNK_BRI, + FTDM_TRUNK_BRI_PTMP, + FTDM_TRUNK_FXO, + FTDM_TRUNK_FXS, + FTDM_TRUNK_EM, + FTDM_TRUNK_NONE +} ftdm_trunk_type_t; +#define TRUNK_STRINGS "E1", "T1", "J1", "BRI", "BRI_PTMP", "FXO", "FXS", "EM", "NONE" + +/*! \brief Move from string to ftdm_trunk_type_t and viceversa */ +FTDM_STR2ENUM_P(ftdm_str2ftdm_trunk_type, ftdm_trunk_type2str, ftdm_trunk_type_t) + /*! \brief Basic channel configuration provided to ftdm_configure_span_channels */ typedef struct ftdm_channel_config { char name[FTDM_MAX_NAME_STR_SZ]; @@ -809,14 +827,18 @@ FT_DECLARE(const char *) ftdm_span_get_last_error(const ftdm_span_t *span); /*! * \brief Create a new span (not needed if you are using freetdm.conf) * - * \param fio The I/O interface the span will use - * \param span Pointer to store the create span + * \param iotype The I/O interface type this span will use. + * This depends on the available I/O modules + * ftmod_wanpipe = "wanpipe" (Sangoma) + * ftmod_zt = "zt" (DAHDI or Zaptel) + * ftmod_pika "pika" (this one is most likely broken) * \param name Name for the span + * \param span Pointer to store the create span * * \retval FTDM_SUCCESS success (the span was created) * \retval FTDM_FAIL failure (span was not created) */ -FT_DECLARE(ftdm_status_t) ftdm_span_create(ftdm_io_interface_t *fio, ftdm_span_t **span, const char *name); +FT_DECLARE(ftdm_status_t) ftdm_span_create(const char *iotype, const char *name, ftdm_span_t **span); /*! * \brief Add a new channel to a span @@ -1144,8 +1166,39 @@ FT_DECLARE(ftdm_status_t) ftdm_conf_node_add_param(ftdm_conf_node_t *node, const * \return FTDM_FAIL failure */ FT_DECLARE(ftdm_status_t) ftdm_conf_node_destroy(ftdm_conf_node_t *node); + +/*! + * \brief Create and configure channels in the given span + * + * \param span The span container + * \param str The channel range null terminated string. "1-10", "24" etc + * \param chan_config The basic channel configuration for each channel within the range + * \param configured Pointer where the number of channels configured will be stored + * + * \return FTDM_SUCCESS success + * \return FTDM_FAIL failure + */ FT_DECLARE(ftdm_status_t) ftdm_configure_span_channels(ftdm_span_t *span, const char *str, ftdm_channel_config_t *chan_config, unsigned *configured); +/*! + * \brief Set the trunk type for a span + * This must be called before configuring any channels within the span + * + * \param span The span + * \param type The trunk type + * + */ +FT_DECLARE(void) ftdm_span_set_trunk_type(ftdm_span_t *span, ftdm_trunk_type_t type); + +/*! + * \brief Get the trunk type for a span + * + * \param span The span + * + * \return The span trunk type + */ +FT_DECLARE(ftdm_trunk_type_t) ftdm_span_get_trunk_type(const ftdm_span_t *span); + /*! * \brief Return the channel identified by the provided id * diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h index 668c3f180c..50f3280d61 100644 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -111,20 +111,6 @@ typedef enum { #define TONEMAP_STRINGS "NONE", "DIAL", "RING", "BUSY", "FAIL1", "FAIL2", "FAIL3", "ATTN", "CALLWAITING-CAS", "CALLWAITING-SAS", "CALLWAITING-ACK", "INVALID" FTDM_STR2ENUM_P(ftdm_str2ftdm_tonemap, ftdm_tonemap2str, ftdm_tonemap_t) -typedef enum { - FTDM_TRUNK_E1, - FTDM_TRUNK_T1, - FTDM_TRUNK_J1, - FTDM_TRUNK_BRI, - FTDM_TRUNK_BRI_PTMP, - FTDM_TRUNK_FXO, - FTDM_TRUNK_FXS, - FTDM_TRUNK_EM, - FTDM_TRUNK_NONE -} ftdm_trunk_type_t; -#define TRUNK_STRINGS "E1", "T1", "J1", "BRI", "BRI_PTMP", "FXO", "FXS", "EM", "NONE" -FTDM_STR2ENUM_P(ftdm_str2ftdm_trunk_type, ftdm_trunk_type2str, ftdm_trunk_type_t) - typedef enum { FTDM_ANALOG_START_KEWL, FTDM_ANALOG_START_LOOP, From 383e272c30ca18eac61e81d205d57e9d3d6b97ec Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 11 May 2010 16:31:24 -0400 Subject: [PATCH 5/5] freetdm: added boost sample app --- libs/freetdm/sample/boost/Makefile | 10 + libs/freetdm/sample/boost/ftdmstart.c | 476 ++++++++++++++++++++++++++ 2 files changed, 486 insertions(+) create mode 100644 libs/freetdm/sample/boost/Makefile create mode 100644 libs/freetdm/sample/boost/ftdmstart.c diff --git a/libs/freetdm/sample/boost/Makefile b/libs/freetdm/sample/boost/Makefile new file mode 100644 index 0000000000..981f6f072f --- /dev/null +++ b/libs/freetdm/sample/boost/Makefile @@ -0,0 +1,10 @@ +CC=gcc +CFLAGS=-Wall -I/usr/local/freeswitch/include +LDFLAGS=-L/usr/local/freeswitch/lib -lfreetdm + +ftdmstart: ftdmstart.o + +clean: + rm -rf ftdmstart.o + + diff --git a/libs/freetdm/sample/boost/ftdmstart.c b/libs/freetdm/sample/boost/ftdmstart.c new file mode 100644 index 0000000000..972ed43146 --- /dev/null +++ b/libs/freetdm/sample/boost/ftdmstart.c @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2010, Sangoma Technologies + * Moises Silva + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Sample program for the boost signaling absraction. + * Usage: testboostalone ... -d [number-to-dial-if-any] + * compile this program linking to the freetdm library (ie -lfreetdm) + **/ + +#ifndef __linux__ +#define _CRT_SECURE_NO_WARNINGS 1 +#endif + +#include + +#include "freetdm.h" +#include +#include +#include + + +/* arbitrary limit for max calls in this sample program */ +#define MAX_CALLS 255 + +/* some timers (in seconds) to fake responses in incoming calls */ +#define PROGRESS_TIMER 1 +#define ANSWER_TIMER 5 +#define HANGUP_TIMER 15 + +/* simple variable used to stop the application */ +static int app_running = 0; + +typedef void (*expired_function_t)(ftdm_channel_t *channel); +typedef struct dummy_timer_s { + int time; + ftdm_channel_t *channel; + expired_function_t expired; +} dummy_timer_t; + +/* dummy second resolution timers */ +static dummy_timer_t g_timers[MAX_CALLS]; + +/* mutex to protect the timers (both, the test thread and the signaling thread may modify them) */ +static ftdm_mutex_t *g_schedule_mutex; + +/* unique outgoing channel */ +static ftdm_channel_t *g_outgoing_channel = NULL; + +static void interrupt_requested(int signal) +{ + app_running = 0; +} + +static void schedule_timer(ftdm_channel_t *channel, int sec, expired_function_t expired) +{ + int i; + ftdm_mutex_lock(g_schedule_mutex); + for (i = 0; i < sizeof(g_timers)/sizeof(g_timers[0]); i++) { + /* check the timer slot is free to use */ + if (!g_timers[i].time) { + g_timers[i].time = sec; + g_timers[i].channel = channel; + g_timers[i].expired = expired; + ftdm_mutex_unlock(g_schedule_mutex); + return; + } + } + ftdm_log(FTDM_LOG_ERROR, "Failed to schedule timer\n"); + ftdm_mutex_unlock(g_schedule_mutex); +} + +static void run_timers(void) +{ + int i; + void *channel; + expired_function_t expired_func = NULL; + ftdm_mutex_lock(g_schedule_mutex); + for (i = 0; i < sizeof(g_timers)/sizeof(g_timers[0]); i++) { + /* if there's time left, decrement */ + if (g_timers[i].time) { + g_timers[i].time--; + } + + /* if time expired and we have an expired function, call it */ + if (!g_timers[i].time && g_timers[i].expired) { + expired_func = g_timers[i].expired; + channel = g_timers[i].channel; + memset(&g_timers[i], 0, sizeof(g_timers[i])); + expired_func(channel); + } + } + ftdm_mutex_unlock(g_schedule_mutex); +} + +static void release_timers(ftdm_channel_t *channel) +{ + int i; + ftdm_mutex_lock(g_schedule_mutex); + for (i = 0; i < sizeof(g_timers)/sizeof(g_timers[0]); i++) { + /* clear any timer belonging to the given channel */ + if (g_timers[i].channel == channel) { + memset(&g_timers[i], 0, sizeof(g_timers[i])); + } + } + ftdm_mutex_unlock(g_schedule_mutex); +} + +/* hangup the call */ +static void send_hangup(ftdm_channel_t *channel) +{ + int spanid = ftdm_channel_get_span_id(channel); + int chanid = ftdm_channel_get_id(channel); + ftdm_log(FTDM_LOG_NOTICE, "-- Requesting hangup in channel %d:%d\n", spanid, chanid); + ftdm_channel_call_hangup(channel); +} + +/* send answer for an incoming call */ +static void send_answer(ftdm_channel_t *channel) +{ + /* we move the channel signaling state machine to UP (answered) */ + int spanid = ftdm_channel_get_span_id(channel); + int chanid = ftdm_channel_get_id(channel); + ftdm_log(FTDM_LOG_NOTICE, "-- Requesting answer in channel %d:%d\n", spanid, chanid); + ftdm_channel_call_answer(channel); + schedule_timer(channel, HANGUP_TIMER, send_hangup); +} + +/* send progress for an incoming */ +static void send_progress(ftdm_channel_t *channel) +{ + /* we move the channel signaling state machine to UP (answered) */ + int spanid = ftdm_channel_get_span_id(channel); + int chanid = ftdm_channel_get_id(channel); + ftdm_log(FTDM_LOG_NOTICE, "-- Requesting progress\n", spanid, chanid); + ftdm_channel_call_indicate(channel, FTDM_CHANNEL_INDICATE_PROGRESS); + schedule_timer(channel, ANSWER_TIMER, send_answer); +} + +/* This function will be called in an undetermined signaling thread, you must not do + * any blocking operations here or the signaling stack may delay other call event processing + * The arguments for this function are defined in FIO_SIGNAL_CB_FUNCTION prototype, I just + * name them here for your convenience: + * ftdm_sigmsg_t *sigmsg + * - The sigmsg structure contains the ftdm_channel structure that represents the channel where + * the event occurred and the event_id of the signaling event that just occurred. + * */ +static FIO_SIGNAL_CB_FUNCTION(on_signaling_event) +{ + switch (sigmsg->event_id) { + /* This event signals the start of an incoming call */ + case FTDM_SIGEVENT_START: + ftdm_log(FTDM_LOG_NOTICE, "Incoming call received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id); + schedule_timer(sigmsg->channel, PROGRESS_TIMER, send_progress); + break; + /* This event signals progress on an outgoing call */ + case FTDM_SIGEVENT_PROGRESS_MEDIA: + ftdm_log(FTDM_LOG_NOTICE, "Progress message received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id); + break; + /* This event signals answer in an outgoing call */ + case FTDM_SIGEVENT_UP: + ftdm_log(FTDM_LOG_NOTICE, "Answer received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id); + /* now the channel is answered and we can use + * ftdm_channel_wait() to wait for input/output in a channel (equivalent to poll() or select()) + * ftdm_channel_read() to read available data in a channel + * ftdm_channel_write() to write to the channel */ + break; + /* This event signals hangup from the other end */ + case FTDM_SIGEVENT_STOP: + ftdm_log(FTDM_LOG_NOTICE, "Hangup received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id); + if (g_outgoing_channel == sigmsg->channel) { + g_outgoing_channel = NULL; + } + /* release any timer for this channel */ + release_timers(sigmsg->channel); + /* acknowledge the hangup */ + ftdm_channel_call_hangup(sigmsg->channel); + break; + default: + ftdm_log(FTDM_LOG_WARNING, "Unhandled event %s in channel %d:%d\n", ftdm_signal_event2str(sigmsg->event_id), + sigmsg->span_id, sigmsg->chan_id); + break; + } + return FTDM_SUCCESS; +} + +static void place_call(const ftdm_span_t *span, const char *number) +{ + ftdm_channel_t *ftdmchan = NULL; + ftdm_caller_data_t caller_data = {{ 0 }}; + ftdm_status_t status = FTDM_FAIL; + + /* set destiny number */ + ftdm_set_string(caller_data.dnis.digits, number); + + /* set callerid */ + ftdm_set_string(caller_data.cid_name, "testsangomaboost"); + ftdm_set_string(caller_data.cid_num.digits, "1234"); + + /* request to search for an outgoing channel top down with the given caller data. + * it is also an option to use ftdm_channel_open_by_group to let freetdm hunt + * an available channel in a given group instead of per span + * */ + status = ftdm_channel_open_by_span(ftdm_span_get_id(span), FTDM_TOP_DOWN, &caller_data, &ftdmchan); + if (status != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "Failed to originate call\n"); + return; + } + + g_outgoing_channel = ftdmchan; + + /* set the caller data for the outgoing channel */ + ftdm_channel_set_caller_data(ftdmchan, &caller_data); + + status = ftdm_channel_call_place(ftdmchan); + if (status != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "Failed to originate call\n"); + return; + } + + /* this is required to initialize the outgoing channel */ + ftdm_channel_init(ftdmchan); +} + +#define ARRLEN(arr) (sizeof(arr)/sizeof(arr[0])) +int main(int argc, char *argv[]) +{ + /* span names can be any null-terminated string, does not need to be a wanpipe port */ + int span_numbers[32]; + char span_names[ARRLEN(span_numbers)][ARRLEN(span_numbers)]; + const char *spanname = NULL; + char wpchans[25]; + unsigned configured = 0; + int i, spanno; + int numspans = 0; + ftdm_status_t status; + ftdm_span_t *span_list[ARRLEN(span_numbers)]; + ftdm_span_t *span; + ftdm_channel_config_t chan_config; + ftdm_conf_parameter_t parameters[20]; + char *todial = NULL; + int32_t ticks = 0; + + /* register a handler to shutdown things properly */ +#ifdef _WIN64 + // still trying to figure this one out otherwise triggers error + if (signal(SIGINT, interrupt_requested) < 0) { +#else + if (signal(SIGINT, interrupt_requested) == SIG_ERR) { +#endif + fprintf(stderr, "Could not set the SIGINT signal handler: %s\n", strerror(errno)); + exit(-1); + } + + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-' && argv[i][1] == 'd') { + i++; + if (i >= argc) { + fprintf(stderr, "Error, -d specified but no number to dial!\n"); + exit(1); + } + todial = argv[i]; + if (!strlen(todial)) { + todial = NULL; + } + printf("Number to dial: %s\n", todial); + continue; + } + spanno = atoi(argv[i]); + span_numbers[numspans] = spanno; + snprintf(span_names[numspans], sizeof(span_names[numspans]), "wanpipe%d", spanno); + numspans++; + } + + if (!numspans) { + fprintf(stderr, "please specify a at least 1 wanpipe port number\n"); + exit(-1); + } + + /* clear any outstanding timers */ + memset(&g_timers, 0, sizeof(g_timers)); + + /* set the logging level to use */ + ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG); + + /* this is optional. + * cpu monitor is a default feature in freetdm that launches 1 thread + * to monitor system-wide CPU usage. If it goes above a predefined threshold + * it will stop accepting calls to try to protect the quality of current calls */ + ftdm_cpu_monitor_disable(); + + + /* Initialize the FTDM library */ + if (ftdm_global_init() != FTDM_SUCCESS) { + fprintf(stderr, "Error loading FreeTDM\n"); + exit(-1); + } + + /* create the schedule mutex */ + ftdm_mutex_create(&g_schedule_mutex); + + /* now we can start creating spans */ + memset(&chan_config, 0, sizeof(chan_config)); + strncpy(chan_config.group_name, "mygroup", sizeof(chan_config.group_name)-1); + chan_config.group_name[sizeof(chan_config.group_name)-1] = 0; + for (i = 0; i < numspans; i++) { + spanname = span_names[i]; + /* "wanpipe" is the special I/O identifier for Sangoma devices */ + ftdm_log(FTDM_LOG_NOTICE, "Creating span %s\n", spanname); + status = ftdm_span_create("wanpipe", spanname, &span_list[i]); + if (status != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_CRIT, "Failed to create span %s\n", spanname); + goto done; + } + span = span_list[i]; + spanno = span_numbers[i]; + + /* set the trunk type for the span */ + ftdm_span_set_trunk_type(span_list[i], FTDM_TRUNK_T1); + + /* configure B channels (syntax for wanpipe channels is span:low_chan-high_chan) */ + chan_config.type = FTDM_CHAN_TYPE_B; + snprintf(wpchans, sizeof(wpchans), "%d:1-23", spanno); + ftdm_configure_span_channels(span, wpchans, &chan_config, &configured); + ftdm_log(FTDM_LOG_NOTICE, "registered %d b channels\n", configured); + } + + /* At this point FreeTDM is ready to be used, the spans defined in freetdm.conf have the basic I/O board configuration + * but no telephony signaling configuration at all. */ + ftdm_log(FTDM_LOG_NOTICE, "FreeTDM loaded ...\n"); + + /* now we can start configuring signaling for the previously created spans */ + for (i = 0; i < numspans; i++) { + spanname = span_names[i]; + + /* Retrieve a span by name (as specified in ftdm_span_create()) */ + if (ftdm_span_find_by_name(spanname, &span) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span %s\n", ftdm_span_get_name(span)); + goto done; + } + + /* prepare the configuration parameters that will be sent down to the signaling stack, the array of paramters must be terminated by an + * array element with a null .var member */ + + /* for sangoma_boost signaling (abstraction signaling used by Sangoma for PRI, BRI and SS7) the first parameter you must send + * is sigmod, which must be either sangoma_prid, if you have the PRI stack available, or sangoma_brid for the BRI stack */ + parameters[0].var = "sigmod"; + parameters[0].val = "sangoma_prid"; + + /* following parameters are signaling stack specific, this ones are for PRI */ + parameters[1].var = "switchtype"; + parameters[1].val = "national"; + + parameters[2].var = "signalling"; + parameters[2].val = "pri_cpe"; + + /* + * parameters[3].var = "nfas_primary"; + * parameters[3].val = "4"; //span number + * + * parameters[4].var = "nfas_secondary"; + * parameters[4].val = "2"; //span number + * + * parameters[5].var = "nfas_group"; + * parameters[5].val = "1"; + * */ + + + /* the last parameter .var member must be NULL! */ + parameters[3].var = NULL; + + /* send the configuration values down to the stack */ + if (ftdm_configure_span_signaling(span, "sangoma_boost", on_signaling_event, parameters) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "Error configuring sangoma_boost signaling abstraction in span %s\n", ftdm_span_get_name(span)); + goto done; + } + + } + + + /* configuration succeeded, we can proceed now to start each span + * This step will launch at least 1 background (may be more, depending on the signaling stack used) + * to handle *ALL* signaling events for this span, your on_signaling_event callback will be called always + * in one of those infraestructure threads and you MUST NOT block in that handler to avoid delays and errors + * in the signaling processing for any call. + * */ + for (i = 0; i < numspans; i++) { + spanname = span_names[i]; + /* Retrieve a span by name (as specified in ftdm_span_create()) */ + if (ftdm_span_find_by_name(spanname, &span) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span %s\n", ftdm_span_get_name(span)); + goto done; + } + + if (ftdm_span_start(span) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "Failing starting signaling on span %s\n", ftdm_span_get_name(span)); + goto done; + } + + } + + app_running = 1; + + /* Retrieve the first created span to place the call (if dialing was specified) */ + if (ftdm_span_find(1, &span) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span 1\n"); + goto done; + } + + /* The application thread can go on and do anything else, like waiting for a shutdown signal */ + while(ftdm_running() && app_running) { + ftdm_sleep(1000); + run_timers(); + ticks++; + if (!(ticks % 10) && todial && !g_outgoing_channel) { + ftdm_log(FTDM_LOG_NOTICE, "Originating call to number %s\n", todial); + place_call(span, todial); + } + } + + done: + + ftdm_log(FTDM_LOG_NOTICE, "Shutting down FreeTDM ...\n"); + + ftdm_mutex_destroy(&g_schedule_mutex); + + /* whenever you're done, this function will shutdown the signaling threads in any span that was started */ + ftdm_global_destroy(); + + printf("Terminated!\n"); + + sleep(2); + + exit(0); +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */