]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
freetdm: refactor channel open APIs
authorMoises Silva <moy@sangoma.com>
Tue, 8 Jun 2010 01:45:24 +0000 (21:45 -0400)
committerMoises Silva <moy@sangoma.com>
Tue, 8 Jun 2010 01:48:33 +0000 (21:48 -0400)
libs/freetdm/src/ftdm_io.c

index c22767b6585eb70ab5f964ae3d241379b7f1663e..a6a83ed84a58b80da7f3fafefa8e2c92c7867cb3 100644 (file)
@@ -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;
+
+       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;
        }
 
-       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 (!(check = span->channels[chan_id])) {
+               ftdm_log(FTDM_LOG_CRIT, "Wow, no channel %d in span %d\n", chan_id, span_id);
                goto done;
        }
-       
-       status = FTDM_FAIL;
+
+       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;