From 63120a7452ad16fe62dd2b5d22135eb6222e6611 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 14 Apr 2010 12:49:02 -0500 Subject: [PATCH 01/18] make break uuid_break and add cascade flag --- .../applications/mod_commands/mod_commands.c | 49 +++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index c62bcd5d5b..23fbaf23a4 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -2622,10 +2622,12 @@ SWITCH_STANDARD_API(session_audio_function) #define BREAK_SYNTAX " [all]" SWITCH_STANDARD_API(break_function) { - switch_core_session_t *psession = NULL; + switch_core_session_t *psession = NULL, *qsession = NULL; char *mycmd = NULL, *flag; - switch_channel_t *channel = NULL; + switch_channel_t *channel = NULL, *qchannel = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; + int all = 0; + int both = 0; if (zstr(cmd)) { stream->write_function(stream, "-USAGE: %s\n", BREAK_SYNTAX); @@ -2644,22 +2646,58 @@ SWITCH_STANDARD_API(break_function) goto done; } - if (flag && !strcasecmp(flag, "all")) { - switch_core_session_flush_private_events(psession); + if (flag) { + if (strstr(flag, "all")) { + all++; + } + if (strstr(flag, "both")) { + both++; + } } channel = switch_core_session_get_channel(psession); + + if (both) { + const char *quuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE); + if (quuid) { + qsession = switch_core_session_locate(quuid); + qchannel = switch_core_session_get_channel(qsession); + } + } + + if (all) { + switch_core_session_flush_private_events(psession); + if (qsession) { + switch_core_session_flush_private_events(qsession); + } + } + + + if (switch_channel_test_flag(channel, CF_BROADCAST)) { switch_channel_stop_broadcast(channel); } else { switch_channel_set_flag(channel, CF_BREAK); } + if (qchannel) { + if (switch_channel_test_flag(qchannel, CF_BROADCAST)) { + switch_channel_stop_broadcast(qchannel); + } else { + switch_channel_set_flag(qchannel, CF_BREAK); + } + } + done: + if (psession) { switch_core_session_rwunlock(psession); } + if (qsession) { + switch_core_session_rwunlock(qsession); + } + switch_safe_free(mycmd); return status; @@ -4164,6 +4202,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) SWITCH_ADD_API(commands_api_interface, "user_data", "find user data", user_data_function, "@ [var|param|attr] "); SWITCH_ADD_API(commands_api_interface, "user_exists", "find a user", user_exists_function, " "); SWITCH_ADD_API(commands_api_interface, "uuid_audio", "uuid_audio", session_audio_function, AUDIO_SYNTAX); + SWITCH_ADD_API(commands_api_interface, "uuid_break", "Break", break_function, BREAK_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_bridge", "uuid_bridge", uuid_bridge_function, ""); SWITCH_ADD_API(commands_api_interface, "uuid_broadcast", "broadcast", uuid_broadcast_function, BROADCAST_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_chat", "Send a chat message", uuid_chat, UUID_CHAT_SYNTAX); @@ -4261,6 +4300,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) switch_console_set_complete("add uuid_audio ::console::list_uuid start write mute"); switch_console_set_complete("add uuid_audio ::console::list_uuid start write level"); switch_console_set_complete("add uuid_audio ::console::list_uuid stop"); + switch_console_set_complete("add uuid_break ::console::list_uuid all"); + switch_console_set_complete("add uuid_break ::console::list_uuid both"); switch_console_set_complete("add uuid_bridge ::console::list_uuid ::console::list_uuid"); switch_console_set_complete("add uuid_broadcast ::console::list_uuid"); switch_console_set_complete("add uuid_chat ::console::list_uuid"); From baeb85350c66a91a8146b76f5775f0a8724f88fb Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Wed, 14 Apr 2010 10:57:50 -0400 Subject: [PATCH 02/18] declare as static --- src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c b/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c index e5d05e7e8d..cf57aeed3b 100644 --- a/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c +++ b/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c @@ -71,10 +71,10 @@ static switch_mutex_t *g_sessions_lock = NULL; unsigned long long g_next_session_id = 0; /* hash of sessions (I think a linked list suits better here, but FS does not have the data type) */ -switch_hash_t *g_sessions_hash = NULL; +static switch_hash_t *g_sessions_hash = NULL; /* global memory pool provided by FS */ -switch_memory_pool_t *g_pool = NULL; +static switch_memory_pool_t *g_pool = NULL; typedef struct vocallo_codec_s { int codec_id; /* vocallo codec ID */ From e3c1906c81644d7b84dfc24d25aef136c91b0c47 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Wed, 14 Apr 2010 11:00:17 -0400 Subject: [PATCH 03/18] add ss7 skeleton config section --- libs/freetdm/mod_freetdm/mod_freetdm.c | 63 ++++++++++++++++++++++++++ libs/freetdm/src/include/ftdm_types.h | 12 ++++- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 9b7f1e1fac..d70a0a550b 100644 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -91,6 +91,7 @@ static struct { char hold_music[256]; switch_mutex_t *mutex; analog_option_t analog_options; + switch_hash_t *ss7_configs; } globals; struct private_object { @@ -1961,6 +1962,15 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal) } +static FIO_SIGNAL_CB_FUNCTION(on_ss7_signal) +{ + if (on_common_signal(sigmsg) == FTDM_BREAK) { + return FTDM_SUCCESS; + } + ftdm_log(FTDM_LOG_DEBUG, "got ss7 sig %d:%d [%s]\n", sigmsg->channel->span_id, sigmsg->channel->chan_id, ftdm_signal_event2str(sigmsg->event_id)); + return FTDM_SUCCESS; +} + static FIO_SIGNAL_CB_FUNCTION(on_analog_signal) { switch_status_t status = SWITCH_STATUS_FALSE; @@ -2022,10 +2032,16 @@ static uint32_t enable_analog_option(const char *str, uint32_t current_options) } +static ftdm_conf_node_t *get_ss7_config_node(switch_xml_t cfg, const char *confname) +{ + return NULL; +} + static switch_status_t load_config(void) { const char *cf = "freetdm.conf"; switch_xml_t cfg, xml, settings, param, spans, myspan; + ftdm_conf_node_t *ss7confnode = NULL; ftdm_span_t *boost_spans[FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN]; ftdm_span_t *boost_span = NULL; unsigned boosti = 0; @@ -2054,6 +2070,53 @@ static switch_status_t load_config(void) } } + switch_core_hash_init(&globals.ss7_configs, module_pool); + if ((spans = switch_xml_child(cfg, "ss7_spans"))) { + for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) { + ftdm_status_t zstatus = FTDM_FAIL; + char *id = (char *) switch_xml_attr(myspan, "id"); + char *name = (char *) switch_xml_attr(myspan, "name"); + char *configname = (char *) switch_xml_attr(myspan, "config"); + ftdm_span_t *span = NULL; + uint32_t span_id = 0; + if (!name || !configname || !id) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ss7 span missing required param 'id' or 'name' or 'config', skipping ...\n"); + continue; + } + if (name) { + zstatus = ftdm_span_find_by_name(name, &span); + } else { + if (switch_is_number(id)) { + span_id = atoi(id); + zstatus = ftdm_span_find(span_id, &span); + } + + if (zstatus != FTDM_SUCCESS) { + zstatus = ftdm_span_find_by_name(id, &span); + } + } + + if (zstatus != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + continue; + } + + if (!span_id) { + span_id = span->span_id; + } + + ss7confnode = get_ss7_config_node(cfg, configname); + + if (ftdm_configure_span("ss7", span, on_ss7_signal, + "confnode", ss7confnode, + TAG_END) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "Error configuring ss7 FreeTDM span %d\n", span_id); + continue; + } + ftdm_log(FTDM_LOG_DEBUG, "Configured ss7 FreeTDM span %d with config node %s\n", span_id, configname); + } + } + if ((spans = switch_xml_child(cfg, "analog_spans"))) { for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) { char *id = (char *) switch_xml_attr(myspan, "id"); diff --git a/libs/freetdm/src/include/ftdm_types.h b/libs/freetdm/src/include/ftdm_types.h index a13179e856..c172ccb4ca 100644 --- a/libs/freetdm/src/include/ftdm_types.h +++ b/libs/freetdm/src/include/ftdm_types.h @@ -572,6 +572,14 @@ typedef ftdm_status_t (*fio_api_t) FIO_API_ARGS ; #include "ftdm_dso.h" +typedef struct ftdm_conf_node_s { + char name[255]; + ftdm_conf_parameter_t attr[10]; + ftdm_conf_parameter_t settings[100]; + struct ftdm_conf_node_t *childs; + struct ftdm_config_node_s *next; +} ftdm_conf_node_t; + typedef struct { char name[256]; fio_io_load_t io_load; @@ -583,9 +591,9 @@ typedef struct { \brief configure a given span signaling \see sig_configure This is just like sig_configure but receives - an array of paramters instead of va_list + an an ftdm_conf_node_t instead I'd like to deprecate sig_configure and move - all modules to use sigparam_configure + all modules to use configure_span_signaling */ fio_configure_span_signaling_t configure_span_signaling; ftdm_dso_lib_t lib; From 99402dd4e02fcf2c64ab240ce96a7a306e6c6c35 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Wed, 14 Apr 2010 17:59:39 -0400 Subject: [PATCH 04/18] implemented freetdm config nodes and ss7 initial configuration --- libs/freetdm/mod_freetdm/mod_freetdm.c | 150 +++++++++++++++++++++++-- libs/freetdm/src/ftdm_config.c | 80 +++++++++++++ libs/freetdm/src/include/freetdm.h | 3 + libs/freetdm/src/include/ftdm_types.h | 26 ++++- 4 files changed, 246 insertions(+), 13 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index d70a0a550b..bc0fd28126 100644 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -2032,9 +2032,133 @@ static uint32_t enable_analog_option(const char *str, uint32_t current_options) } +/* create ftdm_conf_node_t tree based on a fixed pattern XML configuration list + * last 2 args are for limited aka dumb recursivity + * */ +static int add_config_list_nodes(switch_xml_t swnode, ftdm_conf_node_t *rootnode, + const char *list_name, const char *list_element_name, + const char *sub_list_name, const char *sub_list_element_name) +{ + char *var, *val; + switch_xml_t list; + switch_xml_t element; + switch_xml_t param; + + ftdm_conf_node_t *n_list; + ftdm_conf_node_t *n_element; + + list = switch_xml_child(swnode, list_name); + if (!list) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "no list %s found\n", list_name); + return -1; + } + + if ((FTDM_SUCCESS != ftdm_conf_node_create(list_name, &n_list, rootnode))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to create %s node\n", list_name); + return -1; + } + + for (element = switch_xml_child(list, list_element_name); element; element = element->next) { + char *element_name = (char *) switch_xml_attr(element, "name"); + + if (!element_name) { + continue; + } + + if ((FTDM_SUCCESS != ftdm_conf_node_create(list_element_name, &n_element, n_list))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to create %s node for %s\n", list_element_name, element_name); + return -1; + } + ftdm_conf_node_add_param(n_element, "name", element_name); + + for (param = switch_xml_child(element, "param"); param; param = param->next) { + var = (char *) switch_xml_attr_soft(param, "name"); + val = (char *) switch_xml_attr_soft(param, "value"); + ftdm_conf_node_add_param(n_element, var, val); + } + + if (sub_list_name && sub_list_element_name) { + if (add_config_list_nodes(element, n_element, sub_list_name, sub_list_element_name, NULL, NULL)) { + return -1; + } + } + } + + return 0; +} + static ftdm_conf_node_t *get_ss7_config_node(switch_xml_t cfg, const char *confname) { - return NULL; + switch_xml_t signode, ss7configs, isup; + ftdm_conf_node_t *rootnode; + + /* try to find the conf in the hash first */ + rootnode = switch_core_hash_find(globals.ss7_configs, confname); + if (rootnode) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "ss7 config %s was found in the hash already\n", confname); + return rootnode; + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "not found %s config in hash, searching in xml ...\n", confname); + + signode = switch_xml_child(cfg, "signaling_configs"); + if (!signode) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "not found 'signaling_configs' XML config section\n"); + return NULL; + } + + ss7configs = switch_xml_child(signode, "sngss7_configs"); + if (!ss7configs) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "not found 'sngss7_configs' XML config section\n"); + return NULL; + } + + /* search the isup config */ + for (isup = switch_xml_child(ss7configs, "sng_isup"); isup; isup = isup->next) { + char *name = (char *) switch_xml_attr(isup, "name"); + if (!name) { + continue; + } + if (!strcasecmp(name, confname)) { + break; + } + } + + if (!isup) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "not found '%s' sng_isup XML config section\n", confname); + return NULL; + } + + /* found our XML chunk, create the root node */ + if ((FTDM_SUCCESS != ftdm_conf_node_create("sng_isup", &rootnode, NULL))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to create root node for sng_isup config %s\n", confname); + return NULL; + } + + /* add mtp linksets */ + if (add_config_list_nodes(isup, rootnode, "mtp_linksets", "mtp_linkset", "mtp_links", "mtp_link")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process mtp_linksets for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } + + /* add mtp routes */ + if (add_config_list_nodes(isup, rootnode, "mtp_routes", "mtp_route", NULL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process mtp_routes for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } + + /* add isup interfaces */ + if (add_config_list_nodes(isup, rootnode, "isup_interfaces", "isup_interface", NULL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process isup_interfaces for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } + + switch_core_hash_insert(globals.ss7_configs, confname, rootnode); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Added SS7 node configuration %s\n", confname); + return rootnode; } static switch_status_t load_config(void) @@ -2079,8 +2203,12 @@ static switch_status_t load_config(void) char *configname = (char *) switch_xml_attr(myspan, "config"); ftdm_span_t *span = NULL; uint32_t span_id = 0; - if (!name || !configname || !id) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ss7 span missing required param 'id' or 'name' or 'config', skipping ...\n"); + if (!name && !id) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ss7 span missing required attribute 'id' or 'name', skipping ...\n"); + continue; + } + if (!configname) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ss7 span missing required attribute, skipping ...\n"); continue; } if (name) { @@ -2106,13 +2234,19 @@ static switch_status_t load_config(void) } ss7confnode = get_ss7_config_node(cfg, configname); - - if (ftdm_configure_span("ss7", span, on_ss7_signal, - "confnode", ss7confnode, - TAG_END) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error configuring ss7 FreeTDM span %d\n", span_id); + if (!ss7confnode) { + ftdm_log(FTDM_LOG_ERROR, "Error finding ss7config '%s' for FreeTDM span id: %s\n", configname, switch_str_nil(id)); continue; } + + if (0) { + if (ftdm_configure_span("ss7", span, on_ss7_signal, + "confnode", ss7confnode, + TAG_END) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "Error configuring ss7 FreeTDM span %d\n", span_id); + continue; + } + } ftdm_log(FTDM_LOG_DEBUG, "Configured ss7 FreeTDM span %d with config node %s\n", span_id, configname); } } diff --git a/libs/freetdm/src/ftdm_config.c b/libs/freetdm/src/ftdm_config.c index a7a8f041b1..5f9895d04b 100644 --- a/libs/freetdm/src/ftdm_config.c +++ b/libs/freetdm/src/ftdm_config.c @@ -29,6 +29,10 @@ * 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. + * + * Contributors: + * + * Moises Silva */ #include "freetdm.h" @@ -239,6 +243,82 @@ FT_DECLARE (int) ftdm_config_get_cas_bits(char *strvalue, unsigned char *outbits return 0; } +#define PARAMETERS_CHUNK_SIZE 20 +FT_DECLARE(ftdm_status_t) ftdm_conf_node_create(const char *name, ftdm_conf_node_t **node, ftdm_conf_node_t *parent) +{ + ftdm_conf_node_t *newnode; + ftdm_conf_node_t *sibling = NULL; + + ftdm_assert_return(name != NULL, FTDM_FAIL, "null node name"); + + newnode = ftdm_calloc(1, sizeof(**node)); + if (!newnode) { + return FTDM_MEMERR; + } + + strncpy(newnode->name, name, sizeof(newnode->name)-1); + newnode->name[sizeof(newnode->name)-1] = 0; + + newnode->parameters = ftdm_calloc(PARAMETERS_CHUNK_SIZE, sizeof(*newnode->parameters)); + if (!newnode->parameters) { + ftdm_safe_free(newnode); + return FTDM_MEMERR; + } + newnode->t_parameters = PARAMETERS_CHUNK_SIZE; + + if (parent) { + /* store who my parent is */ + newnode->parent = parent; + /* save any siblings */ + sibling = parent->child; + /* as a newborn I am first */ + parent->child = newnode; + if (sibling) { + /* store a pointer to my next sibling */ + newnode->next = sibling; + } + } + + *node = newnode; + + return FTDM_SUCCESS; +} + +FT_DECLARE(ftdm_status_t) ftdm_conf_node_add_param(ftdm_conf_node_t *node, const char *param, const char *val) +{ + void *newparameters; + + ftdm_assert_return(param != NULL, FTDM_FAIL, "param is null"); + ftdm_assert_return(val != NULL, FTDM_FAIL, "val is null"); + + if (node->n_parameters == node->t_parameters) { + newparameters = ftdm_realloc(node->parameters, (node->t_parameters + PARAMETERS_CHUNK_SIZE) * sizeof(*node->parameters)); + if (!newparameters) { + return FTDM_MEMERR; + } + node->parameters = newparameters; + node->t_parameters = node->n_parameters + PARAMETERS_CHUNK_SIZE; + } + node->parameters[node->n_parameters].var = param; + node->parameters[node->n_parameters].val = val; + node->n_parameters++; + return FTDM_SUCCESS; +} + +FT_DECLARE(ftdm_status_t) ftdm_conf_node_destroy(ftdm_conf_node_t *node) +{ + ftdm_conf_node_t *curr = NULL; + ftdm_conf_node_t *child = node->child; + while (child) { + curr = child; + child = curr->next; + ftdm_conf_node_destroy(curr); + } + ftdm_free(node->parameters); + ftdm_free(node); + return FTDM_SUCCESS; +} + /* For Emacs: * Local Variables: * mode:c diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 263e79d40f..a924e3587a 100644 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -827,6 +827,9 @@ FT_DECLARE(char *) ftdm_api_execute(const char *type, const char *cmd); FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap); FT_DECLARE(ftdm_status_t) ftdm_channel_set_caller_data(ftdm_channel_t *ftdmchan, ftdm_caller_data_t *caller_data); FT_DECLARE(void) ftdm_cpu_monitor_disable(void); +FT_DECLARE(ftdm_status_t) ftdm_conf_node_create(const char *name, ftdm_conf_node_t **node, ftdm_conf_node_t *parent); +FT_DECLARE(ftdm_status_t) ftdm_conf_node_add_param(ftdm_conf_node_t *node, const char *param, const char *val); +FT_DECLARE(ftdm_status_t) ftdm_conf_node_destroy(ftdm_conf_node_t *node); FIO_CODEC_FUNCTION(fio_slin2ulaw); FIO_CODEC_FUNCTION(fio_ulaw2slin); diff --git a/libs/freetdm/src/include/ftdm_types.h b/libs/freetdm/src/include/ftdm_types.h index c172ccb4ca..bf7720efd1 100644 --- a/libs/freetdm/src/include/ftdm_types.h +++ b/libs/freetdm/src/include/ftdm_types.h @@ -572,12 +572,28 @@ typedef ftdm_status_t (*fio_api_t) FIO_API_ARGS ; #include "ftdm_dso.h" +#define FTDM_NODE_NAME_SIZE 50 typedef struct ftdm_conf_node_s { - char name[255]; - ftdm_conf_parameter_t attr[10]; - ftdm_conf_parameter_t settings[100]; - struct ftdm_conf_node_t *childs; - struct ftdm_config_node_s *next; + /* node name */ + char name[FTDM_NODE_NAME_SIZE]; + + /* total slots for parameters */ + unsigned int t_parameters; + + /* current number of parameters */ + unsigned int n_parameters; + + /* array of parameters */ + ftdm_conf_parameter_t *parameters; + + /* first node child */ + struct ftdm_conf_node_s *child; + + /* next node sibling */ + struct ftdm_conf_node_s *next; + + /* my parent if any */ + struct ftdm_conf_node_s *parent; } ftdm_conf_node_t; typedef struct { From 4704a30a450ace8bf763a1bb070d0d0c555a997a Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Wed, 14 Apr 2010 18:15:22 -0400 Subject: [PATCH 05/18] destroy ss7 configs on shutdown --- libs/freetdm/mod_freetdm/mod_freetdm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index bc0fd28126..3a4ff4c9fb 100644 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -3391,6 +3391,17 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load) SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_freetdm_shutdown) { + switch_hash_index_t *hi; + + const void *var; + void *val; + + /* destroy ss7 configs */ + for (hi = switch_hash_first(NULL, globals.ss7_configs); hi; hi = switch_hash_next(hi)) { + switch_hash_this(hi, &var, NULL, &val); + ftdm_conf_node_destroy(val); + } + ftdm_global_destroy(); // this breaks pika but they are MIA so *shrug* From 0abbe4bd0e5b20d7e2362b0f3c159ba6a32d4593 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Wed, 14 Apr 2010 18:36:22 -0400 Subject: [PATCH 06/18] complete ss7 config by setting context and dial plan --- libs/freetdm/mod_freetdm/mod_freetdm.c | 50 ++++++++++++++++++-------- libs/freetdm/src/ftdm_io.c | 4 +-- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 3a4ff4c9fb..fc3f1c4ca9 100644 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -2198,11 +2198,15 @@ static switch_status_t load_config(void) if ((spans = switch_xml_child(cfg, "ss7_spans"))) { for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) { ftdm_status_t zstatus = FTDM_FAIL; + const char *context = "default"; + const char *dialplan = "XML"; + ftdm_conf_parameter_t spanparameters[30]; char *id = (char *) switch_xml_attr(myspan, "id"); char *name = (char *) switch_xml_attr(myspan, "name"); char *configname = (char *) switch_xml_attr(myspan, "config"); ftdm_span_t *span = NULL; uint32_t span_id = 0; + unsigned paramindex = 0; if (!name && !id) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ss7 span missing required attribute 'id' or 'name', skipping ...\n"); continue; @@ -2239,14 +2243,38 @@ static switch_status_t load_config(void) continue; } - if (0) { - if (ftdm_configure_span("ss7", span, on_ss7_signal, - "confnode", ss7confnode, - TAG_END) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error configuring ss7 FreeTDM span %d\n", span_id); - continue; + memset(spanparameters, 0, sizeof(spanparameters)); + for (param = switch_xml_child(myspan, "param"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + + if (sizeof(spanparameters)/sizeof(spanparameters[0]) == paramindex) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Too many parameters for ss7 span, ignoring any parameter after %s\n", var); + break; + } + + if (!strcasecmp(var, "context")) { + context = val; + } else if (!strcasecmp(var, "dialplan")) { + dialplan = val; + } else { + spanparameters[paramindex].var = var; + spanparameters[paramindex].val = val; + paramindex++; } } + + if (ftdm_configure_span("ss7", span, on_ss7_signal, + "confnode", ss7confnode, + "parameters", spanparameters, + TAG_END) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "Error configuring ss7 FreeTDM span %d\n", span_id); + continue; + } + SPAN_CONFIG[span->span_id].span = span; + switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context)); + switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan)); + switch_copy_string(SPAN_CONFIG[span->span_id].type, "Sangoma (SS7)", sizeof(SPAN_CONFIG[span->span_id].type)); ftdm_log(FTDM_LOG_DEBUG, "Configured ss7 FreeTDM span %d with config node %s\n", span_id, configname); } } @@ -2701,7 +2729,6 @@ static switch_status_t load_config(void) const char *dialplan = "XML"; uint32_t span_id = 0; ftdm_span_t *span = NULL; - const char *tonegroup = NULL; ftdm_conf_parameter_t spanparameters[30]; unsigned paramindex = 0; @@ -2723,9 +2750,8 @@ static switch_status_t load_config(void) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Too many parameters for boost span, ignoring any parameter after %s\n", var); break; } - if (!strcasecmp(var, "tonegroup")) { - tonegroup = val; - } else if (!strcasecmp(var, "context")) { + + if (!strcasecmp(var, "context")) { context = val; } else if (!strcasecmp(var, "dialplan")) { dialplan = val; @@ -2736,10 +2762,6 @@ static switch_status_t load_config(void) } } - if (!tonegroup) { - tonegroup = "us"; - } - if (name) { zstatus = ftdm_span_find_by_name(name, &span); } else { diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 8c0744538d..089e66da37 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -1623,8 +1623,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_get_sig_status(ftdm_channel_t *ftdmchan, if (ftdmchan->span->get_channel_sig_status) { return ftdmchan->span->get_channel_sig_status(ftdmchan, sigstatus); } else { - ftdm_log(FTDM_LOG_ERROR, "get_channel_sig_status method not implemented!\n"); - return FTDM_FAIL; + /* don't log error here, it can be called just to test if its supported */ + return FTDM_NOTIMPL; } } From c3db6452209f43227977b9b1f7be24271eb08d05 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 14 Apr 2010 18:27:09 -0500 Subject: [PATCH 07/18] add event data to valet parking hold event --- src/mod/applications/mod_valet_parking/mod_valet_parking.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mod/applications/mod_valet_parking/mod_valet_parking.c b/src/mod/applications/mod_valet_parking/mod_valet_parking.c index 2fe2a78c84..9aacdbd33f 100644 --- a/src/mod/applications/mod_valet_parking/mod_valet_parking.c +++ b/src/mod/applications/mod_valet_parking/mod_valet_parking.c @@ -261,6 +261,7 @@ SWITCH_STANDARD_APP(valet_parking_function) switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Valet-Lot-Name", lot_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Valet-Extension", ext); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "hold"); + switch_channel_event_set_data(channel, event); switch_event_fire(&event); } From b4233082fa0afa336a53d69ff1dc373c87b5a2c9 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 14 Apr 2010 19:00:38 -0500 Subject: [PATCH 08/18] set appearance-index in update statement for SLA --- src/mod/endpoints/mod_sofia/sofia_presence.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index 80f7d248ee..0a8a333812 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -614,12 +614,12 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) #endif if (uuid) { - sql = switch_mprintf("update sip_dialogs set call_info_state='%q' where hostname='%q' and uuid='%q'", - call_info_state, mod_sofia_globals.hostname, uuid); + sql = switch_mprintf("update sip_dialogs set call_info='%q',call_info_state='%q' where hostname='%q' and uuid='%q'", + call_info, call_info_state, mod_sofia_globals.hostname, uuid); } else { - sql = switch_mprintf("update sip_dialogs set call_info_state='%q' where hostname='%q' and sip_dialogs.sip_from_user='%q' " + sql = switch_mprintf("update sip_dialogs set call_info='%q', call_info_state='%q' where hostname='%q' and sip_dialogs.sip_from_user='%q' " "and sip_dialogs.sip_from_host='%q' and call_info='%q'", - call_info_state, mod_sofia_globals.hostname, euser, host, call_info); + call_info, call_info_state, mod_sofia_globals.hostname, euser, host, call_info); } From 0f29f4617236686ccfe1dd620064645403bf96b7 Mon Sep 17 00:00:00 2001 From: Marc Olivier Chouinard Date: Wed, 14 Apr 2010 21:36:41 -0400 Subject: [PATCH 09/18] mod_voicemail: Fix vm_prefs profile lock (MODAPP-417) --- src/mod/applications/mod_voicemail/mod_voicemail.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/applications/mod_voicemail/mod_voicemail.c b/src/mod/applications/mod_voicemail/mod_voicemail.c index 4bdae40975..d01205feff 100644 --- a/src/mod/applications/mod_voicemail/mod_voicemail.c +++ b/src/mod/applications/mod_voicemail/mod_voicemail.c @@ -3353,7 +3353,7 @@ SWITCH_STANDARD_API(prefs_api_function) stream->write_function(stream, "-ERR No such profile\n"); goto done; } - if (!(profile = get_profile("default"))) { + if (!profile && !(profile = get_profile("default"))) { stream->write_function(stream, "-ERR profile 'default' doesn't exist\n"); goto done; } From fab8e0d5b67ed6bc51d4f19ad6e77cfef8e0bde9 Mon Sep 17 00:00:00 2001 From: Joao Mesquita Date: Wed, 14 Apr 2010 23:54:59 -0300 Subject: [PATCH 10/18] Fix some things on the console and start implementing the transfer. --- fscomm/call.cpp | 6 ++++++ fscomm/call.h | 5 ++++- fscomm/debugtools/consolewindow.cpp | 20 +++++++++++++++++--- fscomm/mainwindow.cpp | 5 +++-- fscomm/mainwindow.h | 1 + 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/fscomm/call.cpp b/fscomm/call.cpp index 80dc316fb3..0dce6a83cd 100644 --- a/fscomm/call.cpp +++ b/fscomm/call.cpp @@ -112,3 +112,9 @@ QTime Call::getCurrentStateTime() int now = QDateTime::fromTime_t(time).secsTo(QDateTime::currentDateTime()); return QTime::fromString(QString::number(now), "s"); } + +/*bool Call::transfer() +{ + + g_FSHost.sendCmd("uuid_bridge", "") +}*/ diff --git a/fscomm/call.h b/fscomm/call.h index 81f712a679..d2626f35af 100644 --- a/fscomm/call.h +++ b/fscomm/call.h @@ -38,7 +38,8 @@ typedef enum { FSCOMM_CALL_STATE_RINGING = 0, FSCOMM_CALL_STATE_TRYING = 1, FSCOMM_CALL_STATE_ANSWERED = 2, - FSCOMM_CALL_STATE_FAILED = 3 + FSCOMM_CALL_STATE_FAILED = 3, + FSCOMM_CALL_STATE_TRANSFER = 4 } fscomm_call_state_t; typedef enum { @@ -76,6 +77,8 @@ public: void setAnsweredEpoch(qulonglong time) { _answeredEpoch = time/1000000; } QTime getCurrentStateTime(); + /*bool transfer();*/ + private: QSharedPointer _channel; /* This should be our portaudio channel */ QSharedPointer _otherLegChannel; diff --git a/fscomm/debugtools/consolewindow.cpp b/fscomm/debugtools/consolewindow.cpp index aa3b4faa42..25fab26df9 100644 --- a/fscomm/debugtools/consolewindow.cpp +++ b/fscomm/debugtools/consolewindow.cpp @@ -105,9 +105,23 @@ void ConsoleWindow::cmdSendClicked() QString res; g_FSHost.sendCmd(cmd.toAscii().data(), args.toAscii().data(), &res); - QStandardItem *item = new QStandardItem(res); - item->setData(SWITCH_LOG_CONSOLE, ConsoleModel::LogLevelRole); - addNewConsoleItem(item); + if (!res.isEmpty()) + { + /* Remove \r\n */ + QStringList textList = res.split(QRegExp("(\r+)"), QString::SkipEmptyParts); + QString final_str; + for (int line = 0; linesetData(SWITCH_LOG_CONSOLE, ConsoleModel::LogLevelRole); + addNewConsoleItem(item); + } + } ui->lineCmd->clear(); } diff --git a/fscomm/mainwindow.cpp b/fscomm/mainwindow.cpp index 0cfb076f3e..50dca81bee 100644 --- a/fscomm/mainwindow.cpp +++ b/fscomm/mainwindow.cpp @@ -101,6 +101,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->hangupBtn, SIGNAL(clicked()), this, SLOT(paHangup())); connect(ui->recoredCallBtn, SIGNAL(toggled(bool)), SLOT(recordCall(bool))); connect(ui->btnHold, SIGNAL(toggled(bool)), this, SLOT(holdCall(bool))); + /*connect(ui->btnTransfer, SIGNAL(clicked()), this, SLOT(transferCall()));*/ connect(ui->tableCalls, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(callTableDoubleClick(QTableWidgetItem*))); connect(ui->action_Preferences, SIGNAL(triggered()), this, SLOT(prefTriggered())); connect(ui->action_Exit, SIGNAL(triggered()), this, SLOT(close())); @@ -280,9 +281,9 @@ void MainWindow::callTableDoubleClick(QTableWidgetItem *item) void MainWindow::makeCall() { - bool ok; + bool ok = true; QString dialstring = QInputDialog::getText(this, tr("Make new call"), - tr("Number to dial:"), QLineEdit::Normal, NULL,&ok); + tr("Number to dial:"), QLineEdit::Normal, NULL,&ok); QSharedPointer acc = g_FSHost.getCurrentDefaultAccount(); if (!acc.isNull()) { diff --git a/fscomm/mainwindow.h b/fscomm/mainwindow.h index 3b87da18ed..32c4466d20 100644 --- a/fscomm/mainwindow.h +++ b/fscomm/mainwindow.h @@ -77,6 +77,7 @@ private slots: void callFailed(QSharedPointer); void recordCall(bool); void holdCall(bool); + /*void transferCall();*/ void setDefaultAccount(); void accountAdd(QSharedPointer); void accountDel(QSharedPointer); From 7074b07603290ecbae281413af947111ee63d538 Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Thu, 15 Apr 2010 03:20:06 -0400 Subject: [PATCH 11/18] add event for Valet Parking action exit --- .../applications/mod_valet_parking/mod_valet_parking.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/mod/applications/mod_valet_parking/mod_valet_parking.c b/src/mod/applications/mod_valet_parking/mod_valet_parking.c index 9aacdbd33f..430cd2f73e 100644 --- a/src/mod/applications/mod_valet_parking/mod_valet_parking.c +++ b/src/mod/applications/mod_valet_parking/mod_valet_parking.c @@ -287,6 +287,14 @@ SWITCH_STANDARD_APP(valet_parking_function) switch_mutex_lock(lot->mutex); switch_core_hash_delete(lot->hash, ext); switch_mutex_unlock(lot->mutex); + + if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, VALET_EVENT) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Valet-Lot-Name", lot_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Valet-Extension", ext); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "exit"); + switch_channel_event_set_data(channel, event); + switch_event_fire(&event); + } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Usage: %s\n", VALET_APP_SYNTAX); } From e44d79192f0a054347fca16afa65edab68ec9001 Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Thu, 15 Apr 2010 10:54:01 +0200 Subject: [PATCH 12/18] Skinny: Handle backspace --- src/mod/endpoints/mod_skinny/skinny_protocol.c | 16 +++++++++++++++- src/mod/endpoints/mod_skinny/skinny_protocol.h | 11 +++++++++++ src/mod/endpoints/mod_skinny/skinny_tables.c | 1 + src/mod/endpoints/mod_skinny/skinny_tables.h | 2 +- 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index 94c61eb1dd..51cbe9b609 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -606,6 +606,7 @@ switch_status_t skinny_session_process_dest(switch_core_session_t *session, list if (!dest) { if (backspace) { /* backspace */ *tech_pvt->caller_profile->destination_number++ = '\0'; + send_back_space_request(listener, line_instance, tech_pvt->call_id); } if (append_dest != '\0' && !backspace) {/* append digit */ tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, @@ -615,7 +616,6 @@ switch_status_t skinny_session_process_dest(switch_core_session_t *session, list send_start_tone(listener, SKINNY_TONE_DIALTONE, 0, line_instance, tech_pvt->call_id); if(backspace) { send_select_soft_keys(listener, line_instance, tech_pvt->call_id, SKINNY_KEY_SET_OFF_HOOK, 0xffff); - /* TODO: How to clear the screen? */ } } else if (strlen(tech_pvt->caller_profile->destination_number) == 1) {/* first digit */ send_stop_tone(listener, line_instance, tech_pvt->call_id); @@ -1476,6 +1476,20 @@ switch_status_t send_activate_call_plane(listener_t *listener, return skinny_send_reply(listener, message); } +switch_status_t send_back_space_request(listener_t *listener, + uint32_t line_instance, + uint32_t call_id) +{ + skinny_message_t *message; + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.back_space_req)); + message->type = BACK_SPACE_REQ_MESSAGE; + message->length = 4 + sizeof(message->data.back_space_req); + message->data.back_space_req.line_instance = line_instance; + message->data.back_space_req.call_id = call_id; + return skinny_send_reply(listener, message); + +} + switch_status_t send_dialed_number(listener_t *listener, char called_party[24], uint32_t line_instance, diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.h b/src/mod/endpoints/mod_skinny/skinny_protocol.h index 3199738856..c038be5cc9 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.h +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.h @@ -457,6 +457,13 @@ struct unregister_ack_message { uint32_t unregister_status; }; +/* BackSpaceReqMessage */ +#define BACK_SPACE_REQ_MESSAGE 0x0119 +struct back_space_req_message { + uint32_t line_instance; + uint32_t call_id; +}; + /* DialedNumberMessage */ #define DIALED_NUMBER_MESSAGE 0x011D struct dialed_number_message { @@ -540,6 +547,7 @@ union skinny_data { struct clear_prompt_status_message clear_prompt_status; struct activate_call_plane_message activate_call_plane; struct unregister_ack_message unregister_ack; + struct back_space_req_message back_space_req; struct dialed_number_message dialed_number; struct feature_stat_res_message feature_res; struct display_pri_notify_message display_pri_notify; @@ -748,6 +756,9 @@ switch_status_t send_clear_prompt_status(listener_t *listener, uint32_t call_id); switch_status_t send_activate_call_plane(listener_t *listener, uint32_t line_instance); +switch_status_t send_back_space_request(listener_t *listener, + uint32_t line_instance, + uint32_t call_id); switch_status_t send_dialed_number(listener_t *listener, char called_party[24], uint32_t line_instance, diff --git a/src/mod/endpoints/mod_skinny/skinny_tables.c b/src/mod/endpoints/mod_skinny/skinny_tables.c index 5ddd53ac87..b9d6a2e29b 100644 --- a/src/mod/endpoints/mod_skinny/skinny_tables.c +++ b/src/mod/endpoints/mod_skinny/skinny_tables.c @@ -86,6 +86,7 @@ struct skinny_table SKINNY_MESSAGE_TYPES[] = { {"ClearPromptStatusMessage", CLEAR_PROMPT_STATUS_MESSAGE}, {"ActivateCallPlaneMessage", ACTIVATE_CALL_PLANE_MESSAGE}, {"UnregisterAckMessage", UNREGISTER_ACK_MESSAGE}, + {"BackSpaceReqMessage", BACK_SPACE_REQ_MESSAGE}, {"DialedNumberMessage", DIALED_NUMBER_MESSAGE}, {"FeatureResMessage", FEATURE_STAT_RES_MESSAGE}, {"DisplayPriNotifyMessage", DISPLAY_PRI_NOTIFY_MESSAGE}, diff --git a/src/mod/endpoints/mod_skinny/skinny_tables.h b/src/mod/endpoints/mod_skinny/skinny_tables.h index 9e3ab3be4c..8db8209e87 100644 --- a/src/mod/endpoints/mod_skinny/skinny_tables.h +++ b/src/mod/endpoints/mod_skinny/skinny_tables.h @@ -84,7 +84,7 @@ uint32_t func(const char *str)\ } -struct skinny_table SKINNY_MESSAGE_TYPES[56]; +struct skinny_table SKINNY_MESSAGE_TYPES[57]; const char *skinny_message_type2str(uint32_t id); uint32_t skinny_str2message_type(const char *str); #define SKINNY_PUSH_MESSAGE_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_MESSAGE_TYPES) From d41f32356ce0e230b5f5fe776918f17f09f8c3b5 Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Thu, 15 Apr 2010 11:07:45 +0200 Subject: [PATCH 13/18] Skinny: calling shared lines --- src/mod/endpoints/mod_skinny/skinny_protocol.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index 51cbe9b609..4bbe77bf72 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -584,8 +584,12 @@ int skinny_session_process_dest_callback(void *pArg, int argc, char **argv, char && (line_instance == helper->line_instance)) {/* the calling line */ /* nothing */ } else { - /* TODO: capture and check what should happen here*/ - skinny_line_set_state(listener, line_instance, helper->tech_pvt->call_id, SKINNY_IN_USE_REMOTELY); + send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_ON); + skinny_line_set_state(listener, line_instance, helper->tech_pvt->call_id, SKINNY_IN_USE_REMOTELY); + send_select_soft_keys(listener, line_instance, helper->tech_pvt->call_id, 10, 0xffff); + send_display_prompt_status(listener, 0, "\200\037", + line_instance, tech_pvt->call_id); + skinny_send_call_info(session, listener, line_instance); } } return 0; From 93db4451d1d2c6ac28ddf65ce558fa0e13bcb2b0 Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Thu, 15 Apr 2010 11:11:05 +0200 Subject: [PATCH 14/18] Skinny: fix previous commit, define current time on hangup --- src/mod/endpoints/mod_skinny/mod_skinny.c | 2 +- src/mod/endpoints/mod_skinny/skinny_protocol.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index 391923d5e9..2a6e65d695 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -651,7 +651,7 @@ int channel_on_hangup_callback(void *pArg, int argc, char **argv, char **columnN skinny_line_set_state(listener, line_instance, call_id, SKINNY_ON_HOOK); send_select_soft_keys(listener, line_instance, call_id, SKINNY_KEY_SET_ON_HOOK, 0xffff); - /* TODO: DefineTimeDate */ + send_define_current_time_date(listener); send_set_speaker_mode(listener, SKINNY_SPEAKER_OFF); send_set_ringer(listener, SKINNY_RING_OFF, SKINNY_RING_FOREVER, 0, call_id); } diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index 4bbe77bf72..c242e32c3f 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -588,8 +588,8 @@ int skinny_session_process_dest_callback(void *pArg, int argc, char **argv, char skinny_line_set_state(listener, line_instance, helper->tech_pvt->call_id, SKINNY_IN_USE_REMOTELY); send_select_soft_keys(listener, line_instance, helper->tech_pvt->call_id, 10, 0xffff); send_display_prompt_status(listener, 0, "\200\037", - line_instance, tech_pvt->call_id); - skinny_send_call_info(session, listener, line_instance); + line_instance, helper->tech_pvt->call_id); + skinny_send_call_info(helper->tech_pvt->session, listener, line_instance); } } return 0; From 764b435d7cbe65c1d7eb3dcb50cb7fa221cfd9d9 Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Thu, 15 Apr 2010 14:47:01 +0200 Subject: [PATCH 15/18] Skinny: correct backspace handling, and behave more like CCM --- .../endpoints/mod_skinny/skinny_protocol.c | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index c242e32c3f..30bd4b3913 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -608,21 +608,24 @@ switch_status_t skinny_session_process_dest(switch_core_session_t *session, list tech_pvt = switch_core_session_get_private(session); if (!dest) { + if (strlen(tech_pvt->caller_profile->destination_number) == 0) {/* no digit yet */ + send_start_tone(listener, SKINNY_TONE_DIALTONE, 0, line_instance, tech_pvt->call_id); + } if (backspace) { /* backspace */ - *tech_pvt->caller_profile->destination_number++ = '\0'; + tech_pvt->caller_profile->destination_number[strlen(tech_pvt->caller_profile->destination_number)-1] = '\0'; + if (strlen(tech_pvt->caller_profile->destination_number) == 0) { + send_select_soft_keys(listener, line_instance, tech_pvt->call_id, SKINNY_KEY_SET_OFF_HOOK, 0xffff); + } send_back_space_request(listener, line_instance, tech_pvt->call_id); } - if (append_dest != '\0' && !backspace) {/* append digit */ + if (append_dest != '\0') {/* append digit */ tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, "%s%c", tech_pvt->caller_profile->destination_number, append_dest); } - if (strlen(tech_pvt->caller_profile->destination_number) == 0) {/* no digit yet */ - send_start_tone(listener, SKINNY_TONE_DIALTONE, 0, line_instance, tech_pvt->call_id); - if(backspace) { - send_select_soft_keys(listener, line_instance, tech_pvt->call_id, SKINNY_KEY_SET_OFF_HOOK, 0xffff); - } - } else if (strlen(tech_pvt->caller_profile->destination_number) == 1) {/* first digit */ - send_stop_tone(listener, line_instance, tech_pvt->call_id); + if (strlen(tech_pvt->caller_profile->destination_number) == 1) {/* first digit */ + if(!backspace) { + send_stop_tone(listener, line_instance, tech_pvt->call_id); + } send_select_soft_keys(listener, line_instance, tech_pvt->call_id, SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT, 0xffff); } From e7a5420b31e1d0bcacc2a29b7af0db54f3c40b3e Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Thu, 15 Apr 2010 15:05:34 +0200 Subject: [PATCH 16/18] Skinny: handle Hold stimulus --- src/mod/endpoints/mod_skinny/skinny_protocol.c | 18 +++++++++++++----- src/mod/endpoints/mod_skinny/skinny_tables.c | 1 + src/mod/endpoints/mod_skinny/skinny_tables.h | 3 ++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index 30bd4b3913..c74c65c170 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -2223,6 +2223,7 @@ switch_status_t skinny_handle_off_hook_message(listener_t *listener, skinny_mess switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_message_t *request) { + switch_status_t status = SWITCH_STATUS_SUCCESS; struct speed_dial_stat_res_message *button = NULL; uint32_t line_instance = 0; uint32_t call_id = 0; @@ -2239,10 +2240,6 @@ switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_mess skinny_create_ingoing_session(listener, &line_instance, &session); skinny_session_process_dest(session, listener, line_instance, "redial", '\0', 0); break; - case SKINNY_BUTTON_VOICEMAIL: - skinny_create_ingoing_session(listener, &line_instance, &session); - skinny_session_process_dest(session, listener, line_instance, "vmain", '\0', 0); - break; case SKINNY_BUTTON_SPEED_DIAL: skinny_speed_dial_get(listener, request->data.stimulus.instance, &button); if(strlen(button->line) > 0) { @@ -2250,6 +2247,17 @@ switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_mess skinny_session_process_dest(session, listener, line_instance, button->line, '\0', 0); } break; + case SKINNY_BUTTON_HOLD: + session = skinny_profile_find_session(listener->profile, listener, &line_instance, call_id); + + if(session) { + status = skinny_session_hold_line(session, listener, line_instance); + } + break; + case SKINNY_BUTTON_VOICEMAIL: + skinny_create_ingoing_session(listener, &line_instance, &session); + skinny_session_process_dest(session, listener, line_instance, "vmain", '\0', 0); + break; default: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown Stimulus Type Received [%d]\n", request->data.stimulus.instance_type); } @@ -2258,7 +2266,7 @@ switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_mess switch_core_session_rwunlock(session); } - return SWITCH_STATUS_SUCCESS; + return status; } switch_status_t skinny_handle_open_receive_channel_ack_message(listener_t *listener, skinny_message_t *request) diff --git a/src/mod/endpoints/mod_skinny/skinny_tables.c b/src/mod/endpoints/mod_skinny/skinny_tables.c index b9d6a2e29b..a9bf84431f 100644 --- a/src/mod/endpoints/mod_skinny/skinny_tables.c +++ b/src/mod/endpoints/mod_skinny/skinny_tables.c @@ -118,6 +118,7 @@ struct skinny_table SKINNY_BUTTONS[] = { {"Unknown", SKINNY_BUTTON_UNKNOWN}, {"LastNumberRedial", SKINNY_BUTTON_LAST_NUMBER_REDIAL}, {"SpeedDial", SKINNY_BUTTON_SPEED_DIAL}, + {"Hold", SKINNY_BUTTON_HOLD}, {"Line", SKINNY_BUTTON_LINE}, {"Voicemail", SKINNY_BUTTON_VOICEMAIL}, {"Privacy", SKINNY_BUTTON_PRIVACY}, diff --git a/src/mod/endpoints/mod_skinny/skinny_tables.h b/src/mod/endpoints/mod_skinny/skinny_tables.h index 8db8209e87..f3755b5c2f 100644 --- a/src/mod/endpoints/mod_skinny/skinny_tables.h +++ b/src/mod/endpoints/mod_skinny/skinny_tables.h @@ -151,13 +151,14 @@ enum skinny_button_definition { SKINNY_BUTTON_UNKNOWN = 0x00, SKINNY_BUTTON_LAST_NUMBER_REDIAL = 0x01, SKINNY_BUTTON_SPEED_DIAL = 0x02, + SKINNY_BUTTON_HOLD = 0x03, SKINNY_BUTTON_LINE = 0x09, SKINNY_BUTTON_VOICEMAIL = 0x0F, SKINNY_BUTTON_PRIVACY = 0x13, SKINNY_BUTTON_SERVICE_URL = 0x14, SKINNY_BUTTON_UNDEFINED = 0xFF, }; -struct skinny_table SKINNY_BUTTONS[9]; +struct skinny_table SKINNY_BUTTONS[10]; const char *skinny_button2str(uint32_t id); uint32_t skinny_str2button(const char *str); #define SKINNY_PUSH_STIMULI SKINNY_DECLARE_PUSH_MATCH(SKINNY_BUTTONS) From 3a8d9a04dc12f754a307e7f10fc09774d6522504 Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Thu, 15 Apr 2010 15:24:04 +0200 Subject: [PATCH 17/18] Skinny: reordering message types --- .../endpoints/mod_skinny/skinny_protocol.c | 71 +++++++++---------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index c74c65c170..7fd7998545 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -2471,55 +2471,52 @@ switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *re return SWITCH_STATUS_FALSE; } switch(request->type) { - case ALARM_MESSAGE: - return skinny_handle_alarm(listener, request); - /* registering phase */ + case KEEP_ALIVE_MESSAGE: + return skinny_handle_keep_alive_message(listener, request); case REGISTER_MESSAGE: return skinny_handle_register(listener, request); - case HEADSET_STATUS_MESSAGE: - return skinny_headset_status_message(listener, request); - case CONFIG_STAT_REQ_MESSAGE: - return skinny_handle_config_stat_request(listener, request); - case CAPABILITIES_RES_MESSAGE: - return skinny_handle_capabilities_response(listener, request); case PORT_MESSAGE: return skinny_handle_port_message(listener, request); - case BUTTON_TEMPLATE_REQ_MESSAGE: - return skinny_handle_button_template_request(listener, request); - case SOFT_KEY_TEMPLATE_REQ_MESSAGE: - return skinny_handle_soft_key_template_request(listener, request); - case SOFT_KEY_SET_REQ_MESSAGE: - return skinny_handle_soft_key_set_request(listener, request); - case LINE_STAT_REQ_MESSAGE: - return skinny_handle_line_stat_request(listener, request); + case KEYPAD_BUTTON_MESSAGE: + return skinny_handle_keypad_button_message(listener, request); + case STIMULUS_MESSAGE: + return skinny_handle_stimulus_message(listener, request); + case OFF_HOOK_MESSAGE: + return skinny_handle_off_hook_message(listener, request); + case ON_HOOK_MESSAGE: + return skinny_handle_on_hook_message(listener, request); case SPEED_DIAL_STAT_REQ_MESSAGE: return skinny_handle_speed_dial_stat_request(listener, request); + case LINE_STAT_REQ_MESSAGE: + return skinny_handle_line_stat_request(listener, request); + case CONFIG_STAT_REQ_MESSAGE: + return skinny_handle_config_stat_request(listener, request); + case TIME_DATE_REQ_MESSAGE: + return skinny_handle_time_date_request(listener, request); + case BUTTON_TEMPLATE_REQ_MESSAGE: + return skinny_handle_button_template_request(listener, request); + case CAPABILITIES_RES_MESSAGE: + return skinny_handle_capabilities_response(listener, request); + case ALARM_MESSAGE: + return skinny_handle_alarm(listener, request); + case OPEN_RECEIVE_CHANNEL_ACK_MESSAGE: + return skinny_handle_open_receive_channel_ack_message(listener, request); + case SOFT_KEY_SET_REQ_MESSAGE: + return skinny_handle_soft_key_set_request(listener, request); + case SOFT_KEY_EVENT_MESSAGE: + return skinny_handle_soft_key_event_message(listener, request); + case UNREGISTER_MESSAGE: + return skinny_handle_unregister(listener, request); + case SOFT_KEY_TEMPLATE_REQ_MESSAGE: + return skinny_handle_soft_key_template_request(listener, request); case SERVICE_URL_STAT_REQ_MESSAGE: return skinny_handle_service_url_stat_request(listener, request); case FEATURE_STAT_REQ_MESSAGE: return skinny_handle_feature_stat_request(listener, request); + case HEADSET_STATUS_MESSAGE: + return skinny_headset_status_message(listener, request); case REGISTER_AVAILABLE_LINES_MESSAGE: return skinny_handle_register_available_lines_message(listener, request); - case TIME_DATE_REQ_MESSAGE: - return skinny_handle_time_date_request(listener, request); - /* live phase */ - case KEEP_ALIVE_MESSAGE: - return skinny_handle_keep_alive_message(listener, request); - case SOFT_KEY_EVENT_MESSAGE: - return skinny_handle_soft_key_event_message(listener, request); - case OFF_HOOK_MESSAGE: - return skinny_handle_off_hook_message(listener, request); - case STIMULUS_MESSAGE: - return skinny_handle_stimulus_message(listener, request); - case OPEN_RECEIVE_CHANNEL_ACK_MESSAGE: - return skinny_handle_open_receive_channel_ack_message(listener, request); - case KEYPAD_BUTTON_MESSAGE: - return skinny_handle_keypad_button_message(listener, request); - case ON_HOOK_MESSAGE: - return skinny_handle_on_hook_message(listener, request); - /* end phase */ - case UNREGISTER_MESSAGE: - return skinny_handle_unregister(listener, request); default: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled request %s (type=%x,length=%d).\n", skinny_message_type2str(request->type), request->type, request->length); From 573adced1f17ade41b8164d2b14f414195ca2a5e Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Thu, 15 Apr 2010 11:35:37 -0400 Subject: [PATCH 18/18] Multiple updates and bug fixes to ftdm/openzap. Major stress test --- libs/freetdm/src/ftdm_io.c | 19 +- libs/freetdm/src/ftdm_threadmutex.c | 8 +- .../ftmod_sangoma_boost/ftmod_sangoma_boost.c | 307 +++++++++++++++--- .../sangoma_boost_client.c | 4 +- .../src/ftmod/ftmod_sangoma_boost/sigboost.h | 18 + .../ozmod_sangoma_boost/ozmod_sangoma_boost.c | 162 ++++++++- .../src/ozmod/ozmod_sangoma_boost/sigboost.h | 18 + 7 files changed, 467 insertions(+), 69 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 089e66da37..356eba5cb8 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -1087,16 +1087,20 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(ftdm_channel_t *ftdmchan, ftdm_ } } - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { - ftdm_log(FTDM_LOG_CRIT, "Ignored state change request from %s to %s, the previous state change has not been processed yet\n", - ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state)); - return FTDM_FAIL; - } - if (lock) { ftdm_mutex_lock(ftdmchan->mutex); } + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { + ftdm_log(FTDM_LOG_CRIT, "Ignored state change request from %s to %s, the previous state change has not been processed yet\n", + ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state)); + if (lock) { + ftdm_mutex_unlock(ftdmchan->mutex); + } + return FTDM_FAIL; + } + + if (ftdmchan->span->state_map) { ok = ftdm_parse_state_map(ftdmchan, state, ftdmchan->span->state_map); goto end; @@ -1353,7 +1357,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc ftdm_span_channel_use_count(span, &count); if (count >= span->chan_count) { - ftdm_log(FTDM_LOG_CRIT, "All circuits are busy.\n"); + ftdm_log(FTDM_LOG_CRIT, "All circuits are busy: active=%i max=%i.\n", + count, span->chan_count); *ftdmchan = NULL; return FTDM_FAIL; } diff --git a/libs/freetdm/src/ftdm_threadmutex.c b/libs/freetdm/src/ftdm_threadmutex.c index 9eca9eeb3d..1eb34a81f8 100644 --- a/libs/freetdm/src/ftdm_threadmutex.c +++ b/libs/freetdm/src/ftdm_threadmutex.c @@ -414,7 +414,7 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_multiple_wait(ftdm_interrupt_t *interru for (i = 0; i < size; i++) { ints[i] = interrupts[i]->event; if (interrupts[i]->device != FTDM_INVALID_SOCKET) { - ints[i+numdevices] = interrupts[i]->device; + ints[size+numdevices] = interrupts[i]->device; numdevices++; } } @@ -446,9 +446,9 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_multiple_wait(ftdm_interrupt_t *interru ints[i].revents = 0; ints[i].fd = interrupts[i]->readfd; if (interrupts[i]->device != FTDM_INVALID_SOCKET) { - ints[i+numdevices].events = POLLIN; - ints[i+numdevices].revents = 0; - ints[i+numdevices].fd = interrupts[i]->device; + ints[size+numdevices].events = POLLIN; + ints[size+numdevices].revents = 0; + ints[size+numdevices].fd = interrupts[i]->device; numdevices++; } } 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 f8e819e6d2..f7f1aac7ad 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 @@ -89,7 +89,6 @@ typedef uint16_t sangoma_boost_request_id_t; typedef enum { BST_FREE, BST_WAITING, - BST_ACK, BST_READY, BST_FAIL } sangoma_boost_request_status_t; @@ -106,6 +105,13 @@ typedef struct { int flags; } sangoma_boost_request_t; +typedef struct { + int call_setup_id; + int last_event_id; +} sangoma_boost_call_t; + +#define CALL_DATA(ftdmchan) ((sangoma_boost_call_t*)((ftdmchan)->call_data)) + //#define MAX_REQ_ID FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN * FTDM_MAX_CHANNELS_PHYSICAL_SPAN #define MAX_REQ_ID 6000 @@ -132,7 +138,7 @@ static void __release_request_id_span_chan(int span, int chan, const char *func, ftdm_mutex_lock(request_mutex); if ((id = SETUP_GRID[span][chan])) { - assert(id <= MAX_REQ_ID); + ftdm_assert(id <= MAX_REQ_ID, "Invalid id"); req_map[id] = 0; SETUP_GRID[span][chan] = 0; } @@ -148,7 +154,7 @@ static void __release_request_id_span_chan(int span, int chan, const char *func, */ static void __release_request_id(sangoma_boost_request_id_t r, const char *func, int line) { - assert(r <= MAX_REQ_ID); + ftdm_assert(r <= MAX_REQ_ID, "Invalid id"); ftdm_mutex_lock(request_mutex); req_map[r] = 0; ftdm_mutex_unlock(request_mutex); @@ -176,7 +182,7 @@ static sangoma_boost_request_id_t __next_request_id(const char *func, int line) r = ++last_req; if (r >= MAX_REQ_ID) { - r = i = last_req = 1; + r = last_req = 1; } if (req_map[r]) { @@ -201,6 +207,25 @@ static sangoma_boost_request_id_t __next_request_id(const char *func, int line) } #define next_request_id() __next_request_id(__FUNCTION__, __LINE__) + +static void print_request_ids(void) +{ + sangoma_boost_request_id_t i = 0; + + ftdm_mutex_lock(request_mutex); + + for (i=1; i<= MAX_REQ_ID; i++){ + if (req_map[i]) { + ftdm_log(FTDM_LOG_CRIT, "Used Request ID=%i\n",i); + } + } + + ftdm_mutex_unlock(request_mutex); + + return; +} + + /** * \brief Finds the channel that triggered an event * \param span Span where to search the channel @@ -212,9 +237,26 @@ static ftdm_channel_t *find_ftdmchan(ftdm_span_t *span, sangomabc_short_event_t { uint32_t i; ftdm_channel_t *ftdmchan = NULL; - ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data; + ftdm_sangoma_boost_data_t *sangoma_boost_data; uint32_t targetspan = event->span+1; uint32_t targetchan = event->chan+1; + + /* NC: Sanity check in case the call setup id does not relate + to span. This can happen if RESTART is received on a + full load. Where stray ACK messages can arrive after + a RESTART has taken place. + */ + if (!span) { + ftdm_log(FTDM_LOG_CRIT, "No Span for Event=%s s%dc%d cid=%d\n", + BOOST_DECODE_EVENT_ID(event->event_id), + event->span, + event->chan, + event->call_setup_id); + return NULL; + } + + sangoma_boost_data = span->signal_data; + if (sangoma_boost_data->sigmod) { /* span is not strictly needed here since we're supposed to get only events for our span */ targetspan = event->span; @@ -278,12 +320,20 @@ static FIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request) * and PRI stack will retransmit a second SETUP after the first timeout, so * we should allow for at least 8 seconds. */ + int boost_request_timeout = 10000; sangoma_boost_request_status_t st; char dnis[128] = ""; char *gr = NULL; uint32_t count = 0; int tg=0; + + /* NC: On large number of calls 10 seconds is not enough. + Resetting to 30 seconds. Especially on ss7 when + links are reset during large call volume */ + if (!sangoma_boost_data->sigmod) { + boost_request_timeout = 30000; + } if (sangoma_boost_data->sigmod) { ftdm_log(FTDM_LOG_CRIT, "This function should not be called when sigmod was configured in boost\n"); @@ -292,12 +342,22 @@ static FIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request) } if (ftdm_test_flag(span, FTDM_SPAN_SUSPENDED)) { - ftdm_log(FTDM_LOG_CRIT, "SPAN is not online.\n"); + ftdm_log(FTDM_LOG_CRIT, "SPAN is Suspended.\n"); + *ftdmchan = NULL; + return FTDM_FAIL; + } + + if (check_congestion(tg)) { + ftdm_log(FTDM_LOG_CRIT, "All circuits are busy. Trunk Group=%i (CONGESTION)\n",tg+1); + *ftdmchan = NULL; + return FTDM_FAIL; + } + + if (count >= span->chan_count) { + ftdm_log(FTDM_LOG_CRIT, "All circuits are busy.\n"); *ftdmchan = NULL; return FTDM_FAIL; } - - ftdm_set_string(dnis, caller_data->dnis.digits); r = next_request_id(); if (r == 0) { @@ -305,7 +365,11 @@ static FIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request) *ftdmchan = NULL; return FTDM_FAIL; } - sangomabc_call_init(&event, caller_data->cid_num.digits, dnis, r); + + /* After this point we must release request id before we leave the function + in case of an error. */ + + ftdm_set_string(dnis, caller_data->dnis.digits); if ((gr = strchr(dnis, '@'))) { *gr++ = '\0'; @@ -317,22 +381,14 @@ static FIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request) tg--; } } + + sangomabc_call_init(&event, caller_data->cid_num.digits, dnis, r); + event.trunk_group = tg; - if (check_congestion(tg)) { - ftdm_log(FTDM_LOG_CRIT, "All circuits are busy. Trunk Group=%i (BOOST REQUESTED BACK OFF)\n",tg+1); - *ftdmchan = NULL; - return FTDM_FAIL; - } ftdm_span_channel_use_count(span, &count); - if (count >= span->chan_count) { - ftdm_log(FTDM_LOG_CRIT, "All circuits are busy.\n"); - *ftdmchan = NULL; - return FTDM_FAIL; - } - if (gr && *(gr+1)) { switch(*gr) { case 'g': @@ -375,7 +431,7 @@ static FIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request) if (sangomabc_connection_write(&sangoma_boost_data->mcon, &event) <= 0) { ftdm_log(FTDM_LOG_CRIT, "Failed to tx boost event [%s]\n", strerror(errno)); - status = FTDM_FAIL; + status = OUTBOUND_REQUESTS[r].status = FTDM_FAIL; if (!sangoma_boost_data->sigmod) { *ftdmchan = NULL; } @@ -389,7 +445,7 @@ static FIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request) if (!sangoma_boost_data->sigmod) { *ftdmchan = NULL; } - ftdm_log(FTDM_LOG_CRIT, "s%dc%d: Csid:%d Timed out waiting for boost channel request response, current status: BST_WAITING\n", (*ftdmchan)->physical_span_id, (*ftdmchan)->physical_chan_id, r); + ftdm_log(FTDM_LOG_CRIT, "Csid:%d Timed out waiting for boost channel request response, current status: BST_WAITING\n", r); goto done; } } @@ -496,6 +552,7 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(sangoma_boost_outgoing_call) ftdm_log(FTDM_LOG_DEBUG, "Dialing number %s over boost channel with request id %d\n", event.called_number_digits, r); if (sangomabc_connection_write(&sangoma_boost_data->mcon, &event) <= 0) { + release_request_id(r); ftdm_log(FTDM_LOG_CRIT, "Failed to tx boost event [%s]\n", strerror(errno)); return FTDM_FAIL; } @@ -552,7 +609,12 @@ static void handle_call_start_ack(sangomabc_connection_t *mcon, sangomabc_short_ uint32_t event_span = event->span+1; uint32_t event_chan = event->chan+1; + if (nack_map[event->call_setup_id]) { + /* In this scenario outgoing call was alrady stopped + via NACK and now we are expecting an NACK_ACK. + If we receive an ACK its a race condition thus + ignor it */ return; } @@ -614,15 +676,43 @@ static void handle_call_start_ack(sangomabc_connection_t *mcon, sangomabc_short_ OUTBOUND_REQUESTS[event->call_setup_id].status = BST_READY; return; } - } + } else { + + ftdm_assert(!mcon->sigmod, "CALL STOP ACK: Invalid Sigmod Path"); + + if ((ftdmchan = find_ftdmchan(OUTBOUND_REQUESTS[event->call_setup_id].span, (sangomabc_short_event_t*)event, 1))) { + int r; + /* NC: If we get CALL START ACK and channel is in active state + then we are completely out of sync with the other end. + Treat CALL START ACK as CALL STOP and hangup the current call. + */ + + if (ftdmchan->state == FTDM_CHANNEL_STATE_UP || + ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA || + ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS) { + ftdm_log(FTDM_LOG_CRIT, "FTDM_CHAN STATE UP/PROG/PROG_MEDIA -> Changed to HANGUP %d:%d\n", event->span+1,event->chan+1); + ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_HANGUP, 0, r); + + } else if (ftdm_test_sflag(ftdmchan, SFLAG_HANGUP)) { + /* Do nothing because outgoing STOP will generaate a stop ack */ + + } else { + ftdm_log(FTDM_LOG_CRIT, "FTDM_CHAN STATE INVALID %s on IN CALL ACK %d:%d\n", ftdm_channel_state2str(ftdmchan->state),event->span+1,event->chan+1); + + } + ftdmchan=NULL; + } + } + if (!ftdmchan) { ftdm_log(FTDM_LOG_CRIT, "START ACK CANT FIND A CHAN %d:%d\n", event->span+1,event->chan+1); } else { /* only reason to be here is failed to open channel when we we're in sigmod */ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG); } - ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG); + sangomabc_exec_command(mcon, event->span, event->chan, @@ -643,7 +733,7 @@ static void handle_call_done(ftdm_span_t *span, sangomabc_connection_t *mcon, sa { ftdm_channel_t *ftdmchan; int r = 0; - + if ((ftdmchan = find_ftdmchan(span, event, 1))) { ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data; ftdm_mutex_lock(ftdmchan->mutex); @@ -684,6 +774,7 @@ static void handle_call_done(ftdm_span_t *span, sangomabc_connection_t *mcon, sa } } + /** * \brief Handler for call start nack event * \param span Span where event was fired @@ -725,7 +816,7 @@ static void handle_call_start_nack(ftdm_span_t *span, sangomabc_connection_t *mc if (event->call_setup_id) { if (sangoma_boost_data->sigmod) { ftdmchan = OUTBOUND_REQUESTS[event->call_setup_id].ftdmchan; - ftdmchan->call_data = (void*)(intptr_t)event->event_id; + CALL_DATA(ftdmchan)->last_event_id = event->event_id; ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); } else { sangomabc_exec_command(mcon, @@ -747,7 +838,7 @@ static void handle_call_start_nack(ftdm_span_t *span, sangomabc_connection_t *mc /* if there is no call setup id this should not be an outbound channel for sure */ ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND), "Yay, outbound flag should not be set here!\n"); - ftdmchan->call_data = (void*)(intptr_t)event->event_id; + CALL_DATA(ftdmchan)->last_event_id = event->event_id; ftdm_mutex_lock(ftdmchan->mutex); ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r); if (r == FTDM_STATE_CHANGE_SUCCESS) { @@ -800,7 +891,16 @@ static void handle_call_stop(ftdm_span_t *span, sangomabc_connection_t *mcon, sa ftdm_mutex_lock(ftdmchan->mutex); - if (ftdm_test_sflag(ftdmchan, SFLAG_HANGUP)) { + if (ftdm_test_sflag(ftdmchan, SFLAG_HANGUP) || + ftdmchan->state == FTDM_CHANNEL_STATE_DOWN || + ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { + + /* NC: Checking for state DOWN because ss7box can + send CALL_STOP twice in a row. If we do not check for + STATE_DOWN we will set the state back to termnating + and block the channel forever + */ + /* racing condition where both sides initiated a hangup * Do not change current state as channel is already clearing * itself through local initiated hangup */ @@ -855,8 +955,18 @@ static void handle_call_answer(ftdm_span_t *span, sangomabc_connection_t *mcon, if ((ftdmchan = find_ftdmchan(span, event, 1))) { ftdm_mutex_lock(ftdmchan->mutex); - if (ftdmchan->state == FTDM_CHANNEL_STATE_HOLD) { + + if (ftdm_test_sflag(ftdmchan, SFLAG_HANGUP) || + ftdmchan->state == FTDM_CHANNEL_STATE_DOWN || + ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { + + /* NC: Do nothing here because we are in process + of stopping the call. So ignore the ANSWER. */ + ftdm_log(FTDM_LOG_CRIT, "ANSWER BUT CALL IS HANGUP %d:%d\n", event->span+1,event->chan+1); + + } else if (ftdmchan->state == FTDM_CHANNEL_STATE_HOLD) { ftdmchan->init_state = FTDM_CHANNEL_STATE_UP; + } else { int r = 0; ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_UP, 0, r); @@ -888,6 +998,12 @@ static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, s if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 0))) { if ((ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 1))) { int r; + + /* NC: If we get CALL START and channel is in active state + then we are completely out of sync with the other end. + Treat CALL START as CALL STOP and hangup the current call. + */ + if (ftdmchan->state == FTDM_CHANNEL_STATE_UP) { ftdm_log(FTDM_LOG_CRIT, "ZCHAN STATE UP -> Changed to TERMINATING %d:%d\n", event->span+1,event->chan+1); ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r); @@ -1186,8 +1302,12 @@ static int parse_sangoma_event(ftdm_span_t *span, sangomabc_connection_t *mcon, handle_call_done(span, mcon, event); break; case SIGBOOST_EVENT_CALL_START_NACK_ACK: - handle_call_done(span, mcon, event); - nack_map[event->call_setup_id] = 0; + /* On NACK ack span chan are always invalid + All there is to do is to clear the id */ + if (event->call_setup_id) { + nack_map[event->call_setup_id] = 0; + release_request_id(event->call_setup_id); + } break; case SIGBOOST_EVENT_INSERT_CHECK_LOOP: handle_call_loop_start(span, mcon, event); @@ -1253,7 +1373,7 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) if (!ftdm_test_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG)) { ftdm_set_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG); - if (ftdmchan->call_data && ((uint32_t)(intptr_t)ftdmchan->call_data == SIGBOOST_EVENT_CALL_START_NACK)) { + if (ftdmchan->call_data && CALL_DATA(ftdmchan)->last_event_id == SIGBOOST_EVENT_CALL_START_NACK) { sangomabc_exec_command(mcon, BOOST_SPAN(ftdmchan), BOOST_CHAN(ftdmchan), @@ -1273,7 +1393,8 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) } } ftdmchan->sflags = 0; - ftdmchan->call_data = NULL; + memset(ftdmchan->call_data,0,sizeof(sangoma_boost_call_t)); + if (sangoma_boost_data->sigmod && call_stopped_ack_sent) { /* we dont want to call ftdm_channel_done just yet until call released is received */ ftdm_log(FTDM_LOG_DEBUG, "Waiting for call release confirmation before declaring chan %d:%d as available \n", @@ -1464,13 +1585,17 @@ static __inline__ void check_state(ftdm_span_t *span) uint32_t j; ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE); if (susp) { - for (j = 0; j <= span->chan_count; j++) { - ftdm_mutex_lock(span->channels[j]->mutex); - ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE); - ftdm_channel_set_state(span->channels[j], FTDM_CHANNEL_STATE_RESTART, 0); - state_advance(span->channels[j]); - ftdm_channel_complete_state(span->channels[j]); - ftdm_mutex_unlock(span->channels[j]->mutex); + for(j = 1; j <= span->chan_count; j++) { + if (ftdm_test_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE) || susp) { + ftdm_mutex_lock(span->channels[j]->mutex); + ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE); + if (susp && span->channels[j]->state != FTDM_CHANNEL_STATE_DOWN) { + ftdm_channel_set_state(span->channels[j], FTDM_CHANNEL_STATE_RESTART, 0); + } + state_advance(span->channels[j]); + ftdm_channel_complete_state(span->channels[j]); + ftdm_mutex_unlock(span->channels[j]->mutex); + } } } else { while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) { @@ -1649,8 +1774,8 @@ static int ftdm_boost_wait_event(ftdm_span_t *span) sangoma_boost_data->iteration = 0; } #endif - res = ftdm_interrupt_multiple_wait(ints, numints, -1); - if (FTDM_SUCCESS != res) { + res = ftdm_interrupt_multiple_wait(ints, numints, 100); + if (FTDM_SUCCESS != res && FTDM_TIMEOUT != res) { ftdm_log(FTDM_LOG_CRIT, "Unexpected return value from interrupt waiting: %d\n", res); return -1; } @@ -1737,7 +1862,6 @@ static void *ftdm_sangoma_boost_run(ftdm_thread_t *me, void *obj) if (ftdm_boost_wait_event(span) < 0) { ftdm_log(FTDM_LOG_ERROR, "ftdm_boost_wait_event failed\n"); - goto error; } while ((event = ftdm_boost_read_event(span))) { @@ -1750,7 +1874,6 @@ static void *ftdm_sangoma_boost_run(ftdm_thread_t *me, void *obj) goto end; -error: ftdm_log(FTDM_LOG_CRIT, "Boost event processing Error!\n"); end: @@ -1765,6 +1888,37 @@ end: return NULL; } +#if 0 +static int sigmod_ss7box_isup_exec_cmd(ftdm_stream_handle_t *stream, char *cmd) +{ + FILE *fp; + int status=0; + char path[1024]; + + fp = popen(cmd, "r"); + if (fp == NULL) { + stream->write_function(stream, "%s: -ERR failed to execute cmd: %s\n", + __FILE__,cmd); + return -1; + } + + while (fgets(path, sizeof(path)-1, fp) != NULL) { + path[sizeof(path)-1]='\0'; + stream->write_function(stream,"%s", path); + } + + + status = pclose(fp); + if (status == -1) { + /* Error reported by pclose() */ + } else { + /* Use macros described under wait() to inspect `status' in order + to determine success/failure of command executed by popen() */ + } + + return status; +} +#endif #define FTDM_BOOST_SYNTAX "list sigmods | " /** @@ -1787,11 +1941,63 @@ static FIO_API_FUNCTION(ftdm_sangoma_boost_api) if (!strcasecmp(argv[0], "list")) { if (!strcasecmp(argv[1], "sigmods")) { if (ftdm_sangoma_boost_list_sigmods(stream) != FTDM_SUCCESS) { - stream->write_function(stream, "%s: -ERR failed to execute cmd\n", __FILE__); + stream->write_function(stream, "-ERR failed to list sigmods\n"); goto done; } goto done; } + + if (!strcasecmp(argv[1], "ids")) { + print_request_ids(); + goto done; + } + +#ifndef __WINDOWS__ +#if 0 +/* NC: This code crashes the kernel due to fork on heavy fs load */ + } else if (!strcasecmp(argv[0], "ss7box_isupd_ckt")) { + + if (!strcasecmp(argv[1], "used")) { + stream->write_function(stream, "ss7box_isupd: in use\n", FTDM_BOOST_SYNTAX); + sigmod_ss7box_isup_exec_cmd(stream, (char*) "ckt_report.sh inuse"); + } else if (!strcasecmp(argv[1], "reset")) { + stream->write_function(stream, "ss7box_isupd: in reset\n", FTDM_BOOST_SYNTAX); + sigmod_ss7box_isup_exec_cmd(stream, (char*) "ckt_report.sh reset"); + } else if (!strcasecmp(argv[1], "ready")) { + stream->write_function(stream, "ss7box_isupd: ready \n", FTDM_BOOST_SYNTAX); + sigmod_ss7box_isup_exec_cmd(stream, (char*) "ckt_report.sh free"); + } else { + stream->write_function(stream, "ss7box_isupd: list\n", FTDM_BOOST_SYNTAX); + sigmod_ss7box_isup_exec_cmd(stream, (char*) "ckt_report.sh"); + } + + goto done; +#endif +#endif + } else if (!strcasecmp(argv[0], "restart")) { + sangomabc_connection_t *pcon; + ftdm_sangoma_boost_data_t *sangoma_boost_data; + ftdm_span_t *span; + int err = ftdm_span_find_by_name(argv[1], &span); + if (FTDM_SUCCESS != err) { + stream->write_function(stream, "-ERR failed to find span by name %s\n",argv[1]); + goto done; + } + + sangoma_boost_data = span->signal_data; + pcon = &sangoma_boost_data->pcon; + + /* No need to set any span flags because + our RESTART will generate a RESTART from the sig daemon */ + sangomabc_exec_commandp(pcon, + 0, + 0, + -1, + SIGBOOST_EVENT_SYSTEM_RESTART, + 0); + + goto done; + } else { boost_sigmod_interface_t *sigmod_iface = NULL; sigmod_iface = hashtable_search(g_boost_modules_hash, argv[0]); @@ -1829,7 +2035,7 @@ done: */ static FIO_IO_LOAD_FUNCTION(ftdm_sangoma_boost_io_init) { - assert(fio != NULL); + ftdm_assert(fio != NULL, "fio is NULL"); memset(&ftdm_sangoma_boost_interface, 0, sizeof(ftdm_sangoma_boost_interface)); ftdm_sangoma_boost_interface.name = "boost"; @@ -2212,6 +2418,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span) ftdm_dso_lib_t lib = NULL; char path[255] = ""; char *err = NULL; + int j = 0; unsigned paramindex = 0; ftdm_status_t rc = FTDM_SUCCESS; @@ -2306,6 +2513,14 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span) ftdm_set_string(sangoma_boost_data->mcon.cfg.remote_ip, remote_ip); sangoma_boost_data->mcon.cfg.remote_port = remote_port; } + + for (j = 1; j <= span->chan_count; j++) { + span->channels[j]->call_data = ftdm_calloc(1,sizeof(sangoma_boost_call_t)); + if (!span->channels[j]->call_data) { + FAIL_CONFIG_RETURN(FTDM_FAIL); + } + } + span->signal_cb = sig_cb; span->start = ftdm_sangoma_boost_start; span->stop = ftdm_sangoma_boost_stop; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c index c5cb97119f..b2a38b198d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c @@ -77,7 +77,7 @@ static void sangomabc_print_event_call(sangomabc_connection_t *mcon, sangomabc_e if (event->event_id == SIGBOOST_EVENT_HEARTBEAT) return; - ftdm_log(file, func, line, FTDM_LOG_LEVEL_DEBUG, "%s EVENT (%s): %s:(%X) [w%dg%d] CSid=%i Seq=%i Cn=[%s] Cd=[%s] Ci=[%s] Rdnis=[%s]\n", + ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "%s EVENT (%s): %s:(%X) [w%dg%d] CSid=%i Seq=%i Cn=[%s] Cd=[%s] Ci=[%s] Rdnis=[%s]\n", dir ? "TX":"RX", priority ? "P":"N", sangomabc_event_id_name(event->event_id), @@ -96,7 +96,7 @@ static void sangomabc_print_event_short(sangomabc_connection_t *mcon, sangomabc_ { if (event->event_id == SIGBOOST_EVENT_HEARTBEAT) return; - ftdm_log(file, func, line, FTDM_LOG_LEVEL_DEBUG, "%s EVENT (%s): %s:(%X) [s%dc%d] Rc=%i CSid=%i Seq=%i \n", + ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "%s EVENT (%s): %s:(%X) [s%dc%d] Rc=%i CSid=%i Seq=%i \n", dir ? "TX":"RX", priority ? "P":"N", sangomabc_event_id_name(event->event_id), diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sigboost.h b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sigboost.h index 05ca52a487..7975dc5b93 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sigboost.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sigboost.h @@ -51,6 +51,24 @@ enum e_sigboost_event_id_values SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE = 0x8c, /*140*/ SIGBOOST_EVENT_DIGIT_IN = 0x8d, /*141*/ }; + +#define BOOST_DECODE_EVENT_ID(id) \ + (id==SIGBOOST_EVENT_CALL_START)?"SIGBOOST_EVENT_CALL_START": \ + (id==SIGBOOST_EVENT_CALL_START_ACK)?"SIGBOOST_EVENT_CALL_START_ACK": \ + (id==SIGBOOST_EVENT_CALL_START_NACK)?"SIGBOOST_EVENT_CALL_START_NACK": \ + (id==SIGBOOST_EVENT_CALL_ANSWERED)?"SIGBOOST_EVENT_CALL_ANSWERED": \ + (id==SIGBOOST_EVENT_CALL_STOPPED)?"SIGBOOST_EVENT_CALL_STOPPED": \ + (id==SIGBOOST_EVENT_CALL_STOPPED_ACK)?"SIGBOOST_EVENT_CALL_STOPPED_ACK": \ + (id==SIGBOOST_EVENT_SYSTEM_RESTART)?"SIGBOOST_EVENT_SYSTEM_RESTART": \ + (id==SIGBOOST_EVENT_SYSTEM_RESTART_ACK)?"SIGBOOST_EVENT_SYSTEM_RESTART_ACK": \ + (id==SIGBOOST_EVENT_CALL_RELEASED)?"SIGBOOST_EVENT_CALL_RELEASED": \ + (id==SIGBOOST_EVENT_CALL_PROGRESS)?"SIGBOOST_EVENT_CALL_PROGRESS": \ + (id==SIGBOOST_EVENT_HEARTBEAT)?"SIGBOOST_EVENT_HEARTBEAT": \ + (id==SIGBOOST_EVENT_INSERT_CHECK_LOOP)?"SIGBOOST_EVENT_INSERT_CHECK_LOOP": \ + (id==SIGBOOST_EVENT_REMOVE_CHECK_LOOP)?"SIGBOOST_EVENT_REMOVE_CHECK_LOOP": \ + (id==SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE)?"SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE": \ + (id==SIGBOOST_EVENT_DIGIT_IN)?"SIGBOOST_EVENT_DIGIT_IN": "Unknown" + enum e_sigboost_release_cause_values { SIGBOOST_RELEASE_CAUSE_UNDEFINED = 0, diff --git a/libs/openzap/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c b/libs/openzap/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c index 5e0e32d9ee..995d943552 100644 --- a/libs/openzap/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c +++ b/libs/openzap/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c @@ -32,11 +32,14 @@ */ #include "openzap.h" -#include "sangoma_boost_client.h" +#include "sangoma_boost_client.h" #include "zap_sangoma_boost.h" #ifdef HAVE_SYS_SELECT_H #include #endif +#ifndef __WINDOWS__ +#include +#endif #define MAX_TRUNK_GROUPS 64 static time_t congestion_timeouts[MAX_TRUNK_GROUPS]; @@ -484,7 +487,31 @@ static void handle_call_start_ack(sangomabc_connection_t *mcon, sangomabc_short_ OUTBOUND_REQUESTS[event->call_setup_id].status = BST_READY; return; } - } + } else { + if ((zchan = find_zchan(OUTBOUND_REQUESTS[event->call_setup_id].span, (sangomabc_short_event_t*)event, 1))) { + int r; + + /* NC: If we get CALL START ACK and channel is in active state + then we are completely out of sync with the other end. + Treat CALL START ACK as CALL STOP and hangup the current call. + */ + + if (zchan->state == ZAP_CHANNEL_STATE_UP || + zchan->state == ZAP_CHANNEL_STATE_PROGRESS_MEDIA || + zchan->state == ZAP_CHANNEL_STATE_PROGRESS) { + zap_log(ZAP_LOG_CRIT, "ZCHAN STATE UP/PROG/PROG_MEDIA -> Changed to HANGUP %d:%d\n", event->span+1,event->chan+1); + zap_set_state_r(zchan, ZAP_CHANNEL_STATE_HANGUP, 0, r); + + } else if (zap_test_sflag(zchan, SFLAG_HANGUP)) { + /* Do nothing because outgoing STOP will generaate a stop ack */ + + } else { + zap_log(ZAP_LOG_CRIT, "ZCHAN STATE INVALID %s on IN CALL ACK %d:%d\n", zap_channel_state2str(zchan->state),event->span+1,event->chan+1); + + } + zchan=NULL; + } + } //printf("WTF BAD ACK CSid=%d span=%d chan=%d\n", event->call_setup_id, event->span+1,event->chan+1); if ((zchan = find_zchan(OUTBOUND_REQUESTS[event->call_setup_id].span, event, 1))) { @@ -640,7 +667,14 @@ static void handle_call_stop(zap_span_t *span, sangomabc_connection_t *mcon, san zap_mutex_lock(zchan->mutex); - if (zap_test_sflag(zchan, SFLAG_HANGUP)) { + if (zap_test_sflag(zchan, SFLAG_HANGUP) || zchan->state == ZAP_CHANNEL_STATE_DOWN) { + + /* NC: Checking for state DOWN because ss7box can + send CALL_STOP twice in a row. If we do not check for + STATE_DOWN we will set the state back to termnating + and block the channel forever + */ + /* racing condition where both sides initiated a hangup * Do not change current state as channel is already clearing * itself through local initiated hangup */ @@ -697,7 +731,14 @@ static void handle_call_answer(zap_span_t *span, sangomabc_connection_t *mcon, s if ((zchan = find_zchan(span, event, 1))) { zap_mutex_lock(zchan->mutex); - if (zchan->state == ZAP_CHANNEL_STATE_HOLD) { + if (zap_test_sflag(zchan, SFLAG_HANGUP) || + zchan->state == ZAP_CHANNEL_STATE_DOWN || + zchan->state == ZAP_CHANNEL_STATE_TERMINATING) { + /* NC: Do nothing here because we are in process + of stopping the call. So ignore the ANSWER. */ + zap_log(ZAP_LOG_CRIT, "ANSWER BUT CALL IS HANGUP %d:%d\n", event->span+1,event->chan+1); + + } else if (zchan->state == ZAP_CHANNEL_STATE_HOLD) { zchan->init_state = ZAP_CHANNEL_STATE_UP; } else { int r = 0; @@ -731,6 +772,12 @@ static void handle_call_start(zap_span_t *span, sangomabc_connection_t *mcon, sa if (!(zchan = find_zchan(span, (sangomabc_short_event_t*)event, 0))) { if ((zchan = find_zchan(span, (sangomabc_short_event_t*)event, 1))) { int r; + + /* NC: If we get CALL START and channel is in active state + then we are completely out of sync with the other end. + Treat CALL START as CALL STOP and hangup the current call. + */ + if (zchan->state == ZAP_CHANNEL_STATE_UP) { zap_log(ZAP_LOG_CRIT, "ZCHAN STATE UP -> Changed to TERMINATING %d:%d\n", event->span+1,event->chan+1); zap_set_state_r(zchan, ZAP_CHANNEL_STATE_TERMINATING, 0, r); @@ -1380,6 +1427,65 @@ static void *zap_sangoma_events_run(zap_thread_t *me, void *obj) return NULL; } + +#ifndef __WINDOWS__ +static int waitfor_2sockets(int fda, int fdb, char *a, char *b, int timeout) +{ + struct pollfd pfds[2]; + int res = 0; + int errflags = (POLLERR | POLLHUP | POLLNVAL); + + if (fda < 0 || fdb < 0) { + return -1; + } + + +waitfor_2sockets_tryagain: + + *a=0; + *b=0; + + + memset(pfds, 0, sizeof(pfds)); + + pfds[0].fd = fda; + pfds[1].fd = fdb; + pfds[0].events = POLLIN | errflags; + pfds[1].events = POLLIN | errflags; + + res = poll(pfds, 2, timeout); + + if (res > 0) { + res = 1; + if ((pfds[0].revents & errflags) || (pfds[1].revents & errflags)) { + res = -1; + } else { + if ((pfds[0].revents & POLLIN)) { + *a=1; + res++; + } + if ((pfds[1].revents & POLLIN)) { + *b=1; + res++; + } + } + + if (res == 1) { + /* No event found what to do */ + res=-1; + } + } else if (res < 0) { + + if (errno == EINTR || errno == EAGAIN) { + goto waitfor_2sockets_tryagain; + } + + } + + return res; +} +#endif + /** * \brief Main thread function for sangoma boost span (monitor) * \param me Current thread @@ -1391,7 +1497,13 @@ static void *zap_sangoma_boost_run(zap_thread_t *me, void *obj) zap_sangoma_boost_data_t *sangoma_boost_data = span->signal_data; sangomabc_connection_t *mcon, *pcon; uint32_t ms = 10; //, too_long = 20000; - + int max, activity, i; + sangomabc_event_t *event; + struct timeval tv; + fd_set rfds, efds; +#ifndef __WINDOWS__ + char a=0,b=0; +#endif sangoma_boost_data->pcon = sangoma_boost_data->mcon; @@ -1427,10 +1539,13 @@ static void *zap_sangoma_boost_run(zap_thread_t *me, void *obj) zap_set_flag(mcon, MSU_FLAG_DOWN); while (zap_test_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RUNNING)) { - fd_set rfds, efds; - struct timeval tv = { 0, ms * 1000 }; - int max, activity, i = 0; - sangomabc_event_t *event = NULL; + + tv.tv_sec = 0; + tv.tv_usec = ms* 1000; + max=0; + activity=0; + i=0; + event = NULL; if (!zap_running()) { sangomabc_exec_commandp(pcon, @@ -1451,7 +1566,8 @@ static void *zap_sangoma_boost_run(zap_thread_t *me, void *obj) FD_SET(pcon->socket, &efds); max = ((pcon->socket > mcon->socket) ? pcon->socket : mcon->socket) + 1; - + +#ifdef __WINDOWS__ if ((activity = select(max, &rfds, NULL, &efds, &tv)) < 0) { goto error; } @@ -1477,7 +1593,33 @@ static void *zap_sangoma_boost_run(zap_thread_t *me, void *obj) } } +#else + a=0; + b=0; + i=0; + tv.tv_sec=0; + activity = waitfor_2sockets(pcon->socket,mcon->socket,&a,&b,ms); + if (activity) { + if (a) { + while ((event = sangomabc_connection_readp(pcon, i))) { + parse_sangoma_event(span, pcon, (sangomabc_short_event_t*)event); + i++; + } + } + i=0; + + if (b) { + if ((event = sangomabc_connection_read(mcon, i))) { + parse_sangoma_event(span, mcon, (sangomabc_short_event_t*)event); + i++; + } + } + } else if (activity < 0) { + goto error; + } + +#endif pcon->hb_elapsed += ms; diff --git a/libs/openzap/src/ozmod/ozmod_sangoma_boost/sigboost.h b/libs/openzap/src/ozmod/ozmod_sangoma_boost/sigboost.h index 1281069536..7522ea7db4 100644 --- a/libs/openzap/src/ozmod/ozmod_sangoma_boost/sigboost.h +++ b/libs/openzap/src/ozmod/ozmod_sangoma_boost/sigboost.h @@ -57,6 +57,24 @@ enum e_sigboost_event_id_values SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE = 0x8c, /*140*/ SIGBOOST_EVENT_DIGIT_IN = 0x8d, /*141*/ }; + +#define BOOST_DECODE_EVENT_ID(id) \ + (id==SIGBOOST_EVENT_CALL_START)?"SIGBOOST_EVENT_CALL_START": \ + (id==SIGBOOST_EVENT_CALL_START_ACK)?"SIGBOOST_EVENT_CALL_START_ACK": \ + (id==SIGBOOST_EVENT_CALL_START_NACK)?"SIGBOOST_EVENT_CALL_START_NACK": \ + (id==SIGBOOST_EVENT_CALL_ANSWERED)?"SIGBOOST_EVENT_CALL_ANSWERED": \ + (id==SIGBOOST_EVENT_CALL_STOPPED)?"SIGBOOST_EVENT_CALL_STOPPED": \ + (id==SIGBOOST_EVENT_CALL_STOPPED_ACK)?"SIGBOOST_EVENT_CALL_STOPPED_ACK": \ + (id==SIGBOOST_EVENT_SYSTEM_RESTART)?"SIGBOOST_EVENT_SYSTEM_RESTART": \ + (id==SIGBOOST_EVENT_SYSTEM_RESTART_ACK)?"SIGBOOST_EVENT_SYSTEM_RESTART_ACK": \ + (id==SIGBOOST_EVENT_CALL_RELEASED)?"SIGBOOST_EVENT_CALL_RELEASED": \ + (id==SIGBOOST_EVENT_CALL_PROGRESS)?"SIGBOOST_EVENT_CALL_PROGRESS": \ + (id==SIGBOOST_EVENT_HEARTBEAT)?"SIGBOOST_EVENT_HEARTBEAT": \ + (id==SIGBOOST_EVENT_INSERT_CHECK_LOOP)?"SIGBOOST_EVENT_INSERT_CHECK_LOOP": \ + (id==SIGBOOST_EVENT_REMOVE_CHECK_LOOP)?"SIGBOOST_EVENT_REMOVE_CHECK_LOOP": \ + (id==SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE)?"SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE": \ + (id==SIGBOOST_EVENT_DIGIT_IN)?"SIGBOOST_EVENT_DIGIT_IN": "Unknown" + enum e_sigboost_release_cause_values { SIGBOOST_RELEASE_CAUSE_UNDEFINED = 0,