freetdm: ftmod_r2 - handle race on protocol error
This commit is contained in:
parent
fc2f2790c0
commit
315441d219
|
@ -133,14 +133,16 @@ static void dump_chan_io_to_file(ftdm_channel_t *fchan, ftdm_io_dump_t *dump, FI
|
|||
if (dump->wrapped) {
|
||||
rc = fwrite(&dump->buffer[dump->windex], 1, towrite, file);
|
||||
if (rc != towrite) {
|
||||
ftdm_log_chan(fchan, FTDM_LOG_ERROR, "only wrote %d out of %d bytes in DTMF debug buffer\n", rc, towrite);
|
||||
ftdm_log_chan(fchan, FTDM_LOG_ERROR, "only wrote %d out of %d bytes in io dump buffer\n",
|
||||
rc, towrite, strerror(errno));
|
||||
}
|
||||
}
|
||||
if (dump->windex) {
|
||||
towrite = dump->windex;
|
||||
rc = fwrite(&dump->buffer[0], 1, towrite, file);
|
||||
if (rc != towrite) {
|
||||
ftdm_log_chan(fchan, FTDM_LOG_ERROR, "only wrote %d out of %d bytes in DTMF debug buffer\n", rc, towrite);
|
||||
ftdm_log_chan(fchan, FTDM_LOG_ERROR, "only wrote %d out of %d bytes in io dump buffer: %s\n",
|
||||
rc, towrite, strerror(errno));
|
||||
}
|
||||
}
|
||||
dump->windex = 0;
|
||||
|
|
|
@ -73,6 +73,7 @@ typedef struct ftdm_r2_call_t {
|
|||
ftdm_size_t ani_index;
|
||||
char logname[255];
|
||||
char name[10];
|
||||
ftdm_timer_id_t protocol_error_recovery_timer;
|
||||
} ftdm_r2_call_t;
|
||||
|
||||
/* this is just used as place holder in the stack when configuring the span to avoid using bunch of locals */
|
||||
|
@ -334,7 +335,7 @@ static openr2_call_disconnect_cause_t ftdm_r2_ftdm_cause_to_openr2_cause(ftdm_ch
|
|||
static void ft_r2_clean_call(ftdm_r2_call_t *call)
|
||||
{
|
||||
openr2_chan_t *r2chan = call->r2chan;
|
||||
|
||||
|
||||
/* Do not memset call structure, that clears values we do not want to clear,
|
||||
* like the log name set in on_call_log_created() */
|
||||
call->r2chan = r2chan;
|
||||
|
@ -347,6 +348,7 @@ static void ft_r2_clean_call(ftdm_r2_call_t *call)
|
|||
call->dnis_index = 0;
|
||||
call->ani_index = 0;
|
||||
call->name[0] = 0;
|
||||
call->protocol_error_recovery_timer = 0;
|
||||
}
|
||||
|
||||
static void ft_r2_accept_call(ftdm_channel_t *ftdmchan)
|
||||
|
@ -451,6 +453,18 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
|
|||
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Received request to start call\n");
|
||||
|
||||
if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP) {
|
||||
r2call = R2CALL(ftdmchan);
|
||||
if (r2call->protocol_error) {
|
||||
/* we had a protocol error and we were giving some recovery time, cancel the recovery timer now
|
||||
* that is obvious that the other side recovered */
|
||||
ftdm_sched_cancel_timer(r2data->sched, r2call->protocol_error_recovery_timer);
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Cancelled protocol error recovery timer\n");
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
|
||||
ftdm_r2_state_advance_all(ftdmchan);
|
||||
}
|
||||
}
|
||||
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Cannot start call when channel is in use (state = %s)\n", ftdm_channel_state2str(ftdmchan->state));
|
||||
return;
|
||||
|
@ -658,6 +672,7 @@ static void ftdm_r2_recover_from_protocol_error(void *data)
|
|||
goto done;
|
||||
}
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
|
||||
ftdm_r2_state_advance_all(ftdmchan);
|
||||
done:
|
||||
ftdm_channel_unlock(ftdmchan);
|
||||
}
|
||||
|
@ -960,36 +975,37 @@ static int ftdm_r2_io_setup(openr2_chan_t *r2chan)
|
|||
|
||||
static int ftdm_r2_io_get_oob_event(openr2_chan_t *r2chan, openr2_oob_event_t *event)
|
||||
{
|
||||
ftdm_status_t status;
|
||||
ftdm_event_t *fevent = NULL;
|
||||
ftdm_channel_t *ftdmchan = openr2_chan_get_fd(r2chan);
|
||||
ftdm_status_t status;
|
||||
ftdm_event_t *fevent = NULL;
|
||||
ftdm_channel_t *ftdmchan = openr2_chan_get_fd(r2chan);
|
||||
|
||||
*event = OR2_OOB_EVENT_NONE;
|
||||
status = ftdm_channel_read_event(ftdmchan, &fevent);
|
||||
if (status != FTDM_SUCCESS) {
|
||||
*event = OR2_OOB_EVENT_NONE;
|
||||
|
||||
status = ftdm_channel_read_event(ftdmchan, &fevent);
|
||||
|
||||
if (status != FTDM_SUCCESS) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "failed to retrieve freetdm event!\n");
|
||||
return -1;
|
||||
}
|
||||
if (fevent->e_type != FTDM_EVENT_OOB)
|
||||
return 0;
|
||||
switch (fevent->enum_id) {
|
||||
case FTDM_OOB_CAS_BITS_CHANGE:
|
||||
{
|
||||
*event = OR2_OOB_EVENT_CAS_CHANGE;
|
||||
}
|
||||
break;
|
||||
case FTDM_OOB_ALARM_TRAP:
|
||||
{
|
||||
*event = OR2_OOB_EVENT_ALARM_ON;
|
||||
}
|
||||
break;
|
||||
case FTDM_OOB_ALARM_CLEAR:
|
||||
{
|
||||
*event = OR2_OOB_EVENT_ALARM_OFF;
|
||||
}
|
||||
break;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
switch (fevent->enum_id) {
|
||||
case FTDM_OOB_CAS_BITS_CHANGE:
|
||||
{
|
||||
*event = OR2_OOB_EVENT_CAS_CHANGE;
|
||||
}
|
||||
break;
|
||||
case FTDM_OOB_ALARM_TRAP:
|
||||
{
|
||||
*event = OR2_OOB_EVENT_ALARM_ON;
|
||||
}
|
||||
break;
|
||||
case FTDM_OOB_ALARM_CLEAR:
|
||||
{
|
||||
*event = OR2_OOB_EVENT_ALARM_OFF;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static openr2_io_interface_t ftdm_r2_io_iface = {
|
||||
|
@ -1419,7 +1435,8 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
|
|||
{
|
||||
ftdm_sigmsg_t sigev;
|
||||
int ret;
|
||||
openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan;
|
||||
ftdm_r2_call_t *r2call = R2CALL(ftdmchan);
|
||||
openr2_chan_t *r2chan = r2call->r2chan;
|
||||
ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
|
||||
|
||||
memset(&sigev, 0, sizeof(sigev));
|
||||
|
@ -1435,10 +1452,10 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
|
|||
* to complete (the processing is media-bound)
|
||||
* */
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)
|
||||
&& (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) {
|
||||
&& (r2call->chanstate != ftdmchan->state)) {
|
||||
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state));
|
||||
R2CALL(ftdmchan)->chanstate = ftdmchan->state;
|
||||
r2call->chanstate = ftdmchan->state;
|
||||
|
||||
if (IS_ACCEPTING_PENDING(ftdmchan)) {
|
||||
/*
|
||||
|
@ -1487,13 +1504,8 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
|
|||
/* notify the user about the new call */
|
||||
sigev.event_id = FTDM_SIGEVENT_START;
|
||||
|
||||
if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Failed to handle call offered\n");
|
||||
openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL);
|
||||
break;
|
||||
}
|
||||
R2CALL(ftdmchan)->ftdm_call_started = 1;
|
||||
ftdm_span_send_signal(ftdmchan->span, &sigev);
|
||||
r2call->ftdm_call_started = 1;
|
||||
|
||||
break;
|
||||
|
||||
|
@ -1502,7 +1514,7 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
|
|||
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
|
||||
{
|
||||
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
|
||||
if (!R2CALL(ftdmchan)->accepted) {
|
||||
if (!r2call->accepted) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Accepting call\n");
|
||||
ft_r2_accept_call(ftdmchan);
|
||||
}
|
||||
|
@ -1522,11 +1534,11 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
|
|||
{
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call was answered\n");
|
||||
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
|
||||
if (!R2CALL(ftdmchan)->accepted) {
|
||||
if (!r2call->accepted) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call has not been accepted, need to accept first\n");
|
||||
// the answering will be done in the on_call_accepted handler
|
||||
ft_r2_accept_call(ftdmchan);
|
||||
R2CALL(ftdmchan)->answer_pending = 1;
|
||||
r2call->answer_pending = 1;
|
||||
} else {
|
||||
ft_r2_answer_call(ftdmchan);
|
||||
}
|
||||
|
@ -1541,19 +1553,19 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
|
|||
/* just got hangup */
|
||||
case FTDM_CHANNEL_STATE_HANGUP:
|
||||
{
|
||||
if (!R2CALL(ftdmchan)->disconnect_rcvd) {
|
||||
if (!r2call->disconnect_rcvd) {
|
||||
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
|
||||
/* this will disconnect the call, but need to wait for the call end before moving to DOWN */
|
||||
openr2_chan_disconnect_call(r2chan, disconnect_cause);
|
||||
} else if (!R2CALL(ftdmchan)->protocol_error) {
|
||||
} else if (!r2call->protocol_error) {
|
||||
/* just ack the hangup, on_call_end will be called by openr2 right after */
|
||||
openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
|
||||
} else {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Clearing call due to protocol error\n");
|
||||
/* do not set to down yet, give some time for recovery */
|
||||
ftdm_sched_timer(r2data->sched, "protocolerr_recover", 100,
|
||||
ftdm_r2_recover_from_protocol_error, r2chan, NULL);
|
||||
ftdm_r2_recover_from_protocol_error, r2chan, &r2call->protocol_error_recovery_timer);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1561,7 +1573,7 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
|
|||
case FTDM_CHANNEL_STATE_TERMINATING:
|
||||
{
|
||||
/* if the call has not been started yet we must go to HANGUP right here */
|
||||
if (!R2CALL(ftdmchan)->ftdm_call_started) {
|
||||
if (!r2call->ftdm_call_started) {
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
|
||||
} else {
|
||||
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
|
||||
|
@ -1573,19 +1585,10 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
|
|||
}
|
||||
break;
|
||||
|
||||
/* just got hangup from the freetdm side due to abnormal failure */
|
||||
case FTDM_CHANNEL_STATE_CANCEL:
|
||||
{
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Unable to receive call\n");
|
||||
openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
|
||||
}
|
||||
break;
|
||||
|
||||
/* finished call for good */
|
||||
case FTDM_CHANNEL_STATE_DOWN:
|
||||
{
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Call is down\n");
|
||||
openr2_chan_disable_read(r2chan);
|
||||
ret = 1;
|
||||
}
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue