freetdm: General fixes for alarm handling and added MFCR2 suspend support

- Clean up ftdm_channel_set_sig_status locking and sanity checks
         - Set FTDM_CHANNEL_SUSPENDED when delivering FTDM_SIGEVENT_SIGSTATUS changed to SUSPENDED
         - Clear FTDM_CHANNEL_SUSPENDED when delivering FTDM_SIGEVENT_SIGSTATUS changed to UP
         - Update ftmod_r2 to honor local suspend requests when returning from alarm state
This commit is contained in:
Moises Silva 2011-01-17 15:42:36 -05:00
parent a020724030
commit 6734fe711b
3 changed files with 81 additions and 34 deletions

View File

@ -2529,26 +2529,34 @@ done:
return status; return status;
} }
FT_DECLARE(ftdm_status_t) ftdm_channel_set_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t sigstatus) FT_DECLARE(ftdm_status_t) ftdm_channel_set_sig_status(ftdm_channel_t *fchan, ftdm_signaling_status_t sigstatus)
{ {
ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "Null channel\n"); ftdm_status_t res;
ftdm_assert_return(ftdmchan->span != NULL, FTDM_FAIL, "Null span\n");
ftdm_assert_return(fchan != NULL, FTDM_FAIL, "Null channel\n");
ftdm_assert_return(fchan->span != NULL, FTDM_FAIL, "Null span\n");
ftdm_assert_return(fchan->span->set_channel_sig_status != NULL, FTDM_ENOSYS, "Not implemented\n");
ftdm_channel_lock(fchan);
if (ftdm_test_flag(fchan, FTDM_CHANNEL_IN_ALARM)) {
ftdm_log_chan_msg(fchan, FTDM_LOG_WARNING, "You can not set the signaling status of an alarmed channel\n");
res = FTDM_EINVAL;
goto done;
}
if (sigstatus == FTDM_SIG_STATE_DOWN) { if (sigstatus == FTDM_SIG_STATE_DOWN) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "The user is not allowed to set the signaling status to DOWN, valid states are UP or SUSPENDED\n"); ftdm_log_chan_msg(fchan, FTDM_LOG_WARNING, "You can not set the signaling status to DOWN, valid states are UP or SUSPENDED\n");
return FTDM_FAIL; res = FTDM_EINVAL;
goto done;
} }
if (ftdmchan->span->set_channel_sig_status) { res = fchan->span->set_channel_sig_status(fchan, sigstatus);
ftdm_status_t res; done:
ftdm_channel_lock(ftdmchan);
res = ftdmchan->span->set_channel_sig_status(ftdmchan, sigstatus); ftdm_channel_unlock(fchan);
ftdm_channel_unlock(ftdmchan);
return res; return res;
} else {
ftdm_log(FTDM_LOG_ERROR, "set_channel_sig_status method not implemented!\n");
return FTDM_FAIL;
}
} }
FT_DECLARE(ftdm_status_t) ftdm_channel_get_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t *sigstatus) FT_DECLARE(ftdm_status_t) ftdm_channel_get_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t *sigstatus)
@ -5505,8 +5513,14 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t
{ {
if (sigmsg->ev_data.sigstatus.status == FTDM_SIG_STATE_UP) { if (sigmsg->ev_data.sigstatus.status == FTDM_SIG_STATE_UP) {
ftdm_set_flag(sigmsg->channel, FTDM_CHANNEL_SIG_UP); ftdm_set_flag(sigmsg->channel, FTDM_CHANNEL_SIG_UP);
ftdm_clear_flag(sigmsg->channel, FTDM_CHANNEL_SUSPENDED);
} else { } else {
ftdm_clear_flag(sigmsg->channel, FTDM_CHANNEL_SIG_UP); ftdm_clear_flag(sigmsg->channel, FTDM_CHANNEL_SIG_UP);
if (sigmsg->ev_data.sigstatus.status == FTDM_SIG_STATE_SUSPENDED) {
ftdm_set_flag(sigmsg->channel, FTDM_CHANNEL_SUSPENDED);
} else {
ftdm_clear_flag(sigmsg->channel, FTDM_CHANNEL_SUSPENDED);
}
} }
} }
break; break;

View File

@ -70,6 +70,7 @@ typedef struct ftdm_r2_call_t {
int answer_pending:1; int answer_pending:1;
int disconnect_rcvd:1; int disconnect_rcvd:1;
int protocol_error:1; int protocol_error:1;
int localsuspend_on_alarm:1;
ftdm_size_t dnis_index; ftdm_size_t dnis_index;
ftdm_size_t ani_index; ftdm_size_t ani_index;
char logname[255]; char logname[255];
@ -499,8 +500,16 @@ static ftdm_status_t ftdm_r2_stop(ftdm_span_t *span)
static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_channel_sig_status) static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_channel_sig_status)
{ {
openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan;
openr2_cas_signal_t rxcas, txcas;
/* get the current rx and tx cas bits */
openr2_chan_get_cas(r2chan, &rxcas, &txcas);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) { if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) {
*status = FTDM_SIG_STATE_UP; *status = FTDM_SIG_STATE_UP;
} else if (rxcas == OR2_CAS_BLOCK || txcas == OR2_CAS_BLOCK) {
*status = FTDM_SIG_STATE_SUSPENDED;
} else { } else {
*status = FTDM_SIG_STATE_DOWN; *status = FTDM_SIG_STATE_DOWN;
} }
@ -561,6 +570,11 @@ static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_span_sig_status)
for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) { for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) {
ftdm_channel_t *fchan = ftdm_iterator_current(citer); ftdm_channel_t *fchan = ftdm_iterator_current(citer);
ftdm_channel_lock(fchan); ftdm_channel_lock(fchan);
if (ftdm_test_flag(fchan, FTDM_CHANNEL_IN_ALARM)) {
*status = FTDM_SIG_STATE_DOWN;
ftdm_channel_unlock(fchan);
break;
}
if (ftdm_test_flag(fchan, FTDM_CHANNEL_SIG_UP)) { if (ftdm_test_flag(fchan, FTDM_CHANNEL_SIG_UP)) {
*status = FTDM_SIG_STATE_UP; *status = FTDM_SIG_STATE_UP;
ftdm_channel_unlock(fchan); ftdm_channel_unlock(fchan);
@ -825,8 +839,11 @@ static void ftdm_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Alarm notification %d when in state %s (sigstatus = %d)\n", ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Alarm notification %d when in state %s (sigstatus = %d)\n",
alarm, ftdm_channel_state2str(fchan->state), ftdm_test_flag(fchan, FTDM_CHANNEL_SIG_UP) ? 1 : 0); alarm, ftdm_channel_state2str(fchan->state), ftdm_test_flag(fchan, FTDM_CHANNEL_SIG_UP) ? 1 : 0);
if (alarm && ftdm_test_flag(fchan, FTDM_CHANNEL_SIG_UP)) { if (alarm) {
ftdm_r2_set_chan_sig_status(fchan, FTDM_SIG_STATE_DOWN); R2CALL(fchan)->localsuspend_on_alarm = ftdm_test_flag(fchan, FTDM_CHANNEL_SUSPENDED) ? 1 : 0;
if (ftdm_test_flag(fchan, FTDM_CHANNEL_SIG_UP) || ftdm_test_flag(fchan, FTDM_CHANNEL_SUSPENDED)) {
ftdm_r2_set_chan_sig_status(fchan, FTDM_SIG_STATE_DOWN);
}
} }
} }
@ -881,18 +898,31 @@ static void ftdm_r2_on_line_blocked(openr2_chan_t *r2chan)
{ {
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Far end blocked in state %s\n", ftdm_channel_state2str(ftdmchan->state)); ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Far end blocked in state %s\n", ftdm_channel_state2str(ftdmchan->state));
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) { if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)
|| !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED)) {
ftdm_r2_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_SUSPENDED); ftdm_r2_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_SUSPENDED);
} }
} }
static void ftdm_r2_on_line_idle(openr2_chan_t *r2chan) static void ftdm_r2_on_line_idle(openr2_chan_t *r2chan)
{ {
openr2_cas_signal_t rxcas, txcas;
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
/* get the current rx and tx cas bits */
openr2_chan_get_cas(r2chan, &rxcas, &txcas);
ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Far end unblocked in state %s\n", ftdm_channel_state2str(ftdmchan->state)); ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Far end unblocked in state %s\n", ftdm_channel_state2str(ftdmchan->state));
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) { if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)
&& txcas == OR2_CAS_IDLE) {
/* if txcas is not idle, it means we're still blocked as far as the user is concerned, do not send SIGEVENT UP,
* it will be done when the user set the line to IDLE (if the remote is still also IDLE) */
ftdm_r2_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_UP); ftdm_r2_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_UP);
} else if (txcas == OR2_CAS_BLOCK && R2CALL(ftdmchan)->localsuspend_on_alarm) {
/* the user requested to block, we do not notify about state up until the user set the bits to IDLE, however
* if we're just getting back from alarmed condition, we notify about suspended again */
ftdm_r2_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_SUSPENDED);
} }
R2CALL(ftdmchan)->localsuspend_on_alarm = 0;
} }
static void ftdm_r2_write_log(openr2_log_level_t level, const char *file, const char *function, int line, const char *message) static void ftdm_r2_write_log(openr2_log_level_t level, const char *file, const char *function, int line, const char *message)
@ -2018,9 +2048,6 @@ static void __inline__ block_channel(ftdm_channel_t *fchan, ftdm_stream_handle_t
if (fchan->state != FTDM_CHANNEL_STATE_DOWN) { if (fchan->state != FTDM_CHANNEL_STATE_DOWN) {
stream->write_function(stream, "cannot block channel %d:%d because has a call in progress\n", stream->write_function(stream, "cannot block channel %d:%d because has a call in progress\n",
fchan->span_id, fchan->chan_id); fchan->span_id, fchan->chan_id);
} else if (ftdm_test_flag(fchan, FTDM_CHANNEL_SUSPENDED)) {
stream->write_function(stream, "cannot block channel %d:%d because is already blocked\n",
fchan->span_id, fchan->chan_id);
} else { } else {
if (!openr2_chan_set_blocked(r2chan)) { if (!openr2_chan_set_blocked(r2chan)) {
ftdm_set_flag(fchan, FTDM_CHANNEL_SUSPENDED); ftdm_set_flag(fchan, FTDM_CHANNEL_SUSPENDED);
@ -2038,17 +2065,12 @@ static void __inline__ unblock_channel(ftdm_channel_t *fchan, ftdm_stream_handle
{ {
openr2_chan_t *r2chan = R2CALL(fchan)->r2chan; openr2_chan_t *r2chan = R2CALL(fchan)->r2chan;
ftdm_mutex_lock(fchan->mutex); ftdm_mutex_lock(fchan->mutex);
if (ftdm_test_flag(fchan, FTDM_CHANNEL_SUSPENDED)) { if (!openr2_chan_set_idle(r2chan)) {
if (!openr2_chan_set_idle(r2chan)) { ftdm_clear_flag(fchan, FTDM_CHANNEL_SUSPENDED);
ftdm_clear_flag(fchan, FTDM_CHANNEL_SUSPENDED); stream->write_function(stream, "unblocked channel %d:%d\n",
stream->write_function(stream, "unblocked channel %d:%d\n", fchan->span_id, fchan->chan_id);
fchan->span_id, fchan->chan_id);
} else {
stream->write_function(stream, "failed to unblock channel %d:%d\n",
fchan->span_id, fchan->chan_id);
}
} else { } else {
stream->write_function(stream, "cannot unblock channel %d:%d because is not blocked\n", stream->write_function(stream, "failed to unblock channel %d:%d\n",
fchan->span_id, fchan->chan_id); fchan->span_id, fchan->chan_id);
} }
ftdm_mutex_unlock(fchan->mutex); ftdm_mutex_unlock(fchan->mutex);

View File

@ -1257,6 +1257,7 @@ static __inline__ ftdm_status_t wanpipe_channel_process_event(ftdm_channel_t *fc
switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_type) { switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_type) {
case WP_API_EVENT_LINK_STATUS: case WP_API_EVENT_LINK_STATUS:
{ {
#if 0
switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_link_status) { switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED: case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
*event_id = FTDM_OOB_ALARM_CLEAR; *event_id = FTDM_OOB_ALARM_CLEAR;
@ -1265,6 +1266,11 @@ static __inline__ ftdm_status_t wanpipe_channel_process_event(ftdm_channel_t *fc
*event_id = FTDM_OOB_ALARM_TRAP; *event_id = FTDM_OOB_ALARM_TRAP;
break; break;
}; };
#else
/* The WP_API_EVENT_ALARM event should be used to clear alarms */
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Ignoring wanpipe link status event\n", ftdm_oob_event2str(*event_id));
*event_id = FTDM_OOB_NOOP;
#endif
} }
break; break;
@ -1353,8 +1359,13 @@ static __inline__ ftdm_status_t wanpipe_channel_process_event(ftdm_channel_t *fc
break; break;
case WP_API_EVENT_ALARM: case WP_API_EVENT_ALARM:
{ {
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api->wp_tdm_cmd.event.wp_api_event_alarm); if (tdm_api->wp_tdm_cmd.event.wp_api_event_alarm) {
*event_id = FTDM_OOB_ALARM_TRAP; ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Got Wanpipe alarms %d\n", tdm_api->wp_tdm_cmd.event.wp_api_event_alarm);
*event_id = FTDM_OOB_ALARM_TRAP;
} else {
ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "Wanpipe alarms cleared\n");
*event_id = FTDM_OOB_ALARM_CLEAR;
}
} }
break; break;
case WP_API_EVENT_POLARITY_REVERSE: case WP_API_EVENT_POLARITY_REVERSE: