Merge branch 'master' of git.freeswitch.org:freeswitch

This commit is contained in:
Steve Underwood 2012-09-04 08:59:43 +08:00
commit 12b5bde226
4 changed files with 604 additions and 335 deletions

View File

@ -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,21 +924,26 @@ 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:
{ {
ftdm_channel_t *chtmp = chan; if (ftdm_channel_get_type(chan) == FTDM_CHAN_TYPE_B) {
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;
} }
if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) { /* Stop T302 */
ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n", lpwrap_stop_timer(&isdn_data->spri, &chan_priv->t302);
ftdm_channel_get_span_id(chan),
ftdm_channel_get_id(chan)); if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) {
} else { ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n",
ftdm_log(FTDM_LOG_DEBUG, "-- Closed 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)); } else {
ftdm_log(FTDM_LOG_DEBUG, "-- Closed channel %d:%d\n",
ftdm_channel_get_span_id(chan),
ftdm_channel_get_id(chan));
}
} }
} }
break; break;
@ -943,7 +952,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; 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,10 +1068,20 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
case FTDM_CHANNEL_STATE_RESTART: case FTDM_CHANNEL_STATE_RESTART:
{ {
chan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_UNSPECIFIED; if (ftdm_channel_get_type(chan) == FTDM_CHAN_TYPE_B) {
sig.event_id = FTDM_SIGEVENT_RESTART; chan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_UNSPECIFIED;
status = ftdm_span_send_signal(ftdm_channel_get_span(chan), &sig); sig.event_id = FTDM_SIGEVENT_RESTART;
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_DOWN); 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);
}
}
} }
break; break;
@ -1065,7 +1089,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_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);
}
}
}
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); 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,110 +2344,88 @@ 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;
/*
* Open D-Channel
*/
for (i = 1; i <= ftdm_span_get_chan_count(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_open(ftdm_span_get_id(span), i, &isdn_data->dchan) == FTDM_SUCCESS) {
ftdm_log_chan_msg(chan, FTDM_LOG_DEBUG, "Opened D-Channel\n");
break;
} else {
ftdm_log_chan_msg(chan, FTDM_LOG_CRIT, "Failed to open D-Channel\n");
goto out;
}
}
}
/*
* Initialize BRI/PRI context
*/
res = lpwrap_init_pri(&isdn_data->spri, span, isdn_data->dchan,
isdn_data->dialect, isdn_data->mode, isdn_data->debug_mask);
if (res) {
ftdm_log(FTDM_LOG_CRIT, "Failed to initialize BRI/PRI on span %d\n",
ftdm_span_get_id(span));
goto out;
}
#ifdef HAVE_LIBPRI_AOC
/*
* Only enable facility on trunk if really required,
* this may help avoid problems on troublesome lines.
*/
if (isdn_data->opts & FTMOD_LIBPRI_OPT_FACILITY_AOC) {
pri_facility_enable(isdn_data->spri.pri);
}
#endif
/* Support the different switch of service status */
if (isdn_data->service_message_support) {
pri_set_service_message_support(isdn_data->spri.pri, 1);
}
/* 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_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_PROCEEDING, on_proceeding);
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_PROGRESS, on_progress);
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_ANSWER, on_answer);
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_DCHAN_UP, on_dchan_up);
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_DCHAN_DOWN, on_dchan_down);
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, on_hangup);
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_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_FACILITY, on_facility);
/* 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)) { while (ftdm_running() && !ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
if (!got_d) { if (down) {
int i, x; 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);
for (i = 1, x = 0; i <= ftdm_span_get_chan_count(span); i++) { down = 0;
ftdm_channel_t *chan = ftdm_span_get_channel(span, i);
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) {
ftdm_log(FTDM_LOG_DEBUG, "opening D-Channel #%d %d:%d\n", x,
ftdm_channel_get_span_id(isdn_data->dchan), ftdm_channel_get_id(isdn_data->dchan));
got_d = 1;
x++;
break;
} else {
ftdm_log(FTDM_LOG_ERROR, "failed to open D-Channel #%d %d:%d\n", x,
ftdm_channel_get_span_id(chan), ftdm_channel_get_id(chan));
}
}
}
}
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 */ lpwrap_run_pri(&isdn_data->spri);
switch (ftdm_span_get_trunk_type(span)) {
case FTDM_TRUNK_E1:
case FTDM_TRUNK_T1:
case FTDM_TRUNK_J1:
res = lpwrap_init_pri(&isdn_data->spri, span, isdn_data->dchan,
isdn_data->dialect, isdn_data->mode, isdn_data->debug_mask);
break;
case FTDM_TRUNK_BRI:
res = lpwrap_init_bri(&isdn_data->spri, span, isdn_data->dchan,
isdn_data->dialect, isdn_data->mode, 1, isdn_data->debug_mask);
#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;
}
#ifdef HAVE_LIBPRI_AOC
/*
* Only enable facility on trunk if really required,
* this may help avoid problems on troublesome lines.
*/
if (isdn_data->opts & FTMOD_LIBPRI_OPT_FACILITY_AOC) {
pri_facility_enable(isdn_data->spri.pri);
}
#endif
/* Support the different switch of service status */
if (isdn_data->service_message_support) {
pri_set_service_message_support(isdn_data->spri.pri, 1 /* True */);
}
if (res == 0) {
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_RINGING, on_ringing);
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_PROCEEDING, on_proceeding);
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_PROGRESS, on_progress);
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_ANSWER, on_answer);
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_DCHAN_UP, on_dchan_up);
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_DCHAN_DOWN, on_dchan_down);
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, 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_RESTART, on_restart);
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);
#endif
if (down) {
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);
down = 0;
}
isdn_data->spri.on_loop = check_flags;
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; 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;
}
#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;
} }
@ -2609,7 +2697,8 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
memset(isdn_data, 0, sizeof(*isdn_data)); memset(isdn_data, 0, sizeof(*isdn_data));
/* 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;

View File

@ -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:

View File

@ -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; return ret;
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;
}
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 ret = -1;
switch (ftdm_span_get_trunk_type(span)) {
case FTDM_TRUNK_E1:
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;
}
/* Default timeout when no scheduled events are pending */
timeout_ms = LPWRAP_MAX_TIMEOUT_MS;
next_ms = 0;
now_ms = ftdm_current_time_in_ms();
/*
* Get the next scheduled timer from libpri to set the maximum timeout,
* but limit it to MAX_TIMEOUT_MS (100ms).
*/
if ((next = pri_schedule_next(spri->pri))) {
next_ms = timeval_to_ms(next);
if (now_ms >= next_ms) {
/* 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);
} }
} }
if (spri->errs >= 2) { /*
spri->errs = 0; * Next lpwrap_timer timeout
return -1; */
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);
}
} }
FD_ZERO(&rfds); /* */
FD_ZERO(&efds); if (timeout_ms > 0) {
flags = FTDM_READ | FTDM_EVENTS;
ret = ftdm_channel_wait(spri->dchan, &flags, timeout_ms);
#ifdef _MSC_VER if (spri->flags & LPWRAP_PRI_ABORT)
//Windows macro for FD_SET includes a warning C4127: conditional expression is constant return FTDM_SUCCESS;
#pragma warning(push)
#pragma warning(disable:4127)
#endif
FD_SET(pri_fd(spri->pri), &rfds); if (ret == FTDM_TIMEOUT) {
FD_SET(pri_fd(spri->pri), &efds); now_ms = ftdm_current_time_in_ms();
#ifdef _MSC_VER if (next) {
#pragma warning(pop) if (next_ms < now_ms) {
#endif ftdm_log_chan(spri->dchan, FTDM_LOG_DEBUG, "pri timer %d ms late\n",
(int)(now_ms - next_ms));
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))) {
gettimeofday(&now, NULL);
if (now.tv_sec >= next->tv_sec && (now.tv_usec >= next->tv_usec || next->tv_usec <= 100000)) {
//ftdm_log(FTDM_LOG_DEBUG, "Check event\n");
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));
}
lpwrap_run_expired(spri, now_ms);
}
} else if (flags & (FTDM_READ | FTDM_EVENTS)) {
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);
} }
} else if (sel > 0) {
event = pri_check_event(spri->pri);
} }
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 {
#endif spri->errs = 0;
ftdm_log(FTDM_LOG_CRIT, "Error = %i [%s]\n", ret, strerror(errno)); }
if (!ftdm_running())
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

View File

@ -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