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_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)
|
||||
{
|
||||
|
@ -902,8 +904,10 @@ static ftdm_state_map_t isdn_state_map = {
|
|||
*/
|
||||
static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
||||
{
|
||||
ftdm_libpri_data_t *isdn_data = chan->span->signal_data;
|
||||
q931_call *call = (q931_call *)chan->call_data;
|
||||
ftdm_span_t *span = ftdm_channel_get_span(chan);
|
||||
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_sigmsg_t sig;
|
||||
|
||||
|
@ -920,21 +924,26 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
|||
switch (ftdm_channel_get_state(chan)) {
|
||||
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) {
|
||||
pri_destroycall(isdn_data->spri.pri, call);
|
||||
chan->call_data = NULL;
|
||||
}
|
||||
if (call) {
|
||||
pri_destroycall(isdn_data->spri.pri, call);
|
||||
chan_priv->call = NULL;
|
||||
}
|
||||
|
||||
if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n",
|
||||
ftdm_channel_get_span_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));
|
||||
/* Stop T302 */
|
||||
lpwrap_stop_timer(&isdn_data->spri, &chan_priv->t302);
|
||||
|
||||
if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n",
|
||||
ftdm_channel_get_span_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;
|
||||
|
@ -943,7 +952,7 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
|||
{
|
||||
if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
|
||||
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);
|
||||
}
|
||||
} 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)) {
|
||||
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);
|
||||
}
|
||||
} 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)) {
|
||||
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);
|
||||
}
|
||||
} 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)) {
|
||||
/* PROCEED from other end, notify user */
|
||||
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_channel_get_span_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;
|
||||
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 {
|
||||
ftdm_log_chan_msg(chan, FTDM_LOG_ERROR, "Overlap receiving on outbound call?\n");
|
||||
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_acknowledge(isdn_data->spri.pri, call, ftdm_channel_get_id(chan), 0);
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
|
@ -1054,10 +1068,20 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
|||
|
||||
case FTDM_CHANNEL_STATE_RESTART:
|
||||
{
|
||||
chan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_UNSPECIFIED;
|
||||
sig.event_id = FTDM_SIGEVENT_RESTART;
|
||||
status = ftdm_span_send_signal(ftdm_channel_get_span(chan), &sig);
|
||||
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_DOWN);
|
||||
if (ftdm_channel_get_type(chan) == FTDM_CHAN_TYPE_B) {
|
||||
chan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_UNSPECIFIED;
|
||||
sig.event_id = FTDM_SIGEVENT_RESTART;
|
||||
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;
|
||||
|
||||
|
@ -1065,7 +1089,7 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
|||
{
|
||||
if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
|
||||
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);
|
||||
}
|
||||
} else if (call) {
|
||||
|
@ -1109,7 +1133,7 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
|||
ton = isdn_data->ton;
|
||||
}
|
||||
|
||||
chan->call_data = call;
|
||||
chan_priv->call = call;
|
||||
|
||||
sr = pri_sr_new();
|
||||
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_destroycall(isdn_data->spri.pri, call);
|
||||
// chan->call_data = NULL;
|
||||
// chan_priv->call = NULL;
|
||||
}
|
||||
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) {
|
||||
// pri_destroycall(isdn_data->spri.pri, call);
|
||||
// chan->call_data = NULL;
|
||||
// chan_priv->call = NULL;
|
||||
// }
|
||||
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:
|
||||
{
|
||||
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 */
|
||||
}
|
||||
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 event_type Event type (unused)
|
||||
* \param pevent Event
|
||||
* \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_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_libpri_data_t *isdn_data = span->signal_data;
|
||||
|
||||
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);
|
||||
|
@ -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);
|
||||
chan_priv = chan->call_data;
|
||||
|
||||
switch (ftdm_channel_get_state(chan)) {
|
||||
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",
|
||||
pevent->ring.callednum, pevent->ring.complete ? "yes" : "no");
|
||||
case FTDM_CHANNEL_STATE_DIALTONE: /* NT-mode overlap receiving */
|
||||
|
||||
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 */
|
||||
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 */
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
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 */
|
||||
ftdm_set_state(chan, FTDM_CHANNEL_STATE_RING);
|
||||
}
|
||||
break;
|
||||
case FTDM_CHANNEL_STATE_DIALTONE: /* NT-mode overlap receiving */
|
||||
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);
|
||||
} else {
|
||||
/* Restart T302 */
|
||||
lpwrap_start_timer(spri, &chan_priv->t302, isdn_data->overlap_timeout_ms, &on_timeout_t302);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ftdm_log_chan(chan, FTDM_LOG_ERROR, "-- INFORMATION indication on channel %d:%d in invalid state '%s'\n",
|
||||
ftdm_channel_get_span_id(chan),
|
||||
ftdm_channel_get_id(chan),
|
||||
ftdm_log_chan(chan, FTDM_LOG_ERROR, "-- INFORMATION indication in invalid state '%s'\n",
|
||||
ftdm_channel_get_state_str(chan));
|
||||
}
|
||||
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_libpri_data_t *isdn_data = span->signal_data;
|
||||
ftdm_libpri_b_chan_t *chan_priv = NULL;
|
||||
ftdm_channel_t *chan = NULL;
|
||||
ftdm_caller_data_t *caller_data = NULL;
|
||||
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,
|
||||
* 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);
|
||||
chan->call_data = NULL;
|
||||
ftdm_log_chan(chan, FTDM_LOG_WARNING, "Channel already has call %p!\n", chan_priv->call);
|
||||
chan_priv->call = NULL;
|
||||
}
|
||||
|
||||
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......
|
||||
/* 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 */
|
||||
if ((pevent->ring.progressmask & PRI_PROG_INBAND_AVAILABLE)) {
|
||||
|
@ -1799,6 +1856,21 @@ done:
|
|||
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
|
||||
* \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_channel_get_alarms(event->channel, &alarmbits);
|
||||
ftdm_log(FTDM_LOG_WARNING, "channel %d:%d (%d:%d) has alarms! [%s]\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));
|
||||
ftdm_log_chan_msg(event->channel, FTDM_LOG_WARNING, "channel has alarms!\n");
|
||||
}
|
||||
break;
|
||||
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_channel_get_alarms(event->channel, &alarmbits);
|
||||
ftdm_log_chan_msg(event->channel, FTDM_LOG_WARNING, "channel alarms cleared!\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1892,11 +1957,6 @@ static __inline__ void check_events(ftdm_span_t *span)
|
|||
static int check_flags(lpwrap_pri_t *spri)
|
||||
{
|
||||
ftdm_span_t *span = spri->span;
|
||||
|
||||
if (!ftdm_running() || ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
check_state(span);
|
||||
check_events(span);
|
||||
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)
|
||||
{
|
||||
ftdm_channel_t *chan = NULL;
|
||||
ftdm_span_t *span = spri->span;
|
||||
ftdm_channel_t *chan = ftdm_span_get_channel(span, pevent->restart.channel);
|
||||
|
||||
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;
|
||||
}
|
||||
int i;
|
||||
|
||||
if (pevent->restart.channel < 1) {
|
||||
ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
|
||||
} else {
|
||||
ftdm_log_chan_msg(spri->dchan, FTDM_LOG_NOTICE, "-- Restarting interface\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;
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* \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
|
||||
*/
|
||||
|
@ -2224,110 +2344,88 @@ static void *ftdm_libpri_run(ftdm_thread_t *me, void *obj)
|
|||
ftdm_span_t *span = (ftdm_span_t *) obj;
|
||||
ftdm_libpri_data_t *isdn_data = span->signal_data;
|
||||
int down = 0;
|
||||
int got_d = 0;
|
||||
int res = 0;
|
||||
int i;
|
||||
|
||||
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)) {
|
||||
if (!got_d) {
|
||||
int i, x;
|
||||
|
||||
for (i = 1, x = 0; 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(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;
|
||||
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;
|
||||
}
|
||||
|
||||
/* Initialize libpri trunk */
|
||||
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;
|
||||
}
|
||||
lpwrap_run_pri(&isdn_data->spri);
|
||||
|
||||
if (!ftdm_running() || ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
|
||||
break;
|
||||
|
@ -2353,8 +2451,7 @@ out:
|
|||
/* close d-channel, if set */
|
||||
if (isdn_data->dchan) {
|
||||
if (ftdm_channel_close(&isdn_data->dchan) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Failed to close D-Channel %d:%d\n",
|
||||
ftdm_channel_get_span_id(isdn_data->dchan), ftdm_channel_get_id(isdn_data->dchan));
|
||||
ftdm_log_chan_msg(isdn_data->dchan, FTDM_LOG_ERROR, "Failed to close D-Channel\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2363,6 +2460,7 @@ out:
|
|||
ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
|
||||
ftdm_clear_flag(isdn_data, FTMOD_LIBPRI_RUNNING);
|
||||
|
||||
lpwrap_destroy_pri(&isdn_data->spri);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -2381,11 +2479,14 @@ static ftdm_status_t ftdm_libpri_stop(ftdm_span_t *span)
|
|||
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);
|
||||
|
||||
ftdm_set_flag(span, FTDM_SPAN_STOP_THREAD);
|
||||
lpwrap_stop_pri(&isdn_data->spri);
|
||||
|
||||
while (ftdm_test_flag(span, FTDM_SPAN_IN_THREAD)) {
|
||||
ftdm_sleep(100);
|
||||
|
@ -2411,6 +2512,9 @@ static ftdm_status_t ftdm_libpri_start(ftdm_span_t *span)
|
|||
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_IN_THREAD);
|
||||
|
||||
|
@ -2552,7 +2656,6 @@ static uint32_t parse_opts(const char *in)
|
|||
static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
||||
{
|
||||
ftdm_libpri_data_t *isdn_data = NULL;
|
||||
//ftdm_channel_t *dchan = NULL;
|
||||
uint32_t bchan_count = 0;
|
||||
uint32_t dchan_count = 0;
|
||||
uint32_t i;
|
||||
|
@ -2569,23 +2672,10 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
|||
case FTDM_CHAN_TYPE_DQ921:
|
||||
if (dchan_count > 1) {
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
dchan_count++;
|
||||
}
|
||||
dchan_count++;
|
||||
break;
|
||||
|
||||
case FTDM_CHAN_TYPE_B:
|
||||
bchan_count++;
|
||||
break;
|
||||
|
@ -2595,12 +2685,10 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
|||
}
|
||||
if (!dchan_count) {
|
||||
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;
|
||||
}
|
||||
if (!bchan_count) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2609,7 +2697,8 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
|||
memset(isdn_data, 0, sizeof(*isdn_data));
|
||||
|
||||
/* 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 */
|
||||
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:
|
||||
#ifndef HAVE_LIBPRI_BRI
|
||||
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;
|
||||
#endif
|
||||
case FTDM_TRUNK_E1:
|
||||
|
@ -2639,7 +2727,6 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
|||
break;
|
||||
default:
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2648,7 +2735,6 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
|||
*/
|
||||
if (msn_filter_init(isdn_data) != FTDM_SUCCESS) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2663,7 +2749,6 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
|||
|
||||
if (ftdm_strlen_zero(val)) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2691,6 +2776,17 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
|||
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")) {
|
||||
if (parse_debug(val, &isdn_data->debug_mask) == -1) {
|
||||
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")) {
|
||||
if (msn_filter_add(isdn_data, val) != FTDM_SUCCESS) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -2748,8 +2842,28 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
|||
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;
|
||||
error:
|
||||
/* TODO: free per-channel private data */
|
||||
msn_filter_destroy(isdn_data);
|
||||
ftdm_safe_free(isdn_data);
|
||||
return FTDM_FAIL;
|
||||
|
|
|
@ -35,6 +35,10 @@
|
|||
#include "freetdm.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 {
|
||||
SERVICE_CHANGE_STATUS_INSERVICE = 0,
|
||||
SERVICE_CHANGE_STATUS_MAINTENANCE,
|
||||
|
@ -71,6 +75,7 @@ struct ftdm_libpri_data {
|
|||
int mode;
|
||||
int dialect;
|
||||
int overlap; /*!< Overlap dial flags */
|
||||
int overlap_timeout_ms; /*!< Overlap dial timeout */
|
||||
unsigned int layer1;
|
||||
unsigned int ton;
|
||||
unsigned int service_message_support;
|
||||
|
@ -84,6 +89,27 @@ struct ftdm_libpri_data {
|
|||
|
||||
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
|
||||
|
||||
/* For Emacs:
|
||||
|
|
|
@ -36,51 +36,7 @@
|
|||
#include "private/ftdm_core.h"
|
||||
#include "lpwrap_pri.h"
|
||||
|
||||
#ifndef HAVE_GETTIMEOFDAY
|
||||
#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[] = {
|
||||
static struct lpwrap_pri_event_list LPWRAP_PRI_EVENT_LIST[LPWRAP_PRI_EVENT_MAX] = {
|
||||
{0, LPWRAP_PRI_EVENT_ANY, "ANY"},
|
||||
{1, LPWRAP_PRI_EVENT_DCHAN_UP, "DCHAN_UP"},
|
||||
{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"},
|
||||
};
|
||||
|
||||
#define LINE "--------------------------------------------------------------------------------"
|
||||
|
||||
const char *lpwrap_pri_event_str(lpwrap_pri_event_t event_id)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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 ret = -1;
|
||||
|
@ -179,115 +137,255 @@ int lpwrap_init_pri(struct lpwrap_pri *spri, ftdm_span_t *span, ftdm_channel_t *
|
|||
spri->span = span;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if ((spri->pri = pri_new_cb(spri->dchan->sockfd, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri))) {
|
||||
unsigned char buf[4] = { 0 };
|
||||
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");
|
||||
if (ftdm_mutex_create(&spri->timer_mutex) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Failed to create timer list mutex\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)
|
||||
{
|
||||
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
|
||||
memset(spri, 0, sizeof(struct lpwrap_pri));
|
||||
spri->dchan = dchan;
|
||||
spri->span = span;
|
||||
|
||||
if (!spri->dchan) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "No D-Channel available, unable to create BRI\n");
|
||||
case FTDM_TRUNK_BRI:
|
||||
spri->pri = pri_new_bri_cb(spri->dchan->sockfd, 1, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri);
|
||||
break;
|
||||
case FTDM_TRUNK_BRI_PTMP:
|
||||
spri->pri = pri_new_bri_cb(spri->dchan->sockfd, 0, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri);
|
||||
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;
|
||||
}
|
||||
|
||||
if ((spri->pri = pri_new_bri_cb(spri->dchan->sockfd, ptp, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri))) {
|
||||
unsigned char buf[4] = { 0 };
|
||||
size_t buflen = sizeof(buf), len = 0;
|
||||
|
||||
if (spri->pri) {
|
||||
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 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;
|
||||
}
|
||||
|
||||
|
||||
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 timeval now = {0,0}, *next = NULL;
|
||||
struct lpwrap_timer **prev, *cur;
|
||||
|
||||
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;
|
||||
event_handler handler;
|
||||
int sel;
|
||||
ftdm_wait_flag_t flags;
|
||||
ftdm_time_t now_ms, next_ms, timeout_ms, tmp_ms;
|
||||
int ret;
|
||||
|
||||
if (spri->on_loop) {
|
||||
if ((sel = spri->on_loop(spri)) < 0) {
|
||||
return sel;
|
||||
if ((ret = spri->on_loop(spri)) < 0)
|
||||
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;
|
||||
return -1;
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
//Windows macro for FD_SET includes a warning C4127: conditional expression is constant
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
if (spri->flags & LPWRAP_PRI_ABORT)
|
||||
return FTDM_SUCCESS;
|
||||
|
||||
FD_SET(pri_fd(spri->pri), &rfds);
|
||||
FD_SET(pri_fd(spri->pri), &efds);
|
||||
if (ret == FTDM_TIMEOUT) {
|
||||
now_ms = ftdm_current_time_in_ms();
|
||||
|
||||
#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))) {
|
||||
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");
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
event_handler handler;
|
||||
|
||||
/* 0 is catchall event handler */
|
||||
if (event->e < 0 || event->e >= LPWRAP_PRI_EVENT_MAX) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
return sel;
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
int lpwrap_run_pri(struct lpwrap_pri *spri)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
for (;;) {
|
||||
if ((ret = lpwrap_one_loop(spri)) < 0) {
|
||||
#ifndef WIN32 //This needs to be adressed fror WIN32 still
|
||||
if (errno == EINTR){
|
||||
/* Igonore an interrupted system call */
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
ftdm_log(FTDM_LOG_CRIT, "Error = %i [%s]\n", ret, strerror(errno));
|
||||
while (!(spri->flags & LPWRAP_PRI_ABORT)) {
|
||||
ret = lpwrap_run_pri_once(spri);
|
||||
if (ret) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Error = %d, [%s]\n",
|
||||
ret, strerror(errno));
|
||||
spri->errs++;
|
||||
} else {
|
||||
spri->errs = 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
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:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
|
|
|
@ -92,10 +92,14 @@ typedef enum {
|
|||
} lpwrap_pri_switch_t;
|
||||
|
||||
typedef enum {
|
||||
LPWRAP_PRI_READY = (1 << 0)
|
||||
LPWRAP_PRI_READY = (1 << 0),
|
||||
LPWRAP_PRI_ABORT = (1 << 1)
|
||||
} lpwrap_pri_flag_t;
|
||||
|
||||
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 (*loop_handler)(struct lpwrap_pri *);
|
||||
|
||||
|
@ -108,6 +112,8 @@ struct lpwrap_pri {
|
|||
event_handler eventmap[LPWRAP_PRI_EVENT_MAX];
|
||||
loop_handler on_loop;
|
||||
int errs;
|
||||
struct lpwrap_timer *timer_list;
|
||||
ftdm_mutex_t *timer_mutex;
|
||||
};
|
||||
|
||||
typedef struct lpwrap_pri lpwrap_pri_t;
|
||||
|
@ -118,15 +124,21 @@ struct lpwrap_pri_event_list {
|
|||
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;
|
||||
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue