diff --git a/src/mod/endpoints/mod_wanpipe/Makefile b/src/mod/endpoints/mod_wanpipe/Makefile index 414a14971e..9ce1df8c80 100644 --- a/src/mod/endpoints/mod_wanpipe/Makefile +++ b/src/mod/endpoints/mod_wanpipe/Makefile @@ -1,7 +1,7 @@ CFLAGS +=-I/usr/local/include -I/usr/src/libpri -I/usr/src/linux/include -I. -I/usr/include CFLAGS +=-D__LINUX__ -D_REENTRANT -D_GNU_SOURCE -DAFT_A104 -DWANPIPE_TDM_API LDFLAGS += -lsangoma - +OBJS = ss7boost_client.o mod_wanpipe.o ifeq ($(OSARCH),Darwin) LINKER=g++ @@ -14,9 +14,12 @@ all: depends $(MODNAME).$(DYNAMIC_LIB_EXTEN) depends: MAKE=$(MAKE) $(BASE)/build/buildlib.sh $(BASE) install libsangoma --prefix=$(PREFIX) --with-libpri=/usr/src/libpri -$(MODNAME).$(DYNAMIC_LIB_EXTEN): $(MODNAME).c +%.o: %.c + $(CC) $(CFLAGS) $(MOD_CFLAGS) -g -ggdb -Werror -fPIC -c $< -o $@ + +$(MODNAME).$(DYNAMIC_LIB_EXTEN): $(OBJS) $(MODNAME).c $(CC) $(CFLAGS) -fPIC -c $(MODNAME).c -o $(MODNAME).o - $(LINKER) $(SOLINK) -o $(MODNAME).$(DYNAMIC_LIB_EXTEN) $(MODNAME).o $(LDFLAGS) + $(LINKER) $(SOLINK) -o $(MODNAME).$(DYNAMIC_LIB_EXTEN) $(OBJS) $(LDFLAGS) clean: rm -fr *.$(DYNAMIC_LIB_EXTEN) *.o *~ diff --git a/src/mod/endpoints/mod_wanpipe/mod_wanpipe.c b/src/mod/endpoints/mod_wanpipe/mod_wanpipe.c index d5fb140551..868d55b58f 100644 --- a/src/mod/endpoints/mod_wanpipe/mod_wanpipe.c +++ b/src/mod/endpoints/mod_wanpipe/mod_wanpipe.c @@ -34,6 +34,7 @@ #include #include #include +#include #ifndef INVALID_HANDLE_VALUE #define INVALID_HANDLE_VALUE -1 @@ -67,11 +68,39 @@ typedef enum { TFLAG_ABORT = (1 << 8), TFLAG_SWITCH = (1 << 9), TFLAG_NOSIG = (1 << 10), - TFLAG_BYE = (1 << 11) + TFLAG_BYE = (1 << 11), + TFLAG_CODEC = (1 << 12) } TFLAGS; #define DEFAULT_SAMPLES_PER_FRAME 160 +#define MAX_SPANS 128 + +struct channel_map { + char map[SANGOMA_MAX_CHAN_PER_SPAN][SWITCH_UUID_FORMATTED_LENGTH + 1]; +}; + + +unsigned int txseq=0; +unsigned int rxseq=0; + +#define SETUP_LEN CORE_MAX_CHAN_PER_SPAN*CORE_MAX_SPANS+1 + +struct ss7boost_handle { + char *local_ip; + char *remote_ip; + int local_port; + int remote_port; + ss7boost_client_connection_t mcon; + switch_mutex_t *mutex; + struct channel_map span_chanmap[MAX_SPANS]; + char setup_array[SETUP_LEN][SWITCH_UUID_FORMATTED_LENGTH + 1]; + uint32_t setup_index; +}; + +typedef struct ss7boost_handle ss7boost_handle_t; + +static int isup_exec_command(ss7boost_handle_t *ss7boost_handle, int span, int chan, int id, int cmd, int cause); static struct { int debug; @@ -81,10 +110,12 @@ static struct { int dtmf_off; int supress_dtmf_tone; int configured_spans; + int configured_boost_spans; char *dialplan; switch_hash_t *call_hash; switch_mutex_t *hash_mutex; switch_mutex_t *channel_mutex; + ss7boost_handle_t *ss7boost_handle; } globals; struct wanpipe_pri_span { @@ -107,11 +138,8 @@ struct wpsock { typedef struct wpsock wpsock_t; - -#define MAX_SPANS 128 static struct wanpipe_pri_span *SPANS[MAX_SPANS]; - struct private_object { unsigned int flags; /* FLAGS */ switch_frame_t read_frame; /* Frame for Writing */ @@ -135,6 +163,12 @@ struct private_object { unsigned int skip_write_frames; switch_mutex_t *flag_mutex; int frame_size; + ss7boost_handle_t *ss7boost_handle; + int boost_chan_number; + int boost_span_number; + int boost_trunk_group; + uint32_t setup_index; + uint32_t boost_pres; #ifdef DOTRACE int fd; int fd2; @@ -142,10 +176,6 @@ struct private_object { }; typedef struct private_object private_object_t; -struct channel_map { - char map[SANGOMA_MAX_CHAN_PER_SPAN][SWITCH_UUID_FORMATTED_LENGTH + 1]; -}; - static int wp_close(private_object_t *tech_pvt) { int ret = 0; @@ -315,28 +345,21 @@ static void *SWITCH_THREAD_FUNC pri_thread_run(switch_thread_t *thread, void *ob static switch_status_t config_wanpipe(int reload); -/* - State methods they get called when the state changes to the specific state - returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next - so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it. -*/ -static switch_status_t wanpipe_on_init(switch_core_session_t *session) +static switch_status_t wanpipe_codec_init(private_object_t *tech_pvt) { - private_object_t *tech_pvt; - switch_channel_t *channel = NULL; - wanpipe_tdm_api_t tdm_api = {{0}}; int err = 0; + wanpipe_tdm_api_t tdm_api = {{0}}; unsigned int rate = 8000; + switch_channel_t *channel = NULL; + + if (switch_test_flag(tech_pvt, TFLAG_CODEC)) { + return SWITCH_STATUS_SUCCESS; + } - channel = switch_core_session_get_channel(session); + channel = switch_core_session_get_channel(tech_pvt->session); assert(channel != NULL); - tech_pvt = switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - tech_pvt->read_frame.data = tech_pvt->databuf; - err = sangoma_tdm_set_codec(tech_pvt->wpsock->fd, &tdm_api, WP_SLINEAR); sangoma_tdm_set_usr_period(tech_pvt->wpsock->fd, &tdm_api, globals.samples_per_frame / 8); @@ -344,7 +367,7 @@ static switch_status_t wanpipe_on_init(switch_core_session_t *session) if (switch_core_codec_init (&tech_pvt->read_codec, "L16", NULL, rate, globals.samples_per_frame / 8, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, - switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { + switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s Cannot set read codec\n", switch_channel_get_name(channel)); switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); return SWITCH_STATUS_FALSE; @@ -352,15 +375,15 @@ static switch_status_t wanpipe_on_init(switch_core_session_t *session) if (switch_core_codec_init (&tech_pvt->write_codec, "L16", NULL, rate, globals.samples_per_frame / 8, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, - switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { + switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s Cannot set read codec\n", switch_channel_get_name(channel)); switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); return SWITCH_STATUS_FALSE; } tech_pvt->read_frame.rate = rate; tech_pvt->read_frame.codec = &tech_pvt->read_codec; - switch_core_session_set_read_codec(session, &tech_pvt->read_codec); - switch_core_session_set_write_codec(session, &tech_pvt->write_codec); + switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec); + switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec); #ifdef DOTRACE tech_pvt->fd = open("/tmp/wp-in.raw", O_WRONLY | O_TRUNC | O_CREAT); @@ -381,11 +404,74 @@ static switch_status_t wanpipe_on_init(switch_core_session_t *session) tech_pvt->tone_session.wait = globals.dtmf_off * (tech_pvt->tone_session.rate / 1000); teletone_dtmf_detect_init (&tech_pvt->dtmf_detect, rate); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Audio init %s\n", switch_channel_get_name(channel)); + switch_set_flag(tech_pvt, TFLAG_CODEC); + + return SWITCH_STATUS_SUCCESS; + +} + + +/* + State methods they get called when the state changes to the specific state + returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next + so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it. +*/ +static switch_status_t wanpipe_on_init(switch_core_session_t *session) +{ + private_object_t *tech_pvt; + switch_channel_t *channel = NULL; + switch_status_t status; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + tech_pvt->read_frame.data = tech_pvt->databuf; + + if (tech_pvt->ss7boost_handle) { + if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + ss7boost_client_event_t event; + + event.calling_number_presentation = tech_pvt->boost_pres; + event.trunk_group = tech_pvt->boost_trunk_group; + + switch_mutex_lock(tech_pvt->ss7boost_handle->mutex); + tech_pvt->setup_index = ++tech_pvt->ss7boost_handle->setup_index; + if (tech_pvt->ss7boost_handle->setup_index == SETUP_LEN - 1) { + tech_pvt->ss7boost_handle->setup_index = 0; + } + switch_mutex_unlock(tech_pvt->ss7boost_handle->mutex); + + switch_copy_string(tech_pvt->ss7boost_handle->setup_array[tech_pvt->setup_index], + switch_core_session_get_uuid(session), + sizeof(tech_pvt->ss7boost_handle->setup_array[tech_pvt->setup_index])); + + + ss7boost_client_call_init(&event, tech_pvt->caller_profile->caller_id_number, tech_pvt->caller_profile->destination_number, tech_pvt->setup_index); + + if (ss7boost_client_connection_write(&tech_pvt->ss7boost_handle->mcon, &event) <= 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Critical System Error: Failed to tx on ISUP socket [%s]: %s\n", strerror(errno)); + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Call Called Event TG=%d\n", tech_pvt->boost_trunk_group); + goto done; + } + } + + if ((status = wanpipe_codec_init(tech_pvt)) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + return status; + } + if (switch_test_flag(tech_pvt, TFLAG_NOSIG)) { switch_channel_mark_answered(channel); } + done: /* Move Channel's State Machine to RING */ switch_channel_set_state(channel, CS_RING); @@ -423,13 +509,8 @@ static switch_status_t wanpipe_on_hangup(switch_core_session_t *session) tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); - switch_set_flag_locked(tech_pvt, TFLAG_BYE); - if (!switch_test_flag(tech_pvt, TFLAG_NOSIG)) { - chanmap = tech_pvt->spri->private_info; - } - //sangoma_socket_close(&tech_pvt->wpsock->fd); wp_close(tech_pvt); switch_core_codec_destroy(&tech_pvt->read_codec); @@ -438,16 +519,34 @@ static switch_status_t wanpipe_on_hangup(switch_core_session_t *session) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "WANPIPE HANGUP\n"); - if (!switch_test_flag(tech_pvt, TFLAG_NOSIG)) { - pri_hangup(tech_pvt->spri->pri, tech_pvt->call, switch_channel_get_cause(channel)); - pri_destroycall(tech_pvt->spri->pri, tech_pvt->call); + if (tech_pvt->ss7boost_handle) { + switch_mutex_lock(tech_pvt->ss7boost_handle->mutex); + *tech_pvt->ss7boost_handle->span_chanmap[tech_pvt->boost_span_number].map[tech_pvt->boost_chan_number] = '\0'; + switch_mutex_unlock(tech_pvt->ss7boost_handle->mutex); + if (!switch_test_flag(tech_pvt, TFLAG_BYE)) { + isup_exec_command(tech_pvt->ss7boost_handle, + tech_pvt->boost_span_number, + tech_pvt->boost_chan_number, + -1, + SIGBOOST_EVENT_CALL_STOPPED, + SIGBOOST_RELEASE_CAUSE_NORMAL); + } + } else if (tech_pvt->spri) { + chanmap = tech_pvt->spri->private_info; + + if (!switch_test_flag(tech_pvt, TFLAG_BYE)) { + pri_hangup(tech_pvt->spri->pri, tech_pvt->call, switch_channel_get_cause(channel)); + pri_destroycall(tech_pvt->spri->pri, tech_pvt->call); + } switch_mutex_lock(globals.channel_mutex); *chanmap->map[tech_pvt->callno] = '\0'; - switch_mutex_unlock(globals.channel_mutex); + } + switch_set_flag_locked(tech_pvt, TFLAG_BYE); + teletone_destroy_session(&tech_pvt->tone_session); switch_buffer_destroy(&tech_pvt->dtmf_buffer); @@ -490,9 +589,19 @@ static switch_status_t wanpipe_answer_channel(switch_core_session_t *session) tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); - if (switch_test_flag(tech_pvt, TFLAG_INBOUND) && !switch_test_flag(tech_pvt, TFLAG_NOSIG)) { - pri_answer(tech_pvt->spri->pri, tech_pvt->call, 0, 1); + if (tech_pvt->spri) { + if (switch_test_flag(tech_pvt, TFLAG_INBOUND)) { + pri_answer(tech_pvt->spri->pri, tech_pvt->call, 0, 1); + } + } else if (tech_pvt->ss7boost_handle) { + isup_exec_command(tech_pvt->ss7boost_handle, + tech_pvt->boost_span_number, + tech_pvt->boost_chan_number, + -1, + SIGBOOST_EVENT_CALL_ANSWERED, + 0); } + return SWITCH_STATUS_SUCCESS; } @@ -705,10 +814,7 @@ static switch_status_t wanpipe_kill_channel(switch_core_session_t *session, int switch(sig) { case SWITCH_SIG_KILL: - switch_mutex_lock(tech_pvt->flag_mutex); - switch_set_flag(tech_pvt, TFLAG_BYE); - switch_clear_flag(tech_pvt, TFLAG_MEDIA); - switch_mutex_unlock(tech_pvt->flag_mutex); + switch_clear_flag_locked(tech_pvt, TFLAG_MEDIA); break; default: break; @@ -765,29 +871,59 @@ static switch_call_cause_t wanpipe_outgoing_channel(switch_core_session_t *sessi { char *bchan = NULL; char name[128] = ""; - + char *protocol; + char *dest; + int ready = 0, is_pri = 0, is_boost = 0, is_raw = 0; - if (outbound_profile && outbound_profile->destination_number) { - bchan = strchr(outbound_profile->destination_number, '='); - } else { - return SWITCH_STATUS_FALSE; + + if (!outbound_profile) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Doh! no caller profile\n"); + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; } - if (bchan) { - bchan++; - if (!bchan) { - return SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL; + protocol = switch_core_session_strdup(session, outbound_profile->destination_number); + + if (!(dest = strchr(protocol, '/'))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error No protocol specified!\n"); + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + } + + *dest++ = '\0'; + + if (!strcasecmp(protocol, "raw")) { + bchan = dest; + is_raw = ready = 1; + } else if (!strcasecmp(protocol, "pri")) { + if ((is_pri = globals.configured_spans)) { + ready = is_pri; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error No PRI Spans Configured.\n"); } - outbound_profile->destination_number++; - } else if (!globals.configured_spans) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error No Spans Configured.\n"); - SWITCH_CAUSE_NETWORK_OUT_OF_ORDER; + } else if (!strcasecmp(protocol, "ss7boost")) { + if ((is_boost = globals.configured_boost_spans)) { + ready = is_boost; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error No SS7BOOST Spans Configured.\n"); + } + } + + if (!ready) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Continue!\n"); + return SWITCH_CAUSE_NETWORK_OUT_OF_ORDER; } + outbound_profile->destination_number = dest; if ((*new_session = switch_core_session_request(&wanpipe_endpoint_interface, pool))) { private_object_t *tech_pvt; switch_channel_t *channel; + switch_caller_profile_t *caller_profile = NULL; + int callno = 0; + struct sangoma_pri *spri; + int span = 0, autospan = 0, autochan = 0; + char *num, *p; + struct channel_map *chanmap = NULL; + switch_core_session_add_stream(*new_session, NULL); if ((tech_pvt = (private_object_t *) switch_core_session_alloc(*new_session, sizeof(private_object_t)))) { @@ -797,181 +933,193 @@ static switch_call_cause_t wanpipe_outgoing_channel(switch_core_session_t *sessi switch_core_session_set_private(*new_session, tech_pvt); tech_pvt->session = *new_session; } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Hey where is my memory pool?\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); switch_core_session_destroy(new_session); - SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; } - if (outbound_profile) { - switch_caller_profile_t *caller_profile; - struct sangoma_pri *spri; - int span = 0, autospan = 0, autochan = 0; - char *num, *p; - int callno = 0; - struct channel_map *chanmap = NULL; + caller_profile = switch_caller_profile_clone(*new_session, outbound_profile); - caller_profile = switch_caller_profile_clone(*new_session, outbound_profile); - if (!bchan) { - num = caller_profile->destination_number; - if ((p = strchr(num, '/'))) { - *p++ = '\0'; + if (is_pri) { + num = caller_profile->destination_number; + if ((p = strchr(num, '/'))) { + *p++ = '\0'; - if (*num == 'a') { - span = 1; - autospan = 1; - } else if (*num = 'A') { - span = MAX_SPANS - 1; - autospan = -1; - } else { - if (num && *num > 47 && *num < 58) { - span = atoi(num); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invlid Syntax\n"); - switch_core_session_destroy(new_session); - return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; - } - } - num = p; - if ((p = strchr(num, '/'))) { - *p++ = '\0'; - if (*num == 'a') { - autochan = 1; - } else if (*num == 'A') { - autochan = -1; - } else if (num && *num > 47 && *num < 58) { - callno = atoi(num); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invlid Syntax\n"); - switch_core_session_destroy(new_session); - return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; - } - caller_profile->destination_number = p; + if (*num == 'a') { + span = 1; + autospan = 1; + } else if (*num = 'A') { + span = MAX_SPANS - 1; + autospan = -1; + } else { + if (num && *num > 47 && *num < 58) { + span = atoi(num); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invlid Syntax\n"); switch_core_session_destroy(new_session); return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; } } - } - - tech_pvt->caller_profile = caller_profile; - - if (bchan) { - int chan, span; - - if (sangoma_span_chan_fromif(bchan, &span, &chan)) { - if (!wp_open(tech_pvt, span, chan)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open fd for s%dc%d! [%s]\n", span, chan, strerror(errno)); + num = p; + if ((p = strchr(num, '/'))) { + *p++ = '\0'; + if (*num == 'a') { + autochan = 1; + } else if (*num == 'A') { + autochan = -1; + } else if (num && *num > 47 && *num < 58) { + callno = atoi(num); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invlid Syntax\n"); switch_core_session_destroy(new_session); return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; } - switch_set_flag_locked(tech_pvt, TFLAG_NOSIG); - snprintf(name, sizeof(name), "WanPipe/%s/nosig", bchan); - switch_channel_set_name(channel, name); - switch_channel_set_caller_profile(channel, caller_profile); + caller_profile->destination_number = p; } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid address\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invlid Syntax\n"); switch_core_session_destroy(new_session); - return SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL; - } - } else { - switch_mutex_lock(globals.channel_mutex); - callno = 0; - while (!callno) { - if (autospan > 0 && span == MAX_SPANS - 1) { - break; - } - - if (autospan < 0 && span == 0) { - break; - } - - if (SPANS[span] && (spri = &SPANS[span]->spri) && switch_test_flag(spri, SANGOMA_PRI_READY)) { - chanmap = spri->private_info; - - if (autochan > 0) { - for(callno = 1; callno < SANGOMA_MAX_CHAN_PER_SPAN; callno++) { - if ((SPANS[span]->bchans & (1 << callno)) && ! *chanmap->map[callno]) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Choosing channel s%dc%d\n", span, callno); - goto done; - } - } - callno = 0; - } else if (autochan < 0) { - for(callno = SANGOMA_MAX_CHAN_PER_SPAN; callno > 0; callno--) { - if ((SPANS[span]->bchans & (1 << callno)) && ! *chanmap->map[callno]) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Choosing channel s%dc%d\n", span, callno); - goto done; - } - } - callno = 0; - } - } - - if (autospan > 0) { - span++; - } else if (autospan < 0) { - span--; - } - } - done: - switch_mutex_unlock(globals.channel_mutex); - - if (!spri || callno == 0 || callno == (SANGOMA_MAX_CHAN_PER_SPAN)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No Free Channels!\n"); - switch_core_session_destroy(new_session); - return SWITCH_CAUSE_SWITCH_CONGESTION; - } - - tech_pvt->callno = callno; - - if (spri && (tech_pvt->call = pri_new_call(spri->pri))) { - struct pri_sr *sr; - - snprintf(name, sizeof(name), "WanPipe/s%dc%d/%s", spri->span, callno, caller_profile->destination_number); - switch_channel_set_name(channel, name); - switch_channel_set_caller_profile(channel, caller_profile); - sr = pri_sr_new(); - pri_sr_set_channel(sr, callno, 0, 0); - pri_sr_set_bearer(sr, 0, SPANS[span]->l1); - pri_sr_set_called(sr, caller_profile->destination_number, SPANS[span]->dp, 1); - pri_sr_set_caller(sr, - caller_profile->caller_id_number, - caller_profile->caller_id_name, - SPANS[span]->dp, - PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN); - pri_sr_set_redirecting(sr, - caller_profile->caller_id_number, - SPANS[span]->dp, - PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, - PRI_REDIR_UNCONDITIONAL); - - if (pri_setup(spri->pri, tech_pvt->call , sr)) { - switch_core_session_destroy(new_session); - pri_sr_free(sr); - return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; - } - - if (!wp_open(tech_pvt, spri->span, callno)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open fd!\n"); - switch_core_session_destroy(new_session); - pri_sr_free(sr); - return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; - } - pri_sr_free(sr); - switch_copy_string(chanmap->map[callno], - switch_core_session_get_uuid(*new_session), - sizeof(chanmap->map[callno])); - tech_pvt->spri = spri; + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; } } - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Doh! no caller profile\n"); - switch_core_session_destroy(new_session); - return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; } + tech_pvt->caller_profile = caller_profile; + + if (is_raw) { + int chan, span; + + if (sangoma_span_chan_fromif(bchan, &span, &chan)) { + if (!wp_open(tech_pvt, span, chan)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open fd for s%dc%d! [%s]\n", span, chan, strerror(errno)); + switch_core_session_destroy(new_session); + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + } + switch_set_flag_locked(tech_pvt, TFLAG_NOSIG); + snprintf(name, sizeof(name), "wanpipe/%s/nosig", bchan); + switch_channel_set_name(channel, name); + switch_channel_set_caller_profile(channel, caller_profile); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid address\n"); + switch_core_session_destroy(new_session); + return SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL; + } + } else if (is_pri) { + switch_mutex_lock(globals.channel_mutex); + callno = 0; + while (!callno) { + if (autospan > 0 && span == MAX_SPANS - 1) { + break; + } + + if (autospan < 0 && span == 0) { + break; + } + + if (SPANS[span] && (spri = &SPANS[span]->spri) && switch_test_flag(spri, SANGOMA_PRI_READY)) { + chanmap = spri->private_info; + + if (autochan > 0) { + for(callno = 1; callno < SANGOMA_MAX_CHAN_PER_SPAN; callno++) { + if ((SPANS[span]->bchans & (1 << callno)) && ! *chanmap->map[callno]) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Choosing channel s%dc%d\n", span, callno); + goto done; + } + } + callno = 0; + } else if (autochan < 0) { + for(callno = SANGOMA_MAX_CHAN_PER_SPAN; callno > 0; callno--) { + if ((SPANS[span]->bchans & (1 << callno)) && ! *chanmap->map[callno]) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Choosing channel s%dc%d\n", span, callno); + goto done; + } + } + callno = 0; + } + } + + if (autospan > 0) { + span++; + } else if (autospan < 0) { + span--; + } + } + done: + switch_mutex_unlock(globals.channel_mutex); + + if (!spri || callno == 0 || callno == (SANGOMA_MAX_CHAN_PER_SPAN)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No Free Channels!\n"); + switch_core_session_destroy(new_session); + return SWITCH_CAUSE_SWITCH_CONGESTION; + } + + tech_pvt->callno = callno; + + if (spri && (tech_pvt->call = pri_new_call(spri->pri))) { + struct pri_sr *sr; + + snprintf(name, sizeof(name), "wanpipe/pri/s%dc%d/%s", spri->span, callno, caller_profile->destination_number); + switch_channel_set_name(channel, name); + switch_channel_set_caller_profile(channel, caller_profile); + sr = pri_sr_new(); + pri_sr_set_channel(sr, callno, 0, 0); + pri_sr_set_bearer(sr, 0, SPANS[span]->l1); + pri_sr_set_called(sr, caller_profile->destination_number, SPANS[span]->dp, 1); + pri_sr_set_caller(sr, + caller_profile->caller_id_number, + caller_profile->caller_id_name, + SPANS[span]->dp, + PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN); + pri_sr_set_redirecting(sr, + caller_profile->caller_id_number, + SPANS[span]->dp, + PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, + PRI_REDIR_UNCONDITIONAL); + + if (pri_setup(spri->pri, tech_pvt->call , sr)) { + switch_core_session_destroy(new_session); + pri_sr_free(sr); + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + } + + if (!wp_open(tech_pvt, spri->span, callno)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open fd!\n"); + switch_core_session_destroy(new_session); + pri_sr_free(sr); + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + } + pri_sr_free(sr); + switch_copy_string(chanmap->map[callno], + switch_core_session_get_uuid(*new_session), + sizeof(chanmap->map[callno])); + tech_pvt->spri = spri; + } + } else if (is_boost) { + char *p; + + if ((p = strchr(caller_profile->destination_number, '/'))) { + char *grp = caller_profile->destination_number; + *p = '\0'; + caller_profile->destination_number = p+1; + tech_pvt->boost_trunk_group = atoi(grp+1) - 1; + if (tech_pvt->boost_trunk_group < 0) { + tech_pvt->boost_trunk_group = 0; + } + } + sprintf(name, "wanpipe/ss7boost/%s", caller_profile->destination_number); + switch_channel_set_name(channel, name); + tech_pvt->ss7boost_handle = globals.ss7boost_handle; + + if (session && switch_core_session_compare(session, *new_session)) { + private_object_t *otech_pvt = switch_core_session_get_private(session); + tech_pvt->boost_pres = otech_pvt->boost_pres; + } + + } + + + + tech_pvt->caller_profile = caller_profile; switch_channel_set_flag(channel, CF_OUTBOUND); switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND); switch_channel_set_state(channel, CS_INIT); @@ -1069,9 +1217,9 @@ static int on_hangup(struct sangoma_pri *spri, sangoma_pri_event_t event_type, p } tech_pvt->cause = pevent->hangup.cause; - + switch_set_flag_locked(tech_pvt, TFLAG_BYE); switch_channel_hangup(channel, tech_pvt->cause); - + switch_mutex_lock(globals.channel_mutex); *chanmap->map[pevent->hangup.channel] = '\0'; switch_mutex_unlock(globals.channel_mutex); @@ -1207,9 +1355,9 @@ static int on_ring(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session)); channel = switch_core_session_get_channel(session); switch_core_session_set_private(session, tech_pvt); - sprintf(name, "s%dc%d", spri->span, pevent->ring.channel); + sprintf(name, "wanpipe/pri/s%dc%d", spri->span, pevent->ring.channel); switch_channel_set_name(channel, name); - + tech_pvt->session = session; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Hey where is my memory pool?\n"); switch_core_session_destroy(&session); @@ -1379,11 +1527,502 @@ static void pri_thread_launch(struct sangoma_pri *spri) } + +static int isup_exec_command(ss7boost_handle_t *ss7boost_handle, int span, int chan, int id, int cmd, int cause) +{ + ss7boost_client_event_t oevent; + int r = 0; + + switch_mutex_lock(ss7boost_handle->mutex); + ss7boost_client_event_init(&oevent, cmd, chan, span); + oevent.release_cause = cause; + + if (id >= 0) { + oevent.call_setup_id = id; + } + + if (ss7boost_client_connection_write(&ss7boost_handle->mcon, &oevent) <= 0){ + r = -1; + } + + switch_mutex_unlock(ss7boost_handle->mutex); + + return r; +} + +static int waitfor_socket(int fd, int timeout, int flags) +{ + struct pollfd pfds[1]; + int res; + + memset(&pfds[0], 0, sizeof(pfds[0])); + pfds[0].fd = fd; + pfds[0].events = flags; + res = poll(pfds, 1, timeout); + + if (res > 0) { + if(pfds[0].revents & POLLIN) { + res = 1; + } else if ((pfds[0].revents & POLLERR)) { + res = -1; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,"System Error: Poll Event Error no event!\n"); + res = -1; + } + } + + return res; +} + + +static void validate_number(unsigned char *s) +{ + unsigned char *p; + for (p = s; *p; p++) { + if (*p < 48 || *p > 57) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Encountered a non-numeric character [%c]!\n", *p); + *p = '\0'; + break; + } + } +} + + +static void handle_call_stop(ss7boost_handle_t *ss7boost_handle, ss7boost_client_event_t *event) +{ + char *uuid = ss7boost_handle->span_chanmap[event->span].map[event->chan]; + + if (*uuid) { + switch_core_session_t *session; + + if ((session = switch_core_session_locate(uuid))) { + private_object_t *tech_pvt; + switch_channel_t *channel; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + switch_set_flag_locked(tech_pvt, TFLAG_BYE); + switch_channel_hangup(channel, event->release_cause); + switch_core_session_rwunlock(session); + } + *uuid = '\0'; + + } + + isup_exec_command(ss7boost_handle, + event->span, + event->chan, + -1, + SIGBOOST_EVENT_CALL_STOPPED_ACK, + 0); + + +} + +static void handle_call_start(ss7boost_handle_t *ss7boost_handle, ss7boost_client_event_t *event) +{ + switch_core_session_t *session = NULL; + switch_channel_t *channel = NULL; + char name[128]; + + if (*ss7boost_handle->span_chanmap[event->span].map[event->chan]) { + isup_exec_command(ss7boost_handle, + event->span, + event->chan, + -1, + SIGBOOST_EVENT_CALL_START_NACK, + SIGBOOST_RELEASE_CAUSE_BUSY); + return; + } + + + if ((session = switch_core_session_request(&wanpipe_endpoint_interface, NULL))) { + private_object_t *tech_pvt; + + switch_core_session_add_stream(session, NULL); + if ((tech_pvt = (private_object_t *) switch_core_session_alloc(session, sizeof(private_object_t)))) { + memset(tech_pvt, 0, sizeof(*tech_pvt)); + switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session)); + channel = switch_core_session_get_channel(session); + switch_core_session_set_private(session, tech_pvt); + sprintf(name, "wanpipe/ss7boost/s%dc%d", event->span+1, event->chan+1); + switch_channel_set_name(channel, name); + tech_pvt->session = session; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Hey where is my memory pool?\n"); + goto fail; + } + + + if ((tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session), + NULL, + globals.dialplan, + "FreeSWITCH(boost)", + event->calling_number_digits, +#ifdef WIN32 + NULL, +#else + event->calling_number_digits, +#endif + NULL, + NULL, + NULL, + (char *)modname, + NULL, + event->called_number_digits))) { + switch_channel_set_caller_profile(channel, tech_pvt->caller_profile); + } + + switch_set_flag_locked(tech_pvt, TFLAG_INBOUND); + + tech_pvt->cause = -1; + + tech_pvt->ss7boost_handle = ss7boost_handle; + tech_pvt->boost_span_number = event->span; + tech_pvt->boost_chan_number = event->chan; + tech_pvt->boost_pres = event->calling_number_presentation; + + if (!wp_open(tech_pvt, event->span+1, event->chan+1)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open channel %d:%s\n", event->span+1, event->chan+1); + goto fail; + } + + switch_copy_string(ss7boost_handle->span_chanmap[event->span].map[event->chan], switch_core_session_get_uuid(session), + sizeof(ss7boost_handle->span_chanmap[event->span].map[event->chan])); + + switch_channel_set_state(channel, CS_INIT); + isup_exec_command(ss7boost_handle, + event->span, + event->chan, + -1, + SIGBOOST_EVENT_CALL_START_ACK, + 0); + switch_core_session_thread_launch(session); + return; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Create new Inbound Channel!\n"); + } + + + fail: + if (session) { + switch_core_session_destroy(&session); + } + + isup_exec_command(ss7boost_handle, + event->span, + event->chan, + -1, + SIGBOOST_EVENT_CALL_STOPPED, + SIGBOOST_RELEASE_CAUSE_BUSY); + +} + + +static void handle_heartbeat(ss7boost_handle_t *ss7boost_handle, ss7boost_client_event_t *event) +{ + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Heartbeat!\n"); + + isup_exec_command(ss7boost_handle, + event->span, + event->chan, + -1, + SIGBOOST_EVENT_HEARTBEAT, + 0); +} + + +static void handle_call_start_ack(ss7boost_handle_t *ss7boost_handle, ss7boost_client_event_t *event) +{ + char *uuid = ss7boost_handle->setup_array[event->call_setup_id]; + + if (*uuid) { + switch_core_session_t *session; + + if ((session = switch_core_session_locate(uuid))) { + private_object_t *tech_pvt; + switch_channel_t *channel; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + tech_pvt->ss7boost_handle = ss7boost_handle; + tech_pvt->boost_span_number = event->span; + tech_pvt->boost_chan_number = event->chan; + + switch_copy_string(ss7boost_handle->span_chanmap[event->span].map[event->chan], switch_core_session_get_uuid(session), + sizeof(ss7boost_handle->span_chanmap[event->span].map[event->chan])); + + + + if (!tech_pvt->wpsock) { + if (!wp_open(tech_pvt, tech_pvt->boost_span_number+1, tech_pvt->boost_chan_number+1)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open fd for s%dc%d! [%s]\n", + tech_pvt->boost_span_number+1, tech_pvt->boost_chan_number+1, strerror(errno)); + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + return; + } + if (wanpipe_codec_init(tech_pvt) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + return; + } + } + + switch_channel_mark_pre_answered(channel); + + switch_core_session_rwunlock(session); + } + *uuid = '\0'; + } +} + +static void handle_call_start_nack_ack(ss7boost_handle_t *ss7boost_handle, ss7boost_client_event_t *event) +{ + // WTF IS THIS! ? +} + +static void handle_call_answer(ss7boost_handle_t *ss7boost_handle, ss7boost_client_event_t *event) +{ + char *uuid = ss7boost_handle->span_chanmap[event->span].map[event->chan]; + + if (*uuid) { + switch_core_session_t *session; + + if ((session = switch_core_session_locate(uuid))) { + private_object_t *tech_pvt; + switch_channel_t *channel; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + if (!tech_pvt->wpsock) { + if (!wp_open(tech_pvt, tech_pvt->boost_span_number+1, tech_pvt->boost_chan_number+1)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open fd for s%dc%d! [%s]\n", + tech_pvt->boost_span_number+1, tech_pvt->boost_chan_number+1, strerror(errno)); + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + return; + } + if (wanpipe_codec_init(tech_pvt) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + return; + } + } + + switch_channel_mark_answered(channel); + switch_core_session_rwunlock(session); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Session %s missing!\n", uuid); + *uuid = '\0'; + } + + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No UUID?\n"); + } +} + +static void handle_call_stop_ack(ss7boost_handle_t *ss7boost_handle, ss7boost_client_event_t *event) +{ + // TODO anything here? +} + + +static void handle_call_start_nack(ss7boost_handle_t *ss7boost_handle, ss7boost_client_event_t *event) +{ + char *uuid = ss7boost_handle->setup_array[event->call_setup_id]; + + if (*uuid) { + switch_core_session_t *session; + + if ((session = switch_core_session_locate(uuid))) { + private_object_t *tech_pvt; + switch_channel_t *channel; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + tech_pvt->ss7boost_handle = ss7boost_handle; + tech_pvt->boost_span_number = event->span; + tech_pvt->boost_chan_number = event->chan; + + switch_channel_hangup(channel, event->release_cause); + + isup_exec_command(ss7boost_handle, + event->span, + event->chan, + event->call_setup_id, + SIGBOOST_EVENT_CALL_START_NACK_ACK, + 0); + + switch_core_session_rwunlock(session); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Session %s missing!\n", uuid); + } + *uuid = '\0'; + } +} + +static int parse_ss7_event(ss7boost_handle_t *ss7boost_handle, ss7boost_client_event_t *event) +{ + int ret = 0; + + switch_mutex_lock(ss7boost_handle->mutex); + + validate_number((unsigned char*)event->called_number_digits); + validate_number((unsigned char*)event->calling_number_digits); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\nRX EVENT\n" + "===================================\n" + " rType: %s (%0x HEX)\n" + " rSpan: [%d]\n" + " rChan: [%d]\n" + " rCalledNum: %s\n" + " rCallingNum: %s\n" + " rCause: %s\n" + " rInterface : [w%dg%d]\n" + " rEvent ID : [%d]\n" + " rSetup ID: [%d]\n" + " rSeq: [%d]\n" + "===================================\n" + "\n", + ss7boost_client_event_id_name(event->event_id), + event->event_id, + event->span+1, + event->chan+1, + (event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"), + (event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A"), + switch_channel_cause2str(event->release_cause), + event->span+1, + event->chan+1, + event->event_id, + event->call_setup_id, + event->seqno + ); + + + switch(event->event_id) { + + case SIGBOOST_EVENT_CALL_START: + handle_call_start(ss7boost_handle, event); + break; + case SIGBOOST_EVENT_CALL_STOPPED: + handle_call_stop(ss7boost_handle, event); + break; + case SIGBOOST_EVENT_CALL_START_ACK: + handle_call_start_ack(ss7boost_handle, event); + break; + case SIGBOOST_EVENT_CALL_START_NACK: + handle_call_start_nack(ss7boost_handle, event); + break; + case SIGBOOST_EVENT_CALL_ANSWERED: + handle_call_answer(ss7boost_handle, event); + break; + case SIGBOOST_EVENT_HEARTBEAT: + handle_heartbeat(ss7boost_handle, event); + break; + case SIGBOOST_EVENT_CALL_START_NACK_ACK: + handle_call_start_nack_ack(ss7boost_handle, event); + break; + case SIGBOOST_EVENT_CALL_STOPPED_ACK: + handle_call_stop_ack(ss7boost_handle, event); + break; + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Warning no handler implemented for [%s]\n", + ss7boost_client_event_id_name(event->event_id)); + break; + } + switch_mutex_unlock(ss7boost_handle->mutex); + return ret; +} + +static void *SWITCH_THREAD_FUNC boost_thread_run(switch_thread_t *thread, void *obj) +{ + ss7boost_handle_t *ss7boost_handle = (ss7boost_handle_t *) obj; + ss7boost_client_event_t *event; + int ss = 0; + + if (ss7boost_client_connection_open(&ss7boost_handle->mcon, + ss7boost_handle->local_ip, + ss7boost_handle->local_port, + ss7boost_handle->remote_ip, + ss7boost_handle->remote_port, + module_pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FATAL ERROR CREATING CLIENT CONNECTION\n"); + return NULL; + } + + isup_exec_command(ss7boost_handle, + 0, + 0, + -1, + SIGBOOST_EVENT_SYSTEM_RESTART, + 0); + + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Monitor Thread Started\n"); + + switch_mutex_lock(globals.hash_mutex); + globals.configured_boost_spans++; + switch_mutex_unlock(globals.hash_mutex); + + globals.ss7boost_handle = ss7boost_handle; + + for(;;) { + if (ss7boost_client_connection_read(&ss7boost_handle->mcon, &event) == SWITCH_STATUS_SUCCESS) { + struct timeval current; + struct timeval difftime; + gettimeofday(¤t,NULL); + timersub (¤t, &event->tv, &difftime); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Socket Event [%s] T=%d:%d\n", + ss7boost_client_event_id_name(event->event_id), + difftime.tv_sec, difftime.tv_usec); + + parse_ss7_event(ss7boost_handle, event); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: Reading from Boost Socket! %s\n", strerror(errno)); + break; + } + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Close udp socket [%d]\n", ss7boost_handle->mcon.socket); + ss7boost_client_connection_close(&ss7boost_handle->mcon); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Monitor Thread Ended\n"); + + + return NULL; +} + +static void launch_ss7boost_handle(ss7boost_handle_t *ss7boost_handle) +{ + switch_thread_t *thread; + switch_threadattr_t *thd_attr = NULL; + + switch_threadattr_create(&thd_attr, module_pool); + switch_threadattr_detach_set(thd_attr, 1); + switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); + switch_thread_create(&thread, thd_attr, boost_thread_run, ss7boost_handle, module_pool); +} + + + static switch_status_t config_wanpipe(int reload) { char *cf = "wanpipe.conf"; int current_span = 0, min_span = 0, max_span = 0; - switch_xml_t cfg, xml, settings, param, span; + switch_xml_t cfg, xml, settings, param, pri_spans, ss7boost_handles, span; globals.samples_per_frame = DEFAULT_SAMPLES_PER_FRAME; globals.dtmf_on = 150; @@ -1410,14 +2049,55 @@ static switch_status_t config_wanpipe(int reload) globals.dtmf_on = atoi(val); } else if (!strcmp(var, "dtmf-off")) { globals.dtmf_off = atoi(val); + } else if (!strcmp(var, "dialplan")) { + set_global_dialplan(val); } else if (!strcmp(var, "supress-dtmf-tone")) { globals.supress_dtmf_tone = switch_true(val); } } } - - for (span = switch_xml_child(cfg, "span"); span; span = span->next) { + ss7boost_handles = switch_xml_child(cfg, "ss7boost_handles"); + for (span = switch_xml_child(ss7boost_handles, "handle"); span; span = span->next) { + char *local_ip = NULL, *remote_ip = NULL; + int local_port = 0, remote_port = 0; + ss7boost_handle_t *ss7boost_handle; + + for (param = switch_xml_child(span, "param"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + + if (!strcasecmp(var, "local-ip")) { + local_ip = val; + } else if (!strcasecmp(var, "local-port")) { + local_port = atoi(val); + } else if (!strcasecmp(var, "remote-ip")) { + remote_ip = val; + } else if (!strcasecmp(var, "remote-port")) { + remote_port = atoi(val); + } + } + + + if (!(local_ip && local_port && remote_ip && remote_port)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Config, skipping...\n"); + continue; + } + + assert(ss7boost_handle = malloc(sizeof(*ss7boost_handle))); + memset(ss7boost_handle, 0, sizeof(*ss7boost_handle)); + ss7boost_handle->local_ip = switch_core_strdup(module_pool, local_ip); + ss7boost_handle->local_port = local_port; + ss7boost_handle->remote_ip = switch_core_strdup(module_pool, remote_ip); + ss7boost_handle->remote_port = remote_port; + + switch_mutex_init(&ss7boost_handle->mutex, SWITCH_MUTEX_NESTED, module_pool); + launch_ss7boost_handle(ss7boost_handle); + break; + } + + pri_spans = switch_xml_child(cfg, "pri_spans"); + for (span = switch_xml_child(pri_spans, "span"); span; span = span->next) { char *id = (char *) switch_xml_attr(span, "id"); int32_t i = 0; @@ -1498,8 +2178,6 @@ static switch_status_t config_wanpipe(int reload) SPANS[current_span]->dp = str2dp(val); } else if (!strcmp(var, "l1")) { SPANS[current_span]->l1 = str2l1(val); - } else if (!strcmp(var, "dialplan")) { - set_global_dialplan(val); } } } @@ -1507,7 +2185,7 @@ static switch_status_t config_wanpipe(int reload) switch_xml_free(xml); if (!globals.dialplan) { - set_global_dialplan("default"); + set_global_dialplan("XML"); } @@ -1529,7 +2207,9 @@ static switch_status_t config_wanpipe(int reload) } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Launch span %d\n", current_span); pri_thread_launch(&SPANS[current_span]->spri); + switch_mutex_lock(globals.hash_mutex); globals.configured_spans++; + switch_mutex_unlock(globals.hash_mutex); } } diff --git a/src/mod/endpoints/mod_wanpipe/sigboost.h b/src/mod/endpoints/mod_wanpipe/sigboost.h new file mode 100644 index 0000000000..373671afa8 --- /dev/null +++ b/src/mod/endpoints/mod_wanpipe/sigboost.h @@ -0,0 +1,82 @@ +/**************************************************************************** + * sigboost.h $Revision: 1.1 $ + * + * Definitions for the sigboost interface. + * + * WARNING WARNING WARNING + * + * This file is used by sangoma_mgd and perhaps other programs. Any changes + * to this file must be coordinated with other user programs, + * + * Copyright (C) 2005 Xygnada Technology, Inc. + * +****************************************************************************/ +#ifndef _SIGBOOST_H_ +#define _SIGBOOST_H_ + +#include + +enum e_sigboost_event_id_values +{ + SIGBOOST_EVENT_CALL_START = 0x80, /*128*/ + SIGBOOST_EVENT_CALL_START_ACK = 0x81, /*129*/ + SIGBOOST_EVENT_CALL_START_NACK = 0x82, /*130*/ + SIGBOOST_EVENT_CALL_START_NACK_ACK = 0x83, /*131*/ + SIGBOOST_EVENT_CALL_ANSWERED = 0x84, /*132*/ + SIGBOOST_EVENT_CALL_STOPPED = 0x85, /*133*/ + SIGBOOST_EVENT_CALL_STOPPED_ACK = 0x86, /*134*/ + SIGBOOST_EVENT_SYSTEM_RESTART = 0x87, /*135*/ + SIGBOOST_EVENT_HEARTBEAT = 0x88, /*136*/ +}; + +enum e_sigboost_release_cause_values +{ + SIGBOOST_RELEASE_CAUSE_UNDEFINED = 0x00, + SIGBOOST_RELEASE_CAUSE_NORMAL = 0x90, + SIGBOOST_RELEASE_CAUSE_BUSY = 0x91, + SIGBOOST_RELEASE_CAUSE_CALLED_NOT_EXIST = 0x92, + SIGBOOST_RELEASE_CAUSE_CIRCUIT_RESET = 0x93, + SIGBOOST_RELEASE_CAUSE_NOANSWER = 0x94 +}; + +enum e_sigboost_call_setup_ack_nack_cause_values +{ + SIGBOOST_CALL_SETUP_CIRCUIT_RESET = 0x10, + SIGBOOST_CALL_SETUP_NACK_CKT_START_TIMEOUT = 0x11, + SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY = 0x12, + SIGBOOST_CALL_SETUP_NACK_CALLED_NUM_TOO_BIG = 0x13, + SIGBOOST_CALL_SETUP_NACK_CALLING_NUM_TOO_BIG = 0x14, + SIGBOOST_CALL_SETUP_NACK_CALLED_NUM_TOO_SMALL = 0x15, + SIGBOOST_CALL_SETUP_NACK_CALLING_NUM_TOO_SMALL = 0x16, +}; + +#define MAX_DIALED_DIGITS 31 + +/* Next two defines are used to create the range of values for call_setup_id + * in the t_sigboost structure. + * 0..((CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN) - 1) */ +#define CORE_MAX_SPANS 200 +#define CORE_MAX_CHAN_PER_SPAN 30 +#define MAX_PENDING_CALLS CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN +/* 0..(MAX_PENDING_CALLS-1) is range of call_setup_id below */ + +#pragma pack(1) +typedef struct +{ + uint32_t event_id; + uint32_t seqno; + uint32_t call_setup_id; + uint32_t trunk_group; + uint32_t span; + uint32_t chan; + uint32_t called_number_digits_count; + int8_t called_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */ + uint32_t calling_number_digits_count; /* it's an array */ + int8_t calling_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */ + uint32_t release_cause; + struct timeval tv; + uint32_t calling_number_presentation; +} t_sigboost; +#pragma pack() + +#endif diff --git a/src/mod/endpoints/mod_wanpipe/ss7boost_client.c b/src/mod/endpoints/mod_wanpipe/ss7boost_client.c new file mode 100644 index 0000000000..7fd56fb736 --- /dev/null +++ b/src/mod/endpoints/mod_wanpipe/ss7boost_client.c @@ -0,0 +1,263 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005/2006, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * Nenad Corbic + * + * + * ss7boost_client.c Client for the SS7Boost Protocol + * + */ +#include +#include + + +extern unsigned int txseq; +extern unsigned int rxseq; + +struct ss7boost_client_map { + uint32_t event_id; + char *name; +}; + +static struct ss7boost_client_map ss7boost_client_table[] = { + {SIGBOOST_EVENT_CALL_START, "CALL_START"}, + {SIGBOOST_EVENT_CALL_START_ACK, "CALL_START_ACK"}, + {SIGBOOST_EVENT_CALL_START_NACK, "CALL_START_NACK"}, + {SIGBOOST_EVENT_CALL_START_NACK_ACK, "CALL_START_NACK_ACK"}, + {SIGBOOST_EVENT_CALL_ANSWERED, "CALL_ANSWERED"}, + {SIGBOOST_EVENT_CALL_STOPPED, "CALL_STOPPED"}, + {SIGBOOST_EVENT_CALL_STOPPED_ACK, "CALL_STOPPED_ACK"}, + {SIGBOOST_EVENT_SYSTEM_RESTART, "SYSTEM_RESTART"}, + {SIGBOOST_EVENT_HEARTBEAT, "HEARTBEAT"}, +}; + + + +static switch_status_t create_udp_socket(ss7boost_client_connection_t *mcon, char *local_ip, int local_port, char *ip, int port) +{ + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "connect %s:%d->%s:%d\n", local_ip, local_port, ip, port); + + if (switch_sockaddr_info_get(&mcon->local_addr, local_ip, SWITCH_UNSPEC, local_port, 0, mcon->pool) != SWITCH_STATUS_SUCCESS) { + goto fail; + } + + if (switch_sockaddr_info_get(&mcon->remote_addr, ip, SWITCH_UNSPEC, port, 0, mcon->pool) != SWITCH_STATUS_SUCCESS) { + goto fail; + } + + if (switch_socket_create(&mcon->socket, AF_INET, SOCK_DGRAM, 0, mcon->pool) == SWITCH_STATUS_SUCCESS) { + if (switch_socket_bind(mcon->socket, mcon->local_addr) != SWITCH_STATUS_SUCCESS) { + goto fail; + } + } else { + goto fail; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Created boost connection %s:%d->%s:%d\n", local_ip, local_port, ip, port); + return SWITCH_STATUS_SUCCESS; + + fail: + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failure creating boost connection %s:%d->%s:%d\n", local_ip, local_port, ip, port); + return SWITCH_STATUS_FALSE; +} + + + +SWITCH_DECLARE(switch_status_t) ss7boost_client_connection_close(ss7boost_client_connection_t *mcon) +{ + switch_socket_close(mcon->socket); + mcon->socket = NULL; + memset(mcon, 0, sizeof(*mcon)); + + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_DECLARE(switch_status_t) ss7boost_client_connection_open(ss7boost_client_connection_t *mcon, + char *local_ip, + int local_port, + char *ip, + int port, + switch_memory_pool_t *pool) +{ + memset(mcon, 0, sizeof(*mcon)); + mcon->pool = pool; + + if (create_udp_socket(mcon, local_ip, local_port, ip, port) == SWITCH_STATUS_SUCCESS) { + switch_mutex_init(&mcon->mutex, SWITCH_MUTEX_NESTED, mcon->pool); + return SWITCH_STATUS_SUCCESS; + } + + memset(mcon, 0, sizeof(*mcon)); + return SWITCH_STATUS_FALSE; +} + +SWITCH_DECLARE(switch_status_t) ss7boost_client_connection_read(ss7boost_client_connection_t *mcon, ss7boost_client_event_t **event) +{ + unsigned int fromlen = sizeof(struct sockaddr_in); + switch_size_t bytes = 0; + + bytes = sizeof(mcon->event); + + if (switch_socket_recvfrom(mcon->local_addr, mcon->socket, 0, (void *)&mcon->event, &bytes) != SWITCH_STATUS_SUCCESS) { + bytes = 0; + } + + if (bytes == sizeof(mcon->event) || + bytes == (sizeof(mcon->event)-sizeof(uint32_t))) { + if (rxseq != mcon->event.seqno) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, + "------------------------------------------\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, + "Critical Error: Invalid Sequence Number Expect=%i Rx=%i\n", + rxseq,mcon->event.seqno); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, + "------------------------------------------\n"); + } + rxseq++; + + *event = &mcon->event; + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_FALSE; +} + +SWITCH_DECLARE(switch_status_t) ss7boost_client_connection_write(ss7boost_client_connection_t *mcon, ss7boost_client_event_t *event) +{ + int err; + switch_size_t len; + + if (!event) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Critical Error: No Event Device\n"); + return -EINVAL; + } + + if (event->span < 0 || event->chan < 0 || event->span > 7 || event->chan > 30) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, + "------------------------------------------\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, + "Critical Error: Invalid Span=%i Chan=%i\n", + event->span,event->chan); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, + "------------------------------------------\n"); + } + +#ifdef WIN32 + //TODO set the tv with win func +#else + gettimeofday(&event->tv,NULL); +#endif + + switch_mutex_lock(mcon->mutex); + event->seqno=txseq++; + len = sizeof(*event); + if (switch_socket_sendto(mcon->socket, mcon->remote_addr, 0, (void *) event, &len) != SWITCH_STATUS_SUCCESS) { + err = -1; + } + switch_mutex_unlock(mcon->mutex); + + if (len != sizeof(ss7boost_client_event_t)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Write Error: [%d][%d][%s]\n", mcon->socket, errno, strerror(errno)); + err = -1; + } + + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\nTX EVENT\n" + "===================================\n" + " tType: %s (%0x HEX)\n" + " tSpan: [%d]\n" + " tChan: [%d]\n" + " tCalledNum: %s\n" + " tCallingNum: %s\n" + " tCause: %d\n" + " tInterface: [w%dg%d]\n" + " tEvent ID: [%d]\n" + " tSetup ID: [%d]\n" + " tSeq: [%d]\n" + "===================================\n" + "\n", + ss7boost_client_event_id_name(event->event_id), + event->event_id, + event->span+1, + event->chan+1, + (event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"), + (event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A"), + event->release_cause, + event->span+1, + event->chan+1, + event->event_id, + event->call_setup_id, + event->seqno + ); + + + return err ? SWITCH_STATUS_FALSE : SWITCH_STATUS_SUCCESS; +} + +SWITCH_DECLARE(void) ss7boost_client_call_init(ss7boost_client_event_t *event, char *calling, char *called, int setup_id) +{ + memset(event, 0, sizeof(ss7boost_client_event_t)); + event->event_id = SIGBOOST_EVENT_CALL_START; + + if (calling) { + strncpy((char*)event->calling_number_digits, calling, sizeof(event->calling_number_digits)-1); + event->calling_number_digits_count = strlen(calling); + } + + if (called) { + strncpy((char*)event->called_number_digits, called, sizeof(event->called_number_digits)-1); + event->called_number_digits_count = strlen(called); + } + + event->call_setup_id = setup_id; + +} + +SWITCH_DECLARE(void) ss7boost_client_event_init(ss7boost_client_event_t *event, ss7boost_client_event_id_t event_id, int chan, int span) +{ + memset(event, 0, sizeof(ss7boost_client_event_t)); + event->event_id = event_id; + event->chan = chan; + event->span = span; +} + +SWITCH_DECLARE(char *) ss7boost_client_event_id_name(uint32_t event_id) +{ + int x; + char *ret = NULL; + + for (x = 0 ; x < sizeof(ss7boost_client_table)/sizeof(struct ss7boost_client_map); x++) { + if (ss7boost_client_table[x].event_id == event_id) { + ret = ss7boost_client_table[x].name; + break; + } + } + + return ret; +} diff --git a/src/mod/endpoints/mod_wanpipe/ss7boost_client.h b/src/mod/endpoints/mod_wanpipe/ss7boost_client.h new file mode 100644 index 0000000000..5f37886eab --- /dev/null +++ b/src/mod/endpoints/mod_wanpipe/ss7boost_client.h @@ -0,0 +1,107 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005/2006, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * Nenad Corbic + * + * + * ss7boost_client.h Client for the SS7Boost Protocol + * + */ +#ifndef _SS7BOOST_CLIENT_H +#define _SS7BOOST_CLIENT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +#define ss7boost_client_test_flag(p,flag) ({ \ + ((p)->flags & (flag)); \ + }) + +#define ss7boost_client_set_flag(p,flag) do { \ + ((p)->flags |= (flag)); \ + } while (0) + +#define ss7boost_client_clear_flag(p,flag) do { \ + ((p)->flags &= ~(flag)); \ + } while (0) + +#define ss7boost_client_copy_flags(dest,src,flagz) do { \ + (dest)->flags &= ~(flagz); \ + (dest)->flags |= ((src)->flags & (flagz)); \ + } while (0) + +typedef t_sigboost ss7boost_client_event_t; +typedef uint32_t ss7boost_client_event_id_t; + +struct ss7boost_client_connection { + switch_socket_t *socket; + switch_sockaddr_t *local_addr; + switch_sockaddr_t *remote_addr; + ss7boost_client_event_t event; + unsigned int flags; + switch_mutex_t *mutex; + switch_memory_pool_t * pool; +}; + +typedef enum { + MSU_FLAG_EVENT = (1 << 0) +} ss7boost_client_flag_t; + +typedef struct ss7boost_client_connection ss7boost_client_connection_t; + +SWITCH_DECLARE(switch_status_t) ss7boost_client_connection_close(ss7boost_client_connection_t *mcon); +SWITCH_DECLARE(switch_status_t) ss7boost_client_connection_open(ss7boost_client_connection_t *mcon, + char *local_ip, + int local_port, + char *ip, + int port, + switch_memory_pool_t *pool); +SWITCH_DECLARE(switch_status_t) ss7boost_client_connection_read(ss7boost_client_connection_t *mcon, ss7boost_client_event_t **event); +SWITCH_DECLARE(switch_status_t) ss7boost_client_connection_write(ss7boost_client_connection_t *mcon, ss7boost_client_event_t *event); +SWITCH_DECLARE(void) ss7boost_client_event_init(ss7boost_client_event_t *event, ss7boost_client_event_id_t event_id, int chan, int span); +SWITCH_DECLARE(void) ss7boost_client_call_init(ss7boost_client_event_t *event, char *calling, char *called, int setup_id); +SWITCH_DECLARE(char *) ss7boost_client_event_id_name(uint32_t event_id); + +#endif + +