freetdm: Fix segfault due to race condition in ftmod_r2 processing loop

Added SIGEVENT_PROCEED for ftmod_r2
         Cleaned up code in main loop to use channel iterators
This commit is contained in:
Arnaldo Pereira 2010-12-01 20:18:35 -02:00
parent 1b7e4a0df9
commit 87d5826142
1 changed files with 28 additions and 14 deletions

View File

@ -1303,6 +1303,10 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
} }
} else { } else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying progress\n"); ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying progress\n");
sigev.event_id = FTDM_SIGEVENT_PROCEED;
if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
}
sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA; sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) { if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
@ -1417,6 +1421,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
int res, ms; int res, ms;
int index = 0; int index = 0;
struct timeval start, end; struct timeval start, end;
ftdm_iterator_t *chaniter = NULL;
short *poll_events = ftdm_malloc(sizeof(short) * span->chan_count); short *poll_events = ftdm_malloc(sizeof(short) * span->chan_count);
#ifdef __linux__ #ifdef __linux__
@ -1436,6 +1441,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
memset(&start, 0, sizeof(start)); memset(&start, 0, sizeof(start));
memset(&end, 0, sizeof(end)); memset(&end, 0, sizeof(end));
chaniter = ftdm_span_get_chan_iterator(span, NULL);
while (ftdm_running() && ftdm_test_flag(r2data, FTDM_R2_RUNNING)) { while (ftdm_running() && ftdm_test_flag(r2data, FTDM_R2_RUNNING)) {
res = gettimeofday(&end, NULL); res = gettimeofday(&end, NULL);
if (start.tv_sec) { if (start.tv_sec) {
@ -1457,9 +1463,10 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
/* figure out what event to poll each channel for. POLLPRI when the channel is down, /* figure out what event to poll each channel for. POLLPRI when the channel is down,
* POLLPRI|POLLIN|POLLOUT otherwise */ * POLLPRI|POLLIN|POLLOUT otherwise */
memset(poll_events, 0, sizeof(short)*span->chan_count); memset(poll_events, 0, sizeof(short)*span->chan_count);
for (i = 0; i < span->chan_count; i++) { chaniter = ftdm_span_get_chan_iterator(span, chaniter);
r2chan = R2CALL(span->channels[(i+1)])->r2chan; for (i = 0; chaniter; chaniter = ftdm_iterator_next(chaniter), i++) {
ftdmchan = openr2_chan_get_client_data(r2chan); ftdmchan = ftdm_iterator_current(chaniter);
r2chan = R2CALL(ftdmchan)->r2chan;
poll_events[i] = POLLPRI; poll_events[i] = POLLPRI;
if (openr2_chan_get_read_enabled(r2chan)) { if (openr2_chan_get_read_enabled(r2chan)) {
poll_events[i] |= POLLIN; poll_events[i] |= POLLIN;
@ -1481,29 +1488,36 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
continue; continue;
} }
/* XXX /* this main loop takes care of MF and CAS signaling during call setup and tear down
* when ftdm_span_poll_event() returns FTDM_SUCCESS, means there are events pending on the span. * for every single channel in the span, do not perform blocking operations here! */
* is it possible to know on which channels those events are pending, without traversing the span? chaniter = ftdm_span_get_chan_iterator(span, chaniter);
* XXX */ for ( ; chaniter; chaniter = ftdm_iterator_next(chaniter)) {
for (i = 1; i <= span->chan_count; i++) { ftdmchan = ftdm_iterator_current(chaniter);
r2chan = R2CALL(span->channels[i])->r2chan;
ftdmchan = openr2_chan_get_client_data(r2chan);
r2call = R2CALL(ftdmchan);
ftdm_mutex_lock(ftdmchan->mutex); ftdm_mutex_lock(ftdmchan->mutex);
r2chan = R2CALL(span->channels[i])->r2chan;
ftdm_r2_state_advance_all(ftdmchan); ftdm_r2_state_advance_all(ftdmchan);
openr2_chan_process_signaling(r2chan); openr2_chan_process_signaling(r2chan);
ftdm_r2_state_advance_all(ftdmchan); ftdm_r2_state_advance_all(ftdmchan);
ftdm_mutex_unlock(ftdmchan->mutex); ftdm_mutex_unlock(ftdmchan->mutex);
} }
/* deliver the actual events to the user now without any channel locking */
ftdm_span_trigger_signals(span); ftdm_span_trigger_signals(span);
} }
for (i = 1; i <= span->chan_count; i++) { chaniter = ftdm_span_get_chan_iterator(span, chaniter);
r2chan = R2CALL(span->channels[i])->r2chan; for ( ; chaniter; chaniter = ftdm_iterator_next(chaniter)) {
ftdmchan = ftdm_iterator_current(chaniter);
r2chan = R2CALL(ftdmchan)->r2chan;
openr2_chan_set_blocked(r2chan); openr2_chan_set_blocked(r2chan);
} }
ftdm_iterator_free(chaniter);
ftdm_safe_free(poll_events); ftdm_safe_free(poll_events);
ftdm_clear_flag(r2data, FTDM_R2_RUNNING); ftdm_clear_flag(r2data, FTDM_R2_RUNNING);