]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
freetdm: Implement SS7 transparent IAM functionality using the event clones queue
authorMoises Silva <moy@sangoma.com>
Thu, 26 Jan 2012 21:50:38 +0000 (16:50 -0500)
committerMoises Silva <moy@sangoma.com>
Thu, 26 Jan 2012 21:50:38 +0000 (16:50 -0500)
libs/freetdm/mod_freetdm/mod_freetdm.c
libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c
libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h
libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c

index 003be91b17c8d49d8b2f52c50925b54c3c42c23b..204e5a894f505792200012577202c225e66647d6 100755 (executable)
@@ -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);
index ebee2c382ddc0a3b64ea0415a4c31c9bd28e255b..bcb518ff9d50c28ab8198115a8237ea6e477f11b 100644 (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);
index 2a1ca1749e7d11abe61fa4ddff469d9d92537679..2fc6f740c7fdda4bcc850860c7a54b8228410416 100644 (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)
index fbfab15d1e5824c1e842b76ff614bb86fdb587cf..eda03715f3d3d73f00976edcee140a095373f28f 100644 (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 {