From 29436b8cd6fb8664d26bf5123fa928d85fae17aa Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Mon, 4 Jan 2010 15:26:23 +0000 Subject: [PATCH] Support for huntgroups git-svn-id: http://svn.openzap.org/svn/openzap/branches/sangoma_boost@944 a93c3328-9c30-0410-af19-c9cd2b2d52af --- libs/freetdm/mod_openzap/mod_openzap.c | 29 +- libs/freetdm/src/include/openzap.h | 23 +- libs/freetdm/src/include/zap_types.h | 1 + .../ozmod_sangoma_boost/ozmod_sangoma_boost.c | 185 +++++++---- .../ozmod_sangoma_boost/zap_sangoma_boost.h | 11 +- libs/freetdm/src/zap_io.c | 308 +++++++++++++++++- 6 files changed, 470 insertions(+), 87 deletions(-) diff --git a/libs/freetdm/mod_openzap/mod_openzap.c b/libs/freetdm/mod_openzap/mod_openzap.c index 0e4efdb8d5..ee8234c99f 100644 --- a/libs/freetdm/mod_openzap/mod_openzap.c +++ b/libs/freetdm/mod_openzap/mod_openzap.c @@ -1033,7 +1033,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi const char *dest = NULL; char *data = NULL; - int span_id = -1, chan_id = 0; + int span_id = -1, group_id = -1,chan_id = 0; zap_channel_t *zchan = NULL; switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; char name[128]; @@ -1085,7 +1085,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi if (span_id == 0 && chan_id != 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Span 0 is used to pick the first available span, selecting a channel is not supported (and doesn't make sense)\n"); - return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; } if (span_id == -1 && !zstr(span_name)) { @@ -1097,11 +1097,18 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi } if (span_id == -1) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing span\n"); - return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + //Look for a group + zap_group_t *group; + zap_status_t zstatus = zap_group_find_by_name(span_name, &group); + if (zstatus == ZAP_SUCCESS && group) { + group_id = group->group_id; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing span\n"); + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + } } - if (chan_id < 0) { + if (group_id < 0 && chan_id < 0) { direction = ZAP_BOTTOM_UP; chan_id = 0; } @@ -1143,11 +1150,13 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi zap_set_string(caller_data.cid_name, outbound_profile->caller_id_name); zap_set_string(caller_data.cid_num.digits, outbound_profile->caller_id_number); - - if (chan_id) { + + if (group_id >= 0) { + status = zap_channel_open_by_group(group_id, direction, &caller_data, &zchan); + } else if (chan_id) { status = zap_channel_open(span_id, chan_id, &zchan); } else { - status = zap_channel_open_any(span_id, direction, &caller_data, &zchan); + status = zap_channel_open_by_span(span_id, direction, &caller_data, &zchan); } if (status != ZAP_SUCCESS) { @@ -1753,7 +1762,7 @@ static ZIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal) } } break; - case ZAP_SIGEVENT_PROGRESS: + case ZAP_SIGEVENT_PROGRESS: { if ((session = zap_channel_get_session(sigmsg->channel, 0))) { channel = switch_core_session_get_channel(session); @@ -1766,8 +1775,6 @@ static ZIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal) sigmsg->channel->span_id, sigmsg->channel->chan_id, (uuid) ? uuid : "N/A"); } } - break; - default: { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled msg type %d for channel %d:%d\n", diff --git a/libs/freetdm/src/include/openzap.h b/libs/freetdm/src/include/openzap.h index 64791f4eec..15ddf350c1 100644 --- a/libs/freetdm/src/include/openzap.h +++ b/libs/freetdm/src/include/openzap.h @@ -195,6 +195,9 @@ extern "C" { #define ZAP_MAX_CHANNELS_SPAN ZAP_MAX_CHANNELS_PHYSICAL_SPAN * ZAP_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN #define ZAP_MAX_SPANS_INTERFACE 128 +#define ZAP_MAX_CHANNELS_GROUP 1024 +#define ZAP_MAX_GROUPS_INTERFACE ZAP_MAX_SPANS_INTERFACE + #define GOTO_STATUS(label,st) status = st; goto label ; #define zap_copy_string(x,y,z) strncpy(x, y, z - 1) @@ -578,6 +581,16 @@ struct zap_span { struct zap_span *next; }; +struct zap_group { + char *name; + uint32_t group_id; + uint32_t chan_count; + zap_channel_t *channels[ZAP_MAX_CHANNELS_GROUP]; + uint32_t last_used_index; + zap_mutex_t *mutex; + struct zap_group *next; +}; + OZ_DECLARE_DATA extern zap_logger_t zap_log; typedef enum { @@ -706,11 +719,19 @@ OZ_DECLARE(zap_status_t) zap_span_create(zap_io_interface_t *zio, zap_span_t **s OZ_DECLARE(zap_status_t) zap_span_close_all(void); OZ_DECLARE(zap_status_t) zap_span_add_channel(zap_span_t *span, zap_socket_t sockfd, zap_chan_type_t type, zap_channel_t **chan); OZ_DECLARE(zap_status_t) zap_span_set_event_callback(zap_span_t *span, zio_event_cb_t event_callback); +OZ_DECLARE(zap_status_t) zap_channel_add_to_group(const char* name, zap_channel_t* zchan); +OZ_DECLARE(zap_status_t) zap_group_add_channels(const char* name, zap_span_t* span, const char* val); +OZ_DECLARE(zap_status_t) zap_channel_remove_from_group(zap_group_t* group, zap_channel_t* zchan); +OZ_DECLARE(zap_status_t) zap_group_find(uint32_t id, zap_group_t **group); +OZ_DECLARE(zap_status_t) zap_group_find_by_name(const char *name, zap_group_t **group); +OZ_DECLARE(zap_status_t) zap_group_create(zap_group_t **group, const char *name); OZ_DECLARE(zap_status_t) zap_channel_set_event_callback(zap_channel_t *zchan, zio_event_cb_t event_callback); OZ_DECLARE(zap_status_t) zap_channel_open(uint32_t span_id, uint32_t chan_id, zap_channel_t **zchan); OZ_DECLARE(zap_status_t) zap_channel_open_chan(zap_channel_t *zchan); OZ_DECLARE(zap_status_t) zap_span_channel_use_count(zap_span_t *span, uint32_t *count); -OZ_DECLARE(zap_status_t) zap_channel_open_any(uint32_t span_id, zap_direction_t direction, zap_caller_data_t *caller_data, zap_channel_t **zchan); +OZ_DECLARE(zap_status_t) zap_group_channel_use_count(zap_group_t *group, uint32_t *count); +OZ_DECLARE(zap_status_t) zap_channel_open_by_span(uint32_t span_id, zap_direction_t direction, zap_caller_data_t *caller_data, zap_channel_t **zchan); +OZ_DECLARE(zap_status_t) zap_channel_open_by_group(uint32_t group_id, zap_direction_t direction, zap_caller_data_t *caller_data, zap_channel_t **zchan); OZ_DECLARE(zap_status_t) zap_channel_close(zap_channel_t **zchan); OZ_DECLARE(zap_status_t) zap_channel_done(zap_channel_t *zchan); OZ_DECLARE(zap_status_t) zap_channel_use(zap_channel_t *zchan); diff --git a/libs/freetdm/src/include/zap_types.h b/libs/freetdm/src/include/zap_types.h index 8cf2b6b30c..98571e9b84 100644 --- a/libs/freetdm/src/include/zap_types.h +++ b/libs/freetdm/src/include/zap_types.h @@ -458,6 +458,7 @@ typedef struct zap_channel zap_channel_t; typedef struct zap_event zap_event_t; typedef struct zap_sigmsg zap_sigmsg_t; typedef struct zap_span zap_span_t; +typedef struct zap_group zap_group_t; typedef struct zap_caller_data zap_caller_data_t; typedef struct zap_io_interface zap_io_interface_t; diff --git a/libs/freetdm/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c b/libs/freetdm/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c index 5412738bb8..3dfe91006c 100644 --- a/libs/freetdm/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c +++ b/libs/freetdm/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c @@ -55,8 +55,11 @@ zap_mutex_t *g_boost_modules_mutex = NULL; zap_hash_t *g_boost_modules_hash = NULL; #define MAX_TRUNK_GROUPS 64 +//DAVIDY need to merge congestion_timeouts with zap_sangoma_boost_trunkgroups static time_t congestion_timeouts[MAX_TRUNK_GROUPS]; +static zap_sangoma_boost_trunkgroup_t *g_trunkgroups[MAX_TRUNK_GROUPS]; + #define BOOST_QUEUE_SIZE 500 /* get openzap span and chan depending on the span mode */ @@ -303,76 +306,80 @@ static ZIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request) zap_set_string(ani, caller_data->ani.digits); - if ((gr = strchr(ani, '@'))) { - *gr++ = '\0'; - } - - if (gr && *(gr+1)) { - tg = atoi(gr+1); - if (tg > 0) { - tg--; - } - } - event.trunk_group = tg; - - if (check_congestion(tg)) { - zap_log(ZAP_LOG_CRIT, "All circuits are busy. Trunk Group=%i (BOOST REQUESTED BACK OFF)\n",tg+1); - *zchan = NULL; - return ZAP_FAIL; - } - - zap_span_channel_use_count(span, &count); - - if (count >= span->chan_count) { - zap_log(ZAP_LOG_CRIT, "All circuits are busy.\n"); - *zchan = NULL; - return ZAP_FAIL; - } - r = next_request_id(); if (r == 0) { zap_log(ZAP_LOG_CRIT, "All tanks ids are busy.\n"); *zchan = NULL; return ZAP_FAIL; } - sangomabc_call_init(&event, caller_data->cid_num.digits, ani, r); - //sangoma_bc_call_init will clear the trunk_group val so we need to set it again - event.trunk_group=tg; - - if (gr && *(gr+1)) { - switch(*gr) { - case 'g': - event.hunt_group = SIGBOOST_HUNTGRP_SEQ_ASC; - break; - case 'G': - event.hunt_group = SIGBOOST_HUNTGRP_SEQ_DESC; - break; - case 'r': - event.hunt_group = SIGBOOST_HUNTGRP_RR_ASC; - break; - case 'R': - event.hunt_group = SIGBOOST_HUNTGRP_RR_DESC; - break; - default: - zap_log(ZAP_LOG_WARNING, "Failed to determine huntgroup (%s)\n", gr); - event.hunt_group = SIGBOOST_HUNTGRP_SEQ_ASC; + if (sangoma_boost_data->sigmod) { + *zchan = span->channels[chan_id]; + + event.span = (uint8_t) (*zchan)->physical_span_id; + event.chan = (uint8_t) (*zchan)->physical_chan_id; + + zap_set_flag((*zchan), ZAP_CHANNEL_OUTBOUND); + zap_set_flag_locked((*zchan), ZAP_CHANNEL_INUSE); + + OUTBOUND_REQUESTS[r].zchan = *zchan; + } else { + if ((gr = strchr(ani, '@'))) { + *gr++ = '\0'; + } + + if (gr && *(gr+1)) { + tg = atoi(gr+1); + if (tg > 0) { + tg--; + } + } + event.trunk_group = tg; + + if (check_congestion(tg)) { + zap_log(ZAP_LOG_CRIT, "All circuits are busy. Trunk Group=%i (BOOST REQUESTED BACK OFF)\n",tg+1); + *zchan = NULL; + return ZAP_FAIL; + } + + zap_span_channel_use_count(span, &count); + + if (count >= span->chan_count) { + zap_log(ZAP_LOG_CRIT, "All circuits are busy.\n"); + *zchan = NULL; + return ZAP_FAIL; + } + + if (gr && *(gr+1)) { + switch(*gr) { + case 'g': + event.hunt_group = SIGBOOST_HUNTGRP_SEQ_ASC; + break; + case 'G': + event.hunt_group = SIGBOOST_HUNTGRP_SEQ_DESC; + break; + case 'r': + event.hunt_group = SIGBOOST_HUNTGRP_RR_ASC; + break; + case 'R': + event.hunt_group = SIGBOOST_HUNTGRP_RR_DESC; + break; + default: + zap_log(ZAP_LOG_WARNING, "Failed to determine huntgroup (%s)\n", gr); + event.hunt_group = SIGBOOST_HUNTGRP_SEQ_ASC; + } } } zap_set_string(event.calling_name, caller_data->cid_name); zap_set_string(event.isup_in_rdnis, caller_data->rdnis.digits); - if (strlen(caller_data->rdnis.digits)) { - event.isup_in_rdnis_size = (uint16_t)strlen(caller_data->rdnis.digits)+1; - } + if (strlen(caller_data->rdnis.digits)) { + event.isup_in_rdnis_size = (uint16_t)strlen(caller_data->rdnis.digits)+1; + } event.calling_number_screening_ind = caller_data->screen; event.calling_number_presentation = caller_data->pres; - if (sangoma_boost_data->sigmod) { - /* boost sigmods only know about physical spans, give them that and let them hunt there */ - event.span = (uint8_t)span->channels[1]->physical_span_id; - } OUTBOUND_REQUESTS[r].status = BST_WAITING; OUTBOUND_REQUESTS[r].span = span; @@ -380,7 +387,9 @@ static ZIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request) if (sangomabc_connection_write(&sangoma_boost_data->mcon, &event) <= 0) { zap_log(ZAP_LOG_CRIT, "Failed to tx boost event [%s]\n", strerror(errno)); status = ZAP_FAIL; - *zchan = NULL; + if (!sangoma_boost_data->sigmod) { + *zchan = NULL; + } goto done; } @@ -388,8 +397,11 @@ static ZIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request) zap_sleep(1); if (--boost_request_timeout <= 0) { status = ZAP_FAIL; - *zchan = NULL; + if (!sangoma_boost_data->sigmod) { + *zchan = NULL; + } zap_log(ZAP_LOG_CRIT, "Timed out waiting for boost channel request response, current status: BST_WAITING\n"); + zap_log(ZAP_LOG_CRIT, "DYDBG s%dc%d: Csid:%d Timed out waiting for boost channel request response, current status: BST_WAITING\n", (*zchan)->physical_span_id, (*zchan)->physical_chan_id, r); goto done; } } @@ -406,7 +418,9 @@ static ZIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request) zap_sleep(1); if (--boost_request_timeout <= 0) { status = ZAP_FAIL; - *zchan = NULL; + if (!sangoma_boost_data->sigmod) { + *zchan = NULL; + } zap_log(ZAP_LOG_CRIT, "Timed out waiting for boost channel request response, current status: BST_ACK\n"); goto done; } @@ -420,7 +434,9 @@ static ZIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request) zap_log(ZAP_LOG_DEBUG, "Channel state changed to PROGRESS_MEDIA [Csid:%d]\n", r); } else { status = ZAP_FAIL; - *zchan = NULL; + if (!sangoma_boost_data->sigmod) { + *zchan = NULL; + } } done: @@ -433,12 +449,21 @@ static ZIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request) } else if (st != BST_READY) { assert(r <= MAX_REQ_ID); nack_map[r] = 1; - sangomabc_exec_command(&sangoma_boost_data->mcon, - 0, - 0, - r, - SIGBOOST_EVENT_CALL_START_NACK, - 0); + if (sangoma_boost_data->sigmod) { + sangomabc_exec_command(&sangoma_boost_data->mcon, + (*zchan)->physical_span_id, + (*zchan)->physical_chan_id, + r, + SIGBOOST_EVENT_CALL_START_NACK, + 0); + } else { + sangomabc_exec_command(&sangoma_boost_data->mcon, + 0, + 0, + r, + SIGBOOST_EVENT_CALL_START_NACK, + 0); + } } return status; @@ -526,9 +551,11 @@ static void handle_call_progress(sangomabc_connection_t *mcon, sangomabc_short_e */ static void handle_call_start_ack(sangomabc_connection_t *mcon, sangomabc_short_event_t *event) { + zap_channel_t *zchan; uint32_t event_span = event->span+1; uint32_t event_chan = event->chan+1; + if (nack_map[event->call_setup_id]) { return; } @@ -541,12 +568,19 @@ static void handle_call_start_ack(sangomabc_connection_t *mcon, sangomabc_short_ OUTBOUND_REQUESTS[event->call_setup_id].event = *event; SETUP_GRID[event->span][event->chan] = event->call_setup_id; - if ((zchan = find_zchan(OUTBOUND_REQUESTS[event->call_setup_id].span, event, 0))) { + if (mcon->sigmod) { + zchan = OUTBOUND_REQUESTS[event->call_setup_id].zchan; + zap_set_flag(zchan, ZAP_CHANNEL_OUTBOUND); + zap_set_flag_locked(zchan, ZAP_CHANNEL_INUSE); + } else { + zchan = find_zchan(OUTBOUND_REQUESTS[event->call_setup_id].span, event, 0); + } + + + if (zchan) { if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) { zap_log(ZAP_LOG_ERROR, "OPEN ERROR [%s]\n", zchan->last_error); } else { - zap_set_flag(zchan, ZAP_CHANNEL_OUTBOUND); - zap_set_flag_locked(zchan, ZAP_CHANNEL_INUSE); zchan->extra_id = event->call_setup_id; zap_log(ZAP_LOG_DEBUG, "Assign chan %d:%d (%d:%d) CSid=%d\n", zchan->span_id, zchan->chan_id, event_span, event_chan, event->call_setup_id); zchan->sflags = 0; @@ -620,6 +654,7 @@ static void handle_call_done(zap_span_t *span, sangomabc_connection_t *mcon, san static void handle_call_start_nack(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event) { zap_channel_t *zchan; + zap_sangoma_boost_data_t *sangoma_boost_data = span->signal_data; if (event->release_cause == SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY) { uint32_t count = 0; @@ -648,8 +683,10 @@ static void handle_call_start_nack(zap_span_t *span, sangomabc_connection_t *mco event->release_cause = 17; } - if (event->call_setup_id) { - + zap_log(ZAP_LOG_CRIT, "DYDBG setting event->call_setup_id:%d to BST_FAIL\n", event->call_setup_id); + OUTBOUND_REQUESTS[event->call_setup_id].event = *event; + OUTBOUND_REQUESTS[event->call_setup_id].status = BST_FAIL; + if (!sangoma_boost_data->sigmod) { sangomabc_exec_command(mcon, 0, 0, @@ -657,8 +694,6 @@ static void handle_call_start_nack(zap_span_t *span, sangomabc_connection_t *mco SIGBOOST_EVENT_CALL_START_NACK_ACK, 0); - OUTBOUND_REQUESTS[event->call_setup_id].event = *event; - OUTBOUND_REQUESTS[event->call_setup_id].status = BST_FAIL; return; } else { if ((zchan = find_zchan(span, event, 1))) { @@ -677,6 +712,7 @@ static void handle_call_start_nack(zap_span_t *span, sangomabc_connection_t *mco } } +#if 0 if (zchan) { zap_set_sflag_locked(zchan, SFLAG_SENT_FINAL_MSG); } @@ -688,6 +724,7 @@ static void handle_call_start_nack(zap_span_t *span, sangomabc_connection_t *mco 0, SIGBOOST_EVENT_CALL_START_NACK_ACK, 0); +#endif } /** @@ -1528,6 +1565,7 @@ end: */ static ZIO_SIG_LOAD_FUNCTION(zap_sangoma_boost_init) { + int i; g_boost_modules_hash = create_hashtable(10, zap_hash_hashfromstring, zap_hash_equalkeys); if (!g_boost_modules_hash) { return ZAP_FAIL; @@ -1535,6 +1573,10 @@ static ZIO_SIG_LOAD_FUNCTION(zap_sangoma_boost_init) zap_mutex_create(&request_mutex); zap_mutex_create(&signal_mutex); zap_mutex_create(&g_boost_modules_mutex); + + for(i=0;i< MAX_TRUNK_GROUPS;i++) { + g_trunkgroups[i]=NULL; + } return ZAP_SUCCESS; } @@ -1806,7 +1848,6 @@ static ZIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(zap_sangoma_boost_configure_span) } } - if (!sigmod) { if (!local_ip && local_port && remote_ip && remote_port && sig_cb) { zap_set_string(span->last_error, "missing Sangoma boost IP parameters"); diff --git a/libs/freetdm/src/ozmod/ozmod_sangoma_boost/zap_sangoma_boost.h b/libs/freetdm/src/ozmod/ozmod_sangoma_boost/zap_sangoma_boost.h index e08d98b598..91f54f930b 100644 --- a/libs/freetdm/src/ozmod/ozmod_sangoma_boost/zap_sangoma_boost.h +++ b/libs/freetdm/src/ozmod/ozmod_sangoma_boost/zap_sangoma_boost.h @@ -36,6 +36,8 @@ #include "sangoma_boost_client.h" #include "openzap.h" +#define MAX_CHANS_PER_TRUNKGROUP 1024 + typedef enum { ZAP_SANGOMA_BOOST_RUNNING = (1 << 0), ZAP_SANGOMA_BOOST_RESTARTING = (1 << 1) @@ -50,9 +52,16 @@ typedef struct zap_sangoma_boost_data { zio_signal_cb_t signal_cb; uint32_t flags; boost_sigmod_interface_t *sigmod; - zap_queue_t *boost_queue; + zap_queue_t *boost_queue; } zap_sangoma_boost_data_t; +typedef struct zap_sangoma_boost_trunkgroup { + zap_mutex_t *mutex; + zap_size_t size; /* Number of b-channels in group */ + unsigned int last_used_index; /* index of last b-channel used */ + zap_channel_t* zchans[MAX_CHANS_PER_TRUNKGROUP]; + //DAVIDY need to merge congestion timeouts to this struct +} zap_sangoma_boost_trunkgroup_t; #endif /* For Emacs: diff --git a/libs/freetdm/src/zap_io.c b/libs/freetdm/src/zap_io.c index ced0eb82bb..124e371be3 100644 --- a/libs/freetdm/src/zap_io.c +++ b/libs/freetdm/src/zap_io.c @@ -33,6 +33,7 @@ * Contributors: * * Moises Silva + * David Yat Sin * */ @@ -81,11 +82,15 @@ static struct { zap_hash_t *interface_hash; zap_hash_t *module_hash; zap_hash_t *span_hash; + zap_hash_t *group_hash; zap_mutex_t *mutex; zap_mutex_t *span_mutex; + zap_mutex_t *group_mutex; uint32_t span_index; + uint32_t group_index; uint32_t running; zap_span_t *spans; + zap_group_t *groups; } globals; @@ -1008,6 +1013,113 @@ OZ_DECLARE(zap_status_t) zap_channel_set_state(zap_channel_t *zchan, zap_channel return ok ? ZAP_SUCCESS : ZAP_FAIL; } + +OZ_DECLARE(zap_status_t) zap_group_channel_use_count(zap_group_t *group, uint32_t *count) +{ + uint32_t j; + + *count = 0; + + if (!group) { + return ZAP_FAIL; + } + + for(j = 0; j < group->chan_count && group->channels[j]; j++) { + if (group->channels[j]) { + if (zap_test_flag(group->channels[j], ZAP_CHANNEL_INUSE)) { + (*count)++; + } + } + } + + return ZAP_SUCCESS; +} + +OZ_DECLARE(zap_status_t) zap_channel_open_by_group(uint32_t group_id, zap_direction_t direction, zap_caller_data_t *caller_data, zap_channel_t **zchan) +{ + zap_status_t status = ZAP_FAIL; + zap_channel_t *check; + uint32_t i, count; + zap_group_t *group = NULL; + + if (group_id) { + zap_group_find(group_id, &group); + } + + if (!group ) { + zap_log(ZAP_LOG_CRIT, "GROUP NOT DEFINED!\n"); + *zchan = NULL; + return ZAP_FAIL; + } + + zap_group_channel_use_count(group, &count); + + if (count >= group->chan_count) { + zap_log(ZAP_LOG_CRIT, "All circuits are busy.\n"); + *zchan = NULL; + return ZAP_FAIL; + } + + + if (direction == ZAP_TOP_DOWN) { + i = 0; + } else { + i = group->chan_count-1; + } + + zap_mutex_lock(group->mutex); + for (;;) { + if (direction == ZAP_TOP_DOWN) { + if (i >= group->chan_count) { + break; + } + } else { + if (i < 0) { + break; + } + } + + if (!(check = group->channels[i])) { + status = ZAP_FAIL; + break; + } + + if (zap_test_flag(check, ZAP_CHANNEL_READY) && + !zap_test_flag(check, ZAP_CHANNEL_INUSE) && + !zap_test_flag(check, ZAP_CHANNEL_SUSPENDED) && + check->state == ZAP_CHANNEL_STATE_DOWN && + check->type != ZAP_CHAN_TYPE_DQ921 && + check->type != ZAP_CHAN_TYPE_DQ931 + + ) { + zap_span_t* span = NULL; + zap_span_find(check->span_id, &span); + if (span && span->channel_request) { + status = span->channel_request(span, check->physical_chan_id, direction, caller_data, zchan); + break; + } + + status = check->zio->open(check); + + if (status == ZAP_SUCCESS) { + zap_set_flag(check, ZAP_CHANNEL_INUSE); + zap_channel_open_chan(check); + *zchan = check; + break; + } + } + + if (direction == ZAP_TOP_DOWN) { + i++; + } else { + i--; + } + } + zap_mutex_unlock(group->mutex); + return status; +} + + OZ_DECLARE(zap_status_t) zap_span_channel_use_count(zap_span_t *span, uint32_t *count) { uint32_t j; @@ -1029,7 +1141,7 @@ OZ_DECLARE(zap_status_t) zap_span_channel_use_count(zap_span_t *span, uint32_t * return ZAP_SUCCESS; } -OZ_DECLARE(zap_status_t) zap_channel_open_any(uint32_t span_id, zap_direction_t direction, zap_caller_data_t *caller_data, zap_channel_t **zchan) +OZ_DECLARE(zap_status_t) zap_channel_open_by_span(uint32_t span_id, zap_direction_t direction, zap_caller_data_t *caller_data, zap_channel_t **zchan) { zap_status_t status = ZAP_FAIL; zap_channel_t *check; @@ -1172,7 +1284,6 @@ static zap_status_t zap_channel_reset(zap_channel_t *zchan) OZ_DECLARE(zap_status_t) zap_channel_init(zap_channel_t *zchan) { - if (zchan->init_state != ZAP_CHANNEL_STATE_DOWN) { zap_set_state_locked(zchan, zchan->init_state); zchan->init_state = ZAP_CHANNEL_STATE_DOWN; @@ -2438,6 +2549,7 @@ static zap_status_t load_config(void) unsigned configured = 0, d = 0; char name[80] = ""; char number[25] = ""; + char group_name[80] = "default"; zap_io_interface_t *zio = NULL; zap_analog_start_type_t tmp; @@ -2572,6 +2684,9 @@ static zap_status_t load_config(void) } } else if (!strcasecmp(var, "b-channel")) { configured += zio->configure_span(span, val, ZAP_CHAN_TYPE_B, name, number); + if (zap_group_add_channels(group_name, span, val) != ZAP_SUCCESS) { + zap_log(ZAP_LOG_ERROR, "Failed to add channels (%d:%s) to group\n", number, val); + } } else if (!strcasecmp(var, "d-channel")) { if (d) { zap_log(ZAP_LOG_WARNING, "ignoring extra d-channel\n"); @@ -2591,6 +2706,9 @@ static zap_status_t load_config(void) } else if (!strcasecmp(var, "dtmf_hangup")) { span->dtmf_hangup = zap_strdup(val); span->dtmf_hangup_len = strlen(val); + } else if (!strcasecmp(var, "group")) { + memset(group_name, 0, sizeof(group_name)); + memcpy(group_name, val, sizeof(group_name)); } else { zap_log(ZAP_LOG_ERROR, "unknown span variable '%s'\n", var); } @@ -2880,6 +2998,190 @@ OZ_DECLARE(zap_status_t) zap_span_start(zap_span_t *span) return ZAP_FAIL; } +OZ_DECLARE(zap_status_t) zap_channel_add_to_group(const char* name, zap_channel_t* zchan) +{ + int i; + zap_group_t* group = NULL; + + zap_mutex_lock(globals.group_mutex); + + if (zap_group_find_by_name(name, &group) != ZAP_SUCCESS) { + zap_log(ZAP_LOG_DEBUG, "Creating new group:%s\n", name); + zap_group_create(&group, name); + } + + /*verify that group does not already include this channel first */ + for(i=0; i < group->chan_count; i++) { + if (group->channels[i]->physical_span_id == zchan->physical_span_id && + group->channels[i]->physical_chan_id == zchan->physical_chan_id) { + + zap_mutex_unlock(globals.group_mutex); + return ZAP_SUCCESS; + } + } + + if (group->chan_count >= ZAP_MAX_CHANNELS_GROUP) { + zap_log(ZAP_LOG_CRIT, "Max number of channels exceeded (max:%d)\n", ZAP_MAX_CHANNELS_GROUP); + zap_mutex_unlock(globals.group_mutex); + return ZAP_FAIL; + } + + group->channels[group->chan_count++] = zchan; + zap_mutex_unlock(globals.group_mutex); + return ZAP_SUCCESS; +} + +OZ_DECLARE(zap_status_t) zap_channel_remove_from_group(zap_group_t* group, zap_channel_t* zchan) +{ + //Need to test this function + zap_mutex_lock(globals.group_mutex); + int i, j; + + for (i=0; i < group->chan_count; i++) { + if (group->channels[i]->physical_span_id == zchan->physical_span_id && + group->channels[i]->physical_chan_id == zchan->physical_chan_id) { + + j=i; + while(j < group->chan_count-1) { + group->channels[j] = group->channels[j+1]; + j++; + } + group->channels[group->chan_count--] = NULL; + if (group->chan_count <=0) { + /* Delete group if it is empty */ + hashtable_remove(globals.group_hash, (void *)group->name); + } + zap_mutex_unlock(globals.group_mutex); + return ZAP_SUCCESS; + } + } + + zap_mutex_unlock(globals.group_mutex); + //Group does not contain this channel + return ZAP_FAIL; +} + +OZ_DECLARE(zap_status_t) zap_group_add_channels(const char* name, zap_span_t* span, const char* val) +{ + char *p, *mydata, *item_list[10]; + int items, i; + + assert(strlen(name) > 0); + + p = strchr(val, ':'); + mydata = zap_strdup(++p); + + assert(mydata != NULL); + + items = zap_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0]))); + + for(i=0; i < items; i++) { + if (!strchr(item_list[i], '-')) { + int chan_no; + + chan_no = atoi (item_list[i]); + assert(chan_no > 0); + + if (zap_channel_add_to_group(name, span->channels[chan_no]) != ZAP_SUCCESS) { + zap_log(ZAP_LOG_CRIT, "Failed to add chan:%d to group:%s\n", chan_no, name); + } + } else { + int chan_no_start, chan_no_end; + + if (sscanf(item_list[i], "%d-%d", &chan_no_start, &chan_no_end) == 2) { + while (chan_no_start <= chan_no_end) { + if (zap_channel_add_to_group(name, span->channels[chan_no_start++])) { + zap_log(ZAP_LOG_CRIT, "Failed to add chan:%d to group:%s\n", chan_no_start-1, name); + } + } + } + } + } + return ZAP_SUCCESS; +} + +OZ_DECLARE(zap_status_t) zap_group_find(uint32_t id, zap_group_t **group) +{ + zap_group_t *fgroup = NULL, *grp; + + if (id > ZAP_MAX_GROUPS_INTERFACE) { + return ZAP_FAIL; + } + + + zap_mutex_lock(globals.group_mutex); + for (grp = globals.groups; grp; grp = grp->next) { + if (grp->group_id == id) { + fgroup = grp; + break; + } + } + zap_mutex_unlock(globals.group_mutex); + + if (!fgroup) { + return ZAP_FAIL; + } + + *group = fgroup; + + return ZAP_SUCCESS; + +} + +OZ_DECLARE(zap_status_t) zap_group_find_by_name(const char *name, zap_group_t **group) +{ + zap_status_t status = ZAP_FAIL; + + zap_mutex_lock(globals.group_mutex); + if (!zap_strlen_zero(name)) { + if ((*group = hashtable_search(globals.group_hash, (void *) name))) { + status = ZAP_SUCCESS; + } + } + zap_mutex_unlock(globals.group_mutex); + return status; +} + +static void zap_group_add(zap_group_t *group) +{ + zap_group_t *grp; + zap_mutex_lock(globals.group_mutex); + + for (grp = globals.groups; grp && grp->next; grp = grp->next); + + if (grp) { + grp->next = group; + } else { + globals.groups = group; + } + hashtable_insert(globals.group_hash, (void *)group->name, group, HASHTABLE_FLAG_NONE); + + zap_mutex_unlock(globals.group_mutex); +} + + +OZ_DECLARE(zap_status_t) zap_group_create(zap_group_t **group, const char *name) +{ + zap_group_t *new_group = NULL; + zap_status_t status = ZAP_FAIL; + + zap_mutex_lock(globals.mutex); + if (globals.group_index < ZAP_MAX_GROUPS_INTERFACE) { + new_group = zap_malloc(sizeof(*new_group)); + assert(new_group); + memset(new_group, 0, sizeof(*new_group)); + status = zap_mutex_create(&new_group->mutex); + assert(status == ZAP_SUCCESS); + + new_group->group_id = ++globals.group_index; + new_group->name = zap_strdup(name); + zap_group_add(new_group); + *group = new_group; + status = ZAP_SUCCESS; + } + zap_mutex_unlock(globals.mutex); + return status; +} OZ_DECLARE(zap_status_t) zap_global_init(void) { @@ -2893,8 +3195,10 @@ OZ_DECLARE(zap_status_t) zap_global_init(void) globals.interface_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys); globals.module_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys); globals.span_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys); + globals.group_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys); zap_mutex_create(&globals.mutex); zap_mutex_create(&globals.span_mutex); + zap_mutex_create(&globals.group_mutex); globals.running = 1; return ZAP_SUCCESS; }