Merge branch 'master' into netborder

Conflicts:
	libs/freetdm/src/ftdm_io.c
	libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c
	libs/freetdm/src/include/freetdm.h
This commit is contained in:
Moises Silva committed 2011-01-05 13:11:37 -05:00
commit eb84fc772f
224 files changed
+13786 -6134

No files matched your search

@@ -37,7 +37,9 @@
typedef enum {
FTDM_ANALOG_RUNNING = (1 << 0),
FTDM_ANALOG_CALLERID = (1 << 1)
FTDM_ANALOG_CALLERID = (1 << 1),
FTDM_ANALOG_ANSWER_POLARITY_REVERSE = (1 << 2),
FTDM_ANALOG_HANGUP_POLARITY_REVERSE = (1 << 3)
} ftdm_analog_flag_t;
#define FTDM_MAX_HOTLINE_STR 20
@@ -47,11 +49,13 @@ struct ftdm_analog_data {
uint32_t flags;
uint32_t max_dialstr;
uint32_t wait_dialtone_timeout;
uint32_t polarity_delay;
uint32_t digit_timeout;
char hotline[FTDM_MAX_HOTLINE_STR];
};
/* Analog flags to be set in the sflags (signaling flags) channel memeber */
#define AF_POLARITY_REVERSE (1 << 0)
static void *ftdm_analog_run(ftdm_thread_t *me, void *obj);
typedef struct ftdm_analog_data ftdm_analog_data_t;
@@ -96,6 +96,10 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxs_outgoing_call)
static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(analog_get_channel_sig_status)
{
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) {
*status = FTDM_SIG_STATE_DOWN;
return FTDM_SUCCESS;
}
*status = FTDM_SIG_STATE_UP;
return FTDM_SUCCESS;
}
@@ -109,7 +113,25 @@ static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(analog_get_channel_sig_status)
static FIO_SPAN_GET_SIG_STATUS_FUNCTION(analog_get_span_sig_status)
{
*status = FTDM_SIG_STATE_UP;
ftdm_iterator_t *citer = NULL;
ftdm_iterator_t *chaniter = ftdm_span_get_chan_iterator(span, NULL);
if (!chaniter) {
ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name);
return FTDM_FAIL;
}
/* if ALL channels are in alarm, report DOWN, UP otherwise. */
*status = FTDM_SIG_STATE_DOWN;
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_UP;
ftdm_channel_unlock(fchan);
break;
}
ftdm_channel_unlock(fchan);
}
ftdm_iterator_free(chaniter);
return FTDM_SUCCESS;
}
@@ -162,6 +184,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span)
uint32_t digit_timeout = 10;
uint32_t wait_dialtone_timeout = 30000;
uint32_t max_dialstr = MAX_DTMF;
uint32_t polarity_delay = 600;
const char *var, *val;
int *intval;
uint32_t flags = FTDM_ANALOG_CALLERID;
@@ -214,6 +237,29 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span)
} else {
flags &= ~FTDM_ANALOG_CALLERID;
}
} else if (!strcasecmp(var, "answer_polarity_reverse")) {
if (!(val = va_arg(ap, char *))) {
break;
}
if (ftdm_true(val)) {
flags |= FTDM_ANALOG_ANSWER_POLARITY_REVERSE;
} else {
flags &= ~FTDM_ANALOG_ANSWER_POLARITY_REVERSE;
}
} else if (!strcasecmp(var, "hangup_polarity_reverse")) {
if (!(val = va_arg(ap, char *))) {
break;
}
if (ftdm_true(val)) {
flags |= FTDM_ANALOG_HANGUP_POLARITY_REVERSE;
} else {
flags &= ~FTDM_ANALOG_HANGUP_POLARITY_REVERSE;
}
} else if (!strcasecmp(var, "polarity_delay")) {
if (!(intval = va_arg(ap, int *))) {
break;
}
polarity_delay = *intval;
} else if (!strcasecmp(var, "callwaiting")) {
if (!(intval = va_arg(ap, int *))) {
break;
@@ -254,6 +300,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span)
analog_data->flags = flags;
analog_data->digit_timeout = digit_timeout;
analog_data->wait_dialtone_timeout = wait_dialtone_timeout;
analog_data->polarity_delay = polarity_delay;
analog_data->max_dialstr = max_dialstr;
span->signal_cb = sig_cb;
strncpy(analog_data->hotline, hotline, sizeof(analog_data->hotline));
@@ -377,6 +424,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
ftdm_analog_data_t *analog_data = ftdmchan->span->signal_data;
ftdm_channel_t *closed_chan;
uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = analog_data->wait_dialtone_timeout;
uint32_t answer_on_polarity_counter = 0;
ftdm_sigmsg_t sig;
ftdm_status_t status;
@@ -448,7 +496,12 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
if (ftdmchan->needed_tones[FTDM_TONEMAP_DIAL]) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
} else {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
/* do not go up if we're waiting for polarity reversal */
if (ftdm_test_flag(analog_data, FTDM_ANALOG_ANSWER_POLARITY_REVERSE)) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
} else {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
}
}
}
}
@@ -493,8 +546,10 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
if (ftdmchan->type == FTDM_CHAN_TYPE_FXS &&
ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) &&
(ftdmchan->last_state == FTDM_CHANNEL_STATE_RINGING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE
|| ftdmchan->last_state == FTDM_CHANNEL_STATE_RING)) {
(ftdmchan->last_state == FTDM_CHANNEL_STATE_RINGING
|| ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE
|| ftdmchan->last_state == FTDM_CHANNEL_STATE_RING
|| ftdmchan->last_state == FTDM_CHANNEL_STATE_UP)) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
} else {
ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING;
@@ -530,15 +585,37 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
if (done) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
ftdm_channel_complete_state(ftdmchan);
ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] = 0;
}
}
case FTDM_CHANNEL_STATE_UP:
case FTDM_CHANNEL_STATE_RING:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
{
ftdm_sleep(interval);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) &&
ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA &&
ftdm_test_sflag(ftdmchan, AF_POLARITY_REVERSE)) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Answering on polarity reverse\n");
ftdm_clear_sflag(ftdmchan, AF_POLARITY_REVERSE);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
answer_on_polarity_counter = state_counter;
} else if (ftdmchan->state == FTDM_CHANNEL_STATE_UP
&& ftdm_test_sflag(ftdmchan, AF_POLARITY_REVERSE)){
/* if this polarity reverse is close to the answer polarity reverse, ignore it */
if (answer_on_polarity_counter
&& (state_counter - answer_on_polarity_counter) > analog_data->polarity_delay) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Hanging up on polarity reverse\n");
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING,
"Not hanging up on polarity reverse, too close to Answer reverse\n");
}
ftdm_clear_sflag(ftdmchan, AF_POLARITY_REVERSE);
} else {
ftdm_sleep(interval);
}
continue;
}
break;
@@ -551,7 +628,6 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
break;
}
} else {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
ftdm_channel_complete_state(ftdmchan);
indicate = 0;
@@ -591,6 +667,19 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
sig.event_id = FTDM_SIGEVENT_UP;
}
if (ftdmchan->type == FTDM_CHAN_TYPE_FXS &&
!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) &&
ftdm_test_flag(analog_data, FTDM_ANALOG_ANSWER_POLARITY_REVERSE)) {
ftdm_polarity_t polarity = FTDM_POLARITY_REVERSE;
if (ftdmchan->polarity == FTDM_POLARITY_FORWARD) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Reversing polarity on answer\n");
ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_POLARITY, &polarity);
} else {
/* the polarity may be already reversed if this is the second time we
* answer (ie, due to 2 calls being on the same line) */
}
}
ftdm_span_send_signal(ftdmchan->span, &sig);
continue;
}
@@ -615,6 +704,22 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
continue;
}
break;
case FTDM_CHANNEL_STATE_HANGUP:
/* this state is only used when the user hangup, if the device hang up (onhook) we currently
* go straight to DOWN. If we ever change this (as other signaling modules do) by using this
* state for both user and device hangup, we should check here for the type of hangup since
* some actions (polarity reverse) do not make sense if the device hung up */
if (ftdmchan->type == FTDM_CHAN_TYPE_FXS &&
ftdmchan->last_state == FTDM_CHANNEL_STATE_UP &&
ftdm_test_flag(analog_data, FTDM_ANALOG_HANGUP_POLARITY_REVERSE)) {
ftdm_polarity_t polarity = ftdmchan->polarity == FTDM_POLARITY_REVERSE
? FTDM_POLARITY_FORWARD : FTDM_POLARITY_REVERSE;
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Reversing polarity on hangup\n");
ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_POLARITY, &polarity);
}
break;
case FTDM_CHANNEL_STATE_DOWN:
{
sig.event_id = FTDM_SIGEVENT_STOP;
@@ -717,7 +822,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
dtmf_offset = strlen(dtmf);
last_digit = elapsed;
sig.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT;
sig.raw_data = dtmf;
ftdm_set_string(sig.ev_data.collected.digits, dtmf);
if (ftdm_span_send_signal(ftdmchan->span, &sig) == FTDM_BREAK) {
collecting = 0;
}
@@ -823,6 +928,9 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
done:
closed_chan = ftdmchan;
ftdm_channel_lock(closed_chan);
if (ftdmchan->type == FTDM_CHAN_TYPE_FXO && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) {
ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL);
@@ -833,7 +941,8 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
}
closed_chan = ftdmchan;
ftdm_clear_sflag(ftdmchan, AF_POLARITY_REVERSE);
ftdm_channel_close(&ftdmchan);
ftdm_channel_command(closed_chan, FTDM_COMMAND_SET_NATIVE_CODEC, NULL);
@@ -851,8 +960,11 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
}
ftdm_log_chan(closed_chan, FTDM_LOG_DEBUG, "ANALOG CHANNEL %d:%d thread ended.\n", closed_chan->span_id, closed_chan->chan_id);
ftdm_clear_flag(closed_chan, FTDM_CHANNEL_INTHREAD);
ftdm_channel_unlock(closed_chan);
return NULL;
}
@@ -879,19 +991,32 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
ftdm_mutex_lock(event->channel->mutex);
locked++;
/* MAINTENANCE WARNING:
* 1. Be aware you are working on the locked channel
* 2. We should not be calling ftdm_span_send_signal or ftdm_set_state when there is already a channel thread running
* however, since this is old code I am not changing it now, but new code should adhere to that convention
* otherwise, we have possible races where we compete with the user for state changes, ie, the user requests
* a state change and then we process an event, the state change from the user is pending so our ftdm_set_state
* operation will fail. In cases where we win the race, our state change will be accepted but if a user requests
* a state change before the state change we requested here is processed by the channel thread, we'll end up
* rejecting the user request.
*
* See docs/locking.txt for further information about what guarantees should signaling modules provide when
* locking/unlocking a channel
* */
switch(event->enum_id) {
case FTDM_OOB_RING_START:
{
if (event->channel->type != FTDM_CHAN_TYPE_FXO) {
ftdm_log_chan_msg(event->channel, FTDM_LOG_ERROR, "Cannot get a RING_START event on a non-fxo channel, please check your config.\n");
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN);
goto end;
}
if (!event->channel->ring_count && (event->channel->state == FTDM_CHANNEL_STATE_DOWN && !ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD))) {
if (ftdm_test_flag(analog_data, FTDM_ANALOG_CALLERID)) {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_GET_CALLERID);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_GET_CALLERID);
} else {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_RING);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_RING);
}
event->channel->ring_count = 1;
ftdm_mutex_unlock(event->channel->mutex);
@@ -909,24 +1034,33 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
}
if (event->channel->state != FTDM_CHANNEL_STATE_DOWN) {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
if (event->channel->state == FTDM_CHANNEL_STATE_HANGUP &&
ftdm_test_flag(event->channel, FTDM_CHANNEL_STATE_CHANGE)) {
/* we do not need to process HANGUP since the device also hangup already */
ftdm_channel_complete_state(event->channel);
}
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN);
}
if (event->channel->type == FTDM_CHAN_TYPE_FXS) {
/* we always return to forward when the device goes onhook */
ftdm_polarity_t forward_polarity = FTDM_POLARITY_FORWARD;
ftdm_channel_command(event->channel, FTDM_COMMAND_SET_POLARITY, &forward_polarity);
}
}
break;
case FTDM_OOB_FLASH:
{
if (event->channel->state == FTDM_CHANNEL_STATE_CALLWAITING) {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
ftdm_clear_flag_locked(event->channel, FTDM_CHANNEL_STATE_CHANGE);
ftdm_clear_flag_locked(event->channel->span, FTDM_SPAN_STATE_CHANGE);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_UP);
ftdm_clear_flag(event->channel->span, FTDM_SPAN_STATE_CHANGE);
ftdm_channel_complete_state(event->channel);
event->channel->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] = 0;
}
ftdm_channel_rotate_tokens(event->channel);
if (ftdm_test_flag(event->channel, FTDM_CHANNEL_HOLD) && event->channel->token_count != 1) {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_UP);
} else {
sig.event_id = FTDM_SIGEVENT_FLASH;
ftdm_span_send_signal(span, &sig);
@@ -940,12 +1074,12 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
if (ftdm_test_flag(event->channel, FTDM_CHANNEL_RINGING)) {
ftdm_channel_command(event->channel, FTDM_COMMAND_GENERATE_RING_OFF, NULL);
}
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_UP);
} else {
if(!analog_data->max_dialstr) {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_COLLECT);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_COLLECT);
} else {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DIALTONE);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DIALTONE);
}
ftdm_mutex_unlock(event->channel->mutex);
locked = 0;
@@ -957,9 +1091,53 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
ftdm_channel_command(event->channel, FTDM_COMMAND_ONHOOK, NULL);
}
}
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN);
}
}
break;
case FTDM_OOB_ALARM_TRAP:
{
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
sig.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN;
ftdm_span_send_signal(span, &sig);
}
break;
case FTDM_OOB_ALARM_CLEAR:
{
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
sig.ev_data.sigstatus.status = FTDM_SIG_STATE_UP;
ftdm_span_send_signal(span, &sig);
}
break;
case FTDM_OOB_POLARITY_REVERSE:
{
if (event->channel->type != FTDM_CHAN_TYPE_FXO) {
ftdm_log_chan_msg(event->channel, FTDM_LOG_WARNING,
"Ignoring polarity reversal, this should not happen in non-FXO channels!\n");
break;
}
if (!ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD) &&
ftdm_test_flag(event->channel, FTDM_CHANNEL_OFFHOOK)) {
ftdm_log_chan_msg(event->channel, FTDM_LOG_WARNING,
"Forcing onhook in channel not in thread after polarity reversal\n");
ftdm_channel_command(event->channel, FTDM_COMMAND_ONHOOK, NULL);
break;
}
if (!ftdm_test_flag(analog_data, FTDM_ANALOG_ANSWER_POLARITY_REVERSE)
&& !ftdm_test_flag(analog_data, FTDM_ANALOG_HANGUP_POLARITY_REVERSE)) {
ftdm_log_chan_msg(event->channel, FTDM_LOG_DEBUG,
"Ignoring polarity reversal because this channel is not configured for it\n");
break;
}
if (event->channel->state == FTDM_CHANNEL_STATE_DOWN) {
ftdm_log_chan_msg(event->channel, FTDM_LOG_DEBUG,
"Ignoring polarity reversal because this channel is down\n");
break;
}
/* we have a good channel, set the polarity flag and let the channel thread deal with it */
ftdm_set_sflag(event->channel, AF_POLARITY_REVERSE);
}
break;
default:
{
ftdm_log_chan(event->channel, FTDM_LOG_DEBUG, "Ignoring event [%s] in state [%s]\n", ftdm_oob_event2str(event->enum_id), ftdm_channel_state2str(event->channel->state));
@@ -355,7 +355,6 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
break;
}
} else {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
ftdm_channel_complete_state(ftdmchan);
indicate = 0;
@@ -467,7 +466,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
dtmf_offset = strlen(dtmf);
last_digit = elapsed;
sig.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT;
sig.raw_data = dtmf;
ftdm_set_string(sig.ev_data.collected.digits, dtmf);
if (ftdm_span_send_signal(ftdmchan->span, &sig) == FTDM_BREAK) {
collecting = 0;
}
@@ -497,7 +497,7 @@ static ftdm_state_map_t isdn_state_map = {
* \param ftdmchan Channel to handle
* \note This function MUST be called with the channel locked
*/
static __inline__ void state_advance(ftdm_channel_t *chan)
static ftdm_status_t state_advance(ftdm_channel_t *chan)
{
ftdm_libpri_data_t *isdn_data = chan->span->signal_data;
q931_call *call = (q931_call *)chan->call_data;
@@ -511,27 +511,23 @@ static __inline__ void state_advance(ftdm_channel_t *chan)
sig.chan_id = ftdm_channel_get_id(chan);
sig.span_id = ftdm_channel_get_span_id(chan);
sig.channel = chan;
ftdm_channel_complete_state(chan);
switch (ftdm_channel_get_state(chan)) {
case FTDM_CHANNEL_STATE_DOWN:
{
ftdm_channel_t *chtmp = chan;
chan->call_data = NULL;
ftdm_channel_done(chan);
/*
* Close channel completely, BRI PTMP will thank us
*/
if (ftdm_test_flag(chan, FTDM_CHANNEL_OPEN)) {
ftdm_channel_t *chtmp = chan;
if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n",
ftdm_channel_get_span_id(chan),
ftdm_channel_get_id(chan));
} else {
ftdm_log(FTDM_LOG_DEBUG, "-- Closed channel %d:%d\n",
ftdm_channel_get_span_id(chan),
ftdm_channel_get_id(chan));
}
if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n",
ftdm_channel_get_span_id(chan),
ftdm_channel_get_id(chan));
} else {
ftdm_log(FTDM_LOG_DEBUG, "-- Closed channel %d:%d\n",
ftdm_channel_get_span_id(chan),
ftdm_channel_get_id(chan));
}
}
break;
@@ -631,7 +627,7 @@ static __inline__ void state_advance(ftdm_channel_t *chan)
ftdm_channel_get_span_id(chan), ftdm_channel_get_id(chan));
/* TODO: set hangup cause? */
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART);
return;
return FTDM_SUCCESS;
}
ton = caller_data->dnis.type;
@@ -714,6 +710,7 @@ static __inline__ void state_advance(ftdm_channel_t *chan)
default:
break;
}
return FTDM_SUCCESS;
}
/**
@@ -729,13 +726,8 @@ static __inline__ void check_state(ftdm_span_t *span)
for (j = 1; j <= ftdm_span_get_chan_count(span); j++) {
ftdm_channel_t *chan = ftdm_span_get_channel(span, j);
ftdm_channel_lock(chan);
while (ftdm_test_flag(chan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_clear_flag(chan, FTDM_CHANNEL_STATE_CHANGE);
state_advance(chan);
ftdm_channel_complete_state(chan);
}
ftdm_channel_advance_states(chan);
ftdm_channel_unlock(chan);
}
}
@@ -1403,8 +1395,7 @@ static int on_dchan_up(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_ev
sig.chan_id = ftdm_channel_get_id(chan);
sig.channel = chan;
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
sig.raw_data = &status;
sig.ev_data.sigstatus.status = status;
ftdm_span_send_signal(span, &sig);
}
}
@@ -1440,7 +1431,7 @@ static int on_dchan_down(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_
sig.chan_id = ftdm_channel_get_id(chan);
sig.channel = chan;
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
sig.raw_data = &status;
sig.ev_data.sigstatus.status = status;
ftdm_span_send_signal(span, &sig);
}
@@ -1917,6 +1908,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
span->outgoing_call = isdn_outgoing_call;
span->state_map = &isdn_state_map;
span->state_processor = state_advance;
span->get_channel_sig_status = isdn_get_channel_sig_status;
span->get_span_sig_status = isdn_get_span_sig_status;
@@ -127,9 +127,8 @@ static int __pri_lpwrap_read(struct pri *pri, void *buf, int buflen)
} else {
ftdm_log(FTDM_LOG_CRIT, "span %d D-READ TIMEOUT\n", spri->span->span_id);
}
ftdm_clear_flag(spri, LPWRAP_PRI_READY);
return -1;
/* we cannot return -1, libpri seems to expect values >= 0 */
return 0;
}
spri->errs = 0;
res = (int)len;
@@ -156,8 +155,8 @@ static int __pri_lpwrap_write(struct pri *pri, void *buf, int buflen)
if (ftdm_channel_write(spri->dchan, buf, buflen, &len) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_CRIT, "span %d D-WRITE FAIL! [%s]\n", spri->span->span_id, spri->dchan->last_error);
ftdm_clear_flag(spri, LPWRAP_PRI_READY);
return -1;
/* we cannot return -1, libpri seems to expect values >= 0 */
return 0;
}
#ifdef IODEBUG
@@ -265,7 +265,7 @@ static ftdm_state_map_t pritap_state_map = {
}
};
static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
static ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
{
ftdm_status_t status;
ftdm_sigmsg_t sig;
@@ -278,6 +278,8 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
sig.span_id = ftdmchan->span_id;
sig.channel = ftdmchan;
ftdm_channel_complete_state(ftdmchan);
switch (ftdmchan->state) {
case FTDM_CHANNEL_STATE_DOWN:
{
@@ -321,24 +323,20 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
break;
}
return;
return FTDM_SUCCESS;
}
static __inline__ void pritap_check_state(ftdm_span_t *span)
{
if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
uint32_t j;
ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
for(j = 1; j <= span->chan_count; j++) {
if (ftdm_test_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_mutex_lock(span->channels[j]->mutex);
ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
state_advance(span->channels[j]);
ftdm_channel_complete_state(span->channels[j]);
ftdm_mutex_unlock(span->channels[j]->mutex);
}
}
}
if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
uint32_t j;
ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
for(j = 1; j <= span->chan_count; j++) {
ftdm_mutex_lock(span->channels[j]->mutex);
ftdm_channel_advance_states(span->channels[j]);
ftdm_mutex_unlock(span->channels[j]->mutex);
}
}
}
static int pri_io_read(struct pri *pri, void *buf, int buflen)
@@ -896,6 +894,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_pritap_configure_span)
span->get_span_sig_status = pritap_get_span_sig_status;
span->state_map = &pritap_state_map;
span->state_processor = state_advance;
return FTDM_SUCCESS;
}
+325 -237
View File
@@ -33,6 +33,7 @@
* Contributors:
*
* Arnaldo Pereira <arnaldo@sangoma.com>
* Ricardo Barroetaveña <rbarroetavena@anura.com.ar>
*
*/
@@ -49,10 +50,6 @@
#include "freetdm.h"
#include "private/ftdm_core.h"
/* debug thread count for r2 legs */
static ftdm_mutex_t* g_thread_count_mutex;
static int32_t g_thread_count = 0;
typedef int openr2_call_status_t;
/* when the user stops a span, we clear FTDM_R2_SPAN_STARTED, so that the signaling thread
@@ -76,7 +73,6 @@ typedef struct ftdm_r2_call_t {
int disconnect_rcvd:1;
int ftdm_call_started:1;
int protocol_error:1;
ftdm_channel_state_t chanstate;
ftdm_size_t dnis_index;
ftdm_size_t ani_index;
char logname[255];
@@ -171,8 +167,7 @@ static ftdm_hash_t *g_mod_data_hash;
/* IO interface for the command API */
static ftdm_io_interface_t g_ftdm_r2_interface;
static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan);
static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan);
static ftdm_status_t ftdm_r2_state_advance(ftdm_channel_t *ftdmchan);
/* whether R2 call accept process is pending */
#define IS_ACCEPTING_PENDING(ftdmchan) \
@@ -352,7 +347,6 @@ static void ft_r2_clean_call(ftdm_r2_call_t *call)
call->disconnect_rcvd = 0;
call->ftdm_call_started = 0;
call->protocol_error = 0;
call->chanstate = FTDM_CHANNEL_STATE_DOWN;
call->dnis_index = 0;
call->ani_index = 0;
call->name[0] = 0;
@@ -380,11 +374,72 @@ static void ft_r2_answer_call(ftdm_channel_t *ftdmchan)
R2CALL(ftdmchan)->answer_pending = 0;
}
static __inline__ ftdm_calling_party_category_t ftdm_openr2_cpc_to_r2_ftdm_cpc(openr2_calling_party_category_t cpc)
{
switch (cpc) {
case OR2_CALLING_PARTY_CATEGORY_UNKNOWN:
return FTDM_CPC_UNKNOWN;
case OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER:
return FTDM_CPC_ORDINARY;
case OR2_CALLING_PARTY_CATEGORY_NATIONAL_PRIORITY_SUBSCRIBER:
return FTDM_CPC_PRIORITY;
case OR2_CALLING_PARTY_CATEGORY_INTERNATIONAL_SUBSCRIBER:
return FTDM_CPC_UNKNOWN;
case OR2_CALLING_PARTY_CATEGORY_INTERNATIONAL_PRIORITY_SUBSCRIBER:
return FTDM_CPC_UNKNOWN;
case OR2_CALLING_PARTY_CATEGORY_TEST_EQUIPMENT:
return FTDM_CPC_TEST;
case OR2_CALLING_PARTY_CATEGORY_PAY_PHONE:
return FTDM_CPC_PAYPHONE;
case OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL:
return FTDM_CPC_OPERATOR;
}
return FTDM_CPC_INVALID;
}
static __inline openr2_calling_party_category_t ftdm_r2_ftdm_cpc_to_openr2_cpc(ftdm_calling_party_category_t cpc)
{
switch (cpc) {
case FTDM_CPC_UNKNOWN:
return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
case FTDM_CPC_OPERATOR:
return OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL;
case FTDM_CPC_ORDINARY:
return OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
case FTDM_CPC_PRIORITY:
return OR2_CALLING_PARTY_CATEGORY_NATIONAL_PRIORITY_SUBSCRIBER;
case FTDM_CPC_DATA:
return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
case FTDM_CPC_TEST:
return OR2_CALLING_PARTY_CATEGORY_TEST_EQUIPMENT;
case FTDM_CPC_PAYPHONE:
return OR2_CALLING_PARTY_CATEGORY_PAY_PHONE;
case FTDM_CPC_INVALID:
return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
}
return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
}
/* this function must be called with the chan mutex held! */
static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
{
openr2_call_status_t callstatus;
ftdm_r2_data_t *r2data;
openr2_calling_party_category_t category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
r2data = ftdmchan->span->signal_data;
@@ -397,6 +452,12 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
ft_r2_clean_call(ftdmchan->call_data);
if (ftdmchan->caller_data.cpc == FTDM_CPC_INVALID || ftdmchan->caller_data.cpc == FTDM_CPC_UNKNOWN) {
category = r2data->category;
} else {
category = ftdm_r2_ftdm_cpc_to_openr2_cpc(ftdmchan->caller_data.cpc);
}
/* start io dump */
if (r2data->mf_dump_size) {
ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_INPUT_DUMP, &r2data->mf_dump_size);
@@ -404,9 +465,10 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
}
callstatus = openr2_chan_make_call(R2CALL(ftdmchan)->r2chan,
ftdmchan->caller_data.cid_num.digits,
ftdmchan->caller_data.cid_num.digits,
ftdmchan->caller_data.dnis.digits,
r2data->category);
category,
ftdmchan->caller_data.pres == FTDM_PRES_ALLOWED ? 0 : 1);
if (callstatus) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to make call in R2 channel, openr2_chan_make_call failed\n");
@@ -414,7 +476,6 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
}
R2CALL(ftdmchan)->ftdm_call_started = 1;
R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS);
@@ -456,19 +517,40 @@ static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_channel_sig_status)
static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_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 we're already in the state the user asks us to be, we have nothing to do */
if (status == FTDM_SIG_STATE_SUSPENDED && txcas == OR2_CAS_BLOCK) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Channel signaling status already in BLOCK state\n");
return FTDM_SUCCESS;
}
if (status == FTDM_SIG_STATE_UP && txcas == OR2_CAS_IDLE) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Channel signaling status already in IDLE state\n");
return FTDM_SUCCESS;
}
/* set the signaling as requested and send SIGEVENT_SIGSTATUS_CHANGED, if applicable.
* see docs/sigstatus.txt for details */
switch(status) {
case FTDM_SIG_STATE_DOWN:
case FTDM_SIG_STATE_SUSPENDED:
openr2_chan_set_blocked(r2chan);
if (rxcas == OR2_CAS_IDLE) {
ftdm_r2_set_chan_sig_status(ftdmchan, status);
}
break;
case FTDM_SIG_STATE_UP:
openr2_chan_set_idle(r2chan);
if (rxcas == OR2_CAS_IDLE) {
ftdm_r2_set_chan_sig_status(ftdmchan, status);
}
break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%d'\n", status);
return FTDM_FAIL;
}
ftdm_r2_set_chan_sig_status(ftdmchan, status);
return FTDM_SUCCESS;
}
@@ -484,10 +566,13 @@ static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_span_sig_status)
*status = FTDM_SIG_STATE_SUSPENDED;
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_SIG_UP)) {
*status = FTDM_SIG_STATE_UP;
ftdm_channel_unlock(fchan);
break;
}
ftdm_channel_unlock(fchan);
}
ftdm_iterator_free(chaniter);
return FTDM_SUCCESS;
@@ -497,21 +582,6 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_span_sig_status)
{
ftdm_iterator_t *chaniter = NULL;
ftdm_iterator_t *citer = NULL;
uint32_t span_opr = -1;
/* we either set the channels to BLOCK or IDLE */
switch(status) {
case FTDM_SIG_STATE_DOWN:
case FTDM_SIG_STATE_SUSPENDED:
span_opr = 0;
break;
case FTDM_SIG_STATE_UP:
span_opr = 1;
break;
default:
ftdm_log(FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%d'\n", status);
return FTDM_FAIL;
}
chaniter = ftdm_span_get_chan_iterator(span, NULL);
if (!chaniter) {
@@ -521,15 +591,13 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_span_sig_status)
/* iterate over all channels, setting them to the requested state */
for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) {
ftdm_channel_t *fchan = ftdm_iterator_current(citer);
openr2_chan_t *r2chan = R2CALL(fchan)->r2chan;
if (span_opr == 0) {
openr2_chan_set_blocked(r2chan);
ftdm_log_chan_msg(fchan, FTDM_LOG_NOTICE, "Channel blocked\n");
} else {
openr2_chan_set_idle(r2chan);
ftdm_log_chan_msg(fchan, FTDM_LOG_NOTICE, "Channel idle\n");
/* we set channel's state through ftdm_r2_set_channel_sig_status(), since it already takes
* care of notifying the user when appropriate */
ftdm_channel_lock(fchan);
if ((ftdm_r2_set_channel_sig_status(fchan, status)) != FTDM_SUCCESS) {
ftdm_log_chan(fchan, FTDM_LOG_ERROR, "Failed to set signaling status to %s\n", ftdm_signaling_status2str(status));
}
ftdm_r2_set_chan_sig_status(fchan, status);
ftdm_channel_unlock(fchan);
}
ftdm_iterator_free(chaniter);
return FTDM_SUCCESS;
@@ -552,7 +620,7 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
ftdm_sched_cancel_timer(r2data->sched, r2call->protocol_error_recovery_timer);
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Cancelled protocol error recovery timer\n");
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
ftdm_r2_state_advance_all(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
}
}
@@ -586,7 +654,6 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_OUTPUT_DUMP, &r2data->mf_dump_size);
}
R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS);
ftdm_channel_command(ftdmchan, FTDM_COMMAND_FLUSH_TX_BUFFERS, NULL);
@@ -595,12 +662,14 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
static void dump_mf(openr2_chan_t *r2chan);
/* only called for incoming calls when the ANI, DNIS etc is complete and the user has to decide either to accept or reject the call */
static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, openr2_calling_party_category_t category)
static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis,
openr2_calling_party_category_t category, int ani_restricted)
{
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Call offered with ANI = %s, DNIS = %s, Category = (%d)\n", ani, dnis, category);
ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Call offered with ANI = %s, DNIS = %s, Category = %d, ANI restricted = %s\n",
ani, dnis, category, ani_restricted ? "Yes" : "No");
/* nothing went wrong during call setup, MF has ended, we can and must disable the MF dump */
if (r2data->mf_dump_size) {
@@ -615,6 +684,8 @@ static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, cons
} else {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING);
}
ftdmchan->caller_data.cpc = ftdm_openr2_cpc_to_r2_ftdm_cpc(category);
ftdmchan->caller_data.pres = ani_restricted ? FTDM_PRES_RESTRICTED : FTDM_PRES_ALLOWED;
}
/*
@@ -632,12 +703,10 @@ static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, cons
static void clear_accept_pending(ftdm_channel_t *fchan)
{
if (IS_ACCEPTING_PENDING(fchan)) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_channel_complete_state(fchan);
} else if (ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_log_chan(fchan, FTDM_LOG_CRIT, "State change flag set in state %s, last state = %s\n",
ftdm_channel_state2str(fchan->state), ftdm_channel_state2str(fchan->last_state));
ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_channel_complete_state(fchan);
}
}
@@ -745,7 +814,7 @@ static void ftdm_r2_on_call_end(openr2_chan_t *r2chan)
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
/* in some circumstances openr2 can call on_call_init right after this, so let's advance the state right here */
ftdm_r2_state_advance_all(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
}
static void ftdm_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen)
@@ -777,7 +846,7 @@ static void ftdm_r2_recover_from_protocol_error(void *data)
goto done;
}
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
ftdm_r2_state_advance_all(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
done:
ftdm_channel_unlock(ftdmchan);
}
@@ -1158,6 +1227,18 @@ static openr2_log_level_t ftdm_r2_loglevel_from_string(const char *level)
static ftdm_state_map_t r2_state_map = {
{
{
ZSD_INBOUND,
ZSM_UNACCEPTABLE,
{FTDM_ANY_STATE, FTDM_END},
{FTDM_CHANNEL_STATE_RESET, FTDM_END}
},
{
ZSD_INBOUND,
ZSM_UNACCEPTABLE,
{FTDM_CHANNEL_STATE_RESET, FTDM_END},
{FTDM_CHANNEL_STATE_DOWN, FTDM_END}
},
{
ZSD_INBOUND,
ZSM_UNACCEPTABLE,
@@ -1209,6 +1290,20 @@ static ftdm_state_map_t r2_state_map = {
/* Outbound states */
{
ZSD_OUTBOUND,
ZSM_UNACCEPTABLE,
{FTDM_ANY_STATE, FTDM_END},
{FTDM_CHANNEL_STATE_RESET, FTDM_END}
},
{
ZSD_OUTBOUND,
ZSM_UNACCEPTABLE,
{FTDM_CHANNEL_STATE_RESET, FTDM_END},
{FTDM_CHANNEL_STATE_DOWN, FTDM_END}
},
{
ZSD_OUTBOUND,
ZSM_UNACCEPTABLE,
@@ -1515,10 +1610,14 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling)
span->set_channel_sig_status = ftdm_r2_set_channel_sig_status;
span->state_map = &r2_state_map;
span->state_processor = ftdm_r2_state_advance;
/* use signals queue */
ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
/* we can skip states (going straight from RING to UP) */
ftdm_set_flag(span, FTDM_SPAN_USE_SKIP_STATES);
/* setup the scheduler */
snprintf(schedname, sizeof(schedname), "ftmod_r2_%s", span->name);
ftdm_assert(ftdm_sched_create(&r2data->sched, schedname) == FTDM_SUCCESS, "Failed to create schedule!\n");
@@ -1541,10 +1640,10 @@ fail:
}
/* the channel must be locked when calling this function */
static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
static ftdm_status_t ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
{
ftdm_sigmsg_t sigev;
int ret;
ftdm_status_t ret;
ftdm_r2_call_t *r2call = R2CALL(ftdmchan);
openr2_chan_t *r2chan = r2call->r2chan;
ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
@@ -1554,172 +1653,173 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
sigev.span_id = ftdmchan->span_id;
sigev.channel = ftdmchan;
ret = 0;
ret = FTDM_SUCCESS;
/* because we do not always acknowledge the state change (clearing the FTDM_CHANNEL_STATE_CHANGE flag) due to the accept
* procedure described below, we need the chanstate member to NOT process some states twice, so is valid entering this
* function with the FTDM_CHANNEL_STATE_CHANGE flag set but with a state that was already processed and is just waiting
* to complete (the processing is media-bound)
* */
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)
&& (r2call->chanstate != ftdmchan->state)) {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state));
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state));
r2call->chanstate = ftdmchan->state;
if (IS_ACCEPTING_PENDING(ftdmchan)) {
/*
Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call first, and accepting
the call in R2 means sending a tone, then waiting for the acknowledge from the other end,
since all of that requires sending and detecting tones, it takes a few milliseconds (I'd say around 100)
which means during that time the user should not try to perform any operations like answer, hangup or anything
else, therefore we DO NOT clear the FTDM_CHANNEL_STATE_CHANGE flag here, we rely on ftdm_io.c to block
the user thread until we're done with the accept (see on_call_accepted callback) and then we clear the state change flag,
otherwise we have a race condition between freetdm calling openr2_chan_answer_call and openr2 accepting the call first,
if freetdm calls openr2_chan_answer_call before the accept cycle completes, openr2 will fail to answer the call */
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "State ack for state %s will have to wait a bit\n", ftdm_channel_state2str(ftdmchan->state));
} else if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN){
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_channel_complete_state(ftdmchan);
}
switch (ftdmchan->state) {
/* starting an incoming call */
case FTDM_CHANNEL_STATE_COLLECT:
{
uint32_t interval = 0;
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
ftdm_assert(interval != 0, "Invalid interval!");
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting processing of incoming call with interval %d\n", interval);
openr2_chan_enable_read(r2chan);
}
break;
/* starting an outgoing call */
case FTDM_CHANNEL_STATE_DIALING:
{
uint32_t interval = 0;
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
ftdm_assert(interval != 0, "Invalid interval!");
ftdm_log_chan(ftdmchan,
FTDM_LOG_DEBUG, "Starting processing of outgoing call in channel with interval %d\n", interval);
openr2_chan_enable_read(r2chan);
}
break;
/* incoming call was offered */
case FTDM_CHANNEL_STATE_RING:
/* notify the user about the new call */
sigev.event_id = FTDM_SIGEVENT_START;
ftdm_span_send_signal(ftdmchan->span, &sigev);
r2call->ftdm_call_started = 1;
break;
/* the call is making progress */
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
{
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
if (!r2call->accepted) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Accepting call\n");
ft_r2_accept_call(ftdmchan);
}
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying progress\n");
sigev.event_id = FTDM_SIGEVENT_PROCEED;
ftdm_span_send_signal(ftdmchan->span, &sigev);
sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* the call was answered */
case FTDM_CHANNEL_STATE_UP:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call was answered\n");
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
if (!r2call->accepted) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call has not been accepted, need to accept first\n");
// the answering will be done in the on_call_accepted handler
ft_r2_accept_call(ftdmchan);
r2call->answer_pending = 1;
} else {
ft_r2_answer_call(ftdmchan);
}
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying of call answered\n");
sigev.event_id = FTDM_SIGEVENT_UP;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* just got hangup */
case FTDM_CHANNEL_STATE_HANGUP:
{
if (!r2call->disconnect_rcvd) {
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
/* this will disconnect the call, but need to wait for the call end before moving to DOWN */
openr2_chan_disconnect_call(r2chan, disconnect_cause);
} else if (!r2call->protocol_error) {
/* just ack the hangup, on_call_end will be called by openr2 right after */
openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Clearing call due to protocol error\n");
/* do not set to down yet, give some time for recovery */
ftdm_sched_timer(r2data->sched, "protocolerr_recover", 100,
ftdm_r2_recover_from_protocol_error, r2chan, &r2call->protocol_error_recovery_timer);
}
}
break;
case FTDM_CHANNEL_STATE_TERMINATING:
{
/* if the call has not been started yet we must go to HANGUP right here */
if (!r2call->ftdm_call_started) {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
} else {
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
/* notify the user of the call terminating and we wait for the user to move us to hangup */
sigev.event_id = FTDM_SIGEVENT_STOP;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* finished call for good */
case FTDM_CHANNEL_STATE_DOWN:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Call is down\n");
ret = 1;
}
break;
/* INDICATE_RINGING doesn't apply to MFC/R2. maybe we could generate a tone */
case FTDM_CHANNEL_STATE_RINGING:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RINGING indicated, ignoring it as it doesn't apply to MFC/R2\n");
}
break;
default:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state change: %s\n", ftdm_channel_state2str(ftdmchan->state));
}
break;
}
if (IS_ACCEPTING_PENDING(ftdmchan)) {
/*
Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call first, and accepting
the call in R2 means sending a tone, then waiting for the acknowledge from the other end,
since all of that requires sending and detecting tones, it takes a few milliseconds (I'd say around 100)
which means during that time the user should not try to perform any operations like answer, hangup or anything
else, therefore we DO NOT clear the FTDM_CHANNEL_STATE_CHANGE flag here, we rely on ftdm_io.c to block
the user thread until we're done with the accept (see on_call_accepted callback) and then we clear the state change flag,
otherwise we have a race condition between freetdm calling openr2_chan_answer_call and openr2 accepting the call first,
if freetdm calls openr2_chan_answer_call before the accept cycle completes, openr2 will fail to answer the call */
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "State ack for state %s will have to wait a bit\n", ftdm_channel_state2str(ftdmchan->state));
} else if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN){
ftdm_channel_complete_state(ftdmchan);
}
if (ret) {
switch (ftdmchan->state) {
/* starting an incoming call */
case FTDM_CHANNEL_STATE_COLLECT:
{
uint32_t interval = 0;
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
ftdm_assert(interval != 0, "Invalid interval!");
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting processing of incoming call with interval %d\n", interval);
openr2_chan_enable_read(r2chan);
}
break;
/* starting an outgoing call */
case FTDM_CHANNEL_STATE_DIALING:
{
uint32_t interval = 0;
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
ftdm_assert(interval != 0, "Invalid interval!");
ftdm_log_chan(ftdmchan,
FTDM_LOG_DEBUG, "Starting processing of outgoing call in channel with interval %d\n", interval);
openr2_chan_enable_read(r2chan);
}
break;
/* incoming call was offered */
case FTDM_CHANNEL_STATE_RING:
/* notify the user about the new call */
sigev.event_id = FTDM_SIGEVENT_START;
ftdm_span_send_signal(ftdmchan->span, &sigev);
r2call->ftdm_call_started = 1;
break;
/* the call is making progress */
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
{
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
if (!r2call->accepted) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Accepting call\n");
ft_r2_accept_call(ftdmchan);
}
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying progress\n");
sigev.event_id = FTDM_SIGEVENT_PROCEED;
ftdm_span_send_signal(ftdmchan->span, &sigev);
sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* the call was answered */
case FTDM_CHANNEL_STATE_UP:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call was answered\n");
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
if (!r2call->accepted) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call has not been accepted, need to accept first\n");
// the answering will be done in the on_call_accepted handler
ft_r2_accept_call(ftdmchan);
r2call->answer_pending = 1;
} else {
ft_r2_answer_call(ftdmchan);
}
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying of call answered\n");
sigev.event_id = FTDM_SIGEVENT_UP;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* just got hangup */
case FTDM_CHANNEL_STATE_HANGUP:
{
if (!r2call->disconnect_rcvd) {
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
/* this will disconnect the call, but need to wait for the call end before moving to DOWN */
openr2_chan_disconnect_call(r2chan, disconnect_cause);
} else if (!r2call->protocol_error) {
/* just ack the hangup, on_call_end will be called by openr2 right after */
openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Clearing call due to protocol error\n");
/* do not set to down yet, give some time for recovery */
ftdm_sched_timer(r2data->sched, "protocolerr_recover", 100,
ftdm_r2_recover_from_protocol_error, r2chan, &r2call->protocol_error_recovery_timer);
}
}
break;
case FTDM_CHANNEL_STATE_TERMINATING:
{
/* if the call has not been started yet we must go to HANGUP right here */
if (!r2call->ftdm_call_started) {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
} else {
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
/* notify the user of the call terminating and we wait for the user to move us to hangup */
sigev.event_id = FTDM_SIGEVENT_STOP;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* finished call for good */
case FTDM_CHANNEL_STATE_DOWN:
{
if (ftdmchan->last_state != FTDM_CHANNEL_STATE_RESET) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Call is down\n");
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Reset Complete\n");
}
ret = FTDM_BREAK;
}
break;
/* INDICATE_RINGING doesn't apply to MFC/R2. maybe we could generate a tone */
case FTDM_CHANNEL_STATE_RINGING:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RINGING indicated, ignoring it as it doesn't apply to MFC/R2\n");
}
break;
/* put the r2 channel back to IDLE, close ftdmchan and set it's state as DOWN */
case FTDM_CHANNEL_STATE_RESET:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RESET indicated, putting the R2 channel back to IDLE\n");
openr2_chan_set_idle(r2chan);
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
}
break;
default:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state change: %s\n", ftdm_channel_state2str(ftdmchan->state));
}
break;
}
if (ret == FTDM_BREAK) {
ftdm_channel_t *closed_chan;
closed_chan = ftdmchan;
ftdm_channel_close(&closed_chan);
@@ -1728,20 +1828,6 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
return ret;
}
/* the channel must be locked when calling this function */
static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan)
{
/* because we do not always acknowledge the state change (clearing the FTDM_CHANNEL_STATE_CHANGE flag) due to the accept
* procedure described below, we need the chanstate member to NOT process some states twice, so is valid entering this
* function with the FTDM_CHANNEL_STATE_CHANGE flag set but with a state that was already processed and is just waiting
* to complete (the processing is media-bound)
* */
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)
&& (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) {
ftdm_r2_state_advance(ftdmchan);
}
}
static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
{
openr2_chan_t *r2chan = NULL;
@@ -1776,10 +1862,12 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
}
for (i = 1, citer = chaniter; citer; citer = ftdm_iterator_next(citer), i++) {
ftdmchan = ftdm_iterator_current(citer);
ftdm_channel_lock(ftdmchan);
r2chan = R2CALL(ftdmchan)->r2chan;
openr2_chan_set_span_id(r2chan, span->span_id);
openr2_chan_set_idle(r2chan);
openr2_chan_process_cas_signaling(r2chan);
ftdm_channel_unlock(ftdmchan);
ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_TX_QUEUE_SIZE, &txqueue_size);
}
@@ -1861,7 +1949,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
for ( ; citer; citer = ftdm_iterator_next(citer)) {
ftdmchan = ftdm_iterator_current(citer);
ftdm_mutex_lock(ftdmchan->mutex);
ftdm_channel_lock(ftdmchan);
call = R2CALL(ftdmchan);
@@ -1870,12 +1958,12 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_RX_DISABLED);
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TX_DISABLED);
ftdm_r2_state_advance_all(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
r2chan = call->r2chan;
openr2_chan_process_signaling(r2chan);
ftdm_r2_state_advance_all(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
if (!call->accepted) {
/* if the call is not accepted we do not want users reading */
@@ -1883,7 +1971,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_TX_DISABLED);
}
ftdm_mutex_unlock(ftdmchan->mutex);
ftdm_channel_unlock(ftdmchan);
}
}
@@ -1891,8 +1979,10 @@ done:
citer = ftdm_span_get_chan_iterator(span, chaniter);
for ( ; citer; citer = ftdm_iterator_next(citer)) {
ftdmchan = ftdm_iterator_current(citer);
ftdm_channel_lock(ftdmchan);
r2chan = R2CALL(ftdmchan)->r2chan;
openr2_chan_set_blocked(r2chan);
ftdm_channel_unlock(ftdmchan);
}
ftdm_iterator_free(chaniter);
@@ -1947,6 +2037,14 @@ static void __inline__ unblock_channel(ftdm_channel_t *fchan, ftdm_stream_handle
ftdm_mutex_unlock(fchan->mutex);
}
#define FT_SYNTAX "USAGE:\n" \
"--------------------------------------------------------------------------------\n" \
"ftdm r2 status <span_id|span_name>\n" \
"ftdm r2 loopstats <span_id|span_name>\n" \
"ftdm r2 block|unblock <span_id|span_name> [<chan_id>]\n" \
"ftdm r2 version\n" \
"ftdm r2 variants\n" \
"--------------------------------------------------------------------------------\n"
static FIO_API_FUNCTION(ftdm_r2_api)
{
ftdm_span_t *span = NULL;
@@ -2130,14 +2228,6 @@ static FIO_API_FUNCTION(ftdm_r2_api)
}
if (argc == 1) {
if (!strcasecmp(argv[0], "threads")) {
ftdm_mutex_lock(g_thread_count_mutex);
stream->write_function(stream, "%d R2 channel threads up\n", g_thread_count);
ftdm_mutex_unlock(g_thread_count_mutex);
stream->write_function(stream, "+OK.\n");
goto done;
}
if (!strcasecmp(argv[0], "version")) {
stream->write_function(stream, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision());
stream->write_function(stream, "+OK.\n");
@@ -2163,7 +2253,7 @@ static FIO_API_FUNCTION(ftdm_r2_api)
}
}
stream->write_function(stream, "-ERR invalid command.\n");
stream->write_function(stream, "%s", FT_SYNTAX);
done:
@@ -2192,7 +2282,6 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_r2_init)
if (!g_mod_data_hash) {
return FTDM_FAIL;
}
ftdm_mutex_create(&g_thread_count_mutex);
return FTDM_SUCCESS;
}
@@ -2212,7 +2301,6 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_r2_destroy)
}
}
hashtable_destroy(g_mod_data_hash);
ftdm_mutex_destroy(&g_thread_count_mutex);
return FTDM_SUCCESS;
}
@@ -951,7 +951,6 @@ static void handle_call_answer(ftdm_span_t *span, sangomabc_connection_t *mcon,
}
}
static __inline__ void advance_chan_states(ftdm_channel_t *ftdmchan);
static __inline__ void stop_loop(ftdm_channel_t *ftdmchan);
/**
@@ -1002,7 +1001,7 @@ tryagain:
} else if (ftdmchan->state == FTDM_CHANNEL_STATE_IN_LOOP && retry) {
retry = 0;
stop_loop(ftdmchan);
advance_chan_states(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
goto tryagain;
} else {
ftdm_log(FTDM_LOG_ERROR, "s%dc%d: rejecting incoming call in channel state %s\n",
@@ -1267,7 +1266,7 @@ static ftdm_channel_t* event_process_states(ftdm_span_t *span, sangomabc_short_e
}
ftdm_mutex_lock(ftdmchan->mutex);
advance_chan_states(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
return ftdmchan;
}
@@ -1354,11 +1353,11 @@ static int parse_sangoma_event(ftdm_span_t *span, sangomabc_connection_t *mcon,
}
if(ftdmchan != NULL) {
advance_chan_states(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
ftdm_mutex_unlock(ftdmchan->mutex);
}
return 0;
return 0;
}
@@ -1366,7 +1365,7 @@ static int parse_sangoma_event(ftdm_span_t *span, sangomabc_connection_t *mcon,
* \brief Handler for channel state change
* \param ftdmchan Channel to handle
*/
static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
static ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
{
ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
sangomabc_connection_t *mcon = &sangoma_boost_data->mcon;
@@ -1374,12 +1373,6 @@ static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
ftdm_status_t status;
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
} else {
return FTDM_SUCCESS;
}
ftdm_assert_return(ftdmchan->last_state != ftdmchan->state, FTDM_FAIL, "Channel state already processed\n");
ftdm_log(FTDM_LOG_DEBUG, "%d:%d PROCESSING STATE [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
@@ -1389,6 +1382,8 @@ static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
sig.span_id = ftdmchan->span_id;
sig.channel = ftdmchan;
ftdm_channel_complete_state(ftdmchan);
switch (ftdmchan->state) {
case FTDM_CHANNEL_STATE_DOWN:
{
@@ -1640,24 +1635,15 @@ static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
default:
break;
}
ftdm_channel_complete_state(ftdmchan);
return FTDM_SUCCESS;
}
static __inline__ void advance_chan_states(ftdm_channel_t *ftdmchan)
{
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
state_advance(ftdmchan);
}
}
/**
* \brief Initialises outgoing requests array
*/
static __inline__ void init_outgoing_array(void)
{
memset(&OUTBOUND_REQUESTS, 0, sizeof(OUTBOUND_REQUESTS));
}
/**
@@ -1685,7 +1671,7 @@ static __inline__ void check_state(ftdm_span_t *span)
if (susp && span->channels[j]->state != FTDM_CHANNEL_STATE_DOWN) {
ftdm_set_state(span->channels[j], FTDM_CHANNEL_STATE_RESTART);
}
state_advance(span->channels[j]);
ftdm_channel_advance_states(span->channels[j]);
ftdm_mutex_unlock(span->channels[j]->mutex);
}
}
@@ -1695,7 +1681,7 @@ static __inline__ void check_state(ftdm_span_t *span)
* but without taking the chan out of the queue, so check th
* flag before advancing the state */
ftdm_mutex_lock(ftdmchan->mutex);
state_advance(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
ftdm_mutex_unlock(ftdmchan->mutex);
}
}
@@ -2478,7 +2464,7 @@ static BOOST_SIG_STATUS_CB_FUNCTION(ftdm_boost_sig_status_change)
sig.span_id = ftdmchan->span_id;
sig.channel = ftdmchan;
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
sig.raw_data = &status;
sig.ev_data.sigstatus.status = status;
ftdm_span_send_signal(ftdmchan->span, &sig);
return;
}
@@ -2687,6 +2673,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span)
span->get_span_sig_status = sangoma_boost_get_span_sig_status;
span->set_span_sig_status = sangoma_boost_set_span_sig_status;
span->state_map = &boost_state_map;
span->state_processor = state_advance;
sangoma_boost_data->mcon.debuglevel = FTDM_LOG_LEVEL_DEBUG;
sangoma_boost_data->pcon.debuglevel = FTDM_LOG_LEVEL_DEBUG;
ftdm_clear_flag(span, FTDM_SPAN_SUGGEST_CHAN_ID);
@@ -31,6 +31,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define _GNU_SOURCE
#if HAVE_NETDB_H
#include <netdb.h>
#endif
@@ -40,11 +40,12 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;C:\Program Files\libsng_isdn\include&quot;;&quot;C:\Program Files\libsng_isdn\include\sng_isdn&quot;;../../include;&quot;C:\Program Files\Sangoma\include&quot;"
AdditionalIncludeDirectories="&quot;C:\Program Files\sangoma\sng_isdn\include&quot;;../../include;&quot;C:\Program Files\Sangoma\include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
MinimalRebuild="true"
ExceptionHandling="0"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
@@ -63,7 +64,7 @@
Name="VCLinkerTool"
AdditionalDependencies="freetdm.lib libsng_isdn.lib"
LinkIncremental="2"
AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;&quot;C:\Program Files\libsng_isdn\lib&quot;;&quot;C:\Program Files\Sangoma\api\lib\x86&quot;"
AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;&quot;C:\Program Files\sangoma\sng_isdn\lib&quot;;&quot;C:\Program Files\Sangoma\api\lib\x86&quot;"
GenerateDebugInformation="true"
SubSystem="1"
RandomizedBaseAddress="1"
@@ -116,10 +117,11 @@
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;C:\Program Files\sangoma\sng_isdn\include&quot;;../../include;&quot;C:\Program Files\Sangoma\include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
@@ -136,7 +138,9 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="freetdm.lib libsng_isdn.lib"
LinkIncremental="2"
AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;&quot;C:\Program Files\sangoma\sng_isdn\lib&quot;;&quot;C:\Program Files\Sangoma\api\lib\x86&quot;"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
@@ -85,7 +85,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>C:\Program Files\libsng_isdn\include;C:\Program Files\libsng_isdn\include\sng_isdn;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<ExceptionHandling>
@@ -95,10 +95,11 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
<Link>
<AdditionalDependencies>freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\libsng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\sangoma\sng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
@@ -110,7 +111,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>C:\Program Files\libsng_isdn\include;C:\Program Files\libsng_isdn\include\sng_isdn;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
@@ -119,6 +120,7 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
<Link>
<AdditionalDependencies>freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -135,11 +137,13 @@
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<Optimization>Disabled</Optimization>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@@ -147,23 +151,27 @@
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
<AdditionalDependencies>freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\sangoma\sng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<AdditionalDependencies>freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
@@ -46,10 +46,9 @@ static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span);
static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span);
ftdm_channel_t* ftdm_sangoma_isdn_process_event_states(ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event);
static void ftdm_sangoma_isdn_advance_chan_states(ftdm_channel_t *ftdmchan);
static void ftdm_sangoma_isdn_poll_events(ftdm_span_t *span);
static void ftdm_sangoma_isdn_process_phy_events(ftdm_span_t *span, ftdm_oob_event_t event);
static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan);
static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan);
static void ftdm_sangoma_isdn_process_stack_event (ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event);
static void ftdm_sangoma_isdn_wakeup_phy(ftdm_channel_t *dchan);
static void ftdm_sangoma_isdn_dchan_set_queue_size(ftdm_channel_t *ftdmchan);
@@ -270,13 +269,6 @@ ftdm_state_map_t sangoma_isdn_state_map = {
}
};
static __inline__ void ftdm_sangoma_isdn_advance_chan_states(ftdm_channel_t *ftdmchan)
{
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_sangoma_isdn_process_state_change(ftdmchan);
}
}
static void ftdm_sangoma_isdn_process_phy_events(ftdm_span_t *span, ftdm_oob_event_t event)
{
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
@@ -457,7 +449,7 @@ static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj)
while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) {
/* double check that this channel has a state change pending */
ftdm_channel_lock(ftdmchan);
ftdm_sangoma_isdn_advance_chan_states(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
ftdm_channel_unlock(ftdmchan);
}
@@ -470,11 +462,11 @@ static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj)
/* twiddle */
break;
case FTDM_FAIL:
ftdm_log(FTDM_LOG_ERROR,"%s:ftdm_interrupt_wait returned error!\n", span->name);
ftdm_log(FTDM_LOG_ERROR, "%s: ftdm_interrupt_wait returned error!\n", span->name);
break;
default:
ftdm_log(FTDM_LOG_ERROR,"%s:ftdm_interrupt_wait returned with unknown code\n", span->name);
ftdm_log(FTDM_LOG_ERROR, "%s: ftdm_interrupt_wait returned with unknown code\n", span->name);
break;
}
@@ -536,7 +528,7 @@ ftdm_channel_t* ftdm_sangoma_isdn_process_event_states(ftdm_span_t *span, sngisd
break;
}
ftdm_channel_lock(ftdmchan);
ftdm_sangoma_isdn_advance_chan_states(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
return ftdmchan;
}
@@ -600,13 +592,14 @@ static void ftdm_sangoma_isdn_process_stack_event (ftdm_span_t *span, sngisdn_ev
sngisdn_process_rst_ind(sngisdn_event);
break;
}
if(ftdmchan != NULL) {
ftdm_sangoma_isdn_advance_chan_states(ftdmchan);
if (ftdmchan != NULL) {
ftdm_channel_advance_states(ftdmchan);
ftdm_channel_unlock(ftdmchan);
}
}
static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
/* this function is called with the channel already locked by the core */
static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
{
ftdm_sigmsg_t sigev;
ftdm_channel_state_t initial_state;
@@ -618,13 +611,12 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
sigev.span_id = ftdmchan->span_id;
sigev.channel = ftdmchan;
/*first lock the channel*/
ftdm_channel_lock(ftdmchan);
/*clear the state change flag...since we might be setting a new state*/
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
/* Acknowledge the state change */
ftdm_channel_complete_state(ftdmchan);
#ifdef FTDM_DEBUG_CHAN_MEMORY
if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ)==0, "Failed to mprotect");
ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ) == 0, "Failed to mprotect");
}
#endif
@@ -879,11 +871,10 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
}
#ifdef FTDM_DEBUG_CHAN_MEMORY
if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ|PROT_WRITE)==0, "Failed to mprotect");
ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ|PROT_WRITE) == 0, "Failed to mprotect");
}
#endif
ftdm_channel_unlock(ftdmchan);
return;
return FTDM_SUCCESS;
}
static FIO_CHANNEL_SEND_MSG_FUNCTION(ftdm_sangoma_isdn_send_msg)
@@ -1098,6 +1089,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config)
span->get_span_sig_status = ftdm_sangoma_isdn_get_span_sig_status;
span->set_span_sig_status = ftdm_sangoma_isdn_set_span_sig_status;
span->state_map = &sangoma_isdn_state_map;
span->state_processor = ftdm_sangoma_isdn_process_state_change;
ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE);
ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
ftdm_set_flag(span, FTDM_SPAN_USE_PROCEED_STATE);
@@ -137,8 +137,9 @@ void sngisdn_trace_raw_q921(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t d
ftdm_assert(raw_data, "Failed to malloc");
memcpy(raw_data, data, data_len);
sigev.raw_data = raw_data;
sigev.raw_data_len = data_len;
sigev.raw.data = raw_data;
sigev.raw.len = data_len;
sigev.raw.autofree = 1;
ftdm_span_send_signal(signal_data->ftdm_span, &sigev);
}
@@ -250,8 +251,9 @@ void sngisdn_trace_raw_q931(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t d
ftdm_assert(raw_data, "Failed to malloc");
memcpy(raw_data, data, data_len);
sigev.raw_data = raw_data;
sigev.raw_data_len = data_len;
sigev.raw.data = raw_data;
sigev.raw.len = data_len;
sigev.raw.autofree = 1;
ftdm_span_send_signal(signal_data->ftdm_span, &sigev);
}
}
@@ -46,7 +46,6 @@ ftdm_sngss7_data_t g_ftdm_sngss7_data;
/* PROTOTYPES *****************************************************************/
static void *ftdm_sangoma_ss7_run (ftdm_thread_t * me, void *obj);
void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan);
static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_event);
static ftdm_status_t ftdm_sangoma_ss7_stop (ftdm_span_t * span);
@@ -308,9 +307,7 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj)
ftdm_mutex_lock(ftdmchan->mutex);
/* process state changes for this channel until they are all done */
while (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_sangoma_ss7_process_state_change (ftdmchan);
}
ftdm_channel_advance_states(ftdmchan);
/* unlock the channel */
ftdm_mutex_unlock (ftdmchan->mutex);
@@ -403,9 +400,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
ftdm_mutex_lock(ftdmchan->mutex);
/* while there's a state change present on this channel process it */
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_sangoma_ss7_process_state_change(ftdmchan);
}
ftdm_channel_advance_states(ftdmchan);
/* figure out the type of event and send it to the right handler */
switch (sngss7_event->event_id) {
@@ -468,9 +463,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
} /* switch (sngss7_event->event_id) */
/* while there's a state change present on this channel process it */
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_sangoma_ss7_process_state_change(ftdmchan);
}
ftdm_channel_advance_states(ftdmchan);
/* unlock the channel */
ftdm_mutex_unlock(ftdmchan->mutex);
@@ -479,7 +472,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
}
/******************************************************************************/
void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
{
sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;
sng_isup_inf_t *isup_intf = NULL;
@@ -495,7 +488,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
SS7_DEBUG_CHAN(ftdmchan, "ftmod_sangoma_ss7 processing state %s\n", ftdm_channel_state2str (ftdmchan->state));
/* clear the state change flag...since we might be setting a new state */
ftdm_clear_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_channel_complete_state(ftdmchan);
/*check what state we are supposed to be in */
switch (ftdmchan->state) {
@@ -1212,7 +1205,7 @@ suspend_goto_restart:
/**************************************************************************/
}/*switch (ftdmchan->state) */
return;
return FTDM_SUCCESS;
}
/******************************************************************************/
@@ -1476,6 +1469,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config)
span->get_channel_sig_status = ftdm_sangoma_ss7_get_sig_status;
span->set_channel_sig_status = ftdm_sangoma_ss7_set_sig_status;
span->state_map = &sangoma_ss7_state_map;
span->state_processor = ftdm_sangoma_ss7_process_state_change;
span->signal_data = ss7_span_info;
/* set the flag to indicate that this span uses channel state change queues */
@@ -452,7 +452,7 @@ extern int cmbLinkSetId;
/* PROTOTYPES *****************************************************************/
/* in ftmod_sangoma_ss7_main.c */
void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan);
ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan);
/* in ftmod_sangoma_ss7_logger.c */
void handle_sng_log(uint8_t level, char *fmt,...);
@@ -100,7 +100,7 @@
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>freetdm.lib;libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
@@ -127,7 +127,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>freetdm.lib;libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\Sangoma\api\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
@@ -148,7 +148,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>freetdm.lib;libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
@@ -174,7 +174,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>freetdm.lib;libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\Sangoma\api\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
@@ -784,17 +784,27 @@ static FIO_COMMAND_FUNCTION(wanpipe_command)
err = sangoma_set_tx_queue_sz(ftdmchan->sockfd, &tdm_api, queue_size);
}
break;
case FTDM_COMMAND_SET_POLARITY:
{
ftdm_polarity_t polarity = FTDM_COMMAND_OBJ_INT;
err = sangoma_tdm_set_polarity(ftdmchan->sockfd, &tdm_api, polarity);
if (!err) {
ftdmchan->polarity = polarity;
}
}
break;
default:
err = FTDM_NOTIMPL;
break;
};
if (err) {
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
int myerrno = errno;
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Wanpipe failed to execute command %d: %s\n", command, strerror(myerrno));
errno = myerrno;
return err;
}
return FTDM_SUCCESS;
}
@@ -1224,6 +1234,131 @@ static FIO_GET_ALARMS_FUNCTION(wanpipe_get_alarms)
return FTDM_SUCCESS;
}
/**
* \brief Process an event in a channel and set it's OOB event id. The channel must be locked.
* \param fchan Channel in which event occured
* \param event_id Pointer where we save the OOB event id
* \param tdm_api Wanpipe tdm struct that contain the event
* \return FTDM_SUCCESS or FTDM_FAIL
*/
static __inline__ ftdm_status_t wanpipe_channel_process_event(ftdm_channel_t *fchan, ftdm_oob_event_t *event_id, wanpipe_tdm_api_t *tdm_api)
{
switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_type) {
case WP_API_EVENT_LINK_STATUS:
{
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;
break;
default:
*event_id = FTDM_OOB_ALARM_TRAP;
break;
};
}
break;
case WP_API_EVENT_RXHOOK:
{
if (fchan->type == FTDM_CHAN_TYPE_FXS) {
*event_id = tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK;
if (*event_id == FTDM_OOB_OFFHOOK) {
if (ftdm_test_flag(fchan, FTDM_CHANNEL_FLASH)) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_FLASH);
ftdm_clear_flag(fchan, FTDM_CHANNEL_WINK);
*event_id = FTDM_OOB_FLASH;
goto event;
} else {
ftdm_set_flag(fchan, FTDM_CHANNEL_WINK);
}
} else {
if (ftdm_test_flag(fchan, FTDM_CHANNEL_WINK)) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_WINK);
ftdm_clear_flag(fchan, FTDM_CHANNEL_FLASH);
*event_id = FTDM_OOB_WINK;
goto event;
} else {
ftdm_set_flag(fchan, FTDM_CHANNEL_FLASH);
}
}
break;
} else {
ftdm_status_t status;
wanpipe_tdm_api_t onhook_tdm_api;
memset(&onhook_tdm_api, 0, sizeof(onhook_tdm_api));
status = sangoma_tdm_txsig_onhook(fchan->sockfd, &onhook_tdm_api);
if (status) {
snprintf(fchan->last_error, sizeof(fchan->last_error), "ONHOOK Failed");
return FTDM_FAIL;
}
*event_id = onhook_tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP;
}
}
break;
case WP_API_EVENT_RING_DETECT:
{
*event_id = tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP;
}
break;
/*
disabled this ones when configuring, we don't need them, do we?
case WP_API_EVENT_RING_TRIP_DETECT:
{
*event_id = tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK;
}
break;
*/
case WP_API_EVENT_RBS:
{
*event_id = FTDM_OOB_CAS_BITS_CHANGE;
fchan->rx_cas_bits = wanpipe_swap_bits(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
}
break;
case WP_API_EVENT_DTMF:
{
char tmp_dtmf[2] = { tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
*event_id = FTDM_OOB_NOOP;
if (tmp_dtmf[0] == 'f') {
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Ignoring wanpipe DTMF: %c, fax tones will be passed through!\n", tmp_dtmf[0]);
break;
}
if (tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
ftdm_set_flag(fchan, FTDM_CHANNEL_MUTE);
}
if (tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_MUTE);
if (ftdm_test_flag(fchan, FTDM_CHANNEL_INUSE)) {
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
ftdm_channel_queue_dtmf(fchan, tmp_dtmf);
}
}
}
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;
}
break;
case WP_API_EVENT_POLARITY_REVERSE:
{
ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "Got polarity reverse\n");
*event_id = FTDM_OOB_POLARITY_REVERSE;
}
break;
default:
{
ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_type);
*event_id = FTDM_OOB_INVALID;
}
break;
}
event:
return FTDM_SUCCESS;
}
/**
* \brief Retrieves an event from a wanpipe channel
* \param channel Channel to retrieve event from
@@ -1237,8 +1372,9 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event)
wanpipe_tdm_api_t tdm_api;
ftdm_span_t *span = ftdmchan->span;
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT))
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) {
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT);
}
memset(&tdm_api, 0, sizeof(tdm_api));
status = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api);
@@ -1249,115 +1385,11 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event)
}
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "read wanpipe event %d\n", 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_TDMAPI_EVENT_LINK_STATUS:
{
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;
break;
default:
event_id = FTDM_OOB_ALARM_TRAP;
break;
};
}
break;
case WP_TDMAPI_EVENT_RXHOOK:
{
if (ftdmchan->type == FTDM_CHAN_TYPE_FXS) {
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK;
if (event_id == FTDM_OOB_OFFHOOK) {
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_FLASH)) {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH);
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK);
event_id = FTDM_OOB_FLASH;
goto event;
} else {
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_WINK);
}
} else {
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK);
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH);
event_id = FTDM_OOB_WINK;
goto event;
} else {
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH);
}
}
break;
} else {
wanpipe_tdm_api_t onhook_tdm_api;
memset(&onhook_tdm_api, 0, sizeof(onhook_tdm_api));
status = sangoma_tdm_txsig_onhook(ftdmchan->sockfd, &onhook_tdm_api);
if (status) {
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ONHOOK Failed");
return FTDM_FAIL;
}
event_id = onhook_tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP;
}
}
break;
case WP_TDMAPI_EVENT_RING_DETECT:
{
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP;
}
break;
/*
disabled this ones when configuring, we don't need them, do we?
case WP_TDMAPI_EVENT_RING_TRIP_DETECT:
{
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK;
}
break;
*/
case WP_TDMAPI_EVENT_RBS:
{
event_id = FTDM_OOB_CAS_BITS_CHANGE;
ftdmchan->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
}
break;
case WP_TDMAPI_EVENT_DTMF:
{
char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
event_id = FTDM_OOB_NOOP;
if (tmp_dtmf[0] == 'f') {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Ignoring wanpipe DTMF: %c, fax tones will be passed through!\n", tmp_dtmf[0]);
break;
}
if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
}
if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
ftdm_channel_queue_dtmf(ftdmchan, tmp_dtmf);
}
}
}
break;
case WP_TDMAPI_EVENT_ALARM:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm);
event_id = FTDM_OOB_ALARM_TRAP;
}
break;
default:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
event_id = FTDM_OOB_INVALID;
}
break;
if ((wanpipe_channel_process_event(ftdmchan, &event_id, &tdm_api)) != FTDM_SUCCESS) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process event from channel\n");
return FTDM_FAIL;
}
event:
ftdmchan->last_event_time = 0;
span->event_header.e_type = FTDM_EVENT_OOB;
span->event_header.enum_id = event_id;
@@ -1419,114 +1451,15 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event)
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
return FTDM_FAIL;
}
ftdm_log_chan(span->channels[i], FTDM_LOG_DEBUG, "read wanpipe event %d\n", 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_TDMAPI_EVENT_LINK_STATUS:
{
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;
break;
default:
event_id = FTDM_OOB_ALARM_TRAP;
break;
};
}
break;
case WP_TDMAPI_EVENT_RXHOOK:
{
if (span->channels[i]->type == FTDM_CHAN_TYPE_FXS) {
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK;
if (event_id == FTDM_OOB_OFFHOOK) {
if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_FLASH)) {
ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
event_id = FTDM_OOB_FLASH;
goto event;
} else {
ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
}
} else {
if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_WINK)) {
ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
event_id = FTDM_OOB_WINK;
goto event;
} else {
ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
}
}
continue;
} else {
int err;
ftdm_channel_t *ftdmchan = span->channels[i];
err=sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
if (err) {
snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "ONHOOK Failed");
return FTDM_FAIL;
}
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP;
}
}
break;
case WP_TDMAPI_EVENT_RING_DETECT:
{
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP;
}
break;
/*
disabled this ones when configuring, we don't need them, do we?
case WP_TDMAPI_EVENT_RING_TRIP_DETECT:
{
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK;
}
break;
*/
case WP_TDMAPI_EVENT_RBS:
{
event_id = FTDM_OOB_CAS_BITS_CHANGE;
span->channels[i]->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
}
break;
case WP_TDMAPI_EVENT_DTMF:
{
char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
event_id = FTDM_OOB_NOOP;
if (tmp_dtmf[0] == 'f') {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Ignoring wanpipe DTMF: %c, fax tones will be passed through!\n", tmp_dtmf[0]);
break;
}
if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
}
if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
ftdm_channel_queue_dtmf(ftdmchan, tmp_dtmf);
}
}
}
break;
case WP_TDMAPI_EVENT_ALARM:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm);
event_id = FTDM_OOB_ALARM_TRAP;
}
break;
default:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
event_id = FTDM_OOB_INVALID;
}
break;
ftdm_channel_lock(ftdmchan);
if ((wanpipe_channel_process_event(ftdmchan, &event_id, &tdm_api)) != FTDM_SUCCESS) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process events from channel\n");
ftdm_channel_unlock(ftdmchan);
return FTDM_FAIL;
}
ftdm_channel_unlock(ftdmchan);
event:
@@ -1538,9 +1471,7 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event)
return FTDM_SUCCESS;
}
}
return FTDM_FAIL;
}
/**
+191 -116
View File
@@ -52,42 +52,48 @@ static struct {
float txgain;
} zt_globals;
#if defined(__FreeBSD__)
typedef unsigned long ioctlcmd;
#else
typedef int ioctlcmd;
#endif
/**
* \brief General IOCTL codes
*/
struct ioctl_codes {
int GET_BLOCKSIZE;
int SET_BLOCKSIZE;
int FLUSH;
int SYNC;
int GET_PARAMS;
int SET_PARAMS;
int HOOK;
int GETEVENT;
int IOMUX;
int SPANSTAT;
int MAINT;
int GETCONF;
int SETCONF;
int CONFLINK;
int CONFDIAG;
int GETGAINS;
int SETGAINS;
int SPANCONFIG;
int CHANCONFIG;
int SET_BUFINFO;
int GET_BUFINFO;
int AUDIOMODE;
int ECHOCANCEL;
int HDLCRAWMODE;
int HDLCFCSMODE;
int SPECIFY;
int SETLAW;
int SETLINEAR;
int GETCONFMUTE;
int ECHOTRAIN;
int SETTXBITS;
int GETRXBITS;
ioctlcmd GET_BLOCKSIZE;
ioctlcmd SET_BLOCKSIZE;
ioctlcmd FLUSH;
ioctlcmd SYNC;
ioctlcmd GET_PARAMS;
ioctlcmd SET_PARAMS;
ioctlcmd HOOK;
ioctlcmd GETEVENT;
ioctlcmd IOMUX;
ioctlcmd SPANSTAT;
ioctlcmd MAINT;
ioctlcmd GETCONF;
ioctlcmd SETCONF;
ioctlcmd CONFLINK;
ioctlcmd CONFDIAG;
ioctlcmd GETGAINS;
ioctlcmd SETGAINS;
ioctlcmd SPANCONFIG;
ioctlcmd CHANCONFIG;
ioctlcmd SET_BUFINFO;
ioctlcmd GET_BUFINFO;
ioctlcmd AUDIOMODE;
ioctlcmd ECHOCANCEL;
ioctlcmd HDLCRAWMODE;
ioctlcmd HDLCFCSMODE;
ioctlcmd SPECIFY;
ioctlcmd SETLAW;
ioctlcmd SETLINEAR;
ioctlcmd GETCONFMUTE;
ioctlcmd ECHOTRAIN;
ioctlcmd SETTXBITS;
ioctlcmd GETRXBITS;
};
/**
@@ -181,6 +187,7 @@ static ftdm_socket_t CONTROL_FD = ZT_INVALID_SOCKET;
FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event);
FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event);
FIO_CHANNEL_NEXT_EVENT_FUNCTION(zt_channel_next_event);
/**
* \brief Initialises codec, and rx/tx gains
@@ -985,6 +992,124 @@ FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event)
return k ? FTDM_SUCCESS : FTDM_FAIL;
}
/**
* \brief Process an event from a ftdmchan and set the proper OOB event_id. The channel must be locked.
* \param fchan Channel to retrieve event from
* \param event_id Pointer to OOB event id
* \param zt_event_id Zaptel event id
* \return FTDM_SUCCESS or FTDM_FAIL
*/
static __inline__ ftdm_status_t zt_channel_process_event(ftdm_channel_t *fchan, ftdm_oob_event_t *event_id, zt_event_t zt_event_id)
{
switch(zt_event_id) {
case ZT_EVENT_RINGEROFF:
{
return FTDM_FAIL;
}
break;
case ZT_EVENT_RINGERON:
{
return FTDM_FAIL;
}
break;
case ZT_EVENT_RINGBEGIN:
{
*event_id = FTDM_OOB_RING_START;
}
break;
case ZT_EVENT_ONHOOK:
{
*event_id = FTDM_OOB_ONHOOK;
}
break;
case ZT_EVENT_WINKFLASH:
{
if (fchan->state == FTDM_CHANNEL_STATE_DOWN || fchan->state == FTDM_CHANNEL_STATE_DIALING) {
*event_id = FTDM_OOB_WINK;
} else {
*event_id = FTDM_OOB_FLASH;
}
}
break;
case ZT_EVENT_RINGOFFHOOK:
{
if (fchan->type == FTDM_CHAN_TYPE_FXS || (fchan->type == FTDM_CHAN_TYPE_EM && fchan->state != FTDM_CHANNEL_STATE_UP)) {
ftdm_set_flag_locked(fchan, FTDM_CHANNEL_OFFHOOK);
*event_id = FTDM_OOB_OFFHOOK;
} else if (fchan->type == FTDM_CHAN_TYPE_FXO) {
*event_id = FTDM_OOB_RING_START;
} else {
*event_id = FTDM_OOB_NOOP;
}
}
break;
case ZT_EVENT_ALARM:
{
*event_id = FTDM_OOB_ALARM_TRAP;
}
break;
case ZT_EVENT_NOALARM:
{
*event_id = FTDM_OOB_ALARM_CLEAR;
}
break;
case ZT_EVENT_BITSCHANGED:
{
*event_id = FTDM_OOB_CAS_BITS_CHANGE;
int bits = 0;
int err = ioctl(fchan->sockfd, codes.GETRXBITS, &bits);
if (err) {
return FTDM_FAIL;
}
fchan->rx_cas_bits = bits;
}
break;
default:
{
ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Unhandled event %d\n", zt_event_id);
*event_id = FTDM_OOB_INVALID;
}
break;
}
return FTDM_SUCCESS;
}
/**
* \brief Retrieves an event from a ftdm channel
* \param ftdmchan Channel to retrieve event from
* \param event FreeTDM event to return
* \return Success or failure
*/
FIO_CHANNEL_NEXT_EVENT_FUNCTION(zt_channel_next_event)
{
uint32_t event_id = FTDM_OOB_INVALID;
zt_event_t zt_event_id = 0;
ftdm_span_t *span = ftdmchan->span;
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) {
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT);
}
if (ioctl(ftdmchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed retrieving event from channel: %s\n",
strerror(errno));
return FTDM_FAIL;
}
/* the core already locked the channel for us, so it's safe to call zt_channel_process_event() here */
if ((zt_channel_process_event(ftdmchan, &event_id, zt_event_id)) != FTDM_SUCCESS) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process event from channel\n");
return FTDM_FAIL;
}
ftdmchan->last_event_time = 0;
span->event_header.e_type = FTDM_EVENT_OOB;
span->event_header.enum_id = event_id;
span->event_header.channel = ftdmchan;
*event = &span->event_header;
return FTDM_SUCCESS;
}
/**
* \brief Retrieves an event from a ftdmtel span
* \param span Span to retrieve event from
@@ -997,91 +1122,29 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
zt_event_t zt_event_id = 0;
for(i = 1; i <= span->chan_count; i++) {
if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
ftdm_clear_flag(span->channels[i], FTDM_CHANNEL_EVENT);
if (ioctl(span->channels[i]->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
return FTDM_FAIL;
}
switch(zt_event_id) {
case ZT_EVENT_RINGEROFF:
{
return FTDM_FAIL;
}
break;
case ZT_EVENT_RINGERON:
{
return FTDM_FAIL;
}
break;
case ZT_EVENT_RINGBEGIN:
{
event_id = FTDM_OOB_RING_START;
}
break;
case ZT_EVENT_ONHOOK:
{
event_id = FTDM_OOB_ONHOOK;
}
break;
case ZT_EVENT_WINKFLASH:
{
if (span->channels[i]->state == FTDM_CHANNEL_STATE_DOWN || span->channels[i]->state == FTDM_CHANNEL_STATE_DIALING) {
event_id = FTDM_OOB_WINK;
} else {
event_id = FTDM_OOB_FLASH;
}
}
break;
case ZT_EVENT_RINGOFFHOOK:
{
if (span->channels[i]->type == FTDM_CHAN_TYPE_FXS || (span->channels[i]->type == FTDM_CHAN_TYPE_EM && span->channels[i]->state != FTDM_CHANNEL_STATE_UP)) {
ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
event_id = FTDM_OOB_OFFHOOK;
} else if (span->channels[i]->type == FTDM_CHAN_TYPE_FXO) {
event_id = FTDM_OOB_RING_START;
} else {
event_id = FTDM_OOB_NOOP;
}
}
break;
case ZT_EVENT_ALARM:
{
event_id = FTDM_OOB_ALARM_TRAP;
}
break;
case ZT_EVENT_NOALARM:
{
event_id = FTDM_OOB_ALARM_CLEAR;
}
break;
case ZT_EVENT_BITSCHANGED:
{
event_id = FTDM_OOB_CAS_BITS_CHANGE;
int bits = 0;
int err = ioctl(span->channels[i]->sockfd, codes.GETRXBITS, &bits);
if (err) {
return FTDM_FAIL;
}
span->channels[i]->rx_cas_bits = bits;
}
break;
default:
{
ftdm_log(FTDM_LOG_WARNING, "Unhandled event %d for %d:%d\n", zt_event_id, span->span_id, i);
event_id = FTDM_OOB_INVALID;
}
break;
}
span->channels[i]->last_event_time = 0;
span->event_header.e_type = FTDM_EVENT_OOB;
span->event_header.enum_id = event_id;
span->event_header.channel = span->channels[i];
*event = &span->event_header;
return FTDM_SUCCESS;
ftdm_channel_t *fchan = span->channels[i];
if (ftdm_test_flag(fchan, FTDM_CHANNEL_EVENT)) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_EVENT);
}
if (ioctl(fchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
return FTDM_FAIL;
}
ftdm_channel_lock(fchan);
if ((zt_channel_process_event(fchan, &event_id, zt_event_id)) != FTDM_SUCCESS) {
ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "Failed to process event from channel\n");
ftdm_channel_unlock(fchan);
return FTDM_FAIL;
}
ftdm_channel_unlock(fchan);
fchan->last_event_time = 0;
span->event_header.e_type = FTDM_EVENT_OOB;
span->event_header.enum_id = event_id;
span->event_header.channel = fchan;
*event = &span->event_header;
return FTDM_SUCCESS;
}
return FTDM_FAIL;
@@ -1146,6 +1209,7 @@ static FIO_WRITE_FUNCTION(zt_write)
bytes += 2;
}
tryagain:
w = write(ftdmchan->sockfd, data, bytes);
if (w >= 0) {
@@ -1153,6 +1217,17 @@ static FIO_WRITE_FUNCTION(zt_write)
return FTDM_SUCCESS;
}
if (errno == ELAST) {
zt_event_t zt_event_id = 0;
if (ioctl(ftdmchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed retrieving event after ELAST on write: %s\n", strerror(errno));
return FTDM_FAIL;
}
/* we should enqueue this event somewhere so it can be retrieved by the user, for now, dropping it to see what it is! */
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dropping event %d to be able to write data\n", zt_event_id);
goto tryagain;
}
return FTDM_FAIL;
}