freetdm: refactor channel open APIs

This commit is contained in:
Moises Silva 2010-06-07 21:45:24 -04:00
parent d9eb01974f
commit 6bab94445c

View File

@ -1338,6 +1338,57 @@ FT_DECLARE(ftdm_status_t) ftdm_group_channel_use_count(ftdm_group_t *group, uint
return FTDM_SUCCESS; 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) 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; ftdm_status_t status = FTDM_FAIL;
@ -1378,28 +1429,11 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_dir
break; break;
} }
if (ftdm_test_flag(check, FTDM_CHANNEL_READY) && if (request_channel(check, ftdmchan, caller_data, direction)) {
ftdm_test_flag(check, FTDM_CHANNEL_SIG_UP) && status = FTDM_SUCCESS;
!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; break;
} }
status = check->fio->open(check);
if (status == FTDM_SUCCESS) {
ftdm_channel_open_chan(check);
*ftdmchan = check;
break;
}
}
if (direction == FTDM_TOP_DOWN) { if (direction == FTDM_TOP_DOWN) {
if (i >= group->chan_count) { if (i >= group->chan_count) {
break; break;
@ -1501,30 +1535,11 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc
break; break;
} }
if (ftdm_test_flag(check, FTDM_CHANNEL_READY) && if (request_channel(check, ftdmchan, caller_data, direction)) {
ftdm_test_flag(check, FTDM_CHANNEL_SIG_UP) && status = FTDM_SUCCESS;
!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; break;
} }
status = check->fio->open(check);
if (status == FTDM_SUCCESS) {
ftdm_channel_open_chan(check);
*ftdmchan = check;
break;
}
}
if (direction == FTDM_TOP_DOWN) { if (direction == FTDM_TOP_DOWN) {
i++; i++;
} else { } else {
@ -1592,43 +1607,48 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan)
{ {
ftdm_status_t status = FTDM_FAIL; 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)) { if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED)) {
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is suspended\n"); 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)) { if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) {
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is alarmed\n"); 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 && if (globals.cpu_monitor.alarm &&
globals.cpu_monitor.alarm_action_flags & FTDM_CPU_ALARM_ACTION_REJECT) { 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"); 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; ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_SWITCH_CONGESTION;
return FTDM_FAIL; goto done;
} }
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;
}
status = FTDM_FAIL; status = ftdmchan->fio->open(ftdmchan);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY)) {
status = ftdmchan->span->fio->open(ftdmchan);
if (status == FTDM_SUCCESS) { if (status == FTDM_SUCCESS) {
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OPEN | FTDM_CHANNEL_INUSE); ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OPEN | FTDM_CHANNEL_INUSE);
}
} else { } 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); ftdm_mutex_unlock(ftdmchan->mutex);
return status; 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); 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"); ftdm_log(FTDM_LOG_CRIT, "Could not find span!\n");
goto done; 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) { if (span->channel_request) {
ftdm_log(FTDM_LOG_ERROR, "Individual channel selection not implemented on this span.\n"); ftdm_log(FTDM_LOG_ERROR, "Individual channel selection not implemented on this span.\n");
*ftdmchan = NULL; goto done;
}
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; goto done;
} }
if (!(check = span->channels[chan_id])) { if (!(check = span->channels[chan_id])) {
ftdm_log(FTDM_LOG_ERROR, "Invalid Channel %d\n", chan_id); ftdm_log(FTDM_LOG_CRIT, "Wow, no channel %d in span %d\n", chan_id, span_id);
*ftdmchan = NULL;
goto done; goto done;
} }
if (ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) || ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) || ftdm_mutex_lock(check->mutex);
!ftdm_test_flag(check, FTDM_CHANNEL_READY) || (status = ftdm_mutex_trylock(check->mutex)) != FTDM_SUCCESS) {
*ftdmchan = NULL;
goto done;
}
status = FTDM_FAIL;
/* the channel is only allowed to be open if not in use, or, for FXS devices with a call with call waiting enabled */ /* 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)) if (
|| ((check->type == FTDM_CHAN_TYPE_FXS && check->token_count == 1) && (ftdm_channel_test_feature(check, FTDM_CHANNEL_FEATURE_CALLWAITING)))) (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)) { if (!ftdm_test_flag(check, FTDM_CHANNEL_OPEN)) {
status = check->fio->open(check); status = check->fio->open(check);
if (status == FTDM_SUCCESS) { 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); ftdm_set_flag(check, FTDM_CHANNEL_INUSE);
*ftdmchan = check; *ftdmchan = check;
} }
ftdm_mutex_unlock(check->mutex); ftdm_mutex_unlock(check->mutex);
done: done:
ftdm_mutex_unlock(globals.mutex); ftdm_mutex_unlock(globals.mutex);
return status; return status;