freetdm: Implement SS7 transparent IAM functionality using the event clones queue

This commit is contained in:
Moises Silva 2012-01-26 16:50:38 -05:00
parent 1b964054de
commit a1a1af579b
4 changed files with 86 additions and 2 deletions

View File

@ -1603,6 +1603,23 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
hunt_data.tech_pvt = tech_pvt;
caller_data.priv = &hunt_data;
if (session
&& (var = channel_get_variable(session, var_event, FREETDM_VAR_PREFIX "native_sigbridge"))
&& switch_true(var)
&& switch_core_session_compare(*new_session, session)) {
char sigbridge_peer[255];
private_t *peer_pvt = switch_core_session_get_private(session);
switch_channel_t *peer_chan = switch_core_session_get_channel(session);
switch_channel_t *our_chan = switch_core_session_get_channel(*new_session);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT,
"Bridging native signaling of channel %s to channel %s\n",
switch_channel_get_name(peer_chan), switch_channel_get_name(our_chan));
snprintf(sigbridge_peer, sizeof(sigbridge_peer), "%u:%u",
ftdm_channel_get_span_id(peer_pvt->ftdmchan), ftdm_channel_get_id(peer_pvt->ftdmchan));
ftdm_usrmsg_add_var(&usrmsg, "sigbridge_peer", sigbridge_peer);
}
if ((status = ftdm_call_place_ex(&caller_data, &hunting, &usrmsg)) != FTDM_SUCCESS) {
if (tech_pvt->read_codec.implementation) {
switch_core_codec_destroy(&tech_pvt->read_codec);

View File

@ -526,7 +526,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
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("Discarding clone event from past call for circuit = %d!\n", sngss7_event->circuit);
SS7_WARN("[CIC:%d]Discarding clone event from past call!\n", sngss7_info->circuit->cic);
ftdm_safe_free(event_clone);
}
}
@ -1076,6 +1076,19 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
if (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_OPEN)) {
ftdm_channel_t *close_chan = ftdmchan;
/* detach native bridging if needed (only the outbound leg is responsible for that)
Inbound leg was responsible of flushing its queue of events, but peer attach/detach
is left as an outbound leg responsibility
*/
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 */
SS7_DEBUG_CHAN(ftdmchan,"FTDM Channel Close %s\n", "");
ftdm_channel_close (&close_chan);

View File

@ -486,6 +486,7 @@ typedef struct sngss7_chan_data {
sngss7_group_data_t tx_grs;
sngss7_group_data_t ucic;
ftdm_queue_t *event_queue;
struct sngss7_chan_data *peer_data;
} sngss7_chan_data_t;
#define SNGSS7_RX_GRS_PENDING (1 << 0)

View File

@ -44,6 +44,7 @@
/* FUNCTIONS ******************************************************************/
void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
{
const char *var = NULL;
SiConEvnt iam;
sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;;
@ -55,7 +56,59 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
memset (&iam, 0x0, sizeof (iam));
if (sngss7_info->circuit->transparent_iam &&
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);
} 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);
} 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);
}
}
}
}
}
if (sngss7_info->peer_data) {
sngss7_event_data_t *event_clone = ftdm_queue_dequeue(sngss7_info->peer_data->event_queue);
/* Retrieve IAM from our peer */
if (!event_clone) {
SS7_ERROR_CHAN(ftdmchan, "No event clone in peer queue!%s\n", "");
} else if (event_clone->event_id != SNGSS7_CON_IND_EVENT) {
/* first message in the queue should ALWAYS be an IAM */
SS7_ERROR_CHAN(ftdmchan, "Invalid initial peer message type '%d'\n", event_clone->event_id);
} else {
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged)\n", sngss7_info->circuit->cic);
memcpy(&iam, &event_clone->event.siConEvnt, sizeof(iam));
}
} 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);
} else {