]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
freetdm: Initial attempt to bridge natively SS7 signaling between 2 channels
authorMoises Silva <moy@sangoma.com>
Fri, 27 Jan 2012 03:44:19 +0000 (22:44 -0500)
committerMoises Silva <moy@sangoma.com>
Fri, 27 Jan 2012 03:44:19 +0000 (22:44 -0500)
libs/freetdm/src/ftdm_io.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
libs/freetdm/src/include/private/ftdm_core.h
libs/freetdm/src/include/private/ftdm_types.h

index 8b179ccf055c0205587fec36d4aff7f9bf0785a3..6ebe5fc1619a33b5321d51a65c65e4478a708715 100644 (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;
index 96b662bdbbfde374df2f6ac481bea728b66ed675..dddb0b2bef3ffaa934992b1a323607bd66ebab0d 100644 (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);
-                       }
+       /* 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);
                }
-               /* 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);
+       }
+
+       /* 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);
 
-       /* while there's a state change present on this channel process it */
-       ftdm_channel_advance_states(ftdmchan);
+                                       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;
index 2fc6f740c7fdda4bcc850860c7a54b8228410416..7404a8e55d2d4095de3bc4c33a6b3cbf30088949 100644 (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
index eda03715f3d3d73f00976edcee140a095373f28f..96ec5afae9f65b00cc2f8668c92b0fbaa21f7066 100644 (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,
index f27be789e2c36661d919d071da3c3443d19e1207..41504802978c04f03fef8d2e4fbb38f03253dea7 100644 (file)
 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
 */
index 6df25fe4d2c0e70d318df2d72f765a2ef73fb845..17e273c425b41dac51a49bd0dda5ccc055d8083e 100755 (executable)
@@ -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"