freetdm: Initial attempt to bridge natively SS7 signaling between 2 channels

This commit is contained in:
Moises Silva 2012-01-26 22:44:19 -05:00
parent b4e8d5b608
commit 23a328389b
6 changed files with 491 additions and 53 deletions

View File

@ -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;

View File

@ -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,24 +555,60 @@ 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) {
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))) {
SS7_WARN("[CIC:%d]Discarding clone event from past call!\n", sngss7_info->circuit->cic);
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);
/* 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))) {
SS7_WARN("[CIC:%d]Discarding clone event from past call!\n", sngss7_info->circuit->cic);
ftdm_safe_free(event_clone);
}
}
/* while there's a state change present on this channel process it */
ftdm_channel_advance_states(ftdmchan);
/* 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);
}
}
/* 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;

View File

@ -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

View File

@ -58,45 +58,39 @@ 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);
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 {
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);
} else {
sngss7_event_data_t *event_clone = NULL;
peer_info = peer_chan->call_data;
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Starting native bridge with peer CIC %d\n",
sngss7_info->circuit->cic, peer_info->circuit->cic);
/* make each one of us aware of the native bridge */
peer_info->peer_data = sngss7_info;
sngss7_info->peer_data = peer_info;
/* flush our own queue */
while ((event_clone = ftdm_queue_dequeue(sngss7_info->event_queue))) {
SS7_WARN("[CIC:%d]Discarding clone event from past call!\n", sngss7_info->circuit->cic);
ftdm_safe_free(event_clone);
}
sngss7_event_data_t *event_clone = NULL;
peer_info = peer_chan->call_data;
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Starting native bridge with peer CIC %d\n",
sngss7_info->circuit->cic, peer_info->circuit->cic);
/* make each one of us aware of the native bridge */
peer_info->peer_data = sngss7_info;
sngss7_info->peer_data = peer_info;
/* flush our own queue */
while ((event_clone = ftdm_queue_dequeue(sngss7_info->event_queue))) {
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);
@ -322,10 +319,10 @@ void ft_to_sngss7_rel (ftdm_channel_t * ftdmchan)
/* send the REL request to LibSngSS7 */
sng_cc_rel_request (1,
sngss7_info->suInstId,
sngss7_info->spInstId,
sngss7_info->circuit->id,
&rel);
sngss7_info->suInstId,
sngss7_info->spInstId,
sngss7_info->circuit->id,
&rel);
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx REL cause=%d \n",
sngss7_info->circuit->cic,

View File

@ -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
*/

View File

@ -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"