#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
{
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 */
ftdm_channel_close(&chan);
}
}
+
+done:
return status;
}
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),
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");
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) {
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;
/* 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);
/* 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;
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) {
}
/* 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 */
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);
/* 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) {
/**************************************************************************/
}
+done:
/* while there's a state change present on this channel process it */
ftdm_channel_advance_states(ftdmchan);
}
+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;
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) {
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;
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) {
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);
/* 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,