From 2dc5b322dd7cdd7a08c351805769a0a3862b9bbd Mon Sep 17 00:00:00 2001 From: root Date: Fri, 27 Jul 2012 21:31:24 -0400 Subject: [PATCH] Added event system for TDM termination alarms --- libs/freetdm/mod_freetdm/mod_freetdm.c | 6 +- libs/freetdm/mod_freetdm/tdm.c | 205 ++++++++++++++++-- libs/freetdm/src/ftdm_io.c | 15 +- libs/freetdm/src/include/freetdm.h | 12 +- .../mod_media_gateway/media_gateway.c | 61 +++--- .../mod_media_gateway/media_gateway_xml.c | 2 + .../mod_media_gateway/mod_media_gateway.c | 32 ++- .../mod_media_gateway/mod_media_gateway.h | 3 +- 8 files changed, 275 insertions(+), 61 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 34fb3f469a..a746c1877f 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -2097,7 +2097,7 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session static FIO_SIGNAL_CB_FUNCTION(on_common_signal) { uint32_t chanid, spanid; - switch_event_t *event = NULL; + switch_event_t *event = NULL; ftdm_alarm_flag_t alarmbits = FTDM_ALARM_NONE; chanid = ftdm_channel_get_id(sigmsg->channel); @@ -2200,9 +2200,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_common_signal) break; } - if (event) { - - + if (event) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", ftdm_channel_get_span_name(sigmsg->channel)); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-number", "%d", ftdm_channel_get_span_id(sigmsg->channel)); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", ftdm_channel_get_id(sigmsg->channel)); diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index ab061a3812..c5850e6f51 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -68,6 +68,9 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg); static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf); + +static ftdm_status_t ctdm_span_prepare(ftdm_span_t *span); + switch_state_handler_table_t ctdm_state_handlers = { .on_init = channel_on_init, .on_destroy = channel_on_destroy @@ -81,6 +84,115 @@ switch_io_routines_t ctdm_io_routines = { .receive_message = channel_receive_message }; +static void ctdm_report_alarms(ftdm_channel_t *channel) +{ + switch_event_t *event = NULL; + ftdm_alarm_flag_t alarmflag = 0; + + if (switch_event_create(&event, SWITCH_EVENT_TRAP) != SWITCH_STATUS_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "failed to create alarms events\n"); + return; + } + + if (ftdm_channel_get_alarms(channel, &alarmflag) != FTDM_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to retrieve alarms %s:%d\n", ftdm_channel_get_span_name(channel), ftdm_channel_get_id(channel)); + return; + } + + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", ftdm_channel_get_span_name(channel)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-number", "%d", ftdm_channel_get_span_id(channel)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", ftdm_channel_get_id(channel)); + + if (alarmflag) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-clear"); + } else { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-trap"); + } + + if (alarmflag & FTDM_ALARM_RED) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "red"); + } + if (alarmflag & FTDM_ALARM_YELLOW) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "yellow"); + } + if (alarmflag & FTDM_ALARM_RAI) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "rai"); + } + if (alarmflag & FTDM_ALARM_BLUE) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "blue"); + } + if (alarmflag & FTDM_ALARM_AIS) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "ais"); + } + if (alarmflag & FTDM_ALARM_GENERAL) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "general"); + } + + switch_event_fire(&event); + return; +} + + + +static void ctdm_event_handler(switch_event_t *event) +{ + ftdm_status_t status = FTDM_FAIL; + switch(event->event_id) { + case SWITCH_EVENT_TRAP: + { + ftdm_span_t *span = NULL; + ftdm_channel_t *channel = NULL; + const char *span_name = NULL; + const char *chan_number = NULL; + uint32_t chan_id = 0; + const char *cond = switch_event_get_header(event, "condition"); + + if (zstr(cond)) { + return; + } + + span_name = switch_event_get_header(event, "span-name"); + chan_number = switch_event_get_header(event, "chan-number"); + + if (ftdm_span_find_by_name(span_name, &span) != FTDM_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find span [%s]\n", span_name); + return; + } + + if (!strcmp(cond, "mg-tdm-prepare")) { + status = ctdm_span_prepare(span); + if (status == FTDM_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Span %s prepared successfully\n", span_name); + } else if (status != FTDM_EINVAL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to prepare span %s.\n", span_name); + } + } else if (!strcmp(cond, "mg-tdm-check")) { + if (zstr(chan_number)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No channel number specified\n"); + return; + } + chan_id = atoi(chan_number); + if (!chan_id) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid channel number:%s\n", chan_number); + return; + } + + channel = ftdm_span_get_channel(span, chan_id); + if (!channel) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find channel\n"); + return; + } + + ctdm_report_alarms(channel); + } + } + break; + default: + break; + } + return; +} + void ctdm_init(switch_loadable_module_interface_t *module_interface) { switch_endpoint_interface_t *endpoint_interface; @@ -90,7 +202,82 @@ void ctdm_init(switch_loadable_module_interface_t *module_interface) endpoint_interface->io_routines = &ctdm_io_routines; endpoint_interface->state_handler = &ctdm_state_handlers; ctdm.endpoint_interface = endpoint_interface; - + + switch_event_bind("mod_freetdm", SWITCH_EVENT_TRAP, SWITCH_EVENT_SUBCLASS_ANY, ctdm_event_handler, NULL); +} + +static FIO_SIGNAL_CB_FUNCTION(on_signal_cb) +{ + uint32_t chanid, spanid; + switch_event_t *event = NULL; + ftdm_alarm_flag_t alarmbits = FTDM_ALARM_NONE; + + chanid = ftdm_channel_get_id(sigmsg->channel); + spanid = ftdm_channel_get_span_id(sigmsg->channel); + + switch(sigmsg->event_id) { + case FTDM_SIGEVENT_ALARM_CLEAR: + case FTDM_SIGEVENT_ALARM_TRAP: + { + if (ftdm_channel_get_alarms(sigmsg->channel, &alarmbits) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "failed to retrieve alarms\n"); + return FTDM_FAIL; + } + + if (switch_event_create(&event, SWITCH_EVENT_TRAP) != SWITCH_STATUS_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "failed to create alarms events\n"); + return FTDM_FAIL; + } + if (sigmsg->event_id == FTDM_SIGEVENT_ALARM_CLEAR) { + ftdm_log(FTDM_LOG_NOTICE, "Alarm cleared on channel %d:%d\n", spanid, chanid); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-clear"); + } else { + ftdm_log(FTDM_LOG_NOTICE, "Alarm raised on channel %d:%d\n", spanid, chanid); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-trap"); + } + } + break; + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unhandled event %d\n", sigmsg->event_id); + break; + } + + if (event) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", ftdm_channel_get_span_name(sigmsg->channel)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-number", "%d", ftdm_channel_get_span_id(sigmsg->channel)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", ftdm_channel_get_id(sigmsg->channel)); + + if (alarmbits & FTDM_ALARM_RED) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "red"); + } + if (alarmbits & FTDM_ALARM_YELLOW) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "yellow"); + } + if (alarmbits & FTDM_ALARM_RAI) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "rai"); + } + if (alarmbits & FTDM_ALARM_BLUE) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "blue"); + } + if (alarmbits & FTDM_ALARM_AIS) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "ais"); + } + if (alarmbits & FTDM_ALARM_GENERAL) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "general"); + } + + switch_event_fire(&event); + } + return FTDM_SUCCESS; +} + +static ftdm_status_t ctdm_span_prepare(ftdm_span_t *span) +{ + if (ftdm_span_register_signal_cb(span, on_signal_cb) != FTDM_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register signal CB\n"); + return FTDM_FAIL; + } + return ftdm_span_start(span); } static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, @@ -111,10 +298,8 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi const char *dname; ftdm_codec_t codec; uint32_t interval; - /*ftdm_status_t fstatus;*/ - const char *ftdm_start_only = switch_event_get_header(var_event, "ftdm_start_only"); ctdm_private_t *tech_pvt = NULL; - + if (zstr(szchanid) || zstr(span_name)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Both ["kSPAN_ID"] and ["kCHAN_ID"] have to be set.\n"); goto fail; @@ -129,18 +314,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi goto fail; } -#if 0 - if ((fstatus = ftdm_span_start(span)) != FTDM_SUCCESS && fstatus != FTDM_EINVAL) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't start span %s.\n", span_name); - goto fail; - } -#endif - - if (!zstr(ftdm_start_only) && switch_true(ftdm_start_only)) { - goto fail; - } - - if (!(*new_session = switch_core_session_request(ctdm.endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, 0, pool))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't request session.\n"); goto fail; diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 758827c9ed..4e110df659 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -5653,6 +5653,12 @@ static void *ftdm_span_service_events(ftdm_thread_t *me, void *obj) return NULL; } +FT_DECLARE(ftdm_status_t) ftdm_span_register_signal_cb(ftdm_span_t *span, fio_signal_cb_t sig_cb) +{ + span->signal_cb = sig_cb; + return FTDM_SUCCESS; +} + FT_DECLARE(ftdm_status_t) ftdm_span_start(ftdm_span_t *span) { ftdm_status_t status = FTDM_FAIL; @@ -5670,7 +5676,8 @@ FT_DECLARE(ftdm_status_t) ftdm_span_start(ftdm_span_t *span) goto done; } - status = ftdm_report_initial_channels_alarms(span); + //ftdm_report_initial_channels_alarms(span); + ftdm_set_flag_locked(span, FTDM_SPAN_STARTED); goto done; } @@ -5872,8 +5879,10 @@ FT_DECLARE(ftdm_status_t) ftdm_group_create(ftdm_group_t **group, const char *na static ftdm_status_t ftdm_span_trigger_signal(const ftdm_span_t *span, ftdm_sigmsg_t *sigmsg) { - ftdm_status_t status = span->signal_cb(sigmsg); - return status; + if (!span->signal_cb) { + return FTDM_FAIL; + } + return span->signal_cb(sigmsg); } static ftdm_status_t ftdm_span_queue_signal(const ftdm_span_t *span, ftdm_sigmsg_t *sigmsg) diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index f7de8519b7..e041e1f0e7 100755 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -1611,6 +1611,17 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span(ftdm_span_t *span, const char *typ */ FT_DECLARE(ftdm_status_t) ftdm_configure_span_signaling(ftdm_span_t *span, const char *type, fio_signal_cb_t sig_cb, ftdm_conf_parameter_t *parameters); +/*! + * \brief Register callback to listen for incoming events + * \note This function should only be used when there is no signalling module + * \param span The span to register to + * \param sig_cb The callback that the signaling stack will use to notify about events + * + * \retval FTDM_SUCCESS success + * \retval FTDM_FAIL failure + */ +FT_DECLARE(ftdm_status_t) ftdm_span_register_signal_cb(ftdm_span_t *span, fio_signal_cb_t sig_cb); + /*! * \brief Start the span signaling (must call ftdm_configure_span_signaling first) * @@ -1626,7 +1637,6 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_signaling(ftdm_span_t *span, const */ FT_DECLARE(ftdm_status_t) ftdm_span_start(ftdm_span_t *span); - /*! * \brief Stop the span signaling (must call ftdm_span_start first) * \note certain signalings (boost signaling) does not support granular span start/stop diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index ee5abe7d2f..9056ee1bdc 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -155,47 +155,38 @@ done: return SWITCH_STATUS_SUCCESS; } - -/* - * Originate a channel so the target technology gets to run initialization code - */ -switch_status_t megaco_prepare_termination(mg_termination_t *term) +switch_status_t megaco_prepare_tdm_termination(mg_termination_t *term) { - switch_event_t *var_event = NULL; - switch_core_session_t *session = NULL; - switch_status_t status = SWITCH_STATUS_SUCCESS; - char dialstring[100]; - switch_call_cause_t cause; - switch_channel_t *channel; - switch_event_create(&var_event, SWITCH_EVENT_CLONE); - - if (term->type == MG_TERM_RTP) { - } else if (term->type == MG_TERM_TDM) { - switch_snprintf(dialstring, sizeof dialstring, "tdm/%s", term->name); + switch_event_t *event = NULL; + if (switch_event_create(&event, SWITCH_EVENT_TRAP) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to create NOTIFY event\n"); + return SWITCH_STATUS_FALSE; + } - switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "ftdm_start_only", "true"); - switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, kSPAN_NAME, term->u.tdm.span_name); - switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, kCHAN_ID, "%d", term->u.tdm.channel); - } - - /* Set common variables on the channel */ - switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, SWITCH_PARK_AFTER_BRIDGE_VARIABLE, "true"); - if (switch_ivr_originate(NULL, &session, &cause, dialstring, 0, NULL, NULL, NULL, NULL, var_event, 0, NULL) != SWITCH_STATUS_SUCCESS) { - status = SWITCH_STATUS_FALSE; - goto done; - } - channel = switch_core_session_get_channel(session); - switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); - -done: - if (session) { - switch_core_session_rwunlock(session); - } - switch_event_destroy(&var_event); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", term->u.tdm.span_name); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", term->u.tdm.channel); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "mg-tdm-prepare"); + switch_event_fire(&event); return SWITCH_STATUS_SUCCESS; } +/* @Kapil Call this function once H.248 link is up */ +switch_status_t megaco_check_tdm_termination(mg_termination_t *term) +{ + switch_event_t *event = NULL; + if (switch_event_create(&event, SWITCH_EVENT_TRAP) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to create NOTIFY event\n"); + return SWITCH_STATUS_FALSE; + } + + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", term->u.tdm.span_name); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", term->u.tdm.channel); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "mg-tdm-check"); + + switch_event_fire(&event); + return SWITCH_STATUS_SUCCESS; +} mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const char *prefix) { diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index 011c36ce56..1b8173aa1e 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -111,6 +111,8 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) profile->physical_terminations = term; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Mapped termination [%s] to freetdm span: %s chan: %d\n", term->name, term->u.tdm.span_name, term->u.tdm.channel); + + megaco_prepare_tdm_termination(term); } } } diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index de315d7ae9..00f5e9760f 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -56,6 +56,35 @@ static switch_status_t list_profiles(const char *line, const char *cursor, switc return status; } +static void mg_event_handler(switch_event_t *event) +{ + switch(event->event_id) { + case SWITCH_EVENT_TRAP: + { + const char *span_name = NULL; + const char *chan_number = NULL; + const char *cond = NULL; + + cond = switch_event_get_header(event, "condition"); + if (zstr(cond)) { + return; + } + + span_name = switch_event_get_header(event, "span-name"); + chan_number = switch_event_get_header(event, "chan-number"); + + if (!strcmp(cond, "ftdm-alarm-trap")) { + /* @KAPIL: TDM is in alarm, notify MGC */ + } else if (!strcmp(cond, "ftdm-alarm-clear")) { + /* @KAPIL: TDM alarm cleared, notify MGC */ + } + } + break; + default: + break; + } +} + SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load) { switch_api_interface_t *api_interface; @@ -82,7 +111,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load) switch_console_set_complete("add mg logging ::mg::list_profiles disable"); switch_console_add_complete_func("::mg::list_profiles", list_profiles); - /* Initialize MEGACO Stack */ sng_event.mg.sng_mgco_txn_ind = handle_mgco_txn_ind; sng_event.mg.sng_mgco_cmd_ind = handle_mgco_cmd_ind; @@ -96,6 +124,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load) /* Log */ sng_event.sm.sng_log = handle_sng_log; + switch_event_bind("mod_media_gateway", SWITCH_EVENT_TRAP, SWITCH_EVENT_SUBCLASS_ANY, mg_event_handler, NULL); + /* initualize MEGACO stack */ return sng_mgco_init(&sng_event); } diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index 504f147d76..86acb28861 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -256,7 +256,8 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre switch_status_t megaco_context_add_termination(mg_context_t *ctx, mg_termination_t *term); switch_status_t megaco_context_is_term_present(mg_context_t *ctx, mg_termination_t *term); - +switch_status_t megaco_prepare_tdm_termination(mg_termination_t *term); +switch_status_t megaco_check_tdm_termination(mg_termination_t *term); #endif /* MOD_MEGACO_H */