From 6bab94445c20c0573de6e8bb36e5290d72ebc5e0 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 7 Jun 2010 21:45:24 -0400 Subject: [PATCH] freetdm: refactor channel open APIs --- libs/freetdm/src/ftdm_io.c | 185 +++++++++++++++++++++---------------- 1 file changed, 106 insertions(+), 79 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index c22767b658..a6a83ed84a 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -1338,6 +1338,57 @@ FT_DECLARE(ftdm_status_t) ftdm_group_channel_use_count(ftdm_group_t *group, uint return FTDM_SUCCESS; } +static __inline__ int chan_is_avail(ftdm_channel_t *check) +{ + if (!ftdm_test_flag(check, FTDM_CHANNEL_READY) || + !ftdm_test_flag(check, FTDM_CHANNEL_SIG_UP) || + ftdm_test_flag(check, FTDM_CHANNEL_INUSE) || + ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) || + ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) || + check->state != FTDM_CHANNEL_STATE_DOWN || + !FTDM_IS_VOICE_CHANNEL(check)) { + return 0; + } + return 1; +} + +static __inline__ int request_channel(ftdm_channel_t *check, ftdm_channel_t **ftdmchan, + ftdm_caller_data_t *caller_data, ftdm_direction_t direction) +{ + ftdm_status_t status; + if (chan_is_avail(check)) { + /* unlocked testing passed, try again with the channel locked */ + ftdm_mutex_lock(check->mutex); + if (chan_is_avail(check)) { + if (check->span && check->span->channel_request) { + /* I am only unlocking here cuz this function is called + * sometimes with the group or span lock held and were + * blocking anyone hunting for channels available and + * I believe teh channel_request() function may take + * a bit of time + * */ + ftdm_mutex_unlock(check->mutex); + ftdm_set_caller_data(check->span, caller_data); + status = check->span->channel_request(check->span, check->chan_id, + direction, caller_data, ftdmchan); + if (status == FTDM_SUCCESS) { + return 1; + } + } else { + status = ftdm_channel_open_chan(check); + if (status == FTDM_SUCCESS) { + *ftdmchan = check; + ftdm_set_flag(check, FTDM_CHANNEL_OUTBOUND); + ftdm_mutex_unlock(check->mutex); + return 1; + } + } + } + ftdm_mutex_unlock(check->mutex); + } + return 0; +} + FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan) { ftdm_status_t status = FTDM_FAIL; @@ -1376,30 +1427,13 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_dir if (!(check = group->channels[i])) { status = FTDM_FAIL; break; - } - - if (ftdm_test_flag(check, FTDM_CHANNEL_READY) && - ftdm_test_flag(check, FTDM_CHANNEL_SIG_UP) && - !ftdm_test_flag(check, FTDM_CHANNEL_INUSE) && - !ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) && - !ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) && - check->state == FTDM_CHANNEL_STATE_DOWN && - FTDM_IS_VOICE_CHANNEL(check) - ) { - if (check->span->channel_request) { - status = check->span->channel_request(check->span, check->chan_id, direction, caller_data, ftdmchan); - break; - } - - status = check->fio->open(check); - - if (status == FTDM_SUCCESS) { - ftdm_channel_open_chan(check); - *ftdmchan = check; - break; - } } - + + if (request_channel(check, ftdmchan, caller_data, direction)) { + status = FTDM_SUCCESS; + break; + } + if (direction == FTDM_TOP_DOWN) { if (i >= group->chan_count) { break; @@ -1500,31 +1534,12 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc status = FTDM_FAIL; break; } - - if (ftdm_test_flag(check, FTDM_CHANNEL_READY) && - ftdm_test_flag(check, FTDM_CHANNEL_SIG_UP) && - !ftdm_test_flag(check, FTDM_CHANNEL_INUSE) && - !ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) && - !ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) && - check->state == FTDM_CHANNEL_STATE_DOWN && - FTDM_IS_VOICE_CHANNEL(check) - ) { - if (span && span->channel_request) { - ftdm_set_caller_data(span, caller_data); - status = span->channel_request(span, i, direction, caller_data, ftdmchan); - break; - } - - status = check->fio->open(check); - - if (status == FTDM_SUCCESS) { - ftdm_channel_open_chan(check); - *ftdmchan = check; - break; - } + if (request_channel(check, ftdmchan, caller_data, direction)) { + status = FTDM_SUCCESS; + break; } - + if (direction == FTDM_TOP_DOWN) { i++; } else { @@ -1592,43 +1607,48 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan) { ftdm_status_t status = FTDM_FAIL; - assert(ftdmchan != NULL); + ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "invalid ftdmchan pointer\n"); + + ftdm_mutex_lock(ftdmchan->mutex); if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED)) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is suspended\n"); - return FTDM_FAIL; + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Cannot open channel when is suspended\n"); + goto done; } if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is alarmed\n"); - return FTDM_FAIL; + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Cannot open channel when is alarmed\n"); + goto done; + } + + if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY)) { + snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Channel is not ready"); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Cannot open channel when is not ready\n"); + goto done; } if (globals.cpu_monitor.alarm && globals.cpu_monitor.alarm_action_flags & FTDM_CPU_ALARM_ACTION_REJECT) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "CPU usage alarm is on - refusing to open channel\n"); - ftdm_log(FTDM_LOG_WARNING, "CPU usage alarm is on - refusing to open channel\n"); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "CPU usage alarm is on - refusing to open channel\n"); ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_SWITCH_CONGESTION; - return FTDM_FAIL; - } - - if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY) || (status = ftdm_mutex_trylock(ftdmchan->mutex)) != FTDM_SUCCESS) { - snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Channel is not ready or is in use %d %d", ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY), status); - return status; + goto done; } - status = FTDM_FAIL; - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY)) { - status = ftdmchan->span->fio->open(ftdmchan); - if (status == FTDM_SUCCESS) { - ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OPEN | FTDM_CHANNEL_INUSE); - } + status = ftdmchan->fio->open(ftdmchan); + if (status == FTDM_SUCCESS) { + ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OPEN | FTDM_CHANNEL_INUSE); } else { - snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is not ready"); + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "IO open failed: %d\n", status); } +done: + ftdm_mutex_unlock(ftdmchan->mutex); + return status; } @@ -1643,35 +1663,40 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_span_find(span_id, &span); - if (!span || !ftdm_test_flag(span, FTDM_SPAN_CONFIGURED) || chan_id >= FTDM_MAX_CHANNELS_SPAN) { + if (!span) { ftdm_log(FTDM_LOG_CRIT, "Could not find span!\n"); goto done; } + if (!ftdm_test_flag(span, FTDM_SPAN_CONFIGURED)) { + ftdm_log(FTDM_LOG_CRIT, "Span %d is not configured\n", span_id); + goto done; + } + if (span->channel_request) { ftdm_log(FTDM_LOG_ERROR, "Individual channel selection not implemented on this span.\n"); - *ftdmchan = NULL; - goto done; - } - - if (!(check = span->channels[chan_id])) { - ftdm_log(FTDM_LOG_ERROR, "Invalid Channel %d\n", chan_id); - *ftdmchan = NULL; goto done; } - if (ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) || ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) || - !ftdm_test_flag(check, FTDM_CHANNEL_READY) || (status = ftdm_mutex_trylock(check->mutex)) != FTDM_SUCCESS) { - *ftdmchan = NULL; + if (chan_id < 1 || chan_id > span->chan_count) { + ftdm_log(FTDM_LOG_ERROR, "Invalid channel %d to open in span %d\n", chan_id, span_id); goto done; } - - status = FTDM_FAIL; + + if (!(check = span->channels[chan_id])) { + ftdm_log(FTDM_LOG_CRIT, "Wow, no channel %d in span %d\n", chan_id, span_id); + goto done; + } + + ftdm_mutex_lock(check->mutex); /* the channel is only allowed to be open if not in use, or, for FXS devices with a call with call waiting enabled */ - if ((!ftdm_test_flag(check, FTDM_CHANNEL_INUSE)) - || ((check->type == FTDM_CHAN_TYPE_FXS && check->token_count == 1) && (ftdm_channel_test_feature(check, FTDM_CHANNEL_FEATURE_CALLWAITING)))) - { + if ( + (check->type == FTDM_CHAN_TYPE_FXS + && check->token_count == 1 + && ftdm_channel_test_feature(check, FTDM_CHANNEL_FEATURE_CALLWAITING)) + || + chan_is_avail(check)) { if (!ftdm_test_flag(check, FTDM_CHANNEL_OPEN)) { status = check->fio->open(check); if (status == FTDM_SUCCESS) { @@ -1683,9 +1708,11 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_set_flag(check, FTDM_CHANNEL_INUSE); *ftdmchan = check; } + ftdm_mutex_unlock(check->mutex); done: + ftdm_mutex_unlock(globals.mutex); return status;