* Anthony Minessale II <anthm@freeswitch.org>
* Moises Silva <moy@sangoma.com>
* David Yat Sin <dyatsin@sangoma.com>
+ * James Zhang <jzhang@sangoma.com>
*
*
* mod_freetdm.c -- FreeTDM Endpoint Module
ftdm_set_string(caller_data.loc.digits, sipvar);
}
+ sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-LOC-Screen");
+ if (sipvar) {
+ ftdm_usrmsg_add_var(&usrmsg, "ss7_loc_screen_ind", sipvar);
+ }
+
+ sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-LOC-Presentation");
+ if (sipvar) {
+ ftdm_usrmsg_add_var(&usrmsg, "ss7_loc_pres_ind", sipvar);
+ }
+
+ sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-LOC-NADI");
+ if (sipvar) {
+ ftdm_usrmsg_add_var(&usrmsg, "ss7_loc_nadi", sipvar);
+ }
+
sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-DNIS-TON");
if (sipvar) {
caller_data.dnis.type = (uint8_t)atoi(sipvar);
if (sipvar) {
ftdm_usrmsg_add_var(&usrmsg, "ss7_rdinfo_reason", sipvar);
}
+
+ sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-OCN");
+ if (sipvar) {
+ ftdm_usrmsg_add_var(&usrmsg, "ss7_ocn", sipvar);
+ }
+ sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-OCN-NADI");
+ if (sipvar) {
+ ftdm_usrmsg_add_var(&usrmsg, "ss7_ocn_nadi", sipvar);
+ }
+ sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-OCN-Plan");
+ if (sipvar) {
+ ftdm_usrmsg_add_var(&usrmsg, "ss7_ocn_plan", sipvar);
+ }
+ sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-OCN-Presentation");
+ if (sipvar) {
+ ftdm_usrmsg_add_var(&usrmsg, "ss7_ocn_pres", sipvar);
+ }
}
if (switch_test_flag(outbound_profile, SWITCH_CPF_SCREEN)) {
our_chan = switch_core_session_get_channel(*new_session);
+ /* Figure out if there is a native bridge requested through SIP x headers */
if (network_peer_uuid) {
switch_core_session_t *network_peer = switch_core_session_locate(network_peer_uuid);
if (network_peer) {
const char *my_uuid = switch_core_session_get_uuid(*new_session);
private_t *peer_private = switch_core_session_get_private(network_peer);
+ peer_chan = switch_core_session_get_channel(network_peer);
switch_set_string(tech_pvt->network_peer_uuid, network_peer_uuid);
switch_set_string(peer_private->network_peer_uuid, my_uuid);
ftdm_channel_get_span_id(peer_private->ftdmchan), ftdm_channel_get_id(peer_private->ftdmchan));
switch_core_session_rwunlock(network_peer);
}
+
+ /* Figure out if there is a native bridge requested through dial plan variable and the originating channel is also freetdm (not going through SIP) */
+ } else if (session
+ && (var = channel_get_variable(session, var_event, FREETDM_VAR_PREFIX "native_sigbridge"))
+ && switch_true(var)
+ && switch_core_session_compare(*new_session, session)) {
+ private_t *peer_pvt = switch_core_session_get_private(session);
+ peer_chan = switch_core_session_get_channel(session);
+ snprintf(sigbridge_peer, sizeof(sigbridge_peer), "%u:%u",
+ ftdm_channel_get_span_id(peer_pvt->ftdmchan), ftdm_channel_get_id(peer_pvt->ftdmchan));
}
caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
hunt_data.tech_pvt = tech_pvt;
caller_data.priv = &hunt_data;
- if (session
- && (var = channel_get_variable(session, var_event, FREETDM_VAR_PREFIX "native_sigbridge"))
- && switch_true(var)
- && switch_core_session_compare(*new_session, session)) {
- private_t *peer_pvt = switch_core_session_get_private(session);
- snprintf(sigbridge_peer, sizeof(sigbridge_peer), "%u:%u",
- ftdm_channel_get_span_id(peer_pvt->ftdmchan), ftdm_channel_get_id(peer_pvt->ftdmchan));
- }
-
if (session && !zstr(sigbridge_peer)) {
peer_chan = switch_core_session_get_channel(session);
ftdm_usrmsg_add_var(&usrmsg, "sigbridge_peer", sigbridge_peer);
}
-
if ((status = ftdm_call_place_ex(&caller_data, &hunting, &usrmsg)) != FTDM_SUCCESS) {
if (tech_pvt->read_codec.implementation) {
switch_core_codec_destroy(&tech_pvt->read_codec);
}
var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_loc_nadi");
- printf ( "ss7_loc_nadi = %s \n " , var_value );
if (!ftdm_strlen_zero(var_value)) {
switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-LOC-NADI", "%s", var_value);
}
+
+ var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_ocn");
+ if (!ftdm_strlen_zero(var_value)) {
+ switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OCN", "%s", var_value);
+ }
+ var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_ocn_nadi");
+ if (!ftdm_strlen_zero(var_value)) {
+ switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OCN-NADI", "%s", var_value);
+ }
+
+ var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_ocn_plan");
+ if (!ftdm_strlen_zero(var_value)) {
+ switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OCN-Plan", "%s", var_value);
+ }
+
+ var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_ocn_pres");
+ if (!ftdm_strlen_zero(var_value)) {
+ switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OCN-Presentation", "%s", var_value);
+ }
}
/* Add any call variable to the dial plan */
ftdm_time_t diff = 0;
ftdm_channel_state_t state = fchan->state;
+
+#if 0
+ /* I could not perform this sanity check without more disruptive changes. Ideally we should check here if the signaling module completing the state
+ executed a state processor (called ftdm_channel_advance_states() which call fchan->span->state_processor(fchan)) for the state. That is just a
+ sanity check, as in the past we had at least one bug where the signaling module set the state and then accidentally changed the state to a new one
+ without calling ftdm_channel_advance_states(), meaning the state processor for the first state was not executed and that lead to unexpected behavior.
+
+ If we want to be able to perform this kind of sanity check it would be nice to add a new state status (FTDM_STATE_STATUS_PROCESSING), the function
+ ftdm_channel_advance_states() would set the state_status to PROCESSING and then the check below for STATUS_NEW would be valid. Currently is not
+ valid because the signaling module may be completing the state at the end of the state_processor callback and therefore the state will still be
+ in STATUS_NEW, and is perfectly valid ... */
+ if (fchan->state_status == FTDM_STATE_STATUS_NEW) {
+ ftdm_log_chan_ex(fchan, file, func, line, FTDM_LOG_LEVEL_CRIT,
+ "Asking to complete state change from %s to %s in %llums, but the state is still unprocessed (this might be a bug!)\n",
+ ftdm_channel_state2str(fchan->last_state), ftdm_channel_state2str(state), diff);
+ }
+#endif
+
if (fchan->state_status == FTDM_STATE_STATUS_COMPLETED) {
- ftdm_assert_return(!ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE), FTDM_FAIL,
- "State change flag set but state is not completed\n");
+ ftdm_assert_return(!ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE), FTDM_FAIL, "State change flag set but state is already completed\n");
return FTDM_SUCCESS;
}
} else {
SS7_INFO_CHAN(ftdmchan,"No Called party (DNIS) information in IAM!%s\n", " ");
}
+ copy_ocn_from_sngss7(ftdmchan, &siConEvnt->origCdNum);
copy_redirgNum_from_sngss7(ftdmchan, &siConEvnt->redirgNum);
copy_redirgInfo_from_sngss7(ftdmchan, &siConEvnt->redirInfo);
copy_genNmb_from_sngss7(ftdmchan, &siConEvnt->genNmb);
ftdm_status_t copy_redirgNum_from_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *redirgNum);
ftdm_status_t copy_redirgInfo_from_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *redirInfo);
ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *redirInfo);
+ftdm_status_t copy_ocn_to_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum);
+ftdm_status_t copy_ocn_from_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum);
ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum);
ftdm_status_t copy_locPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum);
{
const char *var = NULL;
SiConEvnt iam;
+ ftdm_bool_t native_going_up = FTDM_FALSE;
sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;;
SS7_FUNC_TRACE_ENTER (__FUNCTION__);
/* flush our own queue */
sngss7_flush_queue(sngss7_info->event_queue);
- /* 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);
+ /* Go to up until release comes, note that state processing is done different and much simpler when there is a peer,
+ We can't go to UP state right away yet though, so do not set the state to UP here, wait until the end of this function
+ because moving from one state to another causes the ftdmchan->usrmsg structure to be wiped
+ and we still need those variables for further IAM processing */
+ native_going_up = FTDM_TRUE;
}
}
}
/* Redirecting Information */
copy_redirgInfo_to_sngss7(ftdmchan, &iam.redirInfo);
}
+
+ if (iam.origCdNum.eh.pres != PRSNT_NODEF) {
+ /* Original Called Number */
+ copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum);
+ }
}
/* 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 */
/* Forward Call Indicators */
copy_fwdCallInd_to_sngss7(ftdmchan, &iam.fwdCallInd);
+
+ /* Original Called Number */
+ copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum);
} else {
/* Nature of Connection Indicators */
copy_natConInd_to_sngss7(ftdmchan, &iam.natConInd);
/* Redirecting Information */
copy_redirgInfo_to_sngss7(ftdmchan, &iam.redirInfo);
+ /* Original Called Number */
+ copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum);
/* Access Transport */
copy_accTrnspt_to_sngss7(ftdmchan, &iam.accTrnspt);
&iam,
0);
+
+ if (native_going_up) {
+ /*
+ Note that this function (ft_to_sngss7_iam) is run within the main SS7 processing loop in
+ response to the DIALING state handler, we can set the state to UP here and that will
+ implicitly complete the DIALING state, but we *MUST* also advance the state handler
+ right away for a native bridge, otherwise, the processing state function (ftdm_sangoma_ss7_process_state_change)
+ will complete the state without having executed the handler for FTDM_CHANNEL_STATE_UP, and we won't notify
+ the user sending FTDM_SIGEVENT_UP which can cause the application to misbehave (ie, no audio) */
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP);
+ ftdm_channel_advance_states(ftdmchan);
+ }
+
SS7_FUNC_TRACE_EXIT (__FUNCTION__);
return;
}
sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;
SiCnStEvnt acm;
+ const char *backwardInd = NULL;
memset (&acm, 0x0, sizeof (acm));
acm.bckCallInd.intInd.val = INTIND_NOINTW;
acm.bckCallInd.end2EndInfoInd.pres = PRSNT_NODEF;
acm.bckCallInd.end2EndInfoInd.val = E2EINF_NOINFO;
+
acm.bckCallInd.isdnUsrPrtInd.pres = PRSNT_NODEF;
- acm.bckCallInd.isdnUsrPrtInd.val = ISUP_USED;
+ acm.bckCallInd.isdnUsrPrtInd.val = ISUP_NOTUSED;
+ backwardInd = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "acm_bi_iup");
+ if (!ftdm_strlen_zero(backwardInd)) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied backward indicator ISDN user part indicator ACM, value \"%s\"\n", backwardInd);
+ if (atoi(backwardInd) != 0 ) {
+ acm.bckCallInd.isdnUsrPrtInd.val = ISUP_USED;
+ }
+ }
+
acm.bckCallInd.holdInd.pres = PRSNT_NODEF;
acm.bckCallInd.holdInd.val = HOLD_NOTREQD;
acm.bckCallInd.isdnAccInd.pres = PRSNT_NODEF;
locPtyNum->scrnInd.pres = pres_val;
val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_loc_screen_ind");
if (!ftdm_strlen_zero(val)) {
- locPtyNum->scrnInd.val = atoi(val);
+ locPtyNum->scrnInd.val = atoi(val);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Screening Ind %d\n", locPtyNum->scrnInd.val);
} else {
- locPtyNum->scrnInd.val = caller_data->screen;
+ locPtyNum->scrnInd.val = caller_data->screen;
}
- ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Location Reference Code Screening Ind %d\n", locPtyNum->scrnInd.val);
locPtyNum->presRest.pres = pres_val;
- val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_pres_ind");
+ val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_loc_pres_ind");
if (!ftdm_strlen_zero(val)) {
- locPtyNum->presRest.val = atoi(val);
+ locPtyNum->presRest.val = atoi(val);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Presentation Ind %d\n", locPtyNum->presRest.val);
} else {
- locPtyNum->presRest.val = caller_data->pres;
+ locPtyNum->presRest.val = caller_data->pres;
}
- ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Calling Party Number Presentation Ind %d\n", locPtyNum->presRest.val);
locPtyNum->numPlan.pres = pres_val;
locPtyNum->numPlan.val = 0x01;
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Reference NADI value \"%s\"\n", loc_nadi);
locPtyNum->natAddrInd.val = atoi(loc_nadi);
} else {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied NADI value found for LOC, using \"%d\"\n", locPtyNum->natAddrInd.val);
locPtyNum->natAddrInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].loc_nadi;
locPtyNum->natAddrInd.val = 0x03;
- ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied NADI value found for LOC, using \"%d\"\n", locPtyNum->natAddrInd.val);
}
- ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Location Reference Presentation Ind %d\n", locPtyNum->presRest.val);
return copy_tknStr_to_sngss7(caller_data->loc.digits, &locPtyNum->addrSig, &locPtyNum->oddEven);
}
return FTDM_FAIL;
}
} else if (!ftdm_strlen_zero(caller_data->rdnis.digits)) {
- ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Redirection Number\"%s\"\n", val);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Redirection Number\"%s\"\n", caller_data->rdnis.digits);
if (copy_tknStr_to_sngss7(caller_data->rdnis.digits, &redirgNum->addrSig, &redirgNum->oddEven) != FTDM_SUCCESS) {
return FTDM_FAIL;
}
return FTDM_SUCCESS;
}
+ftdm_status_t copy_ocn_from_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum)
+{
+ char val[20];
+ sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;
+
+ if (origCdNum->eh.pres != PRSNT_NODEF ) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No Original Called Number available\n");
+ return FTDM_SUCCESS;
+ }
+
+ if (origCdNum->addrSig.pres == PRSNT_NODEF) {
+ copy_tknStr_from_sngss7(origCdNum->addrSig, val, origCdNum->oddEven);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number digits:%s\n", val);
+ sngss7_add_var(sngss7_info, "ss7_ocn", val);
+ }
+
+ if (origCdNum->natAddr.pres == PRSNT_NODEF) {
+ snprintf(val, sizeof(val), "%d", origCdNum->natAddr.val);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - NADI:%s\n", val);
+ sngss7_add_var(sngss7_info, "ss7_ocn_nadi", val);
+ }
+
+ if (origCdNum->numPlan.pres == PRSNT_NODEF) {
+ snprintf(val, sizeof(val), "%d", origCdNum->numPlan.val);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number -plan:%s\n", val);
+ sngss7_add_var(sngss7_info, "ss7_ocn_plan", val);
+ }
+
+ if (origCdNum->presRest.pres == PRSNT_NODEF) {
+ snprintf(val, sizeof(val), "%d", origCdNum->presRest.val);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - presentation:%s\n", val);
+ sngss7_add_var(sngss7_info, "ss7_ocn_pres", val);
+ }
+
+ return FTDM_SUCCESS;
+}
+
+ftdm_status_t copy_ocn_to_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum)
+{
+ const char *val = NULL;
+ int bProceed = 0;
+
+ val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn");
+ if (!ftdm_strlen_zero(val)) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number \"%s\"\n", val);
+ if (copy_tknStr_to_sngss7((char*)val, &origCdNum->addrSig, &origCdNum->oddEven) != FTDM_SUCCESS) {
+ return FTDM_FAIL;
+ }
+ origCdNum->addrSig.pres = 1;
+ } else {
+ return FTDM_SUCCESS;
+ }
+
+ val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn_nadi");
+ if (!ftdm_strlen_zero(val)) {
+ origCdNum->natAddr.val = atoi(val);
+ origCdNum->natAddr.pres = 1;
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number NADI value \"%s\"\n", val);
+ bProceed = 1;
+ } else {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Original Called Number NADI value\n");
+ }
+
+ val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn_plan");
+ if (!ftdm_strlen_zero(val)) {
+ origCdNum->numPlan.val = atoi(val);
+ origCdNum->numPlan.pres = 1;
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number Plan value \"%s\"\n", val);
+ bProceed = 1;
+ } else {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Original Called Number Plan value\n");
+ }
+
+ val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn_pres");
+ if (!ftdm_strlen_zero(val)) {
+ origCdNum->presRest.val = atoi(val);
+ origCdNum->presRest.pres = 1;
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number Presentation value \"%s\"\n", val);
+ bProceed = 1;
+ } else {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Original Called Number Presentation value\n");
+ }
+
+ if( bProceed == 1 ) {
+ origCdNum->eh.pres = PRSNT_NODEF;
+ } else {
+ origCdNum->eh.pres = NOTPRSNT;
+ }
+
+ return FTDM_SUCCESS;
+}
+
ftdm_status_t copy_cgPtyCat_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyCat *cgPtyCat)
{
ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;