From a825c1bbf5fc5331a47d1cf8b56578a8466da23b Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 26 Feb 2010 20:57:59 +0000 Subject: [PATCH] Support for SIGBOOST Version 103 Allows passthrough for TON and NPI on outgoing calls via sigboost git-svn-id: http://svn.openzap.org/svn/openzap/trunk@1041 a93c3328-9c30-0410-af19-c9cd2b2d52af --- libs/openzap/mod_openzap/mod_openzap.c | 79 +++++++++++++++++-- libs/openzap/src/include/openzap.h | 20 ++++- .../ozmod_sangoma_boost/ozmod_sangoma_boost.c | 61 ++++++++------ .../src/ozmod/ozmod_sangoma_boost/sigboost.h | 73 +++++++++++++---- .../src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c | 3 + libs/openzap/src/zap_io.c | 43 +++++++++- 6 files changed, 235 insertions(+), 44 deletions(-) diff --git a/libs/openzap/mod_openzap/mod_openzap.c b/libs/openzap/mod_openzap/mod_openzap.c index f542908f33..2961cd0804 100644 --- a/libs/openzap/mod_openzap/mod_openzap.c +++ b/libs/openzap/mod_openzap/mod_openzap.c @@ -61,7 +61,7 @@ struct span_config { char dial_regex[256]; char fail_dial_regex[256]; char hold_music[256]; - char type[256]; + char type[256]; analog_option_t analog_options; }; @@ -133,6 +133,43 @@ zap_status_t zap_channel_from_event(zap_sigmsg_t *sigmsg, switch_core_session_t void dump_chan(zap_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream); void dump_chan_xml(zap_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream); +static void zap_set_npi(const char *npi_string, uint8_t *target) +{ + if (!strcasecmp(npi_string, "isdn") || !strcasecmp(npi_string, "e164")) { + *target = ZAP_NPI_ISDN; + } else if (!strcasecmp(npi_string, "data")) { + *target = ZAP_NPI_DATA; + } else if (!strcasecmp(npi_string, "telex")) { + *target = ZAP_NPI_TELEX; + } else if (!strcasecmp(npi_string, "national")) { + *target = ZAP_NPI_NATIONAL; + } else if (!strcasecmp(npi_string, "private")) { + *target = ZAP_NPI_PRIVATE; + } else if (!strcasecmp(npi_string, "reserved")) { + *target = ZAP_NPI_RESERVED; + } else if (!strcasecmp(npi_string, "unknown")) { + *target = ZAP_NPI_UNKNOWN; + } else { + zap_log(ZAP_LOG_WARNING, "Invalid NPI value (%s)\n", npi_string); + *target = ZAP_NPI_UNKNOWN; + } +} + +static void zap_set_ton(const char *ton_string, uint8_t *target) +{ + if (!strcasecmp(ton_string, "national")) { + *target = ZAP_TON_NATIONAL; + } else if (!strcasecmp(ton_string, "international")) { + *target = ZAP_TON_INTERNATIONAL; + } else if (!strcasecmp(ton_string, "local")) { + *target = ZAP_TON_SUBSCRIBER_NUMBER; + } else if (!strcasecmp(ton_string, "unknown")) { + *target = ZAP_TON_UNKNOWN; + } else { + zap_log(ZAP_LOG_WARNING, "Invalid TON value (%s)\n", ton_string); + *target = ZAP_TON_UNKNOWN; + } +} static switch_core_session_t *zap_channel_get_session(zap_channel_t *channel, int32_t id) { @@ -1109,7 +1146,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi int argc = 0; const char *var; - if (!outbound_profile) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing caller profile\n"); return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; @@ -1196,10 +1232,17 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi } else { caller_data.ani.type = outbound_profile->destination_number_ton; } - + caller_data.ani.plan = outbound_profile->destination_number_numplan; + /* blindly copy data from outbound_profile. They will be overwritten + * by calling zap_caller_data if needed after */ + caller_data.cid_num.type = outbound_profile->caller_ton; + caller_data.cid_num.plan = outbound_profile->caller_numplan; + caller_data.rdnis.type = outbound_profile->rdnis_ton; + caller_data.rdnis.plan = outbound_profile->rdnis_numplan; + #if 0 if (!zstr(outbound_profile->rdnis)) { zap_set_string(caller_data.rdnis.digits, outbound_profile->rdnis); @@ -1211,6 +1254,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi if (chan_id) { status = zap_channel_open(span_id, chan_id, &zchan); + zap_set_caller_data(span_id, &caller_data); } else { status = zap_channel_open_any(span_id, direction, &caller_data, &zchan); } @@ -2198,6 +2242,7 @@ static switch_status_t load_config(void) uint32_t to = 0; int q921loglevel = -1; int q931loglevel = -1; + // quick debug //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ID: '%s', Name:'%s'\n",id,name); @@ -2389,6 +2434,12 @@ static switch_status_t load_config(void) zap_status_t zstatus = ZAP_FAIL; const char *context = "default"; const char *dialplan = "XML"; + const char *outbound_called_ton = "unknown"; + const char *outbound_called_npi = "unknown"; + const char *outbound_calling_ton = "unknown"; + const char *outbound_calling_npi = "unknown"; + const char *outbound_rdnis_ton = "unknown"; + const char *outbound_rdnis_npi = "unknown"; uint32_t span_id = 0; zap_span_t *span = NULL; const char *tonegroup = NULL; @@ -2413,8 +2464,18 @@ static switch_status_t load_config(void) remote_port = atoi(val); } else if (!strcasecmp(var, "context")) { context = val; - } else if (!strcasecmp(var, "dialplan")) { - dialplan = val; + } else if (!strcasecmp(var, "outbound-called-ton")) { + outbound_called_ton = val; + } else if (!strcasecmp(var, "outbound-called-npi")) { + outbound_called_npi = val; + } else if (!strcasecmp(var, "outbound-calling-ton")) { + outbound_calling_ton = val; + } else if (!strcasecmp(var, "outbound-calling-npi")) { + outbound_calling_npi = val; + } else if (!strcasecmp(var, "outbound-rdnis-ton")) { + outbound_rdnis_ton = val; + } else if (!strcasecmp(var, "outbound-rdnis-npi")) { + outbound_rdnis_npi = val; } } @@ -2449,6 +2510,14 @@ static switch_status_t load_config(void) span_id = span->span_id; } + zap_set_npi(outbound_called_npi, &span->default_caller_data.ani.plan); + zap_set_npi(outbound_calling_npi, &span->default_caller_data.cid_num.plan); + zap_set_npi(outbound_rdnis_npi, &span->default_caller_data.rdnis.plan); + + zap_set_ton(outbound_called_ton, &span->default_caller_data.ani.type); + zap_set_ton(outbound_calling_ton, &span->default_caller_data.cid_num.type); + zap_set_ton(outbound_rdnis_ton, &span->default_caller_data.rdnis.type); + if (zap_configure_span("sangoma_boost", span, on_clear_channel_signal, "local_ip", local_ip, "local_port", &local_port, diff --git a/libs/openzap/src/include/openzap.h b/libs/openzap/src/include/openzap.h index 2a654f2406..b7e75575c8 100644 --- a/libs/openzap/src/include/openzap.h +++ b/libs/openzap/src/include/openzap.h @@ -438,9 +438,24 @@ typedef enum { ZAP_TON_NETWORK_SPECIFIC, ZAP_TON_SUBSCRIBER_NUMBER, ZAP_TON_ABBREVIATED_NUMBER, - ZAP_TON_RESERVED + ZAP_TON_RESERVED, + ZAP_TON_INVALID = 255 } zap_ton_t; +/** + * Numbering Plan Identification (NPI) + */ +typedef enum { + ZAP_NPI_UNKNOWN = 0, + ZAP_NPI_ISDN = 1, + ZAP_NPI_DATA = 3, + ZAP_NPI_TELEX = 4, + ZAP_NPI_NATIONAL = 8, + ZAP_NPI_PRIVATE = 9, + ZAP_NPI_RESERVED = 10, + ZAP_NPI_INVALID = 255 +} zap_npi_t; + typedef struct { char digits[25]; uint8_t type; @@ -584,6 +599,7 @@ struct zap_span { size_t dtmf_hangup_len; int suggest_chan_id; zap_state_map_t *state_map; + zap_caller_data_t default_caller_data; struct zap_span *next; }; @@ -700,6 +716,8 @@ OZ_DECLARE(zap_status_t) zap_span_find_by_name(const char *name, zap_span_t **sp OZ_DECLARE(char *) zap_api_execute(const char *type, const char *cmd); OZ_DECLARE(int) zap_vasprintf(char **ret, const char *fmt, va_list ap); +OZ_DECLARE(void) zap_set_caller_data(uint32_t span_id, zap_caller_data_t *caller_data); + ZIO_CODEC_FUNCTION(zio_slin2ulaw); ZIO_CODEC_FUNCTION(zio_ulaw2slin); ZIO_CODEC_FUNCTION(zio_slin2alaw); diff --git a/libs/openzap/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c b/libs/openzap/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c index b0953f2b4d..ae79918b42 100644 --- a/libs/openzap/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c +++ b/libs/openzap/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c @@ -291,6 +291,7 @@ static ZIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request) return ZAP_FAIL; } + /* sangomabc_call_init (event, calling, called, setup_id) */ sangomabc_call_init(&event, caller_data->cid_num.digits, ani, r); //sangoma_bc_call_init will clear the trunk_group val so we need to set it again event.trunk_group=tg; @@ -317,13 +318,22 @@ static ZIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request) } zap_set_string(event.calling_name, caller_data->cid_name); - zap_set_string(event.isup_in_rdnis, caller_data->rdnis.digits); + zap_set_string(event.rdnis.digits, caller_data->rdnis.digits); + if (strlen(caller_data->rdnis.digits)) { - event.isup_in_rdnis_size = strlen(caller_data->rdnis.digits)+1; + event.rdnis.digits_count = strlen(caller_data->rdnis.digits)+1; + event.rdnis.ton = caller_data->rdnis.type; + event.rdnis.npi = caller_data->rdnis.plan; } - event.calling_number_screening_ind = caller_data->screen; - event.calling_number_presentation = caller_data->pres; + event.calling.screening_ind = caller_data->screen; + event.calling.presentation_ind = caller_data->pres; + + event.calling.ton = caller_data->cid_num.type; + event.calling.npi = caller_data->cid_num.plan; + + event.called.ton = caller_data->ani.type; + event.called.npi = caller_data->ani.plan; OUTBOUND_REQUESTS[r].status = BST_WAITING; OUTBOUND_REQUESTS[r].span = span; @@ -728,35 +738,42 @@ static void handle_call_start(zap_span_t *span, sangomabc_connection_t *mcon, sa } zchan->sflags = 0; - zap_set_string(zchan->caller_data.cid_num.digits, (char *)event->calling_number_digits); - zap_set_string(zchan->caller_data.cid_name, (char *)event->calling_number_digits); + zap_set_string(zchan->caller_data.cid_num.digits, (char *)event->calling.digits); + zap_set_string(zchan->caller_data.cid_name, (char *)event->calling.digits); + zap_set_string(zchan->caller_data.ani.digits, (char *)event->calling.digits); + zap_set_string(zchan->caller_data.dnis.digits, (char *)event->called.digits); + zap_set_string(zchan->caller_data.rdnis.digits, (char *)event->rdnis.digits); + if (strlen(event->calling_name)) { zap_set_string(zchan->caller_data.cid_name, (char *)event->calling_name); } - zap_set_string(zchan->caller_data.ani.digits, (char *)event->calling_number_digits); - zap_set_string(zchan->caller_data.dnis.digits, (char *)event->called_number_digits); - if (event->isup_in_rdnis_size) { - char* p; - //Set value of rdnis.digis in case prot daemon is still using older style RDNIS - if (atoi((char *)event->isup_in_rdnis) > 0) { - zap_set_string(zchan->caller_data.rdnis.digits, (char *)event->isup_in_rdnis); - } + zchan->caller_data.cid_num.plan = event->calling.npi; + zchan->caller_data.cid_num.type = event->calling.ton; - p = strstr((char*)event->isup_in_rdnis,"PRI001-ANI2-"); + zchan->caller_data.ani.plan = event->calling.npi; + zchan->caller_data.ani.type = event->calling.ton; + + zchan->caller_data.dnis.plan = event->called.npi; + zchan->caller_data.dnis.type = event->called.ton; + + zchan->caller_data.rdnis.plan = event->rdnis.npi; + zchan->caller_data.rdnis.type = event->rdnis.ton; + + zchan->caller_data.screen = event->calling.screening_ind; + zchan->caller_data.pres = event->calling.presentation_ind; + + if (event->custom_data_size) { + char* p = NULL; + + p = strstr((char*)event->custom_data,"PRI001-ANI2-"); if (p!=NULL) { int ani2 = 0; sscanf(p, "PRI001-ANI2-%d", &ani2); snprintf(zchan->caller_data.aniII, 5, "%.2d", ani2); } - p = strstr((char*)event->isup_in_rdnis,"RDNIS-"); - if (p!=NULL) { - sscanf(p, "RDNIS-%s", &zchan->caller_data.rdnis.digits[0]); - } - } - zchan->caller_data.screen = event->calling_number_screening_ind; - zchan->caller_data.pres = event->calling_number_presentation; + zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RING); return; diff --git a/libs/openzap/src/ozmod/ozmod_sangoma_boost/sigboost.h b/libs/openzap/src/ozmod/ozmod_sangoma_boost/sigboost.h index 1b90930ffe..1281069536 100644 --- a/libs/openzap/src/ozmod/ozmod_sangoma_boost/sigboost.h +++ b/libs/openzap/src/ozmod/ozmod_sangoma_boost/sigboost.h @@ -14,11 +14,15 @@ #ifndef _SIGBOOST_H_ #define _SIGBOOST_H_ -#define SIGBOOST_VERSION 101 +#define SIGBOOST_VERSION 103 #include #include +#ifdef HAVE_FREETDM +#include +#endif + enum e_sigboost_event_id_values { SIGBOOST_EVENT_CALL_START = 0x80, /*128*/ @@ -30,7 +34,22 @@ enum e_sigboost_event_id_values SIGBOOST_EVENT_CALL_STOPPED_ACK = 0x86, /*134*/ SIGBOOST_EVENT_SYSTEM_RESTART = 0x87, /*135*/ SIGBOOST_EVENT_SYSTEM_RESTART_ACK = 0x88, /*136*/ - SIGBOOST_EVENT_CALL_PROGRESS = 0x50, /*decimal 80*/ + /* CALL_RELEASED is aimed to fix a race condition that became obvious + * when the boost socket was replaced by direct function calls + * and the channel hunting was moved to freetdm, the problem is + * we can get CALL_STOPPED msg and reply with CALL_STOPPED_ACK + * but the signaling module will still (in PRI) send RELEASE and + * wait for RELEASE_COMPLETE from the isdn network before + * marking the channel as available, therefore freetdm should + * also not mark the channel as available until CALL_RELEASED + * is received, for socket mode we can continue working as usual + * with CALL_STOPPED being the last step because the hunting is + * done in the signaling module. + * + * CALL_RELEASED is only used in queue mode + * */ + SIGBOOST_EVENT_CALL_RELEASED = 0x51, /* 81 */ + SIGBOOST_EVENT_CALL_PROGRESS = 0x50, /*decimal 80*/ /* Following IDs are ss7boost to sangoma_mgd only. */ SIGBOOST_EVENT_HEARTBEAT = 0x89, /*137*/ SIGBOOST_EVENT_INSERT_CHECK_LOOP = 0x8a, /*138*/ @@ -91,7 +110,12 @@ enum e_sigboost_progress_flags #define CORE_MAX_CHAN_PER_SPAN 32 #define MAX_PENDING_CALLS CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN /* 0..(MAX_PENDING_CALLS-1) is range of call_setup_id below */ -#define SIZE_RDNIS 900 + +/* Should only be used by server */ +#define MAX_CALL_SETUP_ID 0xFFFF + +#define SIZE_CUSTOM 900 +#define SIZE_RDNIS SIZE_CUSTOM #pragma pack(1) @@ -100,7 +124,17 @@ typedef struct { uint8_t capability; uint8_t uil1p; -}t_sigboost_bearer; +} t_sigboost_bearer; + +typedef struct +{ + uint8_t digits_count; + char digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */ + uint8_t npi; + uint8_t ton; + uint8_t screening_ind; + uint8_t presentation_ind; +}t_sigboost_digits; typedef struct { @@ -115,21 +149,30 @@ typedef struct uint8_t chan; uint32_t flags; /* struct timeval tv; */ - uint8_t called_number_digits_count; - char called_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */ - uint8_t calling_number_digits_count; /* it's an array */ - char calling_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */ + t_sigboost_digits called; + t_sigboost_digits calling; + t_sigboost_digits rdnis; /* ref. Q.931 Table 4-11 and Q.951 Section 3 */ - uint8_t calling_number_screening_ind; - uint8_t calling_number_presentation; char calling_name[MAX_DIALED_DIGITS + 1]; t_sigboost_bearer bearer; uint8_t hunt_group; - uint16_t isup_in_rdnis_size; - char isup_in_rdnis [SIZE_RDNIS]; /* it's a null terminated string */ + uint16_t custom_data_size; + char custom_data[SIZE_CUSTOM]; /* it's a null terminated string */ + } t_sigboost_callstart; -#define MIN_SIZE_CALLSTART_MSG sizeof(t_sigboost_callstart) - SIZE_RDNIS +#define called_number_digits_count called.digits_count +#define called_number_digits called.digits +#define calling_number_digits_count calling.digits_count +#define calling_number_digits calling.digits +#define calling_number_screening_ind calling.screening_ind +#define calling_number_presentation calling.presentation_ind + +#define isup_in_rdnis_size custom_data_size +#define isup_in_rdnis custom_data + + +#define MIN_SIZE_CALLSTART_MSG sizeof(t_sigboost_callstart) - SIZE_CUSTOM typedef struct { @@ -154,10 +197,10 @@ static inline int boost_full_event(int event_id) switch (event_id) { case SIGBOOST_EVENT_CALL_START: case SIGBOOST_EVENT_DIGIT_IN: - case SIGBOOST_EVENT_CALL_PROGRESS: + case SIGBOOST_EVENT_CALL_PROGRESS: return 1; default: - return 0; + break; } return 0; diff --git a/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c b/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c index 190edc2a8d..59d4155d33 100644 --- a/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c +++ b/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c @@ -687,6 +687,9 @@ static ZIO_WRITE_FUNCTION(wanpipe_write) /* Do we even need the headerframe here? on windows, we don't even pass it to the driver */ memset(&hdrframe, 0, sizeof(hdrframe)); + if (*datalen == 0) { + return ZAP_SUCCESS; + } bsent = sangoma_writemsg_tdm(zchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (unsigned short)(*datalen),0); /* should we be checking if bsent == *datalen here? */ diff --git a/libs/openzap/src/zap_io.c b/libs/openzap/src/zap_io.c index 92ec4419e8..e0768e145e 100644 --- a/libs/openzap/src/zap_io.c +++ b/libs/openzap/src/zap_io.c @@ -176,6 +176,45 @@ static void default_logger(const char *file, const char *func, int line, int lev } +OZ_DECLARE(void) zap_set_caller_data(uint32_t span_id, zap_caller_data_t *caller_data) +{ + zap_span_t *span = NULL; + if (!span_id) { + zap_log(ZAP_LOG_CRIT, "Error: trying to set caller data, but no span id?\n"); + return; + } + + zap_span_find(span_id, &span); + if (!span) { + zap_log(ZAP_LOG_CRIT, "Error: trying to set caller data, but could not find span\n"); + return; + } + + if (caller_data->cid_num.plan == ZAP_NPI_INVALID) { + caller_data->cid_num.plan = span->default_caller_data.cid_num.plan; + } + + if (caller_data->cid_num.type == ZAP_TON_INVALID) { + caller_data->cid_num.type = span->default_caller_data.cid_num.type; + } + + if (caller_data->ani.plan == ZAP_NPI_INVALID) { + caller_data->ani.plan = span->default_caller_data.ani.plan; + } + + if (caller_data->ani.type == ZAP_TON_INVALID) { + caller_data->ani.type = span->default_caller_data.ani.type; + } + + if (caller_data->rdnis.plan == ZAP_NPI_INVALID) { + caller_data->rdnis.plan = span->default_caller_data.rdnis.plan; + } + + if (caller_data->rdnis.type == ZAP_NPI_INVALID) { + caller_data->rdnis.type = span->default_caller_data.rdnis.type; + } +} + OZ_DECLARE_DATA zap_logger_t zap_log = null_logger; OZ_DECLARE(void) zap_global_set_logger(zap_logger_t logger) @@ -967,7 +1006,9 @@ OZ_DECLARE(zap_status_t) zap_channel_open_any(uint32_t span_id, zap_direction_t *zchan = NULL; return ZAP_FAIL; } - + + zap_set_caller_data(span_id, caller_data); + if (span->channel_request && !span->suggest_chan_id) { return span->channel_request(span, 0, direction, caller_data, zchan); }