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) {
|
if (dump->wrapped) {
|
||||||
rc = fwrite(&dump->buffer[dump->windex], 1, towrite, file);
|
rc = fwrite(&dump->buffer[dump->windex], 1, towrite, file);
|
||||||
if (rc != towrite) {
|
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) {
|
if (dump->windex) {
|
||||||
towrite = dump->windex;
|
towrite = dump->windex;
|
||||||
rc = fwrite(&dump->buffer[0], 1, towrite, file);
|
rc = fwrite(&dump->buffer[0], 1, towrite, file);
|
||||||
if (rc != towrite) {
|
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;
|
dump->windex = 0;
|
||||||
|
|
|
@ -73,6 +73,7 @@ typedef struct ftdm_r2_call_t {
|
||||||
ftdm_size_t ani_index;
|
ftdm_size_t ani_index;
|
||||||
char logname[255];
|
char logname[255];
|
||||||
char name[10];
|
char name[10];
|
||||||
|
ftdm_timer_id_t protocol_error_recovery_timer;
|
||||||
} ftdm_r2_call_t;
|
} ftdm_r2_call_t;
|
||||||
|
|
||||||
/* this is just used as place holder in the stack when configuring the span to avoid using bunch of locals */
|
/* this is just used as place holder in the stack when configuring the span to avoid using bunch of locals */
|
||||||
|
@ -347,6 +348,7 @@ static void ft_r2_clean_call(ftdm_r2_call_t *call)
|
||||||
call->dnis_index = 0;
|
call->dnis_index = 0;
|
||||||
call->ani_index = 0;
|
call->ani_index = 0;
|
||||||
call->name[0] = 0;
|
call->name[0] = 0;
|
||||||
|
call->protocol_error_recovery_timer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ft_r2_accept_call(ftdm_channel_t *ftdmchan)
|
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");
|
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)) {
|
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));
|
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Cannot start call when channel is in use (state = %s)\n", ftdm_channel_state2str(ftdmchan->state));
|
||||||
return;
|
return;
|
||||||
|
@ -658,6 +672,7 @@ static void ftdm_r2_recover_from_protocol_error(void *data)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
|
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
|
||||||
|
ftdm_r2_state_advance_all(ftdmchan);
|
||||||
done:
|
done:
|
||||||
ftdm_channel_unlock(ftdmchan);
|
ftdm_channel_unlock(ftdmchan);
|
||||||
}
|
}
|
||||||
|
@ -965,13 +980,14 @@ static int ftdm_r2_io_get_oob_event(openr2_chan_t *r2chan, openr2_oob_event_t *e
|
||||||
ftdm_channel_t *ftdmchan = openr2_chan_get_fd(r2chan);
|
ftdm_channel_t *ftdmchan = openr2_chan_get_fd(r2chan);
|
||||||
|
|
||||||
*event = OR2_OOB_EVENT_NONE;
|
*event = OR2_OOB_EVENT_NONE;
|
||||||
|
|
||||||
status = ftdm_channel_read_event(ftdmchan, &fevent);
|
status = ftdm_channel_read_event(ftdmchan, &fevent);
|
||||||
|
|
||||||
if (status != FTDM_SUCCESS) {
|
if (status != FTDM_SUCCESS) {
|
||||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "failed to retrieve freetdm event!\n");
|
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "failed to retrieve freetdm event!\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (fevent->e_type != FTDM_EVENT_OOB)
|
|
||||||
return 0;
|
|
||||||
switch (fevent->enum_id) {
|
switch (fevent->enum_id) {
|
||||||
case FTDM_OOB_CAS_BITS_CHANGE:
|
case FTDM_OOB_CAS_BITS_CHANGE:
|
||||||
{
|
{
|
||||||
|
@ -1419,7 +1435,8 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
|
||||||
{
|
{
|
||||||
ftdm_sigmsg_t sigev;
|
ftdm_sigmsg_t sigev;
|
||||||
int ret;
|
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;
|
ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
|
||||||
|
|
||||||
memset(&sigev, 0, sizeof(sigev));
|
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)
|
* to complete (the processing is media-bound)
|
||||||
* */
|
* */
|
||||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)
|
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));
|
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)) {
|
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 */
|
/* notify the user about the new call */
|
||||||
sigev.event_id = FTDM_SIGEVENT_START;
|
sigev.event_id = FTDM_SIGEVENT_START;
|
||||||
|
|
||||||
if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) {
|
ftdm_span_send_signal(ftdmchan->span, &sigev);
|
||||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Failed to handle call offered\n");
|
r2call->ftdm_call_started = 1;
|
||||||
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;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1502,7 +1514,7 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
|
||||||
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
|
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
|
||||||
{
|
{
|
||||||
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
|
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");
|
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Accepting call\n");
|
||||||
ft_r2_accept_call(ftdmchan);
|
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");
|
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call was answered\n");
|
||||||
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
|
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");
|
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
|
// the answering will be done in the on_call_accepted handler
|
||||||
ft_r2_accept_call(ftdmchan);
|
ft_r2_accept_call(ftdmchan);
|
||||||
R2CALL(ftdmchan)->answer_pending = 1;
|
r2call->answer_pending = 1;
|
||||||
} else {
|
} else {
|
||||||
ft_r2_answer_call(ftdmchan);
|
ft_r2_answer_call(ftdmchan);
|
||||||
}
|
}
|
||||||
|
@ -1541,19 +1553,19 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
|
||||||
/* just got hangup */
|
/* just got hangup */
|
||||||
case FTDM_CHANNEL_STATE_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);
|
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));
|
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 */
|
/* this will disconnect the call, but need to wait for the call end before moving to DOWN */
|
||||||
openr2_chan_disconnect_call(r2chan, disconnect_cause);
|
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 */
|
/* just ack the hangup, on_call_end will be called by openr2 right after */
|
||||||
openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
|
openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
|
||||||
} else {
|
} else {
|
||||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Clearing call due to protocol error\n");
|
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 */
|
/* do not set to down yet, give some time for recovery */
|
||||||
ftdm_sched_timer(r2data->sched, "protocolerr_recover", 100,
|
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;
|
break;
|
||||||
|
@ -1561,7 +1573,7 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
|
||||||
case FTDM_CHANNEL_STATE_TERMINATING:
|
case FTDM_CHANNEL_STATE_TERMINATING:
|
||||||
{
|
{
|
||||||
/* if the call has not been started yet we must go to HANGUP right here */
|
/* 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);
|
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
|
||||||
} else {
|
} else {
|
||||||
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
|
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;
|
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 */
|
/* finished call for good */
|
||||||
case FTDM_CHANNEL_STATE_DOWN:
|
case FTDM_CHANNEL_STATE_DOWN:
|
||||||
{
|
{
|
||||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Call is down\n");
|
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Call is down\n");
|
||||||
openr2_chan_disable_read(r2chan);
|
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue