diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 8b179ccf05..6ebe5fc161 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -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; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 96b662bdbb..dddb0b2bef 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -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; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 2fc6f740c7..7404a8e55d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -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 diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index eda03715f3..96ec5afae9 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -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, diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index f27be789e2..4150480297 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -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 */ diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h index 6df25fe4d2..17e273c425 100755 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -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"