提交 23a32838 authored 作者: Moises Silva's avatar Moises Silva

freetdm: Initial attempt to bridge natively SS7 signaling between 2 channels

上级 b4e8d5b6
...@@ -53,8 +53,6 @@ struct tm *localtime_r(const time_t *clock, struct tm *result); ...@@ -53,8 +53,6 @@ struct tm *localtime_r(const time_t *clock, struct tm *result);
#endif #endif
#define FORCE_HANGUP_TIMER 30000 #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_READ_TRACE_INDEX 0
#define FTDM_WRITE_TRACE_INDEX 1 #define FTDM_WRITE_TRACE_INDEX 1
#define MAX_CALLIDS 6000 #define MAX_CALLIDS 6000
...@@ -2201,6 +2199,12 @@ static ftdm_status_t _ftdm_channel_call_hangup_nl(const char *file, const char * ...@@ -2201,6 +2199,12 @@ static ftdm_status_t _ftdm_channel_call_hangup_nl(const char *file, const char *
{ {
ftdm_status_t status = FTDM_SUCCESS; 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_DOWN) {
if (chan->state == FTDM_CHANNEL_STATE_HANGUP) { if (chan->state == FTDM_CHANNEL_STATE_HANGUP) {
/* make user's life easier, and just ignore double hangup requests */ /* 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 * ...@@ -2227,6 +2231,8 @@ static ftdm_status_t _ftdm_channel_call_hangup_nl(const char *file, const char *
ftdm_channel_close(&chan); ftdm_channel_close(&chan);
} }
} }
done:
return status; return status;
} }
...@@ -2322,6 +2328,15 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch ...@@ -2322,6 +2328,15 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch
ftdm_channel_lock(ftdmchan); 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)) { 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_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), ftdm_channel_indication2str(indication),
...@@ -2422,10 +2437,50 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_reset(const char *file, const char *func ...@@ -2422,10 +2437,50 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_reset(const char *file, const char *func
return FTDM_SUCCESS; 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, /* 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 */ * 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) 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_status_t status = FTDM_FAIL;
ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "null channel"); 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 ...@@ -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_set_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED);
ftdm_call_set_call_id(ftdmchan, &ftdmchan->caller_data); 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 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) { if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN) {
...@@ -2662,6 +2728,7 @@ static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan) ...@@ -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_ANSWERED);
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_USER_HANGUP); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_USER_HANGUP);
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_DIGITAL_MEDIA); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_DIGITAL_MEDIA);
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE);
ftdm_mutex_lock(ftdmchan->pre_buffer_mutex); ftdm_mutex_lock(ftdmchan->pre_buffer_mutex);
ftdm_buffer_destroy(&ftdmchan->pre_buffer); ftdm_buffer_destroy(&ftdmchan->pre_buffer);
ftdmchan->pre_buffer_size = 0; ftdmchan->pre_buffer_size = 0;
......
...@@ -81,8 +81,12 @@ typedef enum { ...@@ -81,8 +81,12 @@ typedef enum {
SNGSS7_STA_IND_EVENT, SNGSS7_STA_IND_EVENT,
SNGSS7_SUSP_IND_EVENT, SNGSS7_SUSP_IND_EVENT,
SNGSS7_RESM_IND_EVENT, SNGSS7_RESM_IND_EVENT,
SNGSS7_SSP_STA_CFM_EVENT SNGSS7_SSP_STA_CFM_EVENT,
SNGSS7_INVALID_EVENT,
} sng_event_type_t; } 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 { typedef enum {
SNG_BIT_A = (1 << 0), SNG_BIT_A = (1 << 0),
...@@ -500,6 +504,7 @@ typedef struct sngss7_span_data { ...@@ -500,6 +504,7 @@ typedef struct sngss7_span_data {
sngss7_group_data_t rx_cgu; sngss7_group_data_t rx_cgu;
sngss7_group_data_t tx_cgu; sngss7_group_data_t tx_cgu;
ftdm_queue_t *event_queue; ftdm_queue_t *event_queue;
ftdm_queue_t *peer_chans;
} sngss7_span_data_t; } sngss7_span_data_t;
typedef struct sngss7_event_data typedef struct sngss7_event_data
......
...@@ -58,26 +58,17 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) ...@@ -58,26 +58,17 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
var = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "sigbridge_peer"); var = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "sigbridge_peer");
if (!ftdm_strlen_zero(var)) { if (!ftdm_strlen_zero(var)) {
ftdm_status_t status = FTDM_SUCCESS;
int rc = 0;
ftdm_span_t *peer_span = NULL; ftdm_span_t *peer_span = NULL;
ftdm_channel_t *peer_chan = NULL; ftdm_channel_t *peer_chan = NULL;
sngss7_chan_data_t *peer_info = NULL; sngss7_chan_data_t *peer_info = NULL;
unsigned peer_span_id = 0;
unsigned peer_chan_id = 0; ftdm_get_channel_from_string(var, &peer_span, &peer_chan);
rc = sscanf(var, "%u:%u", &peer_span_id, &peer_chan_id); if (!peer_chan) {
if (rc != 2) { SS7_ERROR_CHAN(ftdmchan, "Failed to find sigbridge peer from string '%s'\n", var);
SS7_ERROR_CHAN(ftdmchan, "Failed to parse sigbridge_peer string '%s'\n", var);
} else {
status = ftdm_span_find(peer_span_id, &peer_span);
if (status != FTDM_SUCCESS || !peer_span) {
SS7_ERROR_CHAN(ftdmchan, "Failed to find peer span for channel id '%u:%u'\n", peer_span_id, peer_chan_id);
} else if (peer_span->signal_type != FTDM_SIGTYPE_SS7) {
SS7_ERROR_CHAN(ftdmchan, "Peer channel %d:%d has different signaling type %d'\n",
peer_span_id, peer_chan_id, peer_span->signal_type);
} else { } else {
if (peer_chan_id > (FTDM_MAX_CHANNELS_SPAN+1) || !(peer_chan = peer_span->channels[peer_chan_id])) { if (peer_span->signal_type != FTDM_SIGTYPE_SS7) {
SS7_ERROR_CHAN(ftdmchan, "Invalid peer channel id '%u:%u'\n", peer_span_id, peer_chan_id); SS7_ERROR_CHAN(ftdmchan, "Peer channel '%s' has different signaling type %d'\n",
var, peer_span->signal_type);
} else { } else {
sngss7_event_data_t *event_clone = NULL; sngss7_event_data_t *event_clone = NULL;
peer_info = peer_chan->call_data; peer_info = peer_chan->call_data;
...@@ -91,12 +82,15 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) ...@@ -91,12 +82,15 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
SS7_WARN("[CIC:%d]Discarding clone event from past call!\n", sngss7_info->circuit->cic); SS7_WARN("[CIC:%d]Discarding clone event from past call!\n", sngss7_info->circuit->cic);
ftdm_safe_free(event_clone); 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) { 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); sngss7_event_data_t *event_clone = ftdm_queue_dequeue(sngss7_info->peer_data->event_queue);
/* Retrieve IAM from our peer */ /* Retrieve IAM from our peer */
if (!event_clone) { if (!event_clone) {
...@@ -108,6 +102,9 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) ...@@ -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); SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged)\n", sngss7_info->circuit->cic);
memcpy(&iam, &event_clone->event.siConEvnt, sizeof(iam)); 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 && } else if (sngss7_info->circuit->transparent_iam &&
sngss7_retrieve_iam(ftdmchan, &iam) == FTDM_SUCCESS) { sngss7_retrieve_iam(ftdmchan, &iam) == FTDM_SUCCESS) {
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Transparent)\n", sngss7_info->circuit->cic); SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Transparent)\n", sngss7_info->circuit->cic);
......
...@@ -130,6 +130,9 @@ ...@@ -130,6 +130,9 @@
extern "C" { extern "C" {
#endif #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 GOTO_STATUS(label,st) status = st; goto label ;
#define ftdm_copy_string(x,y,z) strncpy(x, y, z - 1) #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 ...@@ -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); 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 \brief Assert condition
*/ */
......
...@@ -265,6 +265,8 @@ typedef enum { ...@@ -265,6 +265,8 @@ typedef enum {
#define FTDM_CHANNEL_BLOCKING (1ULL << 35) #define FTDM_CHANNEL_BLOCKING (1ULL << 35)
/*!< Media is digital */ /*!< Media is digital */
#define FTDM_CHANNEL_DIGITAL_MEDIA (1ULL << 36) #define FTDM_CHANNEL_DIGITAL_MEDIA (1ULL << 36)
/*!< Native signaling bridge is enabled */
#define FTDM_CHANNEL_NATIVE_SIGBRIDGE (1ULL << 37)
#include "ftdm_state.h" #include "ftdm_state.h"
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论