]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Add ss7boost signalling to mod_wanpipe
authorAnthony Minessale <anthony.minessale@gmail.com>
Fri, 2 Mar 2007 19:12:26 +0000 (19:12 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Fri, 2 Mar 2007 19:12:26 +0000 (19:12 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4430 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/mod/endpoints/mod_wanpipe/Makefile
src/mod/endpoints/mod_wanpipe/mod_wanpipe.c
src/mod/endpoints/mod_wanpipe/sigboost.h [new file with mode: 0644]
src/mod/endpoints/mod_wanpipe/ss7boost_client.c [new file with mode: 0644]
src/mod/endpoints/mod_wanpipe/ss7boost_client.h [new file with mode: 0644]

index 414a14971e30e3df79050968cdf9ac7bc7de0cd0..9ce1df8c808917bf73419b33ade41a3443814ae2 100644 (file)
@@ -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 *~
index d5fb140551431094be59fff4463921c954a0f2b7..868d55b58fa9eb2b5cc2240f7b53b666814cf4e7 100644 (file)
@@ -34,6 +34,7 @@
 #include <libsangoma.h>
 #include <sangoma_pri.h>
 #include <libteletone.h>
+#include <ss7boost_client.h>
 
 #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,27 +345,20 @@ 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);
-       assert(channel != NULL);
-
-       tech_pvt = switch_core_session_get_private(session);
-       assert(tech_pvt != NULL);
 
-       tech_pvt->read_frame.data = tech_pvt->databuf;
+       channel = switch_core_session_get_channel(tech_pvt->session);
+       assert(channel != NULL);
 
        err = sangoma_tdm_set_codec(tech_pvt->wpsock->fd, &tdm_api, WP_SLINEAR);
        
@@ -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");
+               }
+       } 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");
                }
-               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;
+       }
+       
+       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);
-                       if (!bchan) {
-                               num = caller_profile->destination_number;
+               caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
+
+               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') {
-                                               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;
+                                               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;
+                               } 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;
+               tech_pvt->caller_profile = caller_profile;
 
-                       if (bchan) {
-                               int chan, span;
+               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");
+                       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_REQUESTED_CHAN_UNAVAIL;
+                                       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_mutex_lock(globals.channel_mutex);
-                               callno = 0;
-                               while (!callno) {
-                                       if (autospan > 0 && span == MAX_SPANS - 1) {
-                                               break;
-                                       }
+                               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 (autospan < 0 && span == 0) {
+                                       break;
+                               }
 
-                                       if (SPANS[span] && (spri = &SPANS[span]->spri) && switch_test_flag(spri, SANGOMA_PRI_READY)) {
-                                               chanmap = spri->private_info;
+                               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;
-                                                               }
+                                       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;
+                                       } 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--;
+                                               callno = 0;
                                        }
                                }
-                       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;
+                               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;
+                       tech_pvt->callno = callno;
                                
-                               if (spri && (tech_pvt->call = pri_new_call(spri->pri))) {
-                                       struct pri_sr *sr;
+                       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);
+                               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 (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;
-                                       }
+                               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);
-                                       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;
                                }
+                               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 {
-                       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;
+               } 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(&current,NULL);
+                               timersub (&current, &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 (file)
index 0000000..373671a
--- /dev/null
@@ -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 <stdint.h>
+
+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 (file)
index 0000000..7fd56fb
--- /dev/null
@@ -0,0 +1,263 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * 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 <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Nenad Corbic <ncorbic@sangoma.com>
+ *
+ *
+ * ss7boost_client.c Client for the SS7Boost Protocol
+ *
+ */
+#include <ss7boost_client.h>
+#include <switch.h>
+
+
+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 (file)
index 0000000..5f37886
--- /dev/null
@@ -0,0 +1,107 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * 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 <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Nenad Corbic <ncorbic@sangoma.com>
+ *
+ *
+ * ss7boost_client.h Client for the SS7Boost Protocol
+ *
+ */
+#ifndef _SS7BOOST_CLIENT_H
+#define _SS7BOOST_CLIENT_H
+
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdarg.h>
+#include <netdb.h>
+#include <sigboost.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <switch.h>
+
+
+
+#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
+
+