mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-03-15 21:22:57 +00:00
Merge branch 'master' of git.freeswitch.org:freeswitch
This commit is contained in:
commit
12b5bde226
@ -38,6 +38,8 @@
|
|||||||
static ftdm_status_t ftdm_libpri_start(ftdm_span_t *span);
|
static ftdm_status_t ftdm_libpri_start(ftdm_span_t *span);
|
||||||
static ftdm_io_interface_t ftdm_libpri_interface;
|
static ftdm_io_interface_t ftdm_libpri_interface;
|
||||||
|
|
||||||
|
static int on_timeout_t302(struct lpwrap_pri *spri, struct lpwrap_timer *timer);
|
||||||
|
|
||||||
|
|
||||||
static void _ftdm_channel_set_state_force(ftdm_channel_t *chan, const ftdm_channel_state_t state)
|
static void _ftdm_channel_set_state_force(ftdm_channel_t *chan, const ftdm_channel_state_t state)
|
||||||
{
|
{
|
||||||
@ -902,8 +904,10 @@ static ftdm_state_map_t isdn_state_map = {
|
|||||||
*/
|
*/
|
||||||
static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
||||||
{
|
{
|
||||||
ftdm_libpri_data_t *isdn_data = chan->span->signal_data;
|
ftdm_span_t *span = ftdm_channel_get_span(chan);
|
||||||
q931_call *call = (q931_call *)chan->call_data;
|
ftdm_libpri_data_t *isdn_data = span->signal_data;
|
||||||
|
ftdm_libpri_b_chan_t *chan_priv = chan->call_data;
|
||||||
|
q931_call *call = chan_priv->call;
|
||||||
ftdm_status_t status;
|
ftdm_status_t status;
|
||||||
ftdm_sigmsg_t sig;
|
ftdm_sigmsg_t sig;
|
||||||
|
|
||||||
@ -920,13 +924,17 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
|||||||
switch (ftdm_channel_get_state(chan)) {
|
switch (ftdm_channel_get_state(chan)) {
|
||||||
case FTDM_CHANNEL_STATE_DOWN:
|
case FTDM_CHANNEL_STATE_DOWN:
|
||||||
{
|
{
|
||||||
|
if (ftdm_channel_get_type(chan) == FTDM_CHAN_TYPE_B) {
|
||||||
ftdm_channel_t *chtmp = chan;
|
ftdm_channel_t *chtmp = chan;
|
||||||
|
|
||||||
if (call) {
|
if (call) {
|
||||||
pri_destroycall(isdn_data->spri.pri, call);
|
pri_destroycall(isdn_data->spri.pri, call);
|
||||||
chan->call_data = NULL;
|
chan_priv->call = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Stop T302 */
|
||||||
|
lpwrap_stop_timer(&isdn_data->spri, &chan_priv->t302);
|
||||||
|
|
||||||
if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) {
|
if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) {
|
||||||
ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n",
|
ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n",
|
||||||
ftdm_channel_get_span_id(chan),
|
ftdm_channel_get_span_id(chan),
|
||||||
@ -937,13 +945,14 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
|||||||
ftdm_channel_get_id(chan));
|
ftdm_channel_get_id(chan));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FTDM_CHANNEL_STATE_PROGRESS:
|
case FTDM_CHANNEL_STATE_PROGRESS:
|
||||||
{
|
{
|
||||||
if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
|
if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
|
||||||
sig.event_id = FTDM_SIGEVENT_PROGRESS;
|
sig.event_id = FTDM_SIGEVENT_PROGRESS;
|
||||||
if ((status = ftdm_span_send_signal(ftdm_channel_get_span(chan), &sig) != FTDM_SUCCESS)) {
|
if ((status = ftdm_span_send_signal(span, &sig) != FTDM_SUCCESS)) {
|
||||||
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
|
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
|
||||||
}
|
}
|
||||||
} else if (call) {
|
} else if (call) {
|
||||||
@ -958,7 +967,7 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
|||||||
{
|
{
|
||||||
if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
|
if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
|
||||||
sig.event_id = FTDM_SIGEVENT_RINGING;
|
sig.event_id = FTDM_SIGEVENT_RINGING;
|
||||||
if ((status = ftdm_span_send_signal(ftdm_channel_get_span(chan), &sig) != FTDM_SUCCESS)) {
|
if ((status = ftdm_span_send_signal(span, &sig) != FTDM_SUCCESS)) {
|
||||||
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
|
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
|
||||||
}
|
}
|
||||||
} else if (call) {
|
} else if (call) {
|
||||||
@ -974,7 +983,7 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
|||||||
{
|
{
|
||||||
if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
|
if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
|
||||||
sig.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
|
sig.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
|
||||||
if ((status = ftdm_span_send_signal(ftdm_channel_get_span(chan), &sig) != FTDM_SUCCESS)) {
|
if ((status = ftdm_span_send_signal(span, &sig) != FTDM_SUCCESS)) {
|
||||||
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
|
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
|
||||||
}
|
}
|
||||||
} else if (call) {
|
} else if (call) {
|
||||||
@ -994,7 +1003,7 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
|||||||
if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
|
if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
|
||||||
/* PROCEED from other end, notify user */
|
/* PROCEED from other end, notify user */
|
||||||
sig.event_id = FTDM_SIGEVENT_PROCEED;
|
sig.event_id = FTDM_SIGEVENT_PROCEED;
|
||||||
if ((status = ftdm_span_send_signal(ftdm_channel_get_span(chan), &sig) != FTDM_SUCCESS)) {
|
if ((status = ftdm_span_send_signal(span, &sig) != FTDM_SUCCESS)) {
|
||||||
ftdm_log(FTDM_LOG_ERROR, "Failed to send PROCEED sigevent on Channel %d:%d\n",
|
ftdm_log(FTDM_LOG_ERROR, "Failed to send PROCEED sigevent on Channel %d:%d\n",
|
||||||
ftdm_channel_get_span_id(chan),
|
ftdm_channel_get_span_id(chan),
|
||||||
ftdm_channel_get_id(chan));
|
ftdm_channel_get_id(chan));
|
||||||
@ -1024,6 +1033,11 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
|||||||
caller_data->hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER;
|
caller_data->hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER;
|
||||||
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
|
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
/* Start T302 */
|
||||||
|
lpwrap_start_timer(&isdn_data->spri, &chan_priv->t302,
|
||||||
|
isdn_data->overlap_timeout_ms, &on_timeout_t302);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ftdm_log_chan_msg(chan, FTDM_LOG_ERROR, "Overlap receiving on outbound call?\n");
|
ftdm_log_chan_msg(chan, FTDM_LOG_ERROR, "Overlap receiving on outbound call?\n");
|
||||||
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART);
|
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART);
|
||||||
@ -1042,7 +1056,7 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
|||||||
pri_proceeding(isdn_data->spri.pri, call, ftdm_channel_get_id(chan), 0);
|
pri_proceeding(isdn_data->spri.pri, call, ftdm_channel_get_id(chan), 0);
|
||||||
// pri_acknowledge(isdn_data->spri.pri, call, ftdm_channel_get_id(chan), 0);
|
// pri_acknowledge(isdn_data->spri.pri, call, ftdm_channel_get_id(chan), 0);
|
||||||
sig.event_id = FTDM_SIGEVENT_START;
|
sig.event_id = FTDM_SIGEVENT_START;
|
||||||
if ((status = ftdm_span_send_signal(ftdm_channel_get_span(chan), &sig) != FTDM_SUCCESS)) {
|
if ((status = ftdm_span_send_signal(span, &sig) != FTDM_SUCCESS)) {
|
||||||
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
|
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1054,18 +1068,28 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
|||||||
|
|
||||||
case FTDM_CHANNEL_STATE_RESTART:
|
case FTDM_CHANNEL_STATE_RESTART:
|
||||||
{
|
{
|
||||||
|
if (ftdm_channel_get_type(chan) == FTDM_CHAN_TYPE_B) {
|
||||||
chan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_UNSPECIFIED;
|
chan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_UNSPECIFIED;
|
||||||
sig.event_id = FTDM_SIGEVENT_RESTART;
|
sig.event_id = FTDM_SIGEVENT_RESTART;
|
||||||
status = ftdm_span_send_signal(ftdm_channel_get_span(chan), &sig);
|
status = ftdm_span_send_signal(span, &sig);
|
||||||
|
|
||||||
|
if (!(chan_priv->flags & FTDM_LIBPRI_B_REMOTE_RESTART)) {
|
||||||
|
/* Locally triggered restart, send RESTART to remote, wait for ACK */
|
||||||
|
pri_reset(isdn_data->spri.pri, ftdm_channel_get_id(chan));
|
||||||
|
} else {
|
||||||
|
/* Remote restart complete, clear flag */
|
||||||
|
chan_priv->flags &= ~FTDM_LIBPRI_B_REMOTE_RESTART;
|
||||||
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_DOWN);
|
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_DOWN);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FTDM_CHANNEL_STATE_UP:
|
case FTDM_CHANNEL_STATE_UP:
|
||||||
{
|
{
|
||||||
if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
|
if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
|
||||||
sig.event_id = FTDM_SIGEVENT_UP;
|
sig.event_id = FTDM_SIGEVENT_UP;
|
||||||
if ((status = ftdm_span_send_signal(ftdm_channel_get_span(chan), &sig) != FTDM_SUCCESS)) {
|
if ((status = ftdm_span_send_signal(span, &sig) != FTDM_SUCCESS)) {
|
||||||
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
|
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
|
||||||
}
|
}
|
||||||
} else if (call) {
|
} else if (call) {
|
||||||
@ -1109,7 +1133,7 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
|||||||
ton = isdn_data->ton;
|
ton = isdn_data->ton;
|
||||||
}
|
}
|
||||||
|
|
||||||
chan->call_data = call;
|
chan_priv->call = call;
|
||||||
|
|
||||||
sr = pri_sr_new();
|
sr = pri_sr_new();
|
||||||
if (!sr) {
|
if (!sr) {
|
||||||
@ -1155,7 +1179,7 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
|||||||
|
|
||||||
pri_hangup(isdn_data->spri.pri, call, caller_data->hangup_cause);
|
pri_hangup(isdn_data->spri.pri, call, caller_data->hangup_cause);
|
||||||
// pri_destroycall(isdn_data->spri.pri, call);
|
// pri_destroycall(isdn_data->spri.pri, call);
|
||||||
// chan->call_data = NULL;
|
// chan_priv->call = NULL;
|
||||||
}
|
}
|
||||||
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
|
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
|
||||||
}
|
}
|
||||||
@ -1165,7 +1189,7 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
|||||||
{
|
{
|
||||||
// if (call) {
|
// if (call) {
|
||||||
// pri_destroycall(isdn_data->spri.pri, call);
|
// pri_destroycall(isdn_data->spri.pri, call);
|
||||||
// chan->call_data = NULL;
|
// chan_priv->call = NULL;
|
||||||
// }
|
// }
|
||||||
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_DOWN);
|
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_DOWN);
|
||||||
}
|
}
|
||||||
@ -1174,7 +1198,7 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
|||||||
case FTDM_CHANNEL_STATE_TERMINATING:
|
case FTDM_CHANNEL_STATE_TERMINATING:
|
||||||
{
|
{
|
||||||
sig.event_id = FTDM_SIGEVENT_STOP;
|
sig.event_id = FTDM_SIGEVENT_STOP;
|
||||||
status = ftdm_span_send_signal(ftdm_channel_get_span(chan), &sig);
|
status = ftdm_span_send_signal(span, &sig);
|
||||||
/* user moves us to HANGUP and from there we go to DOWN */
|
/* user moves us to HANGUP and from there we go to DOWN */
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -1203,18 +1227,48 @@ static __inline__ void check_state(ftdm_span_t *span)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Handler for libpri information event (incoming call?)
|
* \brief Handler for libpri keypad digit event
|
||||||
* \param spri Pri wrapper structure (libpri, span, dchan)
|
* \param spri Pri wrapper structure (libpri, span, dchan)
|
||||||
* \param event_type Event type (unused)
|
* \param event_type Event type (unused)
|
||||||
* \param pevent Event
|
* \param pevent Event
|
||||||
* \return 0
|
* \return 0
|
||||||
*/
|
*/
|
||||||
static int on_info(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
|
static int on_keypad_digit(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
|
||||||
{
|
{
|
||||||
ftdm_span_t *span = spri->span;
|
ftdm_span_t *span = spri->span;
|
||||||
ftdm_channel_t *chan = ftdm_span_get_channel(span, pevent->ring.channel);
|
ftdm_channel_t *chan = ftdm_span_get_channel(span, pevent->ring.channel);
|
||||||
|
|
||||||
|
if (!chan) {
|
||||||
|
ftdm_log(FTDM_LOG_ERROR, "-- Keypad event on invalid channel %d:%d\n",
|
||||||
|
ftdm_span_get_id(span), pevent->ring.channel);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ftdm_log_chan(chan, FTDM_LOG_DEBUG, "-- Keypad event received, incoming digits: '%s'\n",
|
||||||
|
pevent->digit.digits);
|
||||||
|
|
||||||
|
/* Enqueue DTMF digits on channel */
|
||||||
|
ftdm_channel_queue_dtmf(chan, pevent->digit.digits);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Handler for libpri information event (overlap receiving)
|
||||||
|
* \param spri Pri wrapper structure (libpri, span, dchan)
|
||||||
|
* \param event_type Event type (unused)
|
||||||
|
* \param pevent Event
|
||||||
|
* \return 0
|
||||||
|
*/
|
||||||
|
static int on_information(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
|
||||||
|
{
|
||||||
|
ftdm_span_t *span = spri->span;
|
||||||
|
ftdm_channel_t *chan = ftdm_span_get_channel(span, pevent->ring.channel);
|
||||||
|
ftdm_libpri_b_chan_t *chan_priv = NULL;
|
||||||
ftdm_caller_data_t *caller_data = NULL;
|
ftdm_caller_data_t *caller_data = NULL;
|
||||||
|
ftdm_libpri_data_t *isdn_data = span->signal_data;
|
||||||
|
|
||||||
if (!chan) {
|
if (!chan) {
|
||||||
ftdm_log(FTDM_LOG_CRIT, "-- Info on channel %d:%d but it's not in use?\n", ftdm_span_get_id(span), pevent->ring.channel);
|
ftdm_log(FTDM_LOG_CRIT, "-- Info on channel %d:%d but it's not in use?\n", ftdm_span_get_id(span), pevent->ring.channel);
|
||||||
@ -1222,11 +1276,19 @@ static int on_info(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event
|
|||||||
}
|
}
|
||||||
|
|
||||||
caller_data = ftdm_channel_get_caller_data(chan);
|
caller_data = ftdm_channel_get_caller_data(chan);
|
||||||
|
chan_priv = chan->call_data;
|
||||||
|
|
||||||
switch (ftdm_channel_get_state(chan)) {
|
switch (ftdm_channel_get_state(chan)) {
|
||||||
case FTDM_CHANNEL_STATE_COLLECT: /* TE-mode overlap receiving */
|
case FTDM_CHANNEL_STATE_COLLECT: /* TE-mode overlap receiving */
|
||||||
ftdm_log_chan(chan, FTDM_LOG_DEBUG, "-- Incoming INFORMATION indication, current called number: '%s', number complete: %s\n",
|
case FTDM_CHANNEL_STATE_DIALTONE: /* NT-mode overlap receiving */
|
||||||
pevent->ring.callednum, pevent->ring.complete ? "yes" : "no");
|
|
||||||
|
ftdm_log_chan(chan, FTDM_LOG_DEBUG, "-- Incoming INFORMATION indication, received digits: '%s', number complete: %c, collected digits: '%s'\n",
|
||||||
|
pevent->ring.callednum,
|
||||||
|
pevent->ring.complete ? 'Y' : 'N',
|
||||||
|
caller_data->dnis.digits);
|
||||||
|
|
||||||
|
/* Stop T302 */
|
||||||
|
lpwrap_stop_timer(spri, &chan_priv->t302);
|
||||||
|
|
||||||
/* append digits to dnis */
|
/* append digits to dnis */
|
||||||
if (!ftdm_strlen_zero(pevent->ring.callednum)) {
|
if (!ftdm_strlen_zero(pevent->ring.callednum)) {
|
||||||
@ -1241,7 +1303,7 @@ static int on_info(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event
|
|||||||
|
|
||||||
len = ftdm_min(sizeof(caller_data->dnis.digits) - 1 - offset, digits); /* max. length without terminator */
|
len = ftdm_min(sizeof(caller_data->dnis.digits) - 1 - offset, digits); /* max. length without terminator */
|
||||||
if (len < digits) {
|
if (len < digits) {
|
||||||
ftdm_log_chan(chan, FTDM_LOG_WARNING, "Length %d of digit string exceeds available space %d of DNIS, truncating!\n",
|
ftdm_log_chan(chan, FTDM_LOG_WARNING, "Digit string of length %d exceeds available space %d of DNIS, truncating!\n",
|
||||||
digits, len);
|
digits, len);
|
||||||
}
|
}
|
||||||
if (len) {
|
if (len) {
|
||||||
@ -1250,25 +1312,16 @@ static int on_info(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pevent->ring.complete) {
|
if (pevent->ring.complete) {
|
||||||
ftdm_log_chan_msg(chan, FTDM_LOG_DEBUG, "Number complete indicated, moving channel to RING state\n");
|
ftdm_log_chan_msg(chan, FTDM_LOG_DEBUG, "Number complete indication received, moving channel to RING state\n");
|
||||||
/* notify switch */
|
/* notify switch */
|
||||||
ftdm_set_state(chan, FTDM_CHANNEL_STATE_RING);
|
ftdm_set_state(chan, FTDM_CHANNEL_STATE_RING);
|
||||||
}
|
} else {
|
||||||
break;
|
/* Restart T302 */
|
||||||
case FTDM_CHANNEL_STATE_DIALTONE: /* NT-mode overlap receiving */
|
lpwrap_start_timer(spri, &chan_priv->t302, isdn_data->overlap_timeout_ms, &on_timeout_t302);
|
||||||
ftdm_log_chan(chan, FTDM_LOG_DEBUG, "-- Incoming INFORMATION indication, current called number: '%s'\n",
|
|
||||||
pevent->ring.callednum);
|
|
||||||
|
|
||||||
/* Need to add proper support for overlap receiving in NT-mode (requires FreeSWITCH + FreeTDM core support) */
|
|
||||||
if (strlen(pevent->ring.callednum) > 3) {
|
|
||||||
ftdm_log(FTDM_LOG_DEBUG, "final number is: %s\n", pevent->ring.callednum);
|
|
||||||
pri_answer(spri->pri, pevent->ring.call, 0, 1);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ftdm_log_chan(chan, FTDM_LOG_ERROR, "-- INFORMATION indication on channel %d:%d in invalid state '%s'\n",
|
ftdm_log_chan(chan, FTDM_LOG_ERROR, "-- INFORMATION indication in invalid state '%s'\n",
|
||||||
ftdm_channel_get_span_id(chan),
|
|
||||||
ftdm_channel_get_id(chan),
|
|
||||||
ftdm_channel_get_state_str(chan));
|
ftdm_channel_get_state_str(chan));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -1650,6 +1703,7 @@ static int on_ring(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event
|
|||||||
{
|
{
|
||||||
ftdm_span_t *span = spri->span;
|
ftdm_span_t *span = spri->span;
|
||||||
ftdm_libpri_data_t *isdn_data = span->signal_data;
|
ftdm_libpri_data_t *isdn_data = span->signal_data;
|
||||||
|
ftdm_libpri_b_chan_t *chan_priv = NULL;
|
||||||
ftdm_channel_t *chan = NULL;
|
ftdm_channel_t *chan = NULL;
|
||||||
ftdm_caller_data_t *caller_data = NULL;
|
ftdm_caller_data_t *caller_data = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@ -1730,11 +1784,14 @@ static int on_ring(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chan->call_data) {
|
/* Get per-channel private data */
|
||||||
|
chan_priv = chan->call_data;
|
||||||
|
|
||||||
|
if (chan_priv->call) {
|
||||||
/* we could drop the incoming call, but most likely the pointer is just a ghost of the past,
|
/* we could drop the incoming call, but most likely the pointer is just a ghost of the past,
|
||||||
* this check is just to detect potentially unreleased pointers */
|
* this check is just to detect potentially unreleased pointers */
|
||||||
ftdm_log_chan(chan, FTDM_LOG_WARNING, "Channel already has call %p!\n", chan->call_data);
|
ftdm_log_chan(chan, FTDM_LOG_WARNING, "Channel already has call %p!\n", chan_priv->call);
|
||||||
chan->call_data = NULL;
|
chan_priv->call = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
caller_data = ftdm_channel_get_caller_data(chan);
|
caller_data = ftdm_channel_get_caller_data(chan);
|
||||||
@ -1761,7 +1818,7 @@ static int on_ring(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event
|
|||||||
|
|
||||||
// scary to trust this pointer, you'd think they would give you a copy of the call data so you own it......
|
// scary to trust this pointer, you'd think they would give you a copy of the call data so you own it......
|
||||||
/* hurr, this is valid as along as nobody releases the call */
|
/* hurr, this is valid as along as nobody releases the call */
|
||||||
chan->call_data = pevent->ring.call;
|
chan_priv->call = pevent->ring.call;
|
||||||
|
|
||||||
/* Open Channel if inband information is available */
|
/* Open Channel if inband information is available */
|
||||||
if ((pevent->ring.progressmask & PRI_PROG_INBAND_AVAILABLE)) {
|
if ((pevent->ring.progressmask & PRI_PROG_INBAND_AVAILABLE)) {
|
||||||
@ -1799,6 +1856,21 @@ done:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timeout handler for T302 (overlap receiving)
|
||||||
|
*/
|
||||||
|
static int on_timeout_t302(struct lpwrap_pri *spri, struct lpwrap_timer *timer)
|
||||||
|
{
|
||||||
|
ftdm_libpri_b_chan_t *chan_priv = ftdm_container_of(timer, ftdm_libpri_b_chan_t, t302);
|
||||||
|
ftdm_channel_t *chan = chan_priv->channel;
|
||||||
|
|
||||||
|
ftdm_log(FTDM_LOG_NOTICE, "-- T302 timed out, going to state RING\n");
|
||||||
|
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RING);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Processes freetdm event
|
* \brief Processes freetdm event
|
||||||
* \param span Span on which the event was fired
|
* \param span Span on which the event was fired
|
||||||
@ -1826,22 +1898,15 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
|
|||||||
}
|
}
|
||||||
|
|
||||||
ftdm_set_flag(event->channel, FTDM_CHANNEL_SUSPENDED);
|
ftdm_set_flag(event->channel, FTDM_CHANNEL_SUSPENDED);
|
||||||
|
|
||||||
ftdm_channel_get_alarms(event->channel, &alarmbits);
|
ftdm_channel_get_alarms(event->channel, &alarmbits);
|
||||||
ftdm_log(FTDM_LOG_WARNING, "channel %d:%d (%d:%d) has alarms! [%s]\n",
|
ftdm_log_chan_msg(event->channel, FTDM_LOG_WARNING, "channel has alarms!\n");
|
||||||
ftdm_channel_get_span_id(event->channel), ftdm_channel_get_id(event->channel),
|
|
||||||
ftdm_channel_get_ph_span_id(event->channel), ftdm_channel_get_ph_id(event->channel),
|
|
||||||
ftdm_channel_get_last_error(event->channel));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FTDM_OOB_ALARM_CLEAR:
|
case FTDM_OOB_ALARM_CLEAR:
|
||||||
{
|
{
|
||||||
ftdm_log(FTDM_LOG_WARNING, "channel %d:%d (%d:%d) alarms Cleared!\n",
|
|
||||||
ftdm_channel_get_span_id(event->channel), ftdm_channel_get_id(event->channel),
|
|
||||||
ftdm_channel_get_ph_span_id(event->channel), ftdm_channel_get_ph_id(event->channel));
|
|
||||||
|
|
||||||
ftdm_clear_flag(event->channel, FTDM_CHANNEL_SUSPENDED);
|
ftdm_clear_flag(event->channel, FTDM_CHANNEL_SUSPENDED);
|
||||||
ftdm_channel_get_alarms(event->channel, &alarmbits);
|
ftdm_channel_get_alarms(event->channel, &alarmbits);
|
||||||
|
ftdm_log_chan_msg(event->channel, FTDM_LOG_WARNING, "channel alarms cleared!\n");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1892,11 +1957,6 @@ static __inline__ void check_events(ftdm_span_t *span)
|
|||||||
static int check_flags(lpwrap_pri_t *spri)
|
static int check_flags(lpwrap_pri_t *spri)
|
||||||
{
|
{
|
||||||
ftdm_span_t *span = spri->span;
|
ftdm_span_t *span = spri->span;
|
||||||
|
|
||||||
if (!ftdm_running() || ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
check_state(span);
|
check_state(span);
|
||||||
check_events(span);
|
check_events(span);
|
||||||
return 0;
|
return 0;
|
||||||
@ -1911,24 +1971,84 @@ static int check_flags(lpwrap_pri_t *spri)
|
|||||||
*/
|
*/
|
||||||
static int on_restart(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
|
static int on_restart(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
|
||||||
{
|
{
|
||||||
|
ftdm_channel_t *chan = NULL;
|
||||||
ftdm_span_t *span = spri->span;
|
ftdm_span_t *span = spri->span;
|
||||||
ftdm_channel_t *chan = ftdm_span_get_channel(span, pevent->restart.channel);
|
int i;
|
||||||
|
|
||||||
ftdm_log(FTDM_LOG_NOTICE, "-- Restarting %d:%d\n", ftdm_span_get_id(span), pevent->restart.channel);
|
|
||||||
_ftdm_channel_set_state_force(spri->dchan, FTDM_CHANNEL_STATE_UP);
|
|
||||||
|
|
||||||
if (!chan) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pevent->restart.channel < 1) {
|
if (pevent->restart.channel < 1) {
|
||||||
ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
|
ftdm_log_chan_msg(spri->dchan, FTDM_LOG_NOTICE, "-- Restarting interface\n");
|
||||||
} else {
|
|
||||||
|
for (i = 1; i <= ftdm_span_get_chan_count(span); i++) {
|
||||||
|
chan = ftdm_span_get_channel(span, i);
|
||||||
|
if (!chan)
|
||||||
|
continue;
|
||||||
|
if (ftdm_channel_get_type(chan) == FTDM_CHAN_TYPE_B) {
|
||||||
|
ftdm_libpri_b_chan_t *chan_priv = chan->call_data;
|
||||||
|
chan_priv->flags |= FTDM_LIBPRI_B_REMOTE_RESTART; /* Remote triggered RESTART, set flag */
|
||||||
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART);
|
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((chan = ftdm_span_get_channel(span, pevent->restart.channel))) {
|
||||||
|
ftdm_libpri_b_chan_t *chan_priv = chan->call_data;
|
||||||
|
|
||||||
|
ftdm_log_chan_msg(chan, FTDM_LOG_NOTICE, "-- Restarting single channel\n");
|
||||||
|
chan_priv->flags |= FTDM_LIBPRI_B_REMOTE_RESTART;
|
||||||
|
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ftdm_log(FTDM_LOG_ERROR, "Invalid restart indicator / channel id '%d' received\n",
|
||||||
|
pevent->restart.channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ftdm_channel_set_state_force(spri->dchan, FTDM_CHANNEL_STATE_UP);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Handler for libpri restart acknowledge event
|
||||||
|
* \param spri Pri wrapper structure (libpri, span, dchan)
|
||||||
|
* \param event_type Event type (unused)
|
||||||
|
* \param pevent Event
|
||||||
|
* \return 0
|
||||||
|
*/
|
||||||
|
static int on_restart_ack(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
|
||||||
|
{
|
||||||
|
ftdm_channel_t *chan = NULL;
|
||||||
|
ftdm_span_t *span = spri->span;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (pevent->restartack.channel < 1) {
|
||||||
|
ftdm_log_chan_msg(spri->dchan, FTDM_LOG_NOTICE, "-- Restart of interface completed\n");
|
||||||
|
|
||||||
|
for (i = 1; i <= ftdm_span_get_chan_count(span); i++) {
|
||||||
|
chan = ftdm_span_get_channel(span, i);
|
||||||
|
if (!chan)
|
||||||
|
continue;
|
||||||
|
if (ftdm_channel_get_type(chan) == FTDM_CHAN_TYPE_B) {
|
||||||
|
ftdm_libpri_b_chan_t *chan_priv = chan->call_data;
|
||||||
|
if (!(chan_priv->flags & FTDM_LIBPRI_B_REMOTE_RESTART)) {
|
||||||
|
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_DOWN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((chan = ftdm_span_get_channel(span, pevent->restart.channel))) {
|
||||||
|
ftdm_log_chan_msg(chan, FTDM_LOG_NOTICE, "-- Restart of channel completed\n");
|
||||||
|
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_DOWN);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ftdm_log(FTDM_LOG_ERROR, "Invalid restart indicator / channel id '%d' received\n",
|
||||||
|
pevent->restartack.channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ftdm_channel_set_state_force(spri->dchan, FTDM_CHANNEL_STATE_UP);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FACILITY Advice-On-Charge handler
|
* FACILITY Advice-On-Charge handler
|
||||||
*/
|
*/
|
||||||
@ -2224,61 +2344,38 @@ static void *ftdm_libpri_run(ftdm_thread_t *me, void *obj)
|
|||||||
ftdm_span_t *span = (ftdm_span_t *) obj;
|
ftdm_span_t *span = (ftdm_span_t *) obj;
|
||||||
ftdm_libpri_data_t *isdn_data = span->signal_data;
|
ftdm_libpri_data_t *isdn_data = span->signal_data;
|
||||||
int down = 0;
|
int down = 0;
|
||||||
int got_d = 0;
|
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
ftdm_set_flag(span, FTDM_SPAN_IN_THREAD);
|
ftdm_set_flag(span, FTDM_SPAN_IN_THREAD);
|
||||||
|
isdn_data->dchan = NULL;
|
||||||
|
|
||||||
while (ftdm_running() && !ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
|
/*
|
||||||
if (!got_d) {
|
* Open D-Channel
|
||||||
int i, x;
|
*/
|
||||||
|
for (i = 1; i <= ftdm_span_get_chan_count(span); i++) {
|
||||||
for (i = 1, x = 0; i <= ftdm_span_get_chan_count(span); i++) {
|
|
||||||
ftdm_channel_t *chan = ftdm_span_get_channel(span, i);
|
ftdm_channel_t *chan = ftdm_span_get_channel(span, i);
|
||||||
|
|
||||||
if (ftdm_channel_get_type(chan) == FTDM_CHAN_TYPE_DQ921) {
|
if (ftdm_channel_get_type(chan) == FTDM_CHAN_TYPE_DQ921) {
|
||||||
if (ftdm_channel_open(ftdm_span_get_id(span), i, &isdn_data->dchan) == FTDM_SUCCESS) {
|
if (ftdm_channel_open(ftdm_span_get_id(span), i, &isdn_data->dchan) == FTDM_SUCCESS) {
|
||||||
ftdm_log(FTDM_LOG_DEBUG, "opening D-Channel #%d %d:%d\n", x,
|
ftdm_log_chan_msg(chan, FTDM_LOG_DEBUG, "Opened D-Channel\n");
|
||||||
ftdm_channel_get_span_id(isdn_data->dchan), ftdm_channel_get_id(isdn_data->dchan));
|
|
||||||
got_d = 1;
|
|
||||||
x++;
|
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
ftdm_log(FTDM_LOG_ERROR, "failed to open D-Channel #%d %d:%d\n", x,
|
ftdm_log_chan_msg(chan, FTDM_LOG_CRIT, "Failed to open D-Channel\n");
|
||||||
ftdm_channel_get_span_id(chan), ftdm_channel_get_id(chan));
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!got_d || !isdn_data->dchan) {
|
|
||||||
ftdm_log(FTDM_LOG_ERROR, "Failed to get a D-Channel in span %d\n", ftdm_span_get_id(span));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize libpri trunk */
|
/*
|
||||||
switch (ftdm_span_get_trunk_type(span)) {
|
* Initialize BRI/PRI context
|
||||||
case FTDM_TRUNK_E1:
|
*/
|
||||||
case FTDM_TRUNK_T1:
|
|
||||||
case FTDM_TRUNK_J1:
|
|
||||||
res = lpwrap_init_pri(&isdn_data->spri, span, isdn_data->dchan,
|
res = lpwrap_init_pri(&isdn_data->spri, span, isdn_data->dchan,
|
||||||
isdn_data->dialect, isdn_data->mode, isdn_data->debug_mask);
|
isdn_data->dialect, isdn_data->mode, isdn_data->debug_mask);
|
||||||
break;
|
|
||||||
case FTDM_TRUNK_BRI:
|
if (res) {
|
||||||
res = lpwrap_init_bri(&isdn_data->spri, span, isdn_data->dchan,
|
ftdm_log(FTDM_LOG_CRIT, "Failed to initialize BRI/PRI on span %d\n",
|
||||||
isdn_data->dialect, isdn_data->mode, 1, isdn_data->debug_mask);
|
ftdm_span_get_id(span));
|
||||||
#ifndef HAVE_LIBPRI_BRI
|
|
||||||
goto out;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case FTDM_TRUNK_BRI_PTMP:
|
|
||||||
res = lpwrap_init_bri(&isdn_data->spri, span, isdn_data->dchan,
|
|
||||||
isdn_data->dialect, isdn_data->mode, 0, isdn_data->debug_mask);
|
|
||||||
#ifndef HAVE_LIBPRI_BRI
|
|
||||||
goto out;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
snprintf(span->last_error, sizeof(span->last_error), "Invalid trunk type");
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2293,10 +2390,10 @@ static void *ftdm_libpri_run(ftdm_thread_t *me, void *obj)
|
|||||||
#endif
|
#endif
|
||||||
/* Support the different switch of service status */
|
/* Support the different switch of service status */
|
||||||
if (isdn_data->service_message_support) {
|
if (isdn_data->service_message_support) {
|
||||||
pri_set_service_message_support(isdn_data->spri.pri, 1 /* True */);
|
pri_set_service_message_support(isdn_data->spri.pri, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res == 0) {
|
/* Callbacks for libpri events */
|
||||||
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_ANY, on_anything);
|
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_ANY, on_anything);
|
||||||
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RING, on_ring);
|
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RING, on_ring);
|
||||||
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RINGING, on_ringing);
|
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RINGING, on_ringing);
|
||||||
@ -2308,26 +2405,27 @@ static void *ftdm_libpri_run(ftdm_thread_t *me, void *obj)
|
|||||||
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_HANGUP_REQ, on_hangup);
|
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_HANGUP_REQ, on_hangup);
|
||||||
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_HANGUP_ACK, on_hangup);
|
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_HANGUP_ACK, on_hangup);
|
||||||
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_HANGUP, on_hangup);
|
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_HANGUP, on_hangup);
|
||||||
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_INFO_RECEIVED, on_info);
|
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_INFO_RECEIVED, on_information);
|
||||||
|
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_KEYPAD_DIGIT, on_keypad_digit);
|
||||||
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RESTART, on_restart);
|
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RESTART, on_restart);
|
||||||
|
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RESTART_ACK, on_restart_ack);
|
||||||
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_IO_FAIL, on_io_fail);
|
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_IO_FAIL, on_io_fail);
|
||||||
#ifdef HAVE_LIBPRI_AOC
|
|
||||||
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_FACILITY, on_facility);
|
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_FACILITY, on_facility);
|
||||||
#endif
|
|
||||||
|
/* Callback invoked on each iteration of the lpwrap_run_pri() event loop */
|
||||||
|
isdn_data->spri.on_loop = check_flags;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Event loop
|
||||||
|
*/
|
||||||
|
while (ftdm_running() && !ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
|
||||||
if (down) {
|
if (down) {
|
||||||
ftdm_log(FTDM_LOG_INFO, "PRI back up on span %d\n", ftdm_span_get_id(span));
|
ftdm_log(FTDM_LOG_INFO, "PRI back up on span %d\n", ftdm_span_get_id(span));
|
||||||
ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
|
ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
|
||||||
down = 0;
|
down = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
isdn_data->spri.on_loop = check_flags;
|
|
||||||
|
|
||||||
lpwrap_run_pri(&isdn_data->spri);
|
lpwrap_run_pri(&isdn_data->spri);
|
||||||
} else {
|
|
||||||
ftdm_log(FTDM_LOG_CRIT, "PRI init failed!\n");
|
|
||||||
snprintf(span->last_error, sizeof(span->last_error), "PRI init failed!");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ftdm_running() || ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
|
if (!ftdm_running() || ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
|
||||||
break;
|
break;
|
||||||
@ -2353,8 +2451,7 @@ out:
|
|||||||
/* close d-channel, if set */
|
/* close d-channel, if set */
|
||||||
if (isdn_data->dchan) {
|
if (isdn_data->dchan) {
|
||||||
if (ftdm_channel_close(&isdn_data->dchan) != FTDM_SUCCESS) {
|
if (ftdm_channel_close(&isdn_data->dchan) != FTDM_SUCCESS) {
|
||||||
ftdm_log(FTDM_LOG_ERROR, "Failed to close D-Channel %d:%d\n",
|
ftdm_log_chan_msg(isdn_data->dchan, FTDM_LOG_ERROR, "Failed to close D-Channel\n");
|
||||||
ftdm_channel_get_span_id(isdn_data->dchan), ftdm_channel_get_id(isdn_data->dchan));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2363,6 +2460,7 @@ out:
|
|||||||
ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
|
ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
|
||||||
ftdm_clear_flag(isdn_data, FTMOD_LIBPRI_RUNNING);
|
ftdm_clear_flag(isdn_data, FTMOD_LIBPRI_RUNNING);
|
||||||
|
|
||||||
|
lpwrap_destroy_pri(&isdn_data->spri);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2381,11 +2479,14 @@ static ftdm_status_t ftdm_libpri_stop(ftdm_span_t *span)
|
|||||||
return FTDM_FAIL;
|
return FTDM_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
|
ftdm_log(FTDM_LOG_INFO, "Stopping span [s%d][%s]\n",
|
||||||
|
ftdm_span_get_id(span), ftdm_span_get_name(span));
|
||||||
|
|
||||||
|
ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
|
||||||
check_state(span);
|
check_state(span);
|
||||||
|
|
||||||
ftdm_set_flag(span, FTDM_SPAN_STOP_THREAD);
|
ftdm_set_flag(span, FTDM_SPAN_STOP_THREAD);
|
||||||
|
lpwrap_stop_pri(&isdn_data->spri);
|
||||||
|
|
||||||
while (ftdm_test_flag(span, FTDM_SPAN_IN_THREAD)) {
|
while (ftdm_test_flag(span, FTDM_SPAN_IN_THREAD)) {
|
||||||
ftdm_sleep(100);
|
ftdm_sleep(100);
|
||||||
@ -2411,6 +2512,9 @@ static ftdm_status_t ftdm_libpri_start(ftdm_span_t *span)
|
|||||||
return FTDM_FAIL;
|
return FTDM_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ftdm_log(FTDM_LOG_INFO, "Starting span [s%d][%s]\n",
|
||||||
|
ftdm_span_get_id(span), ftdm_span_get_name(span));
|
||||||
|
|
||||||
ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD);
|
ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD);
|
||||||
ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
|
ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
|
||||||
|
|
||||||
@ -2552,7 +2656,6 @@ static uint32_t parse_opts(const char *in)
|
|||||||
static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
||||||
{
|
{
|
||||||
ftdm_libpri_data_t *isdn_data = NULL;
|
ftdm_libpri_data_t *isdn_data = NULL;
|
||||||
//ftdm_channel_t *dchan = NULL;
|
|
||||||
uint32_t bchan_count = 0;
|
uint32_t bchan_count = 0;
|
||||||
uint32_t dchan_count = 0;
|
uint32_t dchan_count = 0;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
@ -2569,23 +2672,10 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
|||||||
case FTDM_CHAN_TYPE_DQ921:
|
case FTDM_CHAN_TYPE_DQ921:
|
||||||
if (dchan_count > 1) {
|
if (dchan_count > 1) {
|
||||||
ftdm_log(FTDM_LOG_ERROR, "Span has more than 2 D-Channels!\n");
|
ftdm_log(FTDM_LOG_ERROR, "Span has more than 2 D-Channels!\n");
|
||||||
snprintf(span->last_error, sizeof(span->last_error), "Span has more than 2 D-Channels!");
|
|
||||||
return FTDM_FAIL;
|
|
||||||
} else {
|
|
||||||
#if 0
|
|
||||||
if (ftdm_channel_open(ftdm_span_get_id(span), i, &dchan) == FTDM_SUCCESS) {
|
|
||||||
ftdm_log(FTDM_LOG_DEBUG, "opening D-Channel %d:%d\n", ftdm_channel_get_span_id(dchan), ftdm_channel_get_id(dchan));
|
|
||||||
_ftdm_channel_set_state_force(dchan, FTDM_CHANNEL_STATE_UP);
|
|
||||||
} else {
|
|
||||||
ftdm_log(FTDM_LOG_ERROR, "Failed to open D-Channel %d:%d\n", ftdm_channel_get_span_id(chan), ftdm_channel_getid(chan));
|
|
||||||
snprintf(span->last_error, sizeof(span->last_error), "Failed to open D-Channel %d:%d\n", ftdm_channel_get_span_id(chan), ftdm_channel_getid(chan));
|
|
||||||
return FTDM_FAIL;
|
return FTDM_FAIL;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
dchan_count++;
|
dchan_count++;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FTDM_CHAN_TYPE_B:
|
case FTDM_CHAN_TYPE_B:
|
||||||
bchan_count++;
|
bchan_count++;
|
||||||
break;
|
break;
|
||||||
@ -2595,12 +2685,10 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
|||||||
}
|
}
|
||||||
if (!dchan_count) {
|
if (!dchan_count) {
|
||||||
ftdm_log(FTDM_LOG_ERROR, "Span has no D-Channel!\n");
|
ftdm_log(FTDM_LOG_ERROR, "Span has no D-Channel!\n");
|
||||||
snprintf(span->last_error, sizeof(span->last_error), "Span has no D-Channel!");
|
|
||||||
return FTDM_FAIL;
|
return FTDM_FAIL;
|
||||||
}
|
}
|
||||||
if (!bchan_count) {
|
if (!bchan_count) {
|
||||||
ftdm_log(FTDM_LOG_ERROR, "Span has no B-Channels!\n");
|
ftdm_log(FTDM_LOG_ERROR, "Span has no B-Channels!\n");
|
||||||
snprintf(span->last_error, sizeof(span->last_error), "Span has no B-Channels!");
|
|
||||||
return FTDM_FAIL;
|
return FTDM_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2610,6 +2698,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
|||||||
|
|
||||||
/* set some default values */
|
/* set some default values */
|
||||||
isdn_data->ton = PRI_UNKNOWN;
|
isdn_data->ton = PRI_UNKNOWN;
|
||||||
|
isdn_data->overlap_timeout_ms = OVERLAP_TIMEOUT_MS_DEFAULT;
|
||||||
|
|
||||||
/* Use span's trunk_mode as a reference for the default libpri mode */
|
/* Use span's trunk_mode as a reference for the default libpri mode */
|
||||||
if (ftdm_span_get_trunk_mode(span) == FTDM_TRUNK_MODE_NET) {
|
if (ftdm_span_get_trunk_mode(span) == FTDM_TRUNK_MODE_NET) {
|
||||||
@ -2623,7 +2712,6 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
|||||||
case FTDM_TRUNK_BRI_PTMP:
|
case FTDM_TRUNK_BRI_PTMP:
|
||||||
#ifndef HAVE_LIBPRI_BRI
|
#ifndef HAVE_LIBPRI_BRI
|
||||||
ftdm_log(FTDM_LOG_ERROR, "Unsupported trunk type: '%s', libpri too old\n", ftdm_span_get_trunk_type_str(span));
|
ftdm_log(FTDM_LOG_ERROR, "Unsupported trunk type: '%s', libpri too old\n", ftdm_span_get_trunk_type_str(span));
|
||||||
snprintf(span->last_error, sizeof(span->last_error), "Unsupported trunk type [%s], libpri too old", ftdm_span_get_trunk_type_str(span));
|
|
||||||
goto error;
|
goto error;
|
||||||
#endif
|
#endif
|
||||||
case FTDM_TRUNK_E1:
|
case FTDM_TRUNK_E1:
|
||||||
@ -2639,7 +2727,6 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ftdm_log(FTDM_LOG_ERROR, "Invalid trunk type: '%s'\n", ftdm_span_get_trunk_type_str(span));
|
ftdm_log(FTDM_LOG_ERROR, "Invalid trunk type: '%s'\n", ftdm_span_get_trunk_type_str(span));
|
||||||
snprintf(span->last_error, sizeof(span->last_error), "Invalid trunk type [%s]", ftdm_span_get_trunk_type_str(span));
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2648,7 +2735,6 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
|||||||
*/
|
*/
|
||||||
if (msn_filter_init(isdn_data) != FTDM_SUCCESS) {
|
if (msn_filter_init(isdn_data) != FTDM_SUCCESS) {
|
||||||
ftdm_log(FTDM_LOG_ERROR, "Failed to init MSN filter\n");
|
ftdm_log(FTDM_LOG_ERROR, "Failed to init MSN filter\n");
|
||||||
snprintf(span->last_error, sizeof(span->last_error), "Failed to init MSN filter");
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2663,7 +2749,6 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
|||||||
|
|
||||||
if (ftdm_strlen_zero(val)) {
|
if (ftdm_strlen_zero(val)) {
|
||||||
ftdm_log(FTDM_LOG_ERROR, "Parameter '%s' has no value\n", var);
|
ftdm_log(FTDM_LOG_ERROR, "Parameter '%s' has no value\n", var);
|
||||||
snprintf(span->last_error, sizeof(span->last_error), "Parameter [%s] has no value", var);
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2691,6 +2776,17 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
|||||||
isdn_data->overlap = FTMOD_LIBPRI_OVERLAP_NONE;
|
isdn_data->overlap = FTMOD_LIBPRI_OVERLAP_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "t302")) {
|
||||||
|
int tmp = atoi(val);
|
||||||
|
if (!tmp) {
|
||||||
|
isdn_data->overlap_timeout_ms = 0; /* disabled */
|
||||||
|
}
|
||||||
|
else if ((isdn_data->overlap_timeout_ms = ftdm_clamp(tmp, OVERLAP_TIMEOUT_MS_MIN, OVERLAP_TIMEOUT_MS_MAX)) != tmp) {
|
||||||
|
ftdm_log(FTDM_LOG_WARNING, "'%s' value '%d' outside of range [%d:%d], using '%d' ms instead\n",
|
||||||
|
var, tmp, OVERLAP_TIMEOUT_MS_MIN, OVERLAP_TIMEOUT_MS_MAX,
|
||||||
|
isdn_data->overlap_timeout_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (!strcasecmp(var, "debug")) {
|
else if (!strcasecmp(var, "debug")) {
|
||||||
if (parse_debug(val, &isdn_data->debug_mask) == -1) {
|
if (parse_debug(val, &isdn_data->debug_mask) == -1) {
|
||||||
ftdm_log(FTDM_LOG_ERROR, "Invalid debug flag, ignoring parameter\n");
|
ftdm_log(FTDM_LOG_ERROR, "Invalid debug flag, ignoring parameter\n");
|
||||||
@ -2705,13 +2801,11 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
|||||||
else if (!strcasecmp(var, "local-number") || !strcasecmp(var, "msn")) {
|
else if (!strcasecmp(var, "local-number") || !strcasecmp(var, "msn")) {
|
||||||
if (msn_filter_add(isdn_data, val) != FTDM_SUCCESS) {
|
if (msn_filter_add(isdn_data, val) != FTDM_SUCCESS) {
|
||||||
ftdm_log(FTDM_LOG_ERROR, "Invalid MSN/DDI(s) '%s' specified\n", val);
|
ftdm_log(FTDM_LOG_ERROR, "Invalid MSN/DDI(s) '%s' specified\n", val);
|
||||||
snprintf(span->last_error, sizeof(span->last_error), "Invalid MSN/DDI(s) '%s' specified!", val);
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ftdm_log(FTDM_LOG_ERROR, "Unknown parameter '%s', aborting configuration\n", var);
|
ftdm_log(FTDM_LOG_ERROR, "Unknown parameter '%s', aborting configuration\n", var);
|
||||||
snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2748,8 +2842,28 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
|||||||
ftdm_set_flag(span, FTDM_SPAN_SUGGEST_CHAN_ID);
|
ftdm_set_flag(span, FTDM_SPAN_SUGGEST_CHAN_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Allocate per-channel private data */
|
||||||
|
for (i = 1; i <= ftdm_span_get_chan_count(span); i++) {
|
||||||
|
ftdm_channel_t *chan = ftdm_span_get_channel(span, i);
|
||||||
|
|
||||||
|
if (!chan)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ftdm_channel_get_type(chan) == FTDM_CHAN_TYPE_B) {
|
||||||
|
ftdm_libpri_b_chan_t *priv = NULL;
|
||||||
|
|
||||||
|
priv = calloc(1, sizeof(*priv));
|
||||||
|
if (!priv) {
|
||||||
|
ftdm_log_chan_msg(chan, FTDM_LOG_CRIT, "Failed to allocate per-channel private data\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
priv->channel = chan;
|
||||||
|
chan->call_data = priv;
|
||||||
|
}
|
||||||
|
}
|
||||||
return FTDM_SUCCESS;
|
return FTDM_SUCCESS;
|
||||||
error:
|
error:
|
||||||
|
/* TODO: free per-channel private data */
|
||||||
msn_filter_destroy(isdn_data);
|
msn_filter_destroy(isdn_data);
|
||||||
ftdm_safe_free(isdn_data);
|
ftdm_safe_free(isdn_data);
|
||||||
return FTDM_FAIL;
|
return FTDM_FAIL;
|
||||||
|
@ -35,6 +35,10 @@
|
|||||||
#include "freetdm.h"
|
#include "freetdm.h"
|
||||||
#include "lpwrap_pri.h"
|
#include "lpwrap_pri.h"
|
||||||
|
|
||||||
|
#define OVERLAP_TIMEOUT_MS_DEFAULT 5000 /* 5 sec */
|
||||||
|
#define OVERLAP_TIMEOUT_MS_MIN 3000 /* 3 sec */
|
||||||
|
#define OVERLAP_TIMEOUT_MS_MAX 30000 /* 30 sec */
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SERVICE_CHANGE_STATUS_INSERVICE = 0,
|
SERVICE_CHANGE_STATUS_INSERVICE = 0,
|
||||||
SERVICE_CHANGE_STATUS_MAINTENANCE,
|
SERVICE_CHANGE_STATUS_MAINTENANCE,
|
||||||
@ -71,6 +75,7 @@ struct ftdm_libpri_data {
|
|||||||
int mode;
|
int mode;
|
||||||
int dialect;
|
int dialect;
|
||||||
int overlap; /*!< Overlap dial flags */
|
int overlap; /*!< Overlap dial flags */
|
||||||
|
int overlap_timeout_ms; /*!< Overlap dial timeout */
|
||||||
unsigned int layer1;
|
unsigned int layer1;
|
||||||
unsigned int ton;
|
unsigned int ton;
|
||||||
unsigned int service_message_support;
|
unsigned int service_message_support;
|
||||||
@ -84,6 +89,27 @@ struct ftdm_libpri_data {
|
|||||||
|
|
||||||
typedef struct ftdm_libpri_data ftdm_libpri_data_t;
|
typedef struct ftdm_libpri_data ftdm_libpri_data_t;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* b-channel flags
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
FTDM_LIBPRI_B_NONE = 0,
|
||||||
|
FTDM_LIBPRI_B_REMOTE_RESTART = (1 << 0), /*!< Remote triggered channel restart */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Per-b-channel private data
|
||||||
|
*/
|
||||||
|
struct ftdm_libpri_b_chan {
|
||||||
|
struct lpwrap_timer t302; /*!< T302 overlap receive timer */
|
||||||
|
ftdm_channel_t *channel; /*!< back-pointer to b-channel */
|
||||||
|
q931_call *call; /*!< libpri opaque call handle */
|
||||||
|
uint32_t flags; /*!< channel flags */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ftdm_libpri_b_chan ftdm_libpri_b_chan_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* For Emacs:
|
/* For Emacs:
|
||||||
|
@ -36,51 +36,7 @@
|
|||||||
#include "private/ftdm_core.h"
|
#include "private/ftdm_core.h"
|
||||||
#include "lpwrap_pri.h"
|
#include "lpwrap_pri.h"
|
||||||
|
|
||||||
#ifndef HAVE_GETTIMEOFDAY
|
static struct lpwrap_pri_event_list LPWRAP_PRI_EVENT_LIST[LPWRAP_PRI_EVENT_MAX] = {
|
||||||
#ifdef WIN32
|
|
||||||
#include <mmsystem.h>
|
|
||||||
|
|
||||||
static __inline int gettimeofday(struct timeval *tp, void *nothing)
|
|
||||||
{
|
|
||||||
#ifdef WITHOUT_MM_LIB
|
|
||||||
SYSTEMTIME st;
|
|
||||||
time_t tt;
|
|
||||||
struct tm tmtm;
|
|
||||||
/* mktime converts local to UTC */
|
|
||||||
GetLocalTime (&st);
|
|
||||||
tmtm.tm_sec = st.wSecond;
|
|
||||||
tmtm.tm_min = st.wMinute;
|
|
||||||
tmtm.tm_hour = st.wHour;
|
|
||||||
tmtm.tm_mday = st.wDay;
|
|
||||||
tmtm.tm_mon = st.wMonth - 1;
|
|
||||||
tmtm.tm_year = st.wYear - 1900; tmtm.tm_isdst = -1;
|
|
||||||
tt = mktime (&tmtm);
|
|
||||||
tp->tv_sec = tt;
|
|
||||||
tp->tv_usec = st.wMilliseconds * 1000;
|
|
||||||
#else
|
|
||||||
/**
|
|
||||||
** The earlier time calculations using GetLocalTime
|
|
||||||
** had a time resolution of 10ms.The timeGetTime, part
|
|
||||||
** of multimedia apis offer a better time resolution
|
|
||||||
** of 1ms.Need to link against winmm.lib for this
|
|
||||||
**/
|
|
||||||
unsigned long Ticks = 0;
|
|
||||||
unsigned long Sec =0;
|
|
||||||
unsigned long Usec = 0;
|
|
||||||
Ticks = timeGetTime();
|
|
||||||
|
|
||||||
Sec = Ticks/1000;
|
|
||||||
Usec = (Ticks - (Sec*1000))*1000;
|
|
||||||
tp->tv_sec = Sec;
|
|
||||||
tp->tv_usec = Usec;
|
|
||||||
#endif /* WITHOUT_MM_LIB */
|
|
||||||
(void)nothing;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif /* WIN32 */
|
|
||||||
#endif /* HAVE_GETTIMEOFDAY */
|
|
||||||
|
|
||||||
static struct lpwrap_pri_event_list LPWRAP_PRI_EVENT_LIST[] = {
|
|
||||||
{0, LPWRAP_PRI_EVENT_ANY, "ANY"},
|
{0, LPWRAP_PRI_EVENT_ANY, "ANY"},
|
||||||
{1, LPWRAP_PRI_EVENT_DCHAN_UP, "DCHAN_UP"},
|
{1, LPWRAP_PRI_EVENT_DCHAN_UP, "DCHAN_UP"},
|
||||||
{2, LPWRAP_PRI_EVENT_DCHAN_DOWN, "DCHAN_DOWN"},
|
{2, LPWRAP_PRI_EVENT_DCHAN_DOWN, "DCHAN_DOWN"},
|
||||||
@ -103,8 +59,6 @@ static struct lpwrap_pri_event_list LPWRAP_PRI_EVENT_LIST[] = {
|
|||||||
{19, LPWRAP_PRI_EVENT_IO_FAIL, "IO_FAIL"},
|
{19, LPWRAP_PRI_EVENT_IO_FAIL, "IO_FAIL"},
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LINE "--------------------------------------------------------------------------------"
|
|
||||||
|
|
||||||
const char *lpwrap_pri_event_str(lpwrap_pri_event_t event_id)
|
const char *lpwrap_pri_event_str(lpwrap_pri_event_t event_id)
|
||||||
{
|
{
|
||||||
if (event_id < 0 || event_id >= LPWRAP_PRI_EVENT_MAX)
|
if (event_id < 0 || event_id >= LPWRAP_PRI_EVENT_MAX)
|
||||||
@ -170,6 +124,10 @@ static int __pri_lpwrap_write(struct pri *pri, void *buf, int buflen)
|
|||||||
return (int)buflen;
|
return (int)buflen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unified init function for BRI + PRI libpri spans
|
||||||
|
*/
|
||||||
int lpwrap_init_pri(struct lpwrap_pri *spri, ftdm_span_t *span, ftdm_channel_t *dchan, int swtype, int node, int debug)
|
int lpwrap_init_pri(struct lpwrap_pri *spri, ftdm_span_t *span, ftdm_channel_t *dchan, int swtype, int node, int debug)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
@ -179,115 +137,255 @@ int lpwrap_init_pri(struct lpwrap_pri *spri, ftdm_span_t *span, ftdm_channel_t *
|
|||||||
spri->span = span;
|
spri->span = span;
|
||||||
|
|
||||||
if (!spri->dchan) {
|
if (!spri->dchan) {
|
||||||
ftdm_log(FTDM_LOG_ERROR, "No D-Channel available, unable to create PRI\n");
|
ftdm_log(FTDM_LOG_ERROR, "No D-Channel available, unable to create BRI/PRI\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((spri->pri = pri_new_cb(spri->dchan->sockfd, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri))) {
|
if (ftdm_mutex_create(&spri->timer_mutex) != FTDM_SUCCESS) {
|
||||||
unsigned char buf[4] = { 0 };
|
ftdm_log(FTDM_LOG_ERROR, "Failed to create timer list mutex\n");
|
||||||
size_t buflen = sizeof(buf), len = 0;
|
|
||||||
|
|
||||||
pri_set_debug(spri->pri, debug);
|
|
||||||
#ifdef HAVE_LIBPRI_AOC
|
|
||||||
pri_aoc_events_enable(spri->pri, 1);
|
|
||||||
#endif
|
|
||||||
ftdm_channel_write(spri->dchan, buf, buflen, &len);
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
} else {
|
|
||||||
ftdm_log(FTDM_LOG_ERROR, "Unable to create PRI\n");
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lpwrap_init_bri(struct lpwrap_pri *spri, ftdm_span_t *span, ftdm_channel_t *dchan, int swtype, int node, int ptp, int debug)
|
switch (ftdm_span_get_trunk_type(span)) {
|
||||||
{
|
case FTDM_TRUNK_E1:
|
||||||
int ret = -1;
|
case FTDM_TRUNK_J1:
|
||||||
|
case FTDM_TRUNK_T1:
|
||||||
|
spri->pri = pri_new_cb(spri->dchan->sockfd, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri);
|
||||||
|
break;
|
||||||
#ifdef HAVE_LIBPRI_BRI
|
#ifdef HAVE_LIBPRI_BRI
|
||||||
memset(spri, 0, sizeof(struct lpwrap_pri));
|
case FTDM_TRUNK_BRI:
|
||||||
spri->dchan = dchan;
|
spri->pri = pri_new_bri_cb(spri->dchan->sockfd, 1, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri);
|
||||||
spri->span = span;
|
break;
|
||||||
|
case FTDM_TRUNK_BRI_PTMP:
|
||||||
if (!spri->dchan) {
|
spri->pri = pri_new_bri_cb(spri->dchan->sockfd, 0, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri);
|
||||||
ftdm_log(FTDM_LOG_ERROR, "No D-Channel available, unable to create BRI\n");
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
ftdm_log(FTDM_LOG_CRIT, "Invalid/unsupported trunk type '%s'\n",
|
||||||
|
ftdm_span_get_trunk_type_str(span));
|
||||||
|
ftdm_mutex_destroy(&spri->timer_mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((spri->pri = pri_new_bri_cb(spri->dchan->sockfd, ptp, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri))) {
|
if (spri->pri) {
|
||||||
unsigned char buf[4] = { 0 };
|
|
||||||
size_t buflen = sizeof(buf), len = 0;
|
|
||||||
|
|
||||||
pri_set_debug(spri->pri, debug);
|
pri_set_debug(spri->pri, debug);
|
||||||
#ifdef HAVE_LIBPRI_AOC
|
#ifdef HAVE_LIBPRI_AOC
|
||||||
pri_aoc_events_enable(spri->pri, 1);
|
pri_aoc_events_enable(spri->pri, 1);
|
||||||
#endif
|
#endif
|
||||||
ftdm_channel_write(spri->dchan, buf, buflen, &len);
|
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
} else {
|
} else {
|
||||||
ftdm_log(FTDM_LOG_ERROR, "Unable to create BRI\n");
|
ftdm_log(FTDM_LOG_CRIT, "Unable to create BRI/PRI\n");
|
||||||
|
ftdm_mutex_destroy(&spri->timer_mutex);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
ftdm_log(FTDM_LOG_ERROR, "Installed libpri version (%s) has no BRI support\n",
|
|
||||||
pri_get_version());
|
|
||||||
#endif
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int lpwrap_one_loop(struct lpwrap_pri *spri)
|
#define timeval_to_ms(x) \
|
||||||
|
(((ftdm_time_t)(x)->tv_sec * 1000) + (ftdm_time_t)((x)->tv_usec / 1000))
|
||||||
|
|
||||||
|
int lpwrap_start_timer(struct lpwrap_pri *spri, struct lpwrap_timer *timer, const uint32_t timeout_ms, timeout_handler callback)
|
||||||
{
|
{
|
||||||
fd_set rfds, efds;
|
struct lpwrap_timer **prev, *cur;
|
||||||
struct timeval now = {0,0}, *next = NULL;
|
|
||||||
|
if (!spri || !timer || timer->timeout)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ftdm_log_chan(spri->dchan, FTDM_LOG_DEBUG, "-- Starting timer %p with timeout %u ms\n",
|
||||||
|
timer, timeout_ms);
|
||||||
|
|
||||||
|
timer->timeout = ftdm_current_time_in_ms() + timeout_ms;
|
||||||
|
timer->callback = callback;
|
||||||
|
timer->next = NULL;
|
||||||
|
|
||||||
|
ftdm_mutex_lock(spri->timer_mutex);
|
||||||
|
|
||||||
|
for (prev = &spri->timer_list, cur = spri->timer_list; cur; prev = &(*prev)->next, cur = cur->next) {
|
||||||
|
if (cur->timeout < timer->timeout) {
|
||||||
|
*prev = timer;
|
||||||
|
timer->next = cur;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!cur) {
|
||||||
|
*prev = timer;
|
||||||
|
}
|
||||||
|
|
||||||
|
ftdm_mutex_unlock(spri->timer_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lpwrap_stop_timer(struct lpwrap_pri *spri, struct lpwrap_timer *timer)
|
||||||
|
{
|
||||||
|
struct lpwrap_timer **prev, *cur;
|
||||||
|
|
||||||
|
if (!spri || !timer)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!timer->timeout)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ftdm_log_chan(spri->dchan, FTDM_LOG_DEBUG, "-- Stopping timer %p\n", timer);
|
||||||
|
|
||||||
|
ftdm_mutex_lock(spri->timer_mutex);
|
||||||
|
|
||||||
|
for (prev = &spri->timer_list, cur = spri->timer_list; cur; prev = &(*prev)->next, cur = cur->next) {
|
||||||
|
if (cur == timer) {
|
||||||
|
*prev = cur->next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ftdm_mutex_unlock(spri->timer_mutex);
|
||||||
|
|
||||||
|
timer->next = NULL;
|
||||||
|
timer->timeout = 0;
|
||||||
|
timer->callback = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct lpwrap_timer *lpwrap_timer_next(struct lpwrap_pri *spri)
|
||||||
|
{
|
||||||
|
return spri ? spri->timer_list : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lpwrap_run_expired(struct lpwrap_pri *spri, ftdm_time_t now_ms)
|
||||||
|
{
|
||||||
|
struct lpwrap_timer *expired_list = NULL;
|
||||||
|
struct lpwrap_timer **prev, *cur;
|
||||||
|
|
||||||
|
if (!spri || !spri->timer_list)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ftdm_mutex_lock(spri->timer_mutex);
|
||||||
|
|
||||||
|
/* Move all timers to expired list */
|
||||||
|
expired_list = spri->timer_list;
|
||||||
|
|
||||||
|
for (prev = &expired_list, cur = expired_list; cur; prev = &(*prev)->next, cur = cur->next) {
|
||||||
|
if (cur->timeout > now_ms) {
|
||||||
|
*prev = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Move non-expired timer to front of timer_list (or clear list if there are none) */
|
||||||
|
spri->timer_list = cur;
|
||||||
|
|
||||||
|
ftdm_mutex_unlock(spri->timer_mutex);
|
||||||
|
|
||||||
|
/* fire callbacks */
|
||||||
|
while ((cur = expired_list)) {
|
||||||
|
expired_list = cur->next;
|
||||||
|
if (cur->callback)
|
||||||
|
cur->callback(spri, cur);
|
||||||
|
/* stop timer */
|
||||||
|
cur->next = NULL;
|
||||||
|
cur->timeout = 0;
|
||||||
|
cur->callback = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define LPWRAP_MAX_TIMEOUT_MS 100
|
||||||
|
#define LPWRAP_MAX_ERRORS 2
|
||||||
|
|
||||||
|
int lpwrap_run_pri_once(struct lpwrap_pri *spri)
|
||||||
|
{
|
||||||
|
struct timeval *next = NULL;
|
||||||
|
struct lpwrap_timer *timer = NULL;
|
||||||
pri_event *event = NULL;
|
pri_event *event = NULL;
|
||||||
event_handler handler;
|
ftdm_wait_flag_t flags;
|
||||||
int sel;
|
ftdm_time_t now_ms, next_ms, timeout_ms, tmp_ms;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (spri->on_loop) {
|
if (spri->on_loop) {
|
||||||
if ((sel = spri->on_loop(spri)) < 0) {
|
if ((ret = spri->on_loop(spri)) < 0)
|
||||||
return sel;
|
return FTDM_FAIL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spri->errs >= 2) {
|
/* Default timeout when no scheduled events are pending */
|
||||||
spri->errs = 0;
|
timeout_ms = LPWRAP_MAX_TIMEOUT_MS;
|
||||||
return -1;
|
next_ms = 0;
|
||||||
}
|
now_ms = ftdm_current_time_in_ms();
|
||||||
|
|
||||||
FD_ZERO(&rfds);
|
/*
|
||||||
FD_ZERO(&efds);
|
* Get the next scheduled timer from libpri to set the maximum timeout,
|
||||||
|
* but limit it to MAX_TIMEOUT_MS (100ms).
|
||||||
#ifdef _MSC_VER
|
*/
|
||||||
//Windows macro for FD_SET includes a warning C4127: conditional expression is constant
|
|
||||||
#pragma warning(push)
|
|
||||||
#pragma warning(disable:4127)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
FD_SET(pri_fd(spri->pri), &rfds);
|
|
||||||
FD_SET(pri_fd(spri->pri), &efds);
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma warning(pop)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
now.tv_sec = 0;
|
|
||||||
now.tv_usec = 100000;
|
|
||||||
|
|
||||||
sel = select(pri_fd(spri->pri) + 1, &rfds, NULL, &efds, &now);
|
|
||||||
if (!sel) {
|
|
||||||
if ((next = pri_schedule_next(spri->pri))) {
|
if ((next = pri_schedule_next(spri->pri))) {
|
||||||
gettimeofday(&now, NULL);
|
next_ms = timeval_to_ms(next);
|
||||||
if (now.tv_sec >= next->tv_sec && (now.tv_usec >= next->tv_usec || next->tv_usec <= 100000)) {
|
if (now_ms >= next_ms) {
|
||||||
//ftdm_log(FTDM_LOG_DEBUG, "Check event\n");
|
/* Already late, handle timeout */
|
||||||
|
timeout_ms = 0;
|
||||||
|
} else {
|
||||||
|
/* Calculate new timeout and limit it to MAX_TIMEOUT_MS miliseconds */
|
||||||
|
tmp_ms = ftdm_min(next_ms - now_ms, LPWRAP_MAX_TIMEOUT_MS);
|
||||||
|
timeout_ms = ftdm_min(timeout_ms, tmp_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Next lpwrap_timer timeout
|
||||||
|
*/
|
||||||
|
if ((timer = lpwrap_timer_next(spri))) {
|
||||||
|
if (now_ms >= timer->timeout) {
|
||||||
|
/* Already late, handle timeout */
|
||||||
|
timeout_ms = 0;
|
||||||
|
} else {
|
||||||
|
/* Calculate new timeout and limit it to MAX_TIMEOUT_MS miliseconds */
|
||||||
|
tmp_ms = ftdm_min(timer->timeout - now_ms, LPWRAP_MAX_TIMEOUT_MS);
|
||||||
|
timeout_ms = ftdm_min(timeout_ms, tmp_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
if (timeout_ms > 0) {
|
||||||
|
flags = FTDM_READ | FTDM_EVENTS;
|
||||||
|
ret = ftdm_channel_wait(spri->dchan, &flags, timeout_ms);
|
||||||
|
|
||||||
|
if (spri->flags & LPWRAP_PRI_ABORT)
|
||||||
|
return FTDM_SUCCESS;
|
||||||
|
|
||||||
|
if (ret == FTDM_TIMEOUT) {
|
||||||
|
now_ms = ftdm_current_time_in_ms();
|
||||||
|
|
||||||
|
if (next) {
|
||||||
|
if (next_ms < now_ms) {
|
||||||
|
ftdm_log_chan(spri->dchan, FTDM_LOG_DEBUG, "pri timer %d ms late\n",
|
||||||
|
(int)(now_ms - next_ms));
|
||||||
|
}
|
||||||
event = pri_schedule_run(spri->pri);
|
event = pri_schedule_run(spri->pri);
|
||||||
}
|
}
|
||||||
|
if (timer) {
|
||||||
|
if (timer->timeout < now_ms) {
|
||||||
|
ftdm_log_chan(spri->dchan, FTDM_LOG_DEBUG, "lpwrap timer %d ms late\n",
|
||||||
|
(int)(now_ms - timer->timeout));
|
||||||
}
|
}
|
||||||
} else if (sel > 0) {
|
lpwrap_run_expired(spri, now_ms);
|
||||||
|
}
|
||||||
|
} else if (flags & (FTDM_READ | FTDM_EVENTS)) {
|
||||||
event = pri_check_event(spri->pri);
|
event = pri_check_event(spri->pri);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Scheduled event has already expired, handle it immediately
|
||||||
|
*/
|
||||||
|
if (next) {
|
||||||
|
event = pri_schedule_run(spri->pri);
|
||||||
|
}
|
||||||
|
if (timer) {
|
||||||
|
lpwrap_run_expired(spri, now_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spri->flags & LPWRAP_PRI_ABORT)
|
||||||
|
return FTDM_SUCCESS;
|
||||||
|
|
||||||
if (event) {
|
if (event) {
|
||||||
|
event_handler handler;
|
||||||
|
|
||||||
/* 0 is catchall event handler */
|
/* 0 is catchall event handler */
|
||||||
if (event->e < 0 || event->e >= LPWRAP_PRI_EVENT_MAX) {
|
if (event->e < 0 || event->e >= LPWRAP_PRI_EVENT_MAX) {
|
||||||
handler = spri->eventmap[0];
|
handler = spri->eventmap[0];
|
||||||
@ -303,28 +401,47 @@ int lpwrap_one_loop(struct lpwrap_pri *spri)
|
|||||||
ftdm_log(FTDM_LOG_CRIT, "No event handler found for event %d.\n", event->e);
|
ftdm_log(FTDM_LOG_CRIT, "No event handler found for event %d.\n", event->e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sel;
|
|
||||||
|
return FTDM_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lpwrap_run_pri(struct lpwrap_pri *spri)
|
int lpwrap_run_pri(struct lpwrap_pri *spri)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
for (;;) {
|
while (!(spri->flags & LPWRAP_PRI_ABORT)) {
|
||||||
if ((ret = lpwrap_one_loop(spri)) < 0) {
|
ret = lpwrap_run_pri_once(spri);
|
||||||
#ifndef WIN32 //This needs to be adressed fror WIN32 still
|
if (ret) {
|
||||||
if (errno == EINTR){
|
ftdm_log(FTDM_LOG_ERROR, "Error = %d, [%s]\n",
|
||||||
/* Igonore an interrupted system call */
|
ret, strerror(errno));
|
||||||
continue;
|
spri->errs++;
|
||||||
|
} else {
|
||||||
|
spri->errs = 0;
|
||||||
}
|
}
|
||||||
#endif
|
if (!ftdm_running())
|
||||||
ftdm_log(FTDM_LOG_CRIT, "Error = %i [%s]\n", ret, strerror(errno));
|
break;
|
||||||
|
if (spri->errs >= LPWRAP_MAX_ERRORS) {
|
||||||
|
ftdm_log(FTDM_LOG_CRIT, "Too many errors on span, restarting\n");
|
||||||
|
spri->errs = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lpwrap_stop_pri(struct lpwrap_pri *spri)
|
||||||
|
{
|
||||||
|
spri->flags |= LPWRAP_PRI_ABORT;
|
||||||
|
return FTDM_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lpwrap_destroy_pri(struct lpwrap_pri *spri)
|
||||||
|
{
|
||||||
|
if (spri->timer_mutex)
|
||||||
|
ftdm_mutex_destroy(&spri->timer_mutex);
|
||||||
|
return FTDM_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/* For Emacs:
|
/* For Emacs:
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* mode:c
|
* mode:c
|
||||||
|
@ -92,10 +92,14 @@ typedef enum {
|
|||||||
} lpwrap_pri_switch_t;
|
} lpwrap_pri_switch_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LPWRAP_PRI_READY = (1 << 0)
|
LPWRAP_PRI_READY = (1 << 0),
|
||||||
|
LPWRAP_PRI_ABORT = (1 << 1)
|
||||||
} lpwrap_pri_flag_t;
|
} lpwrap_pri_flag_t;
|
||||||
|
|
||||||
struct lpwrap_pri;
|
struct lpwrap_pri;
|
||||||
|
struct lpwrap_timer;
|
||||||
|
|
||||||
|
typedef int (*timeout_handler)(struct lpwrap_pri *, struct lpwrap_timer *);
|
||||||
typedef int (*event_handler)(struct lpwrap_pri *, lpwrap_pri_event_t, pri_event *);
|
typedef int (*event_handler)(struct lpwrap_pri *, lpwrap_pri_event_t, pri_event *);
|
||||||
typedef int (*loop_handler)(struct lpwrap_pri *);
|
typedef int (*loop_handler)(struct lpwrap_pri *);
|
||||||
|
|
||||||
@ -108,6 +112,8 @@ struct lpwrap_pri {
|
|||||||
event_handler eventmap[LPWRAP_PRI_EVENT_MAX];
|
event_handler eventmap[LPWRAP_PRI_EVENT_MAX];
|
||||||
loop_handler on_loop;
|
loop_handler on_loop;
|
||||||
int errs;
|
int errs;
|
||||||
|
struct lpwrap_timer *timer_list;
|
||||||
|
ftdm_mutex_t *timer_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct lpwrap_pri lpwrap_pri_t;
|
typedef struct lpwrap_pri lpwrap_pri_t;
|
||||||
@ -118,15 +124,21 @@ struct lpwrap_pri_event_list {
|
|||||||
const char *name;
|
const char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct lpwrap_timer {
|
||||||
|
struct lpwrap_timer *next;
|
||||||
|
ftdm_time_t timeout;
|
||||||
|
timeout_handler callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
int lpwrap_start_timer(struct lpwrap_pri *spri, struct lpwrap_timer *timer, const uint32_t timeout_ms, timeout_handler callback);
|
||||||
|
int lpwrap_stop_timer(struct lpwrap_pri *spri, struct lpwrap_timer *timer);
|
||||||
|
|
||||||
#define LPWRAP_MAP_PRI_EVENT(spri, event, func) spri.eventmap[event] = func;
|
#define LPWRAP_MAP_PRI_EVENT(spri, event, func) spri.eventmap[event] = func;
|
||||||
|
|
||||||
const char *lpwrap_pri_event_str(lpwrap_pri_event_t event_id);
|
const char *lpwrap_pri_event_str(lpwrap_pri_event_t event_id);
|
||||||
int lpwrap_one_loop(struct lpwrap_pri *spri);
|
|
||||||
int lpwrap_init_pri(struct lpwrap_pri *spri, ftdm_span_t *span, ftdm_channel_t *dchan, int swtype, int node, int debug);
|
|
||||||
int lpwrap_init_bri(struct lpwrap_pri *spri, ftdm_span_t *span, ftdm_channel_t *dchan, int swtype, int node, int ptp, int debug);
|
|
||||||
int lpwrap_run_pri(struct lpwrap_pri *spri);
|
|
||||||
#define lpwrap_run_bri(x) lpwrap_run_pri(x)
|
|
||||||
|
|
||||||
|
int lpwrap_init_pri(struct lpwrap_pri *spri, ftdm_span_t *span, ftdm_channel_t *dchan, int swtype, int node, int debug);
|
||||||
|
int lpwrap_destroy_pri(struct lpwrap_pri *spri);
|
||||||
|
int lpwrap_run_pri_once(struct lpwrap_pri *spri);
|
||||||
|
int lpwrap_run_pri(struct lpwrap_pri *spri);
|
||||||
|
int lpwrap_stop_pri(struct lpwrap_pri *spri);
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user