1
0
mirror of https://github.com/signalwire/freeswitch.git synced 2025-04-22 11:19:52 +00:00

freetdm: fix hangup race

This commit is contained in:
Moises Silva 2010-07-29 13:15:29 -04:00
parent 910729b5dd
commit 438c93e83f
2 changed files with 44 additions and 3 deletions
libs/freetdm/src
ftdm_io.c
include/private

@ -1899,15 +1899,27 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_unhold(const char *file, const char
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan) FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
{ {
ftdm_status_t status = FTDM_SUCCESS;
ftdm_channel_lock(ftdmchan); ftdm_channel_lock(ftdmchan);
if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call is already terminating\n");
goto done;
}
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_ANSWERED); ftdm_set_flag(ftdmchan, FTDM_CHANNEL_ANSWERED);
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS); ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_MEDIA); ftdm_set_flag(ftdmchan, FTDM_CHANNEL_MEDIA);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
ftdm_channel_unlock(ftdmchan); goto done;
return FTDM_SUCCESS; }
if (ftdmchan->state >= FTDM_CHANNEL_STATE_UP) {
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Ignoring answer because the call state is (%d/%s)\n", ftdmchan->state, ftdm_channel_state2str(ftdmchan->state));
status = FTDM_FAIL;
goto done;
} }
if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) { if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
@ -1920,14 +1932,33 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char
ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 1); ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 1);
done:
ftdm_channel_unlock(ftdmchan); ftdm_channel_unlock(ftdmchan);
return FTDM_SUCCESS; return status;
} }
/* lock must be acquired by the caller! */ /* lock must be acquired by the caller! */
static ftdm_status_t call_hangup(ftdm_channel_t *chan, const char *file, const char *func, int line) static ftdm_status_t call_hangup(ftdm_channel_t *chan, const char *file, const char *func, int line)
{ {
if (chan->state != FTDM_CHANNEL_STATE_DOWN) { if (chan->state != FTDM_CHANNEL_STATE_DOWN) {
if (chan->state == FTDM_CHANNEL_STATE_HANGUP) {
/* make user's life easier, and just ignore double hangup requests */
return FTDM_SUCCESS;
}
if (chan->state == FTDM_CHANNEL_STATE_TERMINATING && ftdm_test_flag(chan, FTDM_CHANNEL_STATE_CHANGE)) {
/* the signaling stack is already terminating the call but has not yet notified the user about it
* with SIGEVENT_STOP, we must flag this channel as hangup and wait for the SIGEVENT_STOP before
* proceeding, at that point we will move the channel to hangup, but the SIGEVENT_STOP will not
* be sent to the user since they already made clear they want to hangup!
* */
ftdm_set_flag(chan, FTDM_CHANNEL_USER_HANGUP);
ftdm_wait_for_flag_cleared(chan, FTDM_CHANNEL_STATE_CHANGE, 5000);
if (ftdm_test_flag(chan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_log_chan(chan, FTDM_LOG_CRIT, "Failed to hangup, state change for %d/%s is still pending!\n", chan->state, ftdm_channel_state2str(chan->state));
return FTDM_FAIL;
}
}
ftdm_channel_set_state(file, func, line, chan, FTDM_CHANNEL_STATE_HANGUP, 1); ftdm_channel_set_state(file, func, line, chan, FTDM_CHANNEL_STATE_HANGUP, 1);
} else { } else {
/* the signaling stack did not touch the state, /* the signaling stack did not touch the state,
@ -2163,6 +2194,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan)
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_PROGRESS); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_MEDIA); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_MEDIA);
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_ANSWERED); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_ANSWERED);
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_USER_HANGUP);
ftdm_mutex_lock(ftdmchan->pre_buffer_mutex); ftdm_mutex_lock(ftdmchan->pre_buffer_mutex);
ftdm_buffer_destroy(&ftdmchan->pre_buffer); ftdm_buffer_destroy(&ftdmchan->pre_buffer);
ftdmchan->pre_buffer_size = 0; ftdmchan->pre_buffer_size = 0;
@ -4214,6 +4246,13 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t
ftdm_clear_flag(sigmsg->channel, FTDM_CHANNEL_HOLD); ftdm_clear_flag(sigmsg->channel, FTDM_CHANNEL_HOLD);
break; break;
case FTDM_SIGEVENT_STOP:
if (ftdm_test_flag(sigmsg->channel, FTDM_CHANNEL_USER_HANGUP)) {
ftdm_log_chan_msg(sigmsg->channel, FTDM_LOG_DEBUG, "Ignoring SIGEVENT_STOP since user already requested hangup\n");
goto done;
}
break;
default: default:
break; break;
@ -4224,6 +4263,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t
status = span->signal_cb(sigmsg); status = span->signal_cb(sigmsg);
} }
done:
if (sigmsg->channel) { if (sigmsg->channel) {
ftdm_mutex_unlock(sigmsg->channel->mutex); ftdm_mutex_unlock(sigmsg->channel->mutex);
} }

@ -250,6 +250,7 @@ typedef enum {
FTDM_CHANNEL_USE_TX_GAIN = (1 << 26), FTDM_CHANNEL_USE_TX_GAIN = (1 << 26),
FTDM_CHANNEL_IN_ALARM = (1 << 27), FTDM_CHANNEL_IN_ALARM = (1 << 27),
FTDM_CHANNEL_SIG_UP = (1 << 28), FTDM_CHANNEL_SIG_UP = (1 << 28),
FTDM_CHANNEL_USER_HANGUP = (1 << 29),
} ftdm_channel_flag_t; } ftdm_channel_flag_t;
#if defined(__cplusplus) && defined(WIN32) #if defined(__cplusplus) && defined(WIN32)
// fix C2676 // fix C2676