]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
freetdm: General fixes for alarm handling and added MFCR2 suspend support
authorMoises Silva <moy@sangoma.com>
Mon, 17 Jan 2011 20:42:36 +0000 (15:42 -0500)
committerMoises Silva <moy@sangoma.com>
Mon, 17 Jan 2011 20:42:36 +0000 (15:42 -0500)
         - 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

libs/freetdm/src/ftdm_io.c
libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c
libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c

index 6cd2a226c85059953208edf1c350613336bfdce3..6bfa37576cb96b9626d15b44cbcb4e601b81ab9e 100644 (file)
@@ -2529,26 +2529,34 @@ done:
        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_assert_return(ftdmchan->span != NULL, FTDM_FAIL, "Null span\n");
+       ftdm_status_t res;
 
-       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");
-               return FTDM_FAIL;
+       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 (ftdmchan->span->set_channel_sig_status) {
-               ftdm_status_t res;
-               ftdm_channel_lock(ftdmchan);
-               res = ftdmchan->span->set_channel_sig_status(ftdmchan, sigstatus);
-               ftdm_channel_unlock(ftdmchan);
-               return res;
-       } else {
-               ftdm_log(FTDM_LOG_ERROR, "set_channel_sig_status method not implemented!\n");
-               return FTDM_FAIL;
+       if (sigstatus == FTDM_SIG_STATE_DOWN) {
+               ftdm_log_chan_msg(fchan, FTDM_LOG_WARNING, "You can not set the signaling status to DOWN, valid states are UP or SUSPENDED\n");
+               res = FTDM_EINVAL;
+               goto done;
        }
+
+       res = fchan->span->set_channel_sig_status(fchan, sigstatus);
+done:
+
+       ftdm_channel_unlock(fchan);
+
+       return res;
 }
 
 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) {
                                ftdm_set_flag(sigmsg->channel, FTDM_CHANNEL_SIG_UP);
+                               ftdm_clear_flag(sigmsg->channel, FTDM_CHANNEL_SUSPENDED);
                        } else {
                                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;
index 2c9c42df128b3fc7d365b7f8067be0cbd30fa161..434417726babd128db2389f2e4ddb39aa2ed4e4f 100644 (file)
@@ -70,6 +70,7 @@ typedef struct ftdm_r2_call_t {
        int answer_pending:1;
        int disconnect_rcvd:1;
        int protocol_error:1;
+       int localsuspend_on_alarm:1;
        ftdm_size_t dnis_index;
        ftdm_size_t ani_index;
        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)
 {
+       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)) {
                *status = FTDM_SIG_STATE_UP;
+       } else if (rxcas ==  OR2_CAS_BLOCK || txcas == OR2_CAS_BLOCK) {
+               *status = FTDM_SIG_STATE_SUSPENDED;
        } else {
                *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)) {
                ftdm_channel_t *fchan = ftdm_iterator_current(citer);
                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)) {
                        *status = FTDM_SIG_STATE_UP;
                        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", 
                        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)) {
-               ftdm_r2_set_chan_sig_status(fchan, FTDM_SIG_STATE_DOWN);
+       if (alarm) {
+               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_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);
        }
 }
 
 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);
+       
+       /* 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));
-       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);
+       } 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)
@@ -2018,9 +2048,6 @@ static void __inline__ block_channel(ftdm_channel_t *fchan, ftdm_stream_handle_t
        if (fchan->state != FTDM_CHANNEL_STATE_DOWN) {
                stream->write_function(stream, "cannot block channel %d:%d because has a call in progress\n", 
                                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 {
                if (!openr2_chan_set_blocked(r2chan)) {
                        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;
        ftdm_mutex_lock(fchan->mutex);
-       if (ftdm_test_flag(fchan, FTDM_CHANNEL_SUSPENDED)) {
-               if (!openr2_chan_set_idle(r2chan)) {
-                       ftdm_clear_flag(fchan, FTDM_CHANNEL_SUSPENDED);
-                       stream->write_function(stream, "unblocked channel %d:%d\n", 
-                                       fchan->span_id, fchan->chan_id);
-               } else {
-                       stream->write_function(stream, "failed to unblock channel %d:%d\n", 
-                                       fchan->span_id, fchan->chan_id);
-               }
+       if (!openr2_chan_set_idle(r2chan)) {
+               ftdm_clear_flag(fchan, FTDM_CHANNEL_SUSPENDED);
+               stream->write_function(stream, "unblocked channel %d:%d\n", 
+                               fchan->span_id, fchan->chan_id);
        } 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);
        }
        ftdm_mutex_unlock(fchan->mutex);
index c73f0c78e3bc6a8fb25f75ab1a5fb78afb1bb98d..1f2ad84d72cf6ffc5f5528b45c79b23a435013cb 100644 (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) {
        case WP_API_EVENT_LINK_STATUS:
                {
+#if 0
                        switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
                        case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
                                *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;
                                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;
 
@@ -1353,8 +1359,13 @@ static __inline__ ftdm_status_t wanpipe_channel_process_event(ftdm_channel_t *fc
                break;
        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);
-                       *event_id = FTDM_OOB_ALARM_TRAP;
+                       if (tdm_api->wp_tdm_cmd.event.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);
+                               *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;
        case WP_API_EVENT_POLARITY_REVERSE: