freetdm: Initial attempt to bridge natively SS7 signaling between 2 channels
This commit is contained in:
parent
b4e8d5b608
commit
23a328389b
|
@ -53,8 +53,6 @@ struct tm *localtime_r(const time_t *clock, struct tm *result);
|
|||
#endif
|
||||
|
||||
#define FORCE_HANGUP_TIMER 30000
|
||||
#define SPAN_PENDING_CHANS_QUEUE_SIZE 1000
|
||||
#define SPAN_PENDING_SIGNALS_QUEUE_SIZE 1000
|
||||
#define FTDM_READ_TRACE_INDEX 0
|
||||
#define FTDM_WRITE_TRACE_INDEX 1
|
||||
#define MAX_CALLIDS 6000
|
||||
|
@ -2201,6 +2199,12 @@ static ftdm_status_t _ftdm_channel_call_hangup_nl(const char *file, const char *
|
|||
{
|
||||
ftdm_status_t status = FTDM_SUCCESS;
|
||||
|
||||
if (ftdm_test_flag(chan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) {
|
||||
ftdm_log_chan_ex(chan, file, func, line, FTDM_LOG_LEVEL_DEBUG,
|
||||
"Ignoring hangup in channel in state %s (native bridge enabled)\n", ftdm_channel_state2str(chan->state));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (chan->state != FTDM_CHANNEL_STATE_DOWN) {
|
||||
if (chan->state == FTDM_CHANNEL_STATE_HANGUP) {
|
||||
/* make user's life easier, and just ignore double hangup requests */
|
||||
|
@ -2227,6 +2231,8 @@ static ftdm_status_t _ftdm_channel_call_hangup_nl(const char *file, const char *
|
|||
ftdm_channel_close(&chan);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -2322,6 +2328,15 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch
|
|||
|
||||
ftdm_channel_lock(ftdmchan);
|
||||
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) {
|
||||
ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_DEBUG,
|
||||
"Ignoring indication %s in channel in state %s (native bridge enabled)\n",
|
||||
ftdm_channel_indication2str(indication),
|
||||
ftdm_channel_state2str(ftdmchan->state));
|
||||
status = FTDM_SUCCESS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IND_ACK_PENDING)) {
|
||||
ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "Cannot indicate %s in channel with indication %s still pending in state %s\n",
|
||||
ftdm_channel_indication2str(indication),
|
||||
|
@ -2422,10 +2437,50 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_reset(const char *file, const char *func
|
|||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
FT_DECLARE(ftdm_status_t) ftdm_get_channel_from_string(const char *string_id, ftdm_span_t **out_span, ftdm_channel_t **out_channel)
|
||||
{
|
||||
ftdm_status_t status = FTDM_SUCCESS;
|
||||
int rc = 0;
|
||||
ftdm_span_t *span = NULL;
|
||||
ftdm_channel_t *ftdmchan = NULL;
|
||||
unsigned span_id = 0;
|
||||
unsigned chan_id = 0;
|
||||
|
||||
*out_span = NULL;
|
||||
*out_channel = NULL;
|
||||
|
||||
rc = sscanf(string_id, "%u:%u", &span_id, &chan_id);
|
||||
if (rc != 2) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Failed to parse channel id string '%s'\n", string_id);
|
||||
status = FTDM_EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = ftdm_span_find(span_id, &span);
|
||||
if (status != FTDM_SUCCESS || !span) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Failed to find span for channel id string '%s'\n", string_id);
|
||||
status = FTDM_EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (chan_id > (FTDM_MAX_CHANNELS_SPAN+1) || !(ftdmchan = span->channels[chan_id])) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Invalid channel id string '%s'\n", string_id);
|
||||
status = FTDM_EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = FTDM_SUCCESS;
|
||||
*out_span = span;
|
||||
*out_channel = ftdmchan;
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
/* this function MUST be called with the channel lock held with lock recursivity of 1 exactly,
|
||||
* and the caller must be aware we might unlock the channel for a brief period of time and then lock it again */
|
||||
static ftdm_status_t _ftdm_channel_call_place_nl(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_usrmsg_t *usrmsg)
|
||||
{
|
||||
const char *var = NULL;
|
||||
ftdm_status_t status = FTDM_FAIL;
|
||||
|
||||
ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "null channel");
|
||||
|
@ -2461,6 +2516,17 @@ static ftdm_status_t _ftdm_channel_call_place_nl(const char *file, const char *f
|
|||
|
||||
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED);
|
||||
ftdm_call_set_call_id(ftdmchan, &ftdmchan->caller_data);
|
||||
var = ftdm_usrmsg_get_var(usrmsg, "sigbridge_peer");
|
||||
if (var) {
|
||||
ftdm_span_t *peer_span = NULL;
|
||||
ftdm_channel_t *peer_chan = NULL;
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "enabling native signaling bridge!\n");
|
||||
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE);
|
||||
ftdm_get_channel_from_string(var, &peer_span, &peer_chan);
|
||||
if (peer_chan) {
|
||||
ftdm_set_flag(peer_chan, FTDM_CHANNEL_NATIVE_SIGBRIDGE);
|
||||
}
|
||||
}
|
||||
|
||||
/* if the signaling stack left the channel in state down on success, is expecting us to move to DIALING */
|
||||
if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN) {
|
||||
|
@ -2662,6 +2728,7 @@ static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan)
|
|||
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_ANSWERED);
|
||||
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_USER_HANGUP);
|
||||
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_DIGITAL_MEDIA);
|
||||
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE);
|
||||
ftdm_mutex_lock(ftdmchan->pre_buffer_mutex);
|
||||
ftdm_buffer_destroy(&ftdmchan->pre_buffer);
|
||||
ftdmchan->pre_buffer_size = 0;
|
||||
|
|
|
@ -55,6 +55,7 @@ ftdm_sngss7_data_t g_ftdm_sngss7_data;
|
|||
/* PROTOTYPES *****************************************************************/
|
||||
static void *ftdm_sangoma_ss7_run (ftdm_thread_t * me, void *obj);
|
||||
static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_event);
|
||||
static void ftdm_sangoma_ss7_process_peer_stack_event (ftdm_channel_t *ftdmchan, sngss7_event_data_t *sngss7_event);
|
||||
|
||||
static ftdm_status_t ftdm_sangoma_ss7_stop (ftdm_span_t * span);
|
||||
static ftdm_status_t ftdm_sangoma_ss7_start (ftdm_span_t * span);
|
||||
|
@ -338,9 +339,10 @@ static void handle_hw_alarm(ftdm_event_t *e)
|
|||
/* MONITIOR THREADS ***********************************************************/
|
||||
static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj)
|
||||
{
|
||||
ftdm_interrupt_t *ftdm_sangoma_ss7_int[2];
|
||||
ftdm_interrupt_t *ftdm_sangoma_ss7_int[3];
|
||||
ftdm_span_t *ftdmspan = (ftdm_span_t *) obj;
|
||||
ftdm_channel_t *ftdmchan = NULL;
|
||||
ftdm_channel_t *peerchan = NULL;
|
||||
ftdm_event_t *event = NULL;
|
||||
sngss7_event_data_t *sngss7_event = NULL;
|
||||
sngss7_span_data_t *sngss7_span = (sngss7_span_data_t *)ftdmspan->signal_data;
|
||||
|
@ -365,6 +367,12 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj)
|
|||
goto ftdm_sangoma_ss7_run_exit;
|
||||
}
|
||||
|
||||
/* get an interrupt queue for this span for peer channel events */
|
||||
if (ftdm_queue_get_interrupt (sngss7_span->peer_chans, &ftdm_sangoma_ss7_int[2]) != FTDM_SUCCESS) {
|
||||
SS7_CRITICAL ("Failed to get a ftdm_interrupt for span = %d for peer channel events queue!\n", ftdmspan->span_id);
|
||||
goto ftdm_sangoma_ss7_run_exit;
|
||||
}
|
||||
|
||||
while (ftdm_running () && !(ftdm_test_flag (ftdmspan, FTDM_SPAN_STOP_THREAD))) {
|
||||
int x = 0;
|
||||
if (b_alarm_test) {
|
||||
|
@ -395,7 +403,7 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj)
|
|||
}
|
||||
|
||||
/* check the channel state queue for an event*/
|
||||
switch ((ftdm_interrupt_multiple_wait(ftdm_sangoma_ss7_int, 2, 100))) {
|
||||
switch ((ftdm_interrupt_multiple_wait(ftdm_sangoma_ss7_int, ftdm_array_len(ftdm_sangoma_ss7_int), 100))) {
|
||||
/**********************************************************************/
|
||||
case FTDM_SUCCESS: /* process all pending state changes */
|
||||
|
||||
|
@ -412,6 +420,31 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj)
|
|||
ftdm_mutex_unlock (ftdmchan->mutex);
|
||||
}
|
||||
|
||||
/* clean out all peer pending channel events */
|
||||
while ((peerchan = ftdm_queue_dequeue (sngss7_span->peer_chans))) {
|
||||
/* note that the channels being dequeued here may not belong to this span
|
||||
they may belong to just about any other span that one of our channels
|
||||
happens to be bridged to */
|
||||
sngss7_chan_data_t *peer_info = peerchan->call_data;
|
||||
sngss7_chan_data_t *chan_info = peer_info->peer_data;
|
||||
ftdmchan = chan_info->ftdmchan;
|
||||
|
||||
/*
|
||||
if there is any state changes at all, those will be done in the opposite channel
|
||||
to peerchan (where the original event was received), therefore we must lock ftdmchan,
|
||||
but do not need to lock peerchan as we only read its event queue, which is already
|
||||
locked when dequeueing */
|
||||
ftdm_channel_lock(ftdmchan);
|
||||
|
||||
/* clean out all pending stack events in the peer channel */
|
||||
while ((sngss7_event = ftdm_queue_dequeue(peer_info->event_queue))) {
|
||||
ftdm_sangoma_ss7_process_peer_stack_event(ftdmchan, sngss7_event);
|
||||
ftdm_safe_free(sngss7_event);
|
||||
}
|
||||
|
||||
ftdm_channel_lock(ftdmchan);
|
||||
}
|
||||
|
||||
/* clean out all pending stack events */
|
||||
while ((sngss7_event = ftdm_queue_dequeue(sngss7_span->event_queue))) {
|
||||
ftdm_sangoma_ss7_process_stack_event(sngss7_event);
|
||||
|
@ -522,7 +555,9 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
|
|||
/* now that we have the right channel ... put a lock on it so no-one else can use it */
|
||||
ftdm_channel_lock(ftdmchan);
|
||||
|
||||
if (sngss7_info->event_queue) {
|
||||
/* while there's a state change present on this channel process it */
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
|
||||
if (sngss7_event->event_id == SNGSS7_CON_IND_EVENT) {
|
||||
/* this is the first event in a call, flush the event queue */
|
||||
while ((event_clone = ftdm_queue_dequeue(sngss7_info->event_queue))) {
|
||||
|
@ -530,16 +565,50 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
|
|||
ftdm_safe_free(event_clone);
|
||||
}
|
||||
}
|
||||
|
||||
/* clone the event and save it for later usage */
|
||||
event_clone = ftdm_calloc(1, sizeof(*sngss7_event));
|
||||
if (event_clone) {
|
||||
memcpy(event_clone, sngss7_event, sizeof(*sngss7_event));
|
||||
ftdm_queue_enqueue(sngss7_info->event_queue, event_clone);
|
||||
if (sngss7_info->peer_data) {
|
||||
sngss7_span_data_t *sngss7_peer_span = (sngss7_span_data_t *)sngss7_info->peer_data->ftdmchan->span->signal_data;
|
||||
/* we already have a peer attached, wake him up */
|
||||
ftdm_queue_enqueue(sngss7_peer_span->peer_chans, sngss7_info->ftdmchan);
|
||||
}
|
||||
}
|
||||
|
||||
/* while there's a state change present on this channel process it */
|
||||
/* we could test for sngss7_info->peer_data too, bit this flag is set earlier, the earlier we know the better */
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) {
|
||||
/* most messages are simply relayed in sig bridge mode, except for hangup which requires state changing */
|
||||
switch (sngss7_event->event_id) {
|
||||
case SNGSS7_REL_IND_EVENT:
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
|
||||
break;
|
||||
case SNGSS7_REL_CFM_EVENT:
|
||||
{
|
||||
ftdm_channel_t *peer_chan = sngss7_info->peer_data->ftdmchan;
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
|
||||
if (peer_chan) {
|
||||
/* we need to unlock our chan or we risk deadlock */
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
ftdm_channel_unlock(ftdmchan);
|
||||
|
||||
ftdm_channel_lock(peer_chan);
|
||||
if (peer_chan->state != FTDM_CHANNEL_STATE_DOWN) {
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
|
||||
}
|
||||
ftdm_channel_unlock(peer_chan);
|
||||
|
||||
ftdm_channel_lock(ftdmchan);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* figure out the type of event and send it to the right handler */
|
||||
switch (sngss7_event->event_id) {
|
||||
|
@ -602,6 +671,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
|
|||
/**************************************************************************/
|
||||
}
|
||||
|
||||
done:
|
||||
/* while there's a state change present on this channel process it */
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
|
||||
|
@ -610,8 +680,290 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
|
|||
|
||||
}
|
||||
|
||||
FTDM_ENUM_NAMES(SNG_EVENT_TYPE_NAMES, SNG_EVENT_TYPE_STRINGS)
|
||||
FTDM_STR2ENUM(ftdm_str2sngss7_event, ftdm_sngss7_event2str, sng_event_type_t, SNG_EVENT_TYPE_NAMES, SNGSS7_INVALID_EVENT)
|
||||
static void ftdm_sangoma_ss7_process_peer_stack_event (ftdm_channel_t *ftdmchan, sngss7_event_data_t *sngss7_event)
|
||||
{
|
||||
sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;
|
||||
|
||||
if (ftdmchan->state < FTDM_CHANNEL_STATE_UP) {
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP);
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
}
|
||||
|
||||
SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]Relaying message %s from bridged peer\n",
|
||||
sngss7_info->circuit->cic, ftdm_sngss7_event2str(sngss7_event->event_id));
|
||||
|
||||
switch (sngss7_event->event_id) {
|
||||
|
||||
case (SNGSS7_CON_IND_EVENT):
|
||||
SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]Rx IAM (bridged)??\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
|
||||
case (SNGSS7_CON_CFM_EVENT):
|
||||
/* send the ANM request to LibSngSS7 */
|
||||
sng_cc_con_response(1,
|
||||
sngss7_info->suInstId,
|
||||
sngss7_info->spInstId,
|
||||
sngss7_info->circuit->id,
|
||||
&sngss7_event->event.siConEvnt,
|
||||
5);
|
||||
|
||||
SS7_INFO_CHAN(ftdmchan, "[CIC:%d]Tx peer ANM\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
|
||||
case (SNGSS7_CON_STA_EVENT):
|
||||
switch (sngss7_event->evntType) {
|
||||
/**************************************************************************/
|
||||
case (ADDRCMPLT):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer ACM\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (MODIFY):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer MODIFY\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (MODCMPLT):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer MODIFY-COMPLETE\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (MODREJ):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer MODIFY-REJECT\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (PROGRESS):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CPG\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (FRWDTRSFR):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer FOT\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (INFORMATION):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer INF\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (INFORMATREQ):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer INR\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (SUBSADDR):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer SAM\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (EXIT):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer EXIT\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (NETRESMGT):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer NRM\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (IDENTREQ):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer IDR\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (IDENTRSP):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer IRS\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (MALCLLPRNT):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer MALICIOUS CALL\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (CHARGE):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CRG\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (TRFFCHGE):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CRG-TARIFF\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (CHARGEACK):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CRG-ACK\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (CALLOFFMSG):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CALL-OFFER\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (LOOPPRVNT):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer LOP\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (TECT_TIMEOUT):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer ECT-Timeout\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (RINGSEND):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer RINGING-SEND\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (CALLCLEAR):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CALL-LINE Clear\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (PRERELEASE):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer PRI\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (APPTRANSPORT):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer APM\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (OPERATOR):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer OPERATOR\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (METPULSE):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer METERING-PULSE\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (CLGPTCLR):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CALLING_PARTY_CLEAR\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (SUBDIRNUM):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer SUB-DIR\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
#ifdef SANGOMA_SPIROU
|
||||
case (CHARGE_ACK):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer TXA\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
case (CHARGE_UNIT):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer ITX\n", sngss7_info->circuit->cic);
|
||||
break;
|
||||
#endif
|
||||
/**************************************************************************/
|
||||
default:
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer Unknown Msg %d\n", sngss7_info->circuit->cic, sngss7_event->evntType);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
}
|
||||
sng_cc_con_status (1,
|
||||
sngss7_info->suInstId,
|
||||
sngss7_info->spInstId,
|
||||
sngss7_info->circuit->id,
|
||||
&sngss7_event->event.siCnStEvnt,
|
||||
sngss7_event->evntType);
|
||||
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (SNGSS7_REL_IND_EVENT):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer REL cause=%d\n", sngss7_info->circuit->cic, sngss7_event->event.siRelEvnt.causeDgn.causeVal.val);
|
||||
|
||||
//handle_rel_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siRelEvnt);
|
||||
sng_cc_rel_request (1,
|
||||
sngss7_info->suInstId,
|
||||
sngss7_info->spInstId,
|
||||
sngss7_info->circuit->id,
|
||||
&sngss7_event->event.siRelEvnt);
|
||||
break;
|
||||
|
||||
/**************************************************************************/
|
||||
case (SNGSS7_REL_CFM_EVENT):
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer RLC\n", sngss7_info->circuit->cic);
|
||||
sng_cc_rel_response (1,
|
||||
sngss7_info->suInstId,
|
||||
sngss7_info->spInstId,
|
||||
sngss7_info->circuit->id,
|
||||
&sngss7_event->event.siRelEvnt);
|
||||
//handle_rel_cfm(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siRelEvnt);
|
||||
break;
|
||||
|
||||
/**************************************************************************/
|
||||
case (SNGSS7_DAT_IND_EVENT):
|
||||
//handle_dat_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siInfoEvnt);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (SNGSS7_FAC_IND_EVENT):
|
||||
//handle_fac_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, sngss7_event->evntType, &sngss7_event->event.siFacEvnt);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (SNGSS7_FAC_CFM_EVENT):
|
||||
//handle_fac_cfm(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, sngss7_event->evntType, &sngss7_event->event.siFacEvnt);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (SNGSS7_UMSG_IND_EVENT):
|
||||
//handle_umsg_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (SNGSS7_STA_IND_EVENT):
|
||||
//handle_sta_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, sngss7_event->globalFlg, sngss7_event->evntType, &sngss7_event->event.siStaEvnt);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (SNGSS7_SUSP_IND_EVENT):
|
||||
//handle_susp_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siSuspEvnt);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (SNGSS7_RESM_IND_EVENT):
|
||||
//handle_resm_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siResmEvnt);
|
||||
break;
|
||||
/**************************************************************************/
|
||||
case (SNGSS7_SSP_STA_CFM_EVENT):
|
||||
SS7_ERROR("dazed and confused ... hu?!\n");
|
||||
break;
|
||||
/**************************************************************************/
|
||||
default:
|
||||
SS7_ERROR("Unknown Event Id!\n");
|
||||
break;
|
||||
/**************************************************************************/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t *ftdmchan);
|
||||
static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t *ftdmchan)
|
||||
{
|
||||
sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;
|
||||
|
||||
ftdm_channel_complete_state(ftdmchan);
|
||||
|
||||
switch (ftdmchan->state) {
|
||||
|
||||
case FTDM_CHANNEL_STATE_DOWN:
|
||||
{
|
||||
/* both peers come here after the channel processing the RLC moves the pair to DOWN */
|
||||
ftdm_channel_t *close_chan = ftdmchan;
|
||||
|
||||
/* detach native bridging if needed (only the outbound leg is responsible for that to avoid races or messy locks) */
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
|
||||
sngss7_chan_data_t *peer_info = sngss7_info->peer_data;
|
||||
sngss7_info->peer_data = NULL;
|
||||
if (peer_info) {
|
||||
peer_info->peer_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* close the channel */
|
||||
ftdm_channel_close (&close_chan);
|
||||
}
|
||||
break;
|
||||
|
||||
case FTDM_CHANNEL_STATE_UP:
|
||||
{
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
|
||||
sngss7_send_signal(sngss7_info, FTDM_SIGEVENT_UP);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FTDM_CHANNEL_STATE_TERMINATING:
|
||||
{
|
||||
/* when receiving REL we move to TERMINATING and notify the user that the bridge is ending */
|
||||
sngss7_send_signal(sngss7_info, FTDM_SIGEVENT_STOP);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
ftdm_status_t 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;
|
||||
|
@ -623,6 +975,9 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
|
|||
sngss7_info->ckt_flags,
|
||||
sngss7_info->blk_flags);
|
||||
|
||||
if (sngss7_info->peer_data) {
|
||||
return ftdm_sangoma_ss7_native_bridge_state_change(ftdmchan);
|
||||
}
|
||||
|
||||
/*check what state we are supposed to be in */
|
||||
switch (ftdmchan->state) {
|
||||
|
@ -1940,6 +2295,12 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config)
|
|||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
/* create an peer channel queue for this span */
|
||||
if ((ftdm_queue_create(&(ss7_span_info)->peer_chans, SPAN_PENDING_CHANS_QUEUE_SIZE)) != FTDM_SUCCESS) {
|
||||
SS7_CRITICAL("Unable to create peer chans queue!\n");
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
/*setup the span structure with the info so far */
|
||||
g_ftdm_sngss7_data.sig_cb = sig_cb;
|
||||
span->start = ftdm_sangoma_ss7_start;
|
||||
|
|
|
@ -81,8 +81,12 @@ typedef enum {
|
|||
SNGSS7_STA_IND_EVENT,
|
||||
SNGSS7_SUSP_IND_EVENT,
|
||||
SNGSS7_RESM_IND_EVENT,
|
||||
SNGSS7_SSP_STA_CFM_EVENT
|
||||
SNGSS7_SSP_STA_CFM_EVENT,
|
||||
SNGSS7_INVALID_EVENT,
|
||||
} sng_event_type_t;
|
||||
#define SNG_EVENT_TYPE_STRINGS "CON_IND", "CON_CFM", "CON_STA", "REL_IND", "REL_CFM", "DAT_IND", "FAC_IND", \
|
||||
"FAC_CFM", "UMSG_IND", "STA_IND", "SUSP_IND", "RESM_IND", "SSP_STA_CFM", "INVALID"
|
||||
FTDM_STR2ENUM_P(ftdm_str2sngss7_event, ftdm_sngss7_event2str, sng_event_type_t)
|
||||
|
||||
typedef enum {
|
||||
SNG_BIT_A = (1 << 0),
|
||||
|
@ -500,6 +504,7 @@ typedef struct sngss7_span_data {
|
|||
sngss7_group_data_t rx_cgu;
|
||||
sngss7_group_data_t tx_cgu;
|
||||
ftdm_queue_t *event_queue;
|
||||
ftdm_queue_t *peer_chans;
|
||||
} sngss7_span_data_t;
|
||||
|
||||
typedef struct sngss7_event_data
|
||||
|
|
|
@ -58,26 +58,17 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
|
|||
|
||||
var = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "sigbridge_peer");
|
||||
if (!ftdm_strlen_zero(var)) {
|
||||
ftdm_status_t status = FTDM_SUCCESS;
|
||||
int rc = 0;
|
||||
ftdm_span_t *peer_span = NULL;
|
||||
ftdm_channel_t *peer_chan = NULL;
|
||||
sngss7_chan_data_t *peer_info = NULL;
|
||||
unsigned peer_span_id = 0;
|
||||
unsigned peer_chan_id = 0;
|
||||
rc = sscanf(var, "%u:%u", &peer_span_id, &peer_chan_id);
|
||||
if (rc != 2) {
|
||||
SS7_ERROR_CHAN(ftdmchan, "Failed to parse sigbridge_peer string '%s'\n", var);
|
||||
|
||||
ftdm_get_channel_from_string(var, &peer_span, &peer_chan);
|
||||
if (!peer_chan) {
|
||||
SS7_ERROR_CHAN(ftdmchan, "Failed to find sigbridge peer from string '%s'\n", var);
|
||||
} else {
|
||||
status = ftdm_span_find(peer_span_id, &peer_span);
|
||||
if (status != FTDM_SUCCESS || !peer_span) {
|
||||
SS7_ERROR_CHAN(ftdmchan, "Failed to find peer span for channel id '%u:%u'\n", peer_span_id, peer_chan_id);
|
||||
} else if (peer_span->signal_type != FTDM_SIGTYPE_SS7) {
|
||||
SS7_ERROR_CHAN(ftdmchan, "Peer channel %d:%d has different signaling type %d'\n",
|
||||
peer_span_id, peer_chan_id, peer_span->signal_type);
|
||||
} else {
|
||||
if (peer_chan_id > (FTDM_MAX_CHANNELS_SPAN+1) || !(peer_chan = peer_span->channels[peer_chan_id])) {
|
||||
SS7_ERROR_CHAN(ftdmchan, "Invalid peer channel id '%u:%u'\n", peer_span_id, peer_chan_id);
|
||||
if (peer_span->signal_type != FTDM_SIGTYPE_SS7) {
|
||||
SS7_ERROR_CHAN(ftdmchan, "Peer channel '%s' has different signaling type %d'\n",
|
||||
var, peer_span->signal_type);
|
||||
} else {
|
||||
sngss7_event_data_t *event_clone = NULL;
|
||||
peer_info = peer_chan->call_data;
|
||||
|
@ -91,12 +82,15 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
|
|||
SS7_WARN("[CIC:%d]Discarding clone event from past call!\n", sngss7_info->circuit->cic);
|
||||
ftdm_safe_free(event_clone);
|
||||
}
|
||||
}
|
||||
/* go up until release comes, note that state processing is done different and much simpler when there is a peer */
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP);
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sngss7_info->peer_data) {
|
||||
sngss7_span_data_t *span_data = ftdmchan->span->signal_data;
|
||||
sngss7_event_data_t *event_clone = ftdm_queue_dequeue(sngss7_info->peer_data->event_queue);
|
||||
/* Retrieve IAM from our peer */
|
||||
if (!event_clone) {
|
||||
|
@ -108,6 +102,9 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
|
|||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged)\n", sngss7_info->circuit->cic);
|
||||
memcpy(&iam, &event_clone->event.siConEvnt, sizeof(iam));
|
||||
}
|
||||
/* since this is the first time we dequeue an event from the peer, make sure our main thread process any other events,
|
||||
this will trigger the interrupt in our span peer_chans queue which will wake up our main thread if it is sleeping */
|
||||
ftdm_queue_enqueue(span_data->peer_chans, sngss7_info->peer_data->ftdmchan);
|
||||
} else if (sngss7_info->circuit->transparent_iam &&
|
||||
sngss7_retrieve_iam(ftdmchan, &iam) == FTDM_SUCCESS) {
|
||||
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Transparent)\n", sngss7_info->circuit->cic);
|
||||
|
|
|
@ -130,6 +130,9 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SPAN_PENDING_CHANS_QUEUE_SIZE 1000
|
||||
#define SPAN_PENDING_SIGNALS_QUEUE_SIZE 1000
|
||||
|
||||
#define GOTO_STATUS(label,st) status = st; goto label ;
|
||||
|
||||
#define ftdm_copy_string(x,y,z) strncpy(x, y, z - 1)
|
||||
|
@ -686,6 +689,9 @@ FT_DECLARE(ftdm_status_t) ftdm_sigmsg_remove_var(ftdm_sigmsg_t *sigmsg, const ch
|
|||
*/
|
||||
FT_DECLARE(ftdm_status_t) ftdm_sigmsg_set_raw_data(ftdm_sigmsg_t *sigmsg, void *data, ftdm_size_t datalen);
|
||||
|
||||
/*! \brief Retrieve a span and channel data structure from a string in the format 'span_id:chan_id'*/
|
||||
FT_DECLARE(ftdm_status_t) ftdm_get_channel_from_string(const char *string_id, ftdm_span_t **out_span, ftdm_channel_t **out_channel);
|
||||
|
||||
/*!
|
||||
\brief Assert condition
|
||||
*/
|
||||
|
|
|
@ -265,6 +265,8 @@ typedef enum {
|
|||
#define FTDM_CHANNEL_BLOCKING (1ULL << 35)
|
||||
/*!< Media is digital */
|
||||
#define FTDM_CHANNEL_DIGITAL_MEDIA (1ULL << 36)
|
||||
/*!< Native signaling bridge is enabled */
|
||||
#define FTDM_CHANNEL_NATIVE_SIGBRIDGE (1ULL << 37)
|
||||
|
||||
#include "ftdm_state.h"
|
||||
|
||||
|
|
Loading…
Reference in New Issue