Merge branch 'master' into netborder
This commit is contained in:
commit
0f91359f3a
|
@ -0,0 +1,59 @@
|
|||
FreeTDM can both notify and set signaling status changes in the different protocols thru a unified interface. More
|
||||
specific details on the C data types and function prototypes are found in freetdm.h
|
||||
|
||||
The API provides the following functions and data types to do it:
|
||||
|
||||
The signaling status in any channel/span is represented thru ftdm_signaling_status_t
|
||||
|
||||
/* The signaling link is down (no d-chans up in the span/group, MFC-R2 bit pattern unidentified) */
|
||||
FTDM_SIG_STATE_DOWN,
|
||||
/* The signaling link is suspended (MFC-R2 bit pattern blocked, PRI maintenance, ss7 blocked?) */
|
||||
FTDM_SIG_STATE_SUSPENDED,
|
||||
/* The signaling link is ready and calls can be placed (ie: d-chan up, MFC-R2 both rx and tx in IDLE) */
|
||||
FTDM_SIG_STATE_UP,
|
||||
/* Invalid status */
|
||||
FTDM_SIG_STATE_INVALID
|
||||
|
||||
Changes in the signaling status are notified to the user using the standard callback notification function provided
|
||||
during configuration using the sigevent type FTDM_SIGEVENT_SIGSTATUS_CHANGED which is sent when the line status changes.
|
||||
|
||||
On startup the signalling status default is FTDM_SIG_STATE_DOWN, and no notification is provided until the state change,
|
||||
so applications must assume the status is down unless told otherwise.
|
||||
|
||||
When ftdm_span_start is called, the signaling stack takes care of attempting to bring the status to UP
|
||||
but it will ultimately depend on the other side too.
|
||||
|
||||
== Setting the signaling status ==
|
||||
|
||||
Users can set the signaling status on a given channel/span thru FreeTDM the following API functions:
|
||||
|
||||
ftdm_channel_set_sig_status
|
||||
ftdm_span_set_sig_status
|
||||
|
||||
If the user calls ftdm_channel_set_sig_status(chan, FTDM_SIG_STATE_SUSPENDED), the signaling stack will try to set
|
||||
the status of the line to the one requested, if successful, it will result in a SIGEVENT_SIGSTATUS_CHANGED notification
|
||||
being sent with status FTDM_SIG_STATE_SUSPENDED.
|
||||
|
||||
** MFC-R2 Signaling Notes **
|
||||
For MFC-R2, calling ftdm_span_start() results in setting the tx CAS bits to IDLE. However, if the rx bits are in BLOCKED state
|
||||
the signaling status will be reported as SUSPENDED.
|
||||
|
||||
If the user calls ftdm_channel_set_sig_status(chan, SUSPENDED), the tx CAS bits will be set to BLOCKED and, if, the current rx bits
|
||||
are IDLE then a SIGEVENT_SIGSTATUS_CHANGED with state SUSPENDED will be sent. If the rx bits are already in blocked then no further
|
||||
SIGEVENT_SIGSTATUS_CHANGED notification is needed (because it was already sent when the rx bits were initially detected as BLOCKED).
|
||||
|
||||
If the user calls ftdm_channel_set_sig_status(chan, UP), the tx CAS bits will be set to IDLE and, if, the current rx bits
|
||||
are IDLE, then SIGEVENT_SIGSTATUS_CHANGED with state UP will be sent. If the rx bits are BLOCKED, then no notification is
|
||||
sent at all until the rx bits change.
|
||||
|
||||
Bottom line is, for MFC-R2, SIGEVENT_SIGSTATUS_CHANGED UP is only sent to the user when both the rx and tx bits are in IDLE, and
|
||||
SIGEVENT_SIGSTATUS_CHANGED SUSPENDED is only sent to the user when any of the rx or tx bits are in BLOCKED.
|
||||
|
||||
== Getting the signaling status ==
|
||||
Users can get the signaling status on a given channel/span thru FreeTDM the following API functions:
|
||||
|
||||
ftdm_channel_get_sig_status
|
||||
ftdm_span_get_sig_status
|
||||
|
||||
The line status returned should be the same as the last time a SIGEVENT_SIGSTATUS_CHANGED was reported.
|
||||
|
|
@ -3543,7 +3543,83 @@ SWITCH_STANDARD_API(ft_function)
|
|||
goto end;
|
||||
}
|
||||
|
||||
if (!strcasecmp(argv[0], "dump")) {
|
||||
if (!strcasecmp(argv[0], "sigstatus")) {
|
||||
ftdm_span_t *span = NULL;
|
||||
ftdm_signaling_status_t sigstatus;
|
||||
|
||||
if (argc < 3) {
|
||||
stream->write_function(stream, "-ERR Usage: ftdm sigstatus get|set [<span_id>] [<channel>] [<sigstatus>]\n");
|
||||
goto end;
|
||||
}
|
||||
if (!strcasecmp(argv[1], "get") && argc < 3) {
|
||||
stream->write_function(stream, "-ERR sigstatus get usage: get <span_id>\n");
|
||||
goto end;
|
||||
}
|
||||
if (!strcasecmp(argv[1], "set") && argc != 5) {
|
||||
stream->write_function(stream, "-ERR sigstatus set usage: set <span_id> <channel>|all <sigstatus>\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
ftdm_span_find_by_name(argv[2], &span);
|
||||
if (!span) {
|
||||
stream->write_function(stream, "-ERR invalid span\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!strcasecmp(argv[1], "get")) {
|
||||
if (argc == 4) {
|
||||
uint32_t chan_id = atol(argv[3]);
|
||||
ftdm_channel_t *fchan = ftdm_span_get_channel(span, chan_id);
|
||||
if (!fchan) {
|
||||
stream->write_function(stream, "-ERR failed to get channel id '%d'\n", chan_id);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((FTDM_SUCCESS == ftdm_channel_get_sig_status(fchan, &sigstatus))) {
|
||||
stream->write_function(stream, "channel %d signaling status: %s\n", chan_id, ftdm_signaling_status2str(sigstatus));
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR failed to get channel sigstatus\n");
|
||||
}
|
||||
goto end;
|
||||
} else {
|
||||
if ((FTDM_SUCCESS == ftdm_span_get_sig_status(span, &sigstatus))) {
|
||||
stream->write_function(stream, "signaling_status: %s\n", ftdm_signaling_status2str(sigstatus));
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR failed to read span status: %s\n", ftdm_span_get_last_error(span));
|
||||
}
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
if (!strcasecmp(argv[1], "set")) {
|
||||
sigstatus = ftdm_str2ftdm_signaling_status(argv[4]);
|
||||
|
||||
if (!strcasecmp(argv[3], "all")) {
|
||||
if ((FTDM_SUCCESS == ftdm_span_set_sig_status(span, sigstatus))) {
|
||||
stream->write_function(stream, "Signaling status of all channels from span %s set to %s\n",
|
||||
ftdm_span_get_name(span), ftdm_signaling_status2str(sigstatus));
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR failed to set span sigstatus to '%s'\n", ftdm_signaling_status2str(sigstatus));
|
||||
}
|
||||
goto end;
|
||||
} else {
|
||||
uint32_t chan_id = atol(argv[3]);
|
||||
ftdm_channel_t *fchan = ftdm_span_get_channel(span, chan_id);
|
||||
if (!fchan) {
|
||||
stream->write_function(stream, "-ERR failed to get channel id '%d'\n", chan_id);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((FTDM_SUCCESS == ftdm_channel_set_sig_status(fchan, sigstatus))) {
|
||||
stream->write_function(stream, "Signaling status of channel %d set to %s\n", chan_id,
|
||||
ftdm_signaling_status2str(sigstatus));
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR failed to set span sigstatus to '%s'\n", ftdm_signaling_status2str(sigstatus));
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (!strcasecmp(argv[0], "dump")) {
|
||||
if (argc < 2) {
|
||||
stream->write_function(stream, "-ERR Usage: ftdm dump <span_id> [<chan_id>]\n");
|
||||
goto end;
|
||||
|
|
|
@ -55,10 +55,13 @@ static int32_t g_thread_count = 0;
|
|||
|
||||
typedef int openr2_call_status_t;
|
||||
|
||||
/* when the users kills a span we clear this flag to kill the signaling thread */
|
||||
/* when the user stops a span, we clear FTDM_R2_SPAN_STARTED, so that the signaling thread
|
||||
* knows it must stop, and we wait for FTDM_R2_RUNNING to be clear, which tells us the
|
||||
* signaling thread is done. */
|
||||
/* FIXME: what about the calls that are already up-and-running? */
|
||||
typedef enum {
|
||||
FTDM_R2_RUNNING = (1 << 0),
|
||||
FTDM_R2_SPAN_STARTED = (1 << 1),
|
||||
} ftdm_r2_flag_t;
|
||||
|
||||
/* private call information stored in ftdmchan->call_data void* ptr,
|
||||
|
@ -424,13 +427,14 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
|
|||
static ftdm_status_t ftdm_r2_start(ftdm_span_t *span)
|
||||
{
|
||||
ftdm_r2_data_t *r2_data = span->signal_data;
|
||||
ftdm_set_flag(r2_data, FTDM_R2_RUNNING);
|
||||
ftdm_set_flag(r2_data, FTDM_R2_SPAN_STARTED);
|
||||
return ftdm_thread_create_detached(ftdm_r2_run, span);
|
||||
}
|
||||
|
||||
static ftdm_status_t ftdm_r2_stop(ftdm_span_t *span)
|
||||
{
|
||||
ftdm_r2_data_t *r2_data = span->signal_data;
|
||||
ftdm_clear_flag(r2_data, FTDM_R2_SPAN_STARTED);
|
||||
while (ftdm_test_flag(r2_data, FTDM_R2_RUNNING)) {
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Waiting for R2 span %s\n", span->name);
|
||||
ftdm_sleep(100);
|
||||
|
@ -461,9 +465,73 @@ static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_channel_sig_status)
|
|||
openr2_chan_set_idle(r2chan);
|
||||
break;
|
||||
default:
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%s'\n", status);
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%d'\n", status);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
ftdm_r2_set_chan_sig_status(ftdmchan, status);
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_span_sig_status)
|
||||
{
|
||||
ftdm_iterator_t *citer = NULL;
|
||||
ftdm_iterator_t *chaniter = ftdm_span_get_chan_iterator(span, NULL);
|
||||
if (!chaniter) {
|
||||
ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
/* if ALL channels are non-idle, report SUSPENDED. UP otherwise. */
|
||||
*status = FTDM_SIG_STATE_SUSPENDED;
|
||||
for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) {
|
||||
ftdm_channel_t *fchan = ftdm_iterator_current(citer);
|
||||
if (ftdm_test_flag(fchan, FTDM_CHANNEL_SIG_UP)) {
|
||||
*status = FTDM_SIG_STATE_UP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ftdm_iterator_free(chaniter);
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_span_sig_status)
|
||||
{
|
||||
ftdm_iterator_t *chaniter = NULL;
|
||||
ftdm_iterator_t *citer = NULL;
|
||||
uint32_t span_opr = -1;
|
||||
|
||||
/* we either set the channels to BLOCK or IDLE */
|
||||
switch(status) {
|
||||
case FTDM_SIG_STATE_DOWN:
|
||||
case FTDM_SIG_STATE_SUSPENDED:
|
||||
span_opr = 0;
|
||||
break;
|
||||
case FTDM_SIG_STATE_UP:
|
||||
span_opr = 1;
|
||||
break;
|
||||
default:
|
||||
ftdm_log(FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%d'\n", status);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
chaniter = ftdm_span_get_chan_iterator(span, NULL);
|
||||
if (!chaniter) {
|
||||
ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
/* iterate over all channels, setting them to the requested state */
|
||||
for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) {
|
||||
ftdm_channel_t *fchan = ftdm_iterator_current(citer);
|
||||
openr2_chan_t *r2chan = R2CALL(fchan)->r2chan;
|
||||
if (span_opr == 0) {
|
||||
openr2_chan_set_blocked(r2chan);
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_NOTICE, "Channel blocked\n");
|
||||
} else {
|
||||
openr2_chan_set_idle(r2chan);
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_NOTICE, "Channel idle\n");
|
||||
}
|
||||
ftdm_r2_set_chan_sig_status(fchan, status);
|
||||
}
|
||||
ftdm_iterator_free(chaniter);
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1441,6 +1509,8 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling)
|
|||
span->signal_type = FTDM_SIGTYPE_R2;
|
||||
span->signal_data = r2data;
|
||||
span->outgoing_call = r2_outgoing_call;
|
||||
span->get_span_sig_status = ftdm_r2_get_span_sig_status;
|
||||
span->set_span_sig_status = ftdm_r2_set_span_sig_status;
|
||||
span->get_channel_sig_status = ftdm_r2_get_channel_sig_status;
|
||||
span->set_channel_sig_status = ftdm_r2_set_channel_sig_status;
|
||||
|
||||
|
@ -1690,6 +1760,9 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
|
|||
uint32_t txqueue_size = 4;
|
||||
short *poll_events = ftdm_malloc(sizeof(short) * span->chan_count);
|
||||
|
||||
/* as long as this thread is running, this flag is set */
|
||||
ftdm_set_flag(r2data, FTDM_R2_RUNNING);
|
||||
|
||||
#ifdef __linux__
|
||||
r2data->monitor_thread_id = syscall(SYS_gettid);
|
||||
#endif
|
||||
|
@ -1712,7 +1785,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
|
|||
|
||||
memset(&start, 0, sizeof(start));
|
||||
memset(&end, 0, sizeof(end));
|
||||
while (ftdm_running() && ftdm_test_flag(r2data, FTDM_R2_RUNNING)) {
|
||||
while (ftdm_running() && ftdm_test_flag(r2data, FTDM_R2_SPAN_STARTED)) {
|
||||
res = gettimeofday(&end, NULL);
|
||||
if (res) {
|
||||
ftdm_log(FTDM_LOG_CRIT, "Failure gettimeofday [%s]\n", strerror(errno));
|
||||
|
|
|
@ -367,6 +367,7 @@ typedef struct ftdm_channel_config {
|
|||
|
||||
/*!
|
||||
\brief Signaling status on a given span or specific channel on protocols that support it
|
||||
\note see docs/sigstatus.txt for more extensive documentation on signaling status
|
||||
*/
|
||||
typedef enum {
|
||||
/* The signaling link is down (no d-chans up in the span/group, MFC-R2 bit pattern unidentified) */
|
||||
|
|
Loading…
Reference in New Issue