From 03e3e52790056d62bf6eb9d9d67ee0548bab9d24 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 3 Sep 2010 16:17:26 -0400 Subject: [PATCH 001/822] sofia contact changes sangoma media gateway banner --- src/mod/endpoints/mod_sofia/mod_sofia.c | 89 +++++++++++++++++++++++++ src/switch_core.c | 16 ++++- 2 files changed, 104 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 58308225ff..df88106262 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -3300,6 +3300,7 @@ SWITCH_STANDARD_API(sofia_contact_function) char *p; sofia_profile_t *profile = NULL; const char *exclude_contact = NULL; + const char *user_replacement = NULL; char *reply = "error/facility_not_subscribed"; if (!cmd) { @@ -3310,6 +3311,7 @@ SWITCH_STANDARD_API(sofia_contact_function) if (session) { switch_channel_t *channel = switch_core_session_get_channel(session); exclude_contact = switch_channel_get_variable(channel, "sip_exclude_contact"); + user_replacement = switch_channel_get_variable(channel, "sip_contact_user_replacement"); } @@ -3388,6 +3390,93 @@ SWITCH_STANDARD_API(sofia_contact_function) reply = "error/user_not_registered"; } + if (user_replacement) { + int urlcount = 0; + int copyerr = 0; + char *newreply = NULL; + char *urlstart = NULL; + char *newptr = NULL; + char *bufend = NULL; + char *str = reply; + switch_size_t copysize = 0; + switch_size_t replacesize = strlen(user_replacement); + switch_size_t allocsize = 0; + + /* first pass to count how many URLs we have */ + while ((urlstart = strcasestr(str, "sip:")) || (urlstart = strcasestr(str, "sips:"))) { + urlcount++; + str = urlstart + 4; + } + + if (!urlcount) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): no sip URLs found to replace the user\n"); + copyerr++; + goto copydone; + } + + /* this allocates a bit more than needed but better safe than sorry doing more funky math */ + allocsize = strlen(reply) + (urlcount * replacesize); + newreply = switch_core_session_alloc(session, allocsize); + if (!newreply) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): no buffer space available for replacement\n"); + copyerr++; + goto copydone; + } + + /* get a working pointer to the new reply */ + newptr = newreply; + + /* pointer to the end of the allocated buffer for safety checks */ + bufend = newreply + allocsize - 1; + *bufend = 0; + + /* go thru all the urls and replace the user part */ + str = reply; + while ((urlstart = strcasestr(str, "sip:")) || (urlstart = strcasestr(str, "sips:"))) { + + /* found an URL, copy up to the start of the url */ + copysize = ( urlstart - str ) + 4; + + /* double check boundaries before copying anything at all (this should not happen) */ + if ((newptr + copysize + replacesize) >= bufend) { + copyerr++; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): wow buffer was not big enough!\n"); + break; + } + + /* copy the original contact string except for the user */ + memcpy(newptr, str, copysize); + newptr += copysize; + + /* copy the user replacement */ + memcpy(newptr, user_replacement, replacesize); + newptr += replacesize; + + /* skip the original user part */ + str = strchr(urlstart, '@'); + if (!str) { + copyerr++; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): not host part found for contact\n"); + break; + } + /* continue searching for the next sip: URL */ + } + +copydone: + if (!copyerr) { + /* copy the remaining reply string */ + copysize = strlen(str); + if ((newptr + copysize) >= bufend) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): wow buffer was not big enough, close, but not enough!\n"); + } else { + strcpy(newptr, str); + reply = newreply; + } + } else { + reply = "error/replacement error"; + } + } + stream->write_function(stream, "%s", reply); reply = NULL; diff --git a/src/switch_core.c b/src/switch_core.c index 4bfc02e655..7fd000a2bd 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1539,7 +1539,7 @@ static void switch_load_core_config(const char *file) SWITCH_DECLARE(const char *) switch_core_banner(void) { - +#if 0 return ("\n" " _____ ______ _____ _____ ____ _ _ \n" " | ___| __ ___ ___/ ___\\ \\ / /_ _|_ _/ ___| | | | \n" @@ -1552,6 +1552,20 @@ SWITCH_DECLARE(const char *) switch_core_banner(void) "* FreeSWITCH (http://www.freeswitch.org) *\n" "* Paypal Donations Appreciated: paypal@freeswitch.org *\n" "* Brought to you by ClueCon http://www.cluecon.com/ *\n" "************************************************************\n" "\n"); +#else + return ( +"\n _____ ___ ___ _ _ _____ _ \n" +"/ ___| | \\/ | | (_) | __ \\ | | \n" +"\\ `--. __ _ _ __ __ _ ___ _ __ ___ __ _ | . . | ___ __| |_ __ _ | | \\/ __ _| |_ _____ ____ _ _ _ \n" +" `--. \\/ _` | '_ \\ / _` |/ _ \\| '_ ` _ \\ / _` | | |\\/| |/ _ \\/ _` | |/ _` | | | __ / _` | __|/ _ \\ \\ /\\ / / _` | | | |\n" +"/\\__/ / (_| | | | | (_| | (_) | | | | | | (_| | | | | | __/ (_| | | (_| | | |_\\ \\ (_| | |_| __/\\ V V / (_| | |_| |\n" +"\\____/ \\__,_|_| |_|\\__, |\\___/|_| |_| |_|\\__,_| \\_| |_/\\___|\\__,_|_|\\__,_| \\____/\\__,_|\\__|\\___| \\_/\\_/ \\__,_|\\__, |\n" +" __/ | __/ |\n" +" |___/ |___/ \n" + "************************************************************\n" + "* Powered by: FreeSWITCH (http://www.freeswitch.org) *\n" + "************************************************************\n" "\n"); +#endif } From 970a3755f319547fd509c1fb4142d06c9885a44e Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 3 Sep 2010 16:52:25 -0400 Subject: [PATCH 002/822] test --- src/switch_profile.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/switch_profile.c b/src/switch_profile.c index f1c2247979..17c1dc1214 100644 --- a/src/switch_profile.c +++ b/src/switch_profile.c @@ -280,6 +280,7 @@ SWITCH_DECLARE(void) switch_delete_profile_timer(switch_profile_timer_t **p) if (!p) return; #ifdef __linux__ + test close((*p)->procfd); #endif free(*p); From 59221a32b93f000d1a0f5036621ac680bc927fa2 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 7 Sep 2010 14:04:52 -0400 Subject: [PATCH 003/822] change versioning information --- src/mod/endpoints/mod_sofia/mod_sofia.h | 2 +- src/switch.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index aa2149503a..ab94a00df1 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -88,7 +88,7 @@ typedef struct private_object private_object_t; #define MULTICAST_EVENT "multicast::event" #define SOFIA_REPLACES_HEADER "_sofia_replaces_" -#define SOFIA_USER_AGENT "FreeSWITCH-mod_sofia/" SWITCH_VERSION_MAJOR "." SWITCH_VERSION_MINOR "." SWITCH_VERSION_MICRO "-" SWITCH_VERSION_REVISION +#define SOFIA_USER_AGENT "SangomaMediaGateway/" SWITCH_VERSION_MAJOR "." SWITCH_VERSION_MINOR "." SWITCH_VERSION_MICRO "-" SWITCH_VERSION_REVISION #define SOFIA_CHAT_PROTO "sip" #define SOFIA_MULTIPART_PREFIX "sip_mp_" #define SOFIA_MULTIPART_PREFIX_T "~sip_mp_" diff --git a/src/switch.c b/src/switch.c index b59097ac89..e4865757b2 100644 --- a/src/switch.c +++ b/src/switch.c @@ -469,7 +469,7 @@ int main(int argc, char *argv[]) } if (local_argv[x] && !strcmp(local_argv[x], "-version")) { - fprintf(stdout, "FreeSWITCH version: %s\n", SWITCH_VERSION_FULL); + fprintf(stdout, "Sangoma Media Gateway Version: %s\n", SWITCH_VERSION_FULL); return 0; known_opt++; } From 0ecaf2eba2aa8eb1226acebf5f2b54f342759393 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 7 Sep 2010 14:53:17 -0400 Subject: [PATCH 004/822] doh! --- src/switch_profile.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/switch_profile.c b/src/switch_profile.c index 17c1dc1214..f1c2247979 100644 --- a/src/switch_profile.c +++ b/src/switch_profile.c @@ -280,7 +280,6 @@ SWITCH_DECLARE(void) switch_delete_profile_timer(switch_profile_timer_t **p) if (!p) return; #ifdef __linux__ - test close((*p)->procfd); #endif free(*p); From 6f9ae9bd7a46c7ce4b0952c05a263eb31749fbd7 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 7 Sep 2010 15:21:20 -0400 Subject: [PATCH 005/822] more renaming --- src/mod/applications/mod_commands/mod_commands.c | 2 +- src/switch_console.c | 2 +- src/switch_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index e1eb2a6b6a..6900c5dc4a 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -73,7 +73,7 @@ SWITCH_STANDARD_API(shutdown_function) SWITCH_STANDARD_API(version_function) { - stream->write_function(stream, "FreeSWITCH Version %s\n", SWITCH_VERSION_FULL); + stream->write_function(stream, "Sangoma Media Gateway Version %s\n", SWITCH_VERSION_FULL); return SWITCH_STATUS_SUCCESS; } diff --git a/src/switch_console.c b/src/switch_console.c index 30d1d97fed..60c8ca9345 100644 --- a/src/switch_console.c +++ b/src/switch_console.c @@ -975,7 +975,7 @@ static unsigned char console_f12key(EditLine * el, int ch) char *prompt(EditLine * e) { if (*prompt_str == '\0') { - switch_snprintf(prompt_str, sizeof(prompt_str), "freeswitch@%s> ", hostname); + switch_snprintf(prompt_str, sizeof(prompt_str), "sangoma-media-gateway@%s> ", hostname); } return prompt_str; diff --git a/src/switch_core.c b/src/switch_core.c index 7fd000a2bd..dd12aef908 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1627,7 +1627,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_init_and_modload(switch_core_flag_t switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, - "\nFreeSWITCH Version %s Started.\nMax Sessions[%u]\nSession Rate[%d]\nSQL [%s]\n", SWITCH_VERSION_FULL, + "\nSangoma Media Gateway Version %s Started.\nMax Sessions[%u]\nSession Rate[%d]\nSQL [%s]\n", SWITCH_VERSION_FULL, switch_core_session_limit(0), switch_core_sessions_per_second(0), switch_test_flag((&runtime), SCF_USE_SQL) ? "Enabled" : "Disabled"); From 6d4c1b7d1a1a58d541504697088cd8afe3c86df5 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 10 Sep 2010 13:37:33 -0400 Subject: [PATCH 006/822] freetdm: remove iterator free log --- libs/freetdm/src/ftdm_io.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index c774e61901..47d6936c54 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -3603,7 +3603,9 @@ FT_DECLARE(ftdm_iterator_t *) ftdm_iterator_next(ftdm_iterator_t *iter) return iter; case FTDM_ITERATOR_CHANS: ftdm_assert_return(iter->pvt.chaniter.index, NULL, "channel iterator index cannot be zero!\n"); - ftdm_assert_return(iter->pvt.chaniter.index <= iter->pvt.chaniter.span->chan_count, NULL, "channel iterator index bigger than span chan count!\n"); + if (iter->pvt.chaniter.index == iter->pvt.chaniter.span->chan_count) { + return NULL; + } iter->pvt.chaniter.index++; return iter; default: @@ -3651,7 +3653,6 @@ FT_DECLARE(ftdm_status_t) ftdm_iterator_free(ftdm_iterator_t *iter) } ftdm_assert_return(iter->type, FTDM_FAIL, "Cannot free invalid iterator\n"); - ftdm_log(FTDM_LOG_DEBUG, "Freeing iterator %p\n", iter); ftdm_safe_free(iter); return FTDM_SUCCESS; From 700fab4c821e980536638fbc704097277fc4976b Mon Sep 17 00:00:00 2001 From: Konrad Hammel Date: Fri, 10 Sep 2010 15:34:13 -0400 Subject: [PATCH 007/822] freetdm: ss7 - switching back to sending RSC rather then GRS at start --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index b5fe619446..70a1a05440 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1249,7 +1249,7 @@ static ftdm_status_t ftdm_sangoma_ss7_start(ftdm_span_t * span) /* throw the pause flag */ sngss7_set_flag(sngss7_info, FLAG_INFID_PAUSED); - +#if 0 /* throw the grp reset flag */ sngss7_set_flag(sngss7_info, FLAG_GRP_RESET_TX); if (x == 1) { @@ -1257,7 +1257,10 @@ static ftdm_status_t ftdm_sangoma_ss7_start(ftdm_span_t * span) sngss7_span->tx_grs.circuit = sngss7_info->circuit->id; sngss7_span->tx_grs.range = span->chan_count -1; } - +#else + /* throw the channel into reset */ + sngss7_set_flag(sngss7_info, FLAG_RESET_TX); +#endif /* throw the channel to suspend */ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); From 4aac01cfc46913a4ed5d7c3cdcc6d47e6f511f12 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 13 Sep 2010 15:04:55 -0400 Subject: [PATCH 008/822] fs_cli rebranding --- libs/esl/fs_cli.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/libs/esl/fs_cli.c b/libs/esl/fs_cli.c index 91836b7aec..60dd8d8012 100644 --- a/libs/esl/fs_cli.c +++ b/libs/esl/fs_cli.c @@ -8,6 +8,7 @@ #include #define CMD_BUFLEN 1024 +#define PROMPT_PREFIX "sangoma-media-gateway" #ifdef WIN32 #define strdup(src) _strdup(src) @@ -811,17 +812,10 @@ static void print_banner(FILE *stream) fprintf(stream, - " _____ ____ ____ _ ___ \n" - " | ___/ ___| / ___| | |_ _| \n" - " | |_ \\___ \\ | | | | | | \n" - " | _| ___) | | |___| |___ | | \n" - " |_| |____/ \\____|_____|___| \n" "\n" "*******************************************************\n" - "* Anthony Minessale II, Ken Rice, Michael Jerris *\n" - "* FreeSWITCH (http://www.freeswitch.org) *\n" - "* Paypal Donations Appreciated: paypal@freeswitch.org *\n" - "* Brought to you by ClueCon http://www.cluecon.com/ *\n" + "* Sangoma Media Gateway *\n" + "* Powered by FreeSWITCH (http://www.freeswitch.org) *\n" "*******************************************************\n" "\n" "Type /help to see a list of commands\n\n\n" @@ -968,13 +962,13 @@ int main(int argc, char *argv[]) int rv = 0; #ifndef WIN32 - char hfile[512] = "/etc/fs_cli_history"; - char cfile[512] = "/etc/fs_cli.conf"; - char dft_cfile[512] = "/etc/fs_cli.conf"; + char hfile[512] = "/etc/smg_cli_history"; + char cfile[512] = "/etc/smg_cli.conf"; + char dft_cfile[512] = "/etc/smg_cli.conf"; #else - char hfile[512] = "fs_cli_history"; - char cfile[512] = "fs_cli.conf"; - char dft_cfile[512] = "fs_cli.conf"; + char hfile[512] = "smg_cli_history"; + char cfile[512] = "smg_cli.conf"; + char dft_cfile[512] = "smg_cli.conf"; #endif char *home = getenv("HOME"); /* Vars for optargs */ @@ -1018,8 +1012,8 @@ int main(int argc, char *argv[]) if (home) { - snprintf(hfile, sizeof(hfile), "%s/.fs_cli_history", home); - snprintf(cfile, sizeof(cfile), "%s/.fs_cli_conf", home); + snprintf(hfile, sizeof(hfile), "%s/.smg_cli_history", home); + snprintf(cfile, sizeof(cfile), "%s/.smg_cli_conf", home); } signal(SIGINT, handle_SIGINT); @@ -1189,12 +1183,12 @@ int main(int argc, char *argv[]) if (argv_host) { if (argv_port && profile->port != 8021) { - snprintf(prompt_str, sizeof(prompt_str), "freeswitch@%s:%u@%s> ", profile->host, profile->port, profile->name); + snprintf(prompt_str, sizeof(prompt_str), PROMPT_PREFIX "@%s:%u@%s> ", profile->host, profile->port, profile->name); } else { - snprintf(prompt_str, sizeof(prompt_str), "freeswitch@%s@%s> ", profile->host, profile->name); + snprintf(prompt_str, sizeof(prompt_str), PROMPT_PREFIX "@%s@%s> ", profile->host, profile->name); } } else { - snprintf(prompt_str, sizeof(prompt_str), "freeswitch@%s> ", profile->name); + snprintf(prompt_str, sizeof(prompt_str), PROMPT_PREFIX "@%s> ", profile->name); } connect: @@ -1320,7 +1314,7 @@ int main(int argc, char *argv[]) print_banner(stdout); - esl_log(ESL_LOG_INFO, "FS CLI Ready.\nenter /help for a list of commands.\n"); + esl_log(ESL_LOG_INFO, "Sangoma Media Gateway CLI Ready.\nenter /help for a list of commands.\n"); printf("%s\n", handle.last_sr_reply); while (running > 0) { From 5a49352a0b79efbb12b3ffd69c1dd9e3302ea488 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 13 Sep 2010 15:15:36 -0400 Subject: [PATCH 009/822] add -base option to modify the base directory --- src/switch.c | 19 ++++++++++++++++++- src/switch_core.c | 4 ++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/switch.c b/src/switch.c index e4865757b2..ae38ab5fb8 100644 --- a/src/switch.c +++ b/src/switch.c @@ -48,7 +48,7 @@ #include "private/switch_core_pvt.h" /* pid filename: Stores the process id of the freeswitch process */ -#define PIDFILE "freeswitch.pid" +#define PIDFILE "sangoma-media-gateway.pid" static char *pfile = PIDFILE; @@ -346,6 +346,7 @@ int main(int argc, char *argv[]) "\t-stop -- stop freeswitch\n" "\t-nc -- do not output to a console and background\n" "\t-c -- output to a console and stay in the foreground\n" + "\t-base [basedir] -- specify an alternate base dir\n" "\t-conf [confdir] -- specify an alternate config dir\n" "\t-log [logdir] -- specify an alternate log dir\n" "\t-run [rundir] -- specify an alternate run dir\n" @@ -578,6 +579,22 @@ int main(int argc, char *argv[]) known_opt++; } + if (local_argv[x] && !strcmp(local_argv[x], "-base")) { + x++; + if (local_argv[x] && strlen(local_argv[x])) { + SWITCH_GLOBAL_dirs.base_dir = (char *) malloc(strlen(local_argv[x]) + 1); + if (!SWITCH_GLOBAL_dirs.base_dir) { + fprintf(stderr, "Allocation error\n"); + return 255; + } + strcpy(SWITCH_GLOBAL_dirs.base_dir, local_argv[x]); + } else { + fprintf(stderr, "When using -base you must specify a base directory\n"); + return 255; + } + known_opt++; + } + if (local_argv[x] && !strcmp(local_argv[x], "-log")) { x++; if (local_argv[x] && strlen(local_argv[x])) { diff --git a/src/switch_core.c b/src/switch_core.c index dd12aef908..9a4a967447 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -447,6 +447,9 @@ SWITCH_DECLARE(void) switch_core_set_globals(void) base_dir[(lastbacklash - base_dir)] = '\0'; #else char base_dir[1024] = SWITCH_PREFIX_DIR; + if (SWITCH_GLOBAL_dirs.base_dir) { + snprintf(base_dir, sizeof(base_dir), "%s", SWITCH_GLOBAL_dirs.base_dir); + } #endif if (!SWITCH_GLOBAL_dirs.base_dir && (SWITCH_GLOBAL_dirs.base_dir = (char *) malloc(BUFSIZE))) { @@ -1296,6 +1299,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc switch_find_local_ip(guess_ip, sizeof(guess_ip), NULL, AF_INET6); switch_core_set_variable("local_ip_v6", guess_ip); switch_core_set_variable("base_dir", SWITCH_GLOBAL_dirs.base_dir); + switch_core_set_variable("base_logdir", SWITCH_GLOBAL_dirs.log_dir); switch_core_set_variable("recordings_dir", SWITCH_GLOBAL_dirs.recordings_dir); switch_core_set_variable("sound_prefix", SWITCH_GLOBAL_dirs.sounds_dir); switch_core_set_variable("sounds_dir", SWITCH_GLOBAL_dirs.sounds_dir); From 4cabfdbd6b131d26de3cbbea75097beae7c55209 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 13 Sep 2010 15:41:03 -0400 Subject: [PATCH 010/822] do not create some directories automagically --- src/switch_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/switch_core.c b/src/switch_core.c index 9a4a967447..9df50a6eab 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1258,12 +1258,14 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc switch_dir_make_recursive(SWITCH_GLOBAL_dirs.log_dir, SWITCH_DEFAULT_DIR_PERMS, runtime.memory_pool); switch_dir_make_recursive(SWITCH_GLOBAL_dirs.run_dir, SWITCH_DEFAULT_DIR_PERMS, runtime.memory_pool); switch_dir_make_recursive(SWITCH_GLOBAL_dirs.db_dir, SWITCH_DEFAULT_DIR_PERMS, runtime.memory_pool); +#if 0 switch_dir_make_recursive(SWITCH_GLOBAL_dirs.script_dir, SWITCH_DEFAULT_DIR_PERMS, runtime.memory_pool); switch_dir_make_recursive(SWITCH_GLOBAL_dirs.htdocs_dir, SWITCH_DEFAULT_DIR_PERMS, runtime.memory_pool); switch_dir_make_recursive(SWITCH_GLOBAL_dirs.grammar_dir, SWITCH_DEFAULT_DIR_PERMS, runtime.memory_pool); switch_dir_make_recursive(SWITCH_GLOBAL_dirs.recordings_dir, SWITCH_DEFAULT_DIR_PERMS, runtime.memory_pool); switch_dir_make_recursive(SWITCH_GLOBAL_dirs.sounds_dir, SWITCH_DEFAULT_DIR_PERMS, runtime.memory_pool); switch_dir_make_recursive(SWITCH_GLOBAL_dirs.temp_dir, SWITCH_DEFAULT_DIR_PERMS, runtime.memory_pool); +#endif switch_mutex_init(&runtime.uuid_mutex, SWITCH_MUTEX_NESTED, runtime.memory_pool); From 613e08d352d65bff137ac865e681cb1efc001dd0 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 14 Sep 2010 14:01:22 -0400 Subject: [PATCH 011/822] Increased SQLLEN to 1024*1024 --- src/switch_core_sqldb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index 3a5e0bb6e2..b170b6a4ad 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -35,7 +35,7 @@ #include #include "private/switch_core_pvt.h" -#define SQLLEN 32768 +#define SQLLEN 1024*1024 static struct { switch_cache_db_handle_t *event_db; From 284e30317082da1cddb0f3e4519bc59b3b7709da Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 17 Sep 2010 18:43:50 -0400 Subject: [PATCH 012/822] add switch wrapping support for apr_stat --- src/include/switch_apr.h | 120 +++++++++++++++++++++++++++++++++++++++ src/switch_apr.c | 12 ++++ 2 files changed, 132 insertions(+) diff --git a/src/include/switch_apr.h b/src/include/switch_apr.h index f82b81a7f8..84fcb61004 100644 --- a/src/include/switch_apr.h +++ b/src/include/switch_apr.h @@ -647,12 +647,99 @@ SWITCH_DECLARE(switch_status_t) switch_queue_trypush(switch_queue_t *queue, void * @{ */ +/** File types. */ +typedef enum { + SWITCH_NOFILE = 0, /**< no file type determined */ + SWITCH_REG, /**< a regular file */ + SWITCH_DIR, /**< a directory */ + SWITCH_CHR, /**< a character device */ + SWITCH_BLK, /**< a block device */ + SWITCH_PIPE, /**< a FIFO / pipe */ + SWITCH_LNK, /**< a symbolic link */ + SWITCH_SOCK, /**< a [unix domain] socket */ + SWITCH_UNKFILE = 127 /**< a file of some other unknown type */ +} switch_filetype_e; + + /** Structure for referencing files. */ typedef struct apr_file_t switch_file_t; typedef int32_t switch_fileperms_t; typedef int switch_seek_where_t; +/** + * Structure for determining user ownership. + */ +#ifdef WIN32 +typedef PSID switch_uid_t; +#else +typedef uid_t switch_uid_t; +#endif + +/** + * Structure for determining group ownership. + */ +#ifdef WIN32 +typedef PSID switch_gid_t; +#else +typedef gid_t switch_gid_t; +#endif + +#ifdef WIN32 + typedef uint32_t switch_dev_t; + typedef uint64_t switch_ino_t; +#else + typedef ino_t switch_ino_t; + typedef dev_t switch_dev_t; +#endif + typedef off_t switch_off_t; + +/** + * Structure for referencing file information + */ +//typedef struct apr_stat_t switch_finfo_t; +typedef struct { + /** Allocates memory and closes lingering handles in the specified pool */ + switch_memory_pool_t *pool; + /** The bitmask describing valid fields of this switch_finfo_t structure + * including all available 'wanted' fields and potentially more */ + int32_t valid; + /** The access permissions of the file. Mimics Unix access rights. */ + switch_fileperms_t protection; + /** The type of file. One of APR_REG, APR_DIR, APR_CHR, APR_BLK, APR_PIPE, + * APR_LNK or APR_SOCK. If the type is undetermined, the value is APR_NOFILE. + * If the type cannot be determined, the value is APR_UNKFILE. + */ + switch_filetype_e filetype; + /** The user id that owns the file */ + switch_uid_t user; + /** The group id that owns the file */ + switch_gid_t group; + /** The inode of the file. */ + switch_ino_t inode; + /** The id of the device the file is on. */ + switch_dev_t device; + /** The number of hard links to the file. */ + int32_t nlink; + /** The size of the file */ + switch_off_t size; + /** The storage size consumed by the file */ + switch_off_t csize; + /** The time the file was last accessed */ + switch_time_t atime; + /** The time the file was last modified */ + switch_time_t mtime; + /** The time the file was created, or the inode was last changed */ + switch_time_t ctime; + /** The pathname of the file (possibly unrooted) */ + const char *fname; + /** The file's name (no path) in filesystem case */ + const char *name; + /** The file's handle, if accessed (can be submitted to apr_duphandle) */ + switch_file_t *filehand; +} switch_finfo_t; + + /** * @defgroup apr_file_seek_flags File Seek Flags * @{ @@ -739,6 +826,37 @@ SWITCH_DECLARE(switch_status_t) switch_queue_trypush(switch_queue_t *queue, void #define SWITCH_FOPEN_LARGEFILE 0x04000 /**< Platform dependent flag to enable large file support */ /** @} */ +/** + * @defgroup switch_file_stat flags + * @ingroup switch_file_io + * @{ + */ +#define SWITCH_FINFO_LINK 0x00000001 /**< Stat the link not the file itself if it is a link */ +#define SWITCH_FINFO_MTIME 0x00000010 /**< Modification Time */ +#define SWITCH_FINFO_CTIME 0x00000020 /**< Creation or inode-changed time */ +#define SWITCH_FINFO_ATIME 0x00000040 /**< Access Time */ +#define SWITCH_FINFO_SIZE 0x00000100 /**< Size of the file */ +#define SWITCH_FINFO_CSIZE 0x00000200 /**< Storage size consumed by the file */ +#define SWITCH_FINFO_DEV 0x00001000 /**< Device */ +#define SWITCH_FINFO_INODE 0x00002000 /**< Inode */ +#define SWITCH_FINFO_NLINK 0x00004000 /**< Number of links */ +#define SWITCH_FINFO_TYPE 0x00008000 /**< Type */ +#define SWITCH_FINFO_USER 0x00010000 /**< User */ +#define SWITCH_FINFO_GROUP 0x00020000 /**< Group */ +#define SWITCH_FINFO_UPROT 0x00100000 /**< User protection bits */ +#define SWITCH_FINFO_GPROT 0x00200000 /**< Group protection bits */ +#define SWITCH_FINFO_WPROT 0x00400000 /**< World protection bits */ +#define SWITCH_FINFO_ICASE 0x01000000 /**< if dev is case insensitive */ +#define SWITCH_FINFO_NAME 0x02000000 /**< ->name in proper case */ + +#define SWITCH_FINFO_MIN 0x00008170 /**< type, mtime, ctime, atime, size */ +#define SWITCH_FINFO_IDENT 0x00003000 /**< dev and inode */ +#define SWITCH_FINFO_OWNER 0x00030000 /**< user and group */ +#define SWITCH_FINFO_PROT 0x00700000 /**< all protections */ +#define SWITCH_FINFO_NORM 0x0073b170 /**< an atomic unix apr_stat() */ +#define SWITCH_FINFO_DIRENT 0x02000000 /**< an atomic unix apr_dir_read() */ +/** @} */ + /** * Open the specified file. * @param newf The opened file descriptor. @@ -782,6 +900,8 @@ SWITCH_DECLARE(switch_status_t) switch_file_seek(switch_file_t *thefile, switch_ SWITCH_DECLARE(switch_status_t) switch_file_copy(const char *from_path, const char *to_path, switch_fileperms_t perms, switch_memory_pool_t *pool); +SWITCH_DECLARE(switch_status_t) switch_file_stat(switch_finfo_t *finfo, const char *fname, int32_t wanted, switch_memory_pool_t *pool); + /** * Close the specified file. * @param thefile The file descriptor to close. diff --git a/src/switch_apr.c b/src/switch_apr.c index bdff179b4a..b0f736720f 100644 --- a/src/switch_apr.c +++ b/src/switch_apr.c @@ -416,6 +416,18 @@ SWITCH_DECLARE(switch_status_t) switch_file_copy(const char *from_path, const ch return apr_file_copy(from_path, to_path, perms, pool); } +SWITCH_DECLARE(switch_status_t) switch_file_stat(switch_finfo_t *finfo, const char *fname, int32_t wanted, switch_memory_pool_t *pool) +{ + apr_status_t status; + apr_finfo_t aprinfo; + if (sizeof(*finfo) != sizeof(aprinfo)) { + return SWITCH_STATUS_MEMERR; + } + status = apr_stat(&aprinfo, fname, wanted, pool); + memcpy(finfo, &aprinfo, sizeof(*finfo)); + return status; +} + SWITCH_DECLARE(switch_status_t) switch_file_close(switch_file_t *thefile) { From b106d590bcad3976a30fc358c81ecc6e650484ec Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 17 Sep 2010 18:46:09 -0400 Subject: [PATCH 013/822] add support for deleting old logfiles (maxfilecount parameter for mod_logfile) --- src/mod/loggers/mod_logfile/mod_logfile.c | 65 +++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/mod/loggers/mod_logfile/mod_logfile.c b/src/mod/loggers/mod_logfile/mod_logfile.c index 8cdaf9615a..77fcfe09bd 100644 --- a/src/mod/loggers/mod_logfile/mod_logfile.c +++ b/src/mod/loggers/mod_logfile/mod_logfile.c @@ -53,6 +53,7 @@ struct logfile_profile { char *name; switch_size_t log_size; /* keep the log size in check for rotation */ switch_size_t roll_size; /* the size that we want to rotate the file at */ + uint32_t max_file_count; /* Max number of log files */ char *logfile; switch_file_t *log_afd; switch_hash_t *log_hash; @@ -114,6 +115,8 @@ static switch_status_t mod_logfile_openlogfile(logfile_profile_t *profile, switc static switch_status_t mod_logfile_rotate(logfile_profile_t *profile) { unsigned int i = 0; + unsigned int fcount = 0; + const char *fname = NULL; char *filename = NULL; switch_status_t stat = 0; int64_t offset = 0; @@ -121,6 +124,15 @@ static switch_status_t mod_logfile_rotate(logfile_profile_t *profile) switch_time_exp_t tm; char date[80] = ""; switch_size_t retsize; + char *dend = NULL; + char *hay = NULL; + switch_dir_t *dirhandle = NULL; + switch_time_t wtime = 0; + char dirname[128]; + char filebuf[128]; + char fullfile[512]; + char filetodelete[128]; + switch_finfo_t statinfo; switch_status_t status = SWITCH_STATUS_SUCCESS; switch_mutex_lock(globals.mutex); @@ -157,6 +169,54 @@ static switch_status_t mod_logfile_rotate(logfile_profile_t *profile) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "New log started.\n"); + if (profile->max_file_count) { + switch_copy_string(dirname, profile->logfile, sizeof(dirname)); + dend = strstr(dirname, SWITCH_PATH_SEPARATOR); + if (dend) { + dend++; + while ((hay = strstr(dend, SWITCH_PATH_SEPARATOR))) { + hay += strlen(SWITCH_PATH_SEPARATOR); + dend = hay; + } + *dend = '\0'; +scanning: + status = switch_dir_open(&dirhandle, dirname, pool); + if (status != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open directory: %s\n", dirname); + goto end; + } + + wtime = switch_time_now(); + while ((fname = switch_dir_next_file(dirhandle, filebuf, sizeof(filebuf)))) { + memset(&statinfo, 0, sizeof(statinfo)); + snprintf(fullfile, sizeof(fullfile), "%s%s", dirname, fname); + if (strstr(fullfile, profile->logfile)) { + if (switch_file_stat(&statinfo, fullfile, SWITCH_FINFO_CTIME, pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to stat file %s\n", fullfile); + continue; + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "File: %s has stat %llu, size = %llu\n", fullfile, (unsigned long long)statinfo.ctime, (unsigned long long)statinfo.size); + if (statinfo.ctime < wtime) { + switch_copy_string(filetodelete, fullfile, sizeof(filetodelete)); + wtime = statinfo.ctime; + } + fcount++; + } + } + if (fcount > profile->max_file_count) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Deleting old logfile: %s\n", filetodelete); + switch_file_remove(filetodelete, pool); + fcount--; + } + switch_dir_close(dirhandle); + if (fcount > profile->max_file_count) { + goto scanning; + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "No separator %s found in %s\n", SWITCH_PATH_SEPARATOR, dirname); + } + } + end: if (pool) { @@ -271,6 +331,11 @@ static switch_status_t load_profile(switch_xml_t xml) if (new_profile->roll_size < 0) { new_profile->roll_size = 0; } + } else if (!strcmp(var, "maxfilecount")) { + new_profile->max_file_count = atoi(val); + if (new_profile->max_file_count < 1) { + new_profile->max_file_count = 1; + } } else if (!strcmp(var, "uuid") && switch_true(val)) { new_profile->log_uuid = SWITCH_TRUE; } From 85f405703d1fdd8d32d73eb2ba09a91b4bc6e199 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 28 Sep 2010 10:47:16 -0400 Subject: [PATCH 014/822] freetdm: stop scheduler but do not destroy it until the very end --- libs/freetdm/src/ftdm_io.c | 19 ++++++++----------- libs/freetdm/src/ftdm_sched.c | 18 ++++++++++++++++++ libs/freetdm/src/include/private/ftdm_sched.h | 3 +++ 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 299106f599..79d55c4d16 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -4932,16 +4932,19 @@ FT_DECLARE(uint32_t) ftdm_running(void) FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void) { ftdm_span_t *sp; - uint32_t sanity = 100; time_end(); + /* many freetdm event loops rely on this variable to decide when to stop, do this first */ globals.running = 0; - ftdm_sched_destroy(&globals.timingsched); + /* stop the scheduling thread */ + ftdm_free_sched_stop(); + /* stop the cpu monitor thread */ ftdm_cpu_monitor_stop(); + /* now destroy channels and spans */ globals.span_index = 0; ftdm_span_close_all(); @@ -4966,18 +4969,12 @@ FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void) globals.spans = NULL; ftdm_mutex_unlock(globals.span_mutex); + /* destroy signaling and io modules */ ftdm_unload_modules(); - while (ftdm_free_sched_running() && --sanity) { - ftdm_log(FTDM_LOG_DEBUG, "Waiting for schedule thread to finish\n"); - ftdm_sleep(100); - } - - if (!sanity) { - ftdm_log(FTDM_LOG_CRIT, "schedule thread did not stop running, we may crash on shutdown\n"); - } - + /* finally destroy the globals */ ftdm_mutex_lock(globals.mutex); + ftdm_sched_destroy(&globals.timingsched); hashtable_destroy(globals.interface_hash); hashtable_destroy(globals.module_hash); hashtable_destroy(globals.span_hash); diff --git a/libs/freetdm/src/ftdm_sched.c b/libs/freetdm/src/ftdm_sched.c index be21696d71..47df7d973c 100644 --- a/libs/freetdm/src/ftdm_sched.c +++ b/libs/freetdm/src/ftdm_sched.c @@ -176,6 +176,24 @@ FT_DECLARE(ftdm_bool_t) ftdm_free_sched_running(void) return sched_globals.running; } +FT_DECLARE(ftdm_bool_t) ftdm_free_sched_stop(void) +{ + /* currently we really dont stop the thread here, we rely on freetdm being shutdown and ftdm_running() to be false + * so the scheduling thread dies and we just wait for it here */ + uint32_t sanity = 100; + while (ftdm_free_sched_running() && --sanity) { + ftdm_log(FTDM_LOG_DEBUG, "Waiting for main schedule thread to finish\n"); + ftdm_sleep(100); + } + + if (!sanity) { + ftdm_log(FTDM_LOG_CRIT, "schedule thread did not stop running, we may crash on shutdown\n"); + return FTDM_FALSE; + } + + return FTDM_TRUE; +} + FT_DECLARE(ftdm_status_t) ftdm_sched_create(ftdm_sched_t **sched, const char *name) { ftdm_sched_t *newsched = NULL; diff --git a/libs/freetdm/src/include/private/ftdm_sched.h b/libs/freetdm/src/include/private/ftdm_sched.h index 9a222896f5..c1818d8bb5 100644 --- a/libs/freetdm/src/include/private/ftdm_sched.h +++ b/libs/freetdm/src/include/private/ftdm_sched.h @@ -95,6 +95,9 @@ FT_DECLARE(ftdm_status_t) ftdm_sched_global_init(void); /*! \brief Checks if the main scheduling thread is running */ FT_DECLARE(ftdm_bool_t) ftdm_free_sched_running(void); +/*! \brief Stop the main scheduling thread (if running) */ +FT_DECLARE(ftdm_bool_t) ftdm_free_sched_stop(void); + #ifdef __cplusplus } #endif From a165917a3d7c5d9d6981c39b6bb1f4440dd053d0 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Thu, 30 Sep 2010 08:04:45 -0700 Subject: [PATCH 015/822] Fix for structure size mismatch in switch_file_stat --- src/include/switch_apr.h | 2 +- src/switch_apr.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/include/switch_apr.h b/src/include/switch_apr.h index 84fcb61004..b049c05d40 100644 --- a/src/include/switch_apr.h +++ b/src/include/switch_apr.h @@ -692,7 +692,7 @@ typedef gid_t switch_gid_t; typedef ino_t switch_ino_t; typedef dev_t switch_dev_t; #endif - typedef off_t switch_off_t; + typedef off64_t switch_off_t; /** * Structure for referencing file information diff --git a/src/switch_apr.c b/src/switch_apr.c index b0f736720f..9a46b112c6 100644 --- a/src/switch_apr.c +++ b/src/switch_apr.c @@ -421,6 +421,7 @@ SWITCH_DECLARE(switch_status_t) switch_file_stat(switch_finfo_t *finfo, const ch apr_status_t status; apr_finfo_t aprinfo; if (sizeof(*finfo) != sizeof(aprinfo)) { + fprintf(stderr, "Error:structure file mismatch switch_finfo_t:%u apr_finfo_t:%u\n", sizeof(*finfo), sizeof(aprinfo)); return SWITCH_STATUS_MEMERR; } status = apr_stat(&aprinfo, fname, wanted, pool); From 8c4cc6d95bbc6a48dc96d15ede069c861c020fe5 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Thu, 30 Sep 2010 13:49:40 -0400 Subject: [PATCH 016/822] Fix for compilation issue, introduced in previous commit --- src/switch_apr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/switch_apr.c b/src/switch_apr.c index 9a46b112c6..bc1af4678b 100644 --- a/src/switch_apr.c +++ b/src/switch_apr.c @@ -421,7 +421,7 @@ SWITCH_DECLARE(switch_status_t) switch_file_stat(switch_finfo_t *finfo, const ch apr_status_t status; apr_finfo_t aprinfo; if (sizeof(*finfo) != sizeof(aprinfo)) { - fprintf(stderr, "Error:structure file mismatch switch_finfo_t:%u apr_finfo_t:%u\n", sizeof(*finfo), sizeof(aprinfo)); + fprintf(stderr, "Error:structure file mismatch switch_finfo_t:%zd apr_finfo_t:%zd\n", sizeof(*finfo), sizeof(aprinfo)); return SWITCH_STATUS_MEMERR; } status = apr_stat(&aprinfo, fname, wanted, pool); From a00f7ccd9428bc24144048c5cca24334557baf25 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Thu, 30 Sep 2010 14:50:02 -0700 Subject: [PATCH 017/822] Fix for compilation error --- src/switch_apr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/switch_apr.c b/src/switch_apr.c index 9a46b112c6..bc1af4678b 100644 --- a/src/switch_apr.c +++ b/src/switch_apr.c @@ -421,7 +421,7 @@ SWITCH_DECLARE(switch_status_t) switch_file_stat(switch_finfo_t *finfo, const ch apr_status_t status; apr_finfo_t aprinfo; if (sizeof(*finfo) != sizeof(aprinfo)) { - fprintf(stderr, "Error:structure file mismatch switch_finfo_t:%u apr_finfo_t:%u\n", sizeof(*finfo), sizeof(aprinfo)); + fprintf(stderr, "Error:structure file mismatch switch_finfo_t:%zd apr_finfo_t:%zd\n", sizeof(*finfo), sizeof(aprinfo)); return SWITCH_STATUS_MEMERR; } status = apr_stat(&aprinfo, fname, wanted, pool); From 63533ed0ae6f46973756fedebeb65619d2cdf339 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Thu, 30 Sep 2010 11:41:47 -0400 Subject: [PATCH 018/822] Fix for not handling a call state Fix for MSN on BRI --- .../ftmod_sangoma_isdn/ftmod_sangoma_isdn.c | 15 ++++-- .../ftmod_sangoma_isdn/ftmod_sangoma_isdn.h | 7 ++- .../ftmod_sangoma_isdn_cfg.c | 18 +++++++ .../ftmod_sangoma_isdn_stack_hndl.c | 54 +++++++++++++++---- .../ftmod_sangoma_isdn_stack_rcv.c | 2 +- .../ftmod_sangoma_isdn_support.c | 6 ++- 6 files changed, 83 insertions(+), 19 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c index 08f340dc83..0ed5902153 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c @@ -726,7 +726,7 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_set_span_sig_status) } static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span) -{ +{ ftdm_log(FTDM_LOG_INFO,"Starting span %s:%u.\n",span->name,span->span_id); if (sng_isdn_stack_start(span) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_CRIT, "Failed to start span %s\n", span->name); @@ -747,9 +747,11 @@ static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span) } static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span) -{ +{ ftdm_iterator_t *chaniter = NULL; ftdm_iterator_t *curr = NULL; + unsigned i; + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data; ftdm_log(FTDM_LOG_INFO, "Stopping span %s\n", span->name); /* throw the STOP_THREAD flag to signal monitor thread stop */ @@ -772,8 +774,13 @@ static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span) } ftdm_iterator_free(chaniter); - ftdm_sched_destroy(&((sngisdn_span_data_t*)span->signal_data)->sched); - ftdm_queue_destroy(&((sngisdn_span_data_t*)span->signal_data)->event_queue); + ftdm_sched_destroy(&signal_data->sched); + ftdm_queue_destroy(&signal_data->event_queue); + for (i = 0 ; i < signal_data->num_local_numbers ; i++) { + if (signal_data->local_numbers[i] != NULL) { + ftdm_safe_free(signal_data->local_numbers[i]); + } + } ftdm_safe_free(span->signal_data); ftdm_log(FTDM_LOG_DEBUG, "Finished stopping span %s\n", span->name); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h index ae6c0d92f7..bc928354a7 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h @@ -55,6 +55,7 @@ #define NUM_BRI_CHANNELS_PER_SPAN 2 #define SNGISDN_EVENT_QUEUE_SIZE 100 #define SNGISDN_EVENT_POLL_RATE 100 +#define SNGISDN_NUM_LOCAL_NUMBERS 8 /* TODO: rename all *_cc_* to *_an_* */ @@ -161,7 +162,7 @@ typedef struct sngisdn_chan_data { /* Span specific data */ typedef struct sngisdn_span_data { - ftdm_span_t *ftdm_span; + ftdm_span_t *ftdm_span; uint8_t link_id; uint8_t switchtype; uint8_t signalling; /* SNGISDN_SIGNALING_CPE or SNGISDN_SIGNALING_NET */ @@ -175,7 +176,9 @@ typedef struct sngisdn_span_data { uint8_t setup_arb; uint8_t facility; int8_t facility_timeout; - ftdm_sched_t *sched; + uint8_t num_local_numbers; + char* local_numbers[SNGISDN_NUM_LOCAL_NUMBERS]; + ftdm_sched_t *sched; ftdm_queue_t *event_queue; } sngisdn_span_data_t; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c index 361b389f96..64d7a2403f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c @@ -36,9 +36,23 @@ ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span); ftdm_status_t parse_signalling(const char* signalling, ftdm_span_t *span); +ftdm_status_t add_local_number(const char* val, ftdm_span_t *span); extern ftdm_sngisdn_data_t g_sngisdn_data; +ftdm_status_t add_local_number(const char* val, ftdm_span_t *span) +{ + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data; + + if (signal_data->num_local_numbers >= SNGISDN_NUM_LOCAL_NUMBERS) { + ftdm_log(FTDM_LOG_ERROR, "%s: Maximum number of local-numbers exceeded (max:%d)\n", span->name, SNGISDN_NUM_LOCAL_NUMBERS); + return FTDM_FAIL; + } + + signal_data->local_numbers[signal_data->num_local_numbers++] = ftdm_strdup(val); + return FTDM_SUCCESS; +} + ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span) { unsigned i; @@ -253,6 +267,10 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_ ftdm_span_set_bearer_capability(val, &span->default_caller_data.bearer_capability); } else if (!strcasecmp(var, "outbound-bearer_layer1")) { ftdm_span_set_bearer_layer1(val, &span->default_caller_data.bearer_layer1); + } else if (!strcasecmp(var, "local-number")) { + if (add_local_number(val, span) != FTDM_SUCCESS) { + return FTDM_FAIL; + } } else if (!strcasecmp(var, "facility-timeout")) { signal_data->facility_timeout = atoi(val); if (signal_data->facility_timeout < 0) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c index b7af8e98c5..827647f1f6 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c @@ -43,7 +43,7 @@ extern ftdm_status_t cpy_calling_name_from_stack(ftdm_caller_data_t *ftdm, Displ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); - + unsigned i; int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; @@ -57,7 +57,7 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n"); ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); - + switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_DOWN: /* Proper state to receive a SETUP */ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE) || @@ -80,11 +80,35 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) sngisdn_info->suInstId = get_unique_suInstId(suId); sngisdn_info->spInstId = spInstId; + if (conEvnt->cdPtyNmb.eh.pres && signal_data->num_local_numbers) { + uint8_t local_number_matched = 0; + for (i = 0 ; i < signal_data->num_local_numbers ; i++) { + if (!strcmp(signal_data->local_numbers[i], (char*)conEvnt->cdPtyNmb.nmbDigits.val)) { + local_number_matched++; + break; + } + } + if (!local_number_matched) { + ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received SETUP, but local-number %s does not match - ignoring\n", conEvnt->cdPtyNmb.nmbDigits.val); + /* Special case to tell the stack to clear all internal resources about this call. We will no receive any event for this call after sending disconnect request */ + ftdmchan->caller_data.hangup_cause = IN_CCNORTTODEST; + ftdm_sched_timer(signal_data->sched, "delayed_disconnect", 1, sngisdn_delayed_disconnect, (void*) sngisdn_info, NULL); + return; + } + } + /* If this is a glared call that was previously saved, we moved all the info to the current call, so clear the glared saved data */ if (sngisdn_info->glare.spInstId == spInstId) { clear_call_glare_data(sngisdn_info); - } + } + + + if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) { + if (signal_data->signalling == SNGISDN_SIGNALING_NET) { + sngisdn_info->ces = ces; + } + } ftdm_mutex_lock(g_sngisdn_data.ccs[suId].mutex); g_sngisdn_data.ccs[suId].active_suInstIds[sngisdn_info->suInstId] = sngisdn_info; @@ -92,11 +116,6 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND); - if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP && - signal_data->signalling == SNGISDN_SIGNALING_NET) { - sngisdn_info->ces = ces; - } - /* try to open the channel */ if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to open channel"); @@ -122,14 +141,13 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) ftdmchan->caller_data.bearer_layer1 = sngisdn_get_infoTranCap_from_stack(conEvnt->bearCap[0].usrInfoLyr1Prot.val); ftdmchan->caller_data.bearer_capability = sngisdn_get_infoTranCap_from_stack(conEvnt->bearCap[0].infoTranCap.val); } - + if (signal_data->switchtype == SNGISDN_SWITCH_NI2) { if (conEvnt->shift11.eh.pres && conEvnt->ni2OctStr.eh.pres) { if (conEvnt->ni2OctStr.str.len == 4 && conEvnt->ni2OctStr.str.val[0] == 0x37) { snprintf(ftdmchan->caller_data.aniII, 5, "%.2d", conEvnt->ni2OctStr.str.val[3]); } } - if (signal_data->facility == SNGISDN_OPT_TRUE && conEvnt->facilityStr.eh.pres) { /* Verify whether the Caller Name will come in a subsequent FACILITY message */ @@ -260,6 +278,10 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event) case FTDM_CHANNEL_STATE_DIALING: ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP); break; + case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: + case FTDM_CHANNEL_STATE_HANGUP: + /* Race condition, we just hung up the call - ignore this message */ + break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Processing CONNECT/CONNECT ACK in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state)); @@ -274,7 +296,7 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event) /* do nothing */ break; case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: - /* We just hung up an incoming call right after we sent a CONNECT so ignore this message */ + /* Race condition, We just hung up an incoming call right after we sent a CONNECT - ignore this message */ break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Processing CONNECT/CONNECT ACK in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state)); @@ -923,6 +945,16 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event) break; } break; + case 12: /* We received a disconnect indication */ + switch (ftdmchan->state) { + case FTDM_CHANNEL_STATE_TERMINATING: + /* We are already waiting for user app to handle the disconnect, do nothing */ + break; + default: + ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); + break; + } + break; case 22: switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_UP: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c index 791c6b7d8c..9bf60537fe 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c @@ -706,7 +706,7 @@ void sngisdn_rcv_q931_ind(InMngmt *status) ftdm_span_t *ftdmspan; sngisdn_span_data_t *signal_data = g_sngisdn_data.spans[status->t.usta.suId]; if (!signal_data) { - ftdm_log(FTDM_LOG_INFO, "Received q921 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.suId); + ftdm_log(FTDM_LOG_INFO, "Received q931 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.suId); return; } ftdmspan = signal_data->ftdm_span; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c index db22fe5ce8..691e3104c0 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c @@ -424,11 +424,15 @@ void sngisdn_delayed_disconnect(void* p_sngisdn_info) sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; ftdm_mutex_lock(ftdmchan->mutex); - if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) { + if (ftdmchan->caller_data.hangup_cause == IN_CCNORTTODEST || ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) { ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending delayed DISCONNECT (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->glare.spInstId, sngisdn_info->glare.suInstId); sngisdn_snd_disconnect(ftdmchan); + if (ftdmchan->caller_data.hangup_cause == IN_CCNORTTODEST) { + ftdm_channel_t *close_chan = ftdmchan; + ftdm_channel_close(&close_chan); + } } ftdm_mutex_unlock(ftdmchan->mutex); From 4a9edf679fd0bc21655c43a111974309036fa0c4 Mon Sep 17 00:00:00 2001 From: Konrad Hammel Date: Thu, 10 Feb 2011 16:26:40 -0500 Subject: [PATCH 019/822] bug fix for mod_sofia, sofia_contact_user_replacement was off by 1 when replacing the dialed number causing it to not copy anything --- src/mod/endpoints/mod_sofia/mod_sofia.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 8f1a374aa4..8e31e13864 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -3588,7 +3588,7 @@ SWITCH_STANDARD_API(sofia_contact_function) newptr = newreply; /* pointer to the end of the allocated buffer for safety checks */ - bufend = newreply + allocsize - 1; + bufend = newreply + allocsize; *bufend = 0; /* go thru all the urls and replace the user part */ From 94e6bcfd2be07308c91da7ac15ea226059a05614 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 28 Feb 2011 16:36:28 -0500 Subject: [PATCH 020/822] mod_sofia: fix bugzilla 6341 - dialplan not replacing user in contact string --- src/mod/endpoints/mod_sofia/mod_sofia.c | 184 ++++++++++++------------ 1 file changed, 93 insertions(+), 91 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 5ce681880c..82f4c2ca02 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -3552,97 +3552,6 @@ SWITCH_STANDARD_API(sofia_contact_function) } } - if (user_replacement) { - int urlcount = 0; - int copyerr = 0; - char *newreply = NULL; - char *urlstart = NULL; - char *newptr = NULL; - char *bufend = NULL; - char *str = reply; - switch_size_t copysize = 0; - switch_size_t replacesize = strlen(user_replacement); - switch_size_t allocsize = 0; - - /* first pass to count how many URLs we have */ - while ((urlstart = strcasestr(str, "sip:")) || (urlstart = strcasestr(str, "sips:"))) { - urlcount++; - str = urlstart + 4; - } - - if (!urlcount) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): no sip URLs found to replace the user\n"); - copyerr++; - goto copydone; - } - - /* this allocates a bit more than needed but better safe than sorry doing more funky math */ - allocsize = strlen(reply) + (urlcount * replacesize); - newreply = switch_core_session_alloc(session, allocsize); - if (!newreply) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): no buffer space available for replacement\n"); - copyerr++; - goto copydone; - } - - /* get a working pointer to the new reply */ - newptr = newreply; - - /* pointer to the end of the allocated buffer for safety checks */ - bufend = newreply + allocsize; - *bufend = 0; - - /* go thru all the urls and replace the user part */ - str = reply; - while ((urlstart = strcasestr(str, "sip:")) || (urlstart = strcasestr(str, "sips:"))) { - - /* found an URL, copy up to the start of the url */ - copysize = ( urlstart - str ) + 4; - - /* double check boundaries before copying anything at all (this should not happen) */ - if ((newptr + copysize + replacesize) >= bufend) { - copyerr++; - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): wow buffer was not big enough!\n"); - break; - } - - /* copy the original contact string except for the user */ - memcpy(newptr, str, copysize); - newptr += copysize; - - /* copy the user replacement */ - memcpy(newptr, user_replacement, replacesize); - newptr += replacesize; - - /* skip the original user part */ - str = strchr(urlstart, '@'); - if (!str) { - copyerr++; - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): not host part found for contact\n"); - break; - } - /* continue searching for the next sip: URL */ - } - -copydone: - if (!copyerr) { - /* copy the remaining reply string */ - copysize = strlen(str); - if ((newptr + copysize) >= bufend) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): wow buffer was not big enough, close, but not enough!\n"); - } else { - strcpy(newptr, str); - reply = newreply; - } - } else { - reply = "error/replacement error"; - } - } - - stream->write_function(stream, "%s", reply); - reply = NULL; - - switch_safe_free(mystream.data); } switch_mutex_unlock(mod_sofia_globals.hash_mutex); @@ -3650,6 +3559,99 @@ copydone: reply = (char *) mystream.data; + if (user_replacement) { + int urlcount = 0; + int copyerr = 0; + char *newreply = NULL; + char *urlstart = NULL; + char *newptr = NULL; + char *bufend = NULL; + char *str = reply; + switch_size_t copysize = 0; + switch_size_t replacesize = strlen(user_replacement); + switch_size_t allocsize = 0; + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sofia_contact(): trying to replace %s in %s\n", + user_replacement, str); + + /* first pass to count how many URLs we have */ + while ((urlstart = strcasestr(str, "sip:")) || (urlstart = strcasestr(str, "sips:"))) { + urlcount++; + str = urlstart + 4; + } + + if (!urlcount) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): no sip URLs found to replace the user\n"); + copyerr++; + goto copydone; + } + + /* this allocates a bit more than needed but better safe than sorry doing more funky math */ + allocsize = strlen(reply) + (urlcount * replacesize); + newreply = switch_core_session_alloc(session, allocsize); + if (!newreply) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): no buffer space available for replacement\n"); + copyerr++; + goto copydone; + } + + /* get a working pointer to the new reply */ + newptr = newreply; + + /* pointer to the end of the allocated buffer for safety checks */ + bufend = newreply + allocsize; + *bufend = 0; + + /* go thru all the urls and replace the user part */ + str = reply; + while ((urlstart = strcasestr(str, "sip:")) || (urlstart = strcasestr(str, "sips:"))) { + + /* found an URL, copy up to the start of the url */ + copysize = ( urlstart - str ) + 4; + + /* double check boundaries before copying anything at all (this should not happen) */ + if ((newptr + copysize + replacesize) >= bufend) { + copyerr++; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): wow buffer was not big enough!\n"); + break; + } + + /* copy the original contact string except for the user */ + memcpy(newptr, str, copysize); + newptr += copysize; + + /* copy the user replacement */ + memcpy(newptr, user_replacement, replacesize); + newptr += replacesize; + + /* skip the original user part */ + str = strchr(urlstart, '@'); + if (!str) { + copyerr++; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): not host part found for contact\n"); + break; + } + /* continue searching for the next sip: URL */ + } + +copydone: + if (!copyerr) { + /* copy the remaining reply string */ + copysize = strlen(str); + if ((newptr + copysize) >= bufend) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): wow buffer was not big enough, close, but not enough!\n"); + } else { + strcpy(newptr, str); + reply = newreply; + goto end; + } + } else { + /* on error, we do nothing and just default to the original stream returned (mystream.data) */ + } + } + + reply = (char *) mystream.data; + end: if (zstr(reply)) { From 6692a70c52db01b1206cc153a0967226f18cb310 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 1 Mar 2011 12:31:35 -0500 Subject: [PATCH 021/822] set default smg event socket port to 8821 instead of 8021 which is for FreeSWITCH event socket --- libs/esl/fs_cli.c | 6 +++--- libs/esl/fs_cli.conf | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/esl/fs_cli.c b/libs/esl/fs_cli.c index 5a52c63085..749c8df167 100644 --- a/libs/esl/fs_cli.c +++ b/libs/esl/fs_cli.c @@ -1040,7 +1040,7 @@ int main(int argc, char *argv[]) strncpy(internal_profile.host, "127.0.0.1", sizeof(internal_profile.host)); strncpy(internal_profile.pass, "ClueCon", sizeof(internal_profile.pass)); strncpy(internal_profile.name, "internal", sizeof(internal_profile.name)); - internal_profile.port = 8021; + internal_profile.port = 8821; set_fn_keys(&internal_profile); @@ -1139,7 +1139,7 @@ int main(int argc, char *argv[]) esl_set_string(profiles[pcount].name, cur_cat); esl_set_string(profiles[pcount].host, "localhost"); esl_set_string(profiles[pcount].pass, "ClueCon"); - profiles[pcount].port = 8021; + profiles[pcount].port = 8821; set_fn_keys(&profiles[pcount]); esl_log(ESL_LOG_DEBUG, "Found Profile [%s]\n", profiles[pcount].name); pcount++; @@ -1218,7 +1218,7 @@ int main(int argc, char *argv[]) esl_log(ESL_LOG_DEBUG, "Using profile %s [%s]\n", profile->name, profile->host); if (argv_host) { - if (argv_port && profile->port != 8021) { + if (argv_port && profile->port != 8821) { snprintf(prompt_str, sizeof(prompt_str), PROMPT_PREFIX "@%s:%u@%s> ", profile->host, profile->port, profile->name); } else { snprintf(prompt_str, sizeof(prompt_str), PROMPT_PREFIX "@%s@%s> ", profile->host, profile->name); diff --git a/libs/esl/fs_cli.conf b/libs/esl/fs_cli.conf index 34932df48a..47de41be70 100644 --- a/libs/esl/fs_cli.conf +++ b/libs/esl/fs_cli.conf @@ -4,7 +4,7 @@ host => 127.0.0.1 password => ClueCon -port => 8021 +port => 8821 debug => 2 key_f1 => help From a60086cd22766fd9b9dc0ccfe243d12b47d958c5 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 11 Mar 2011 17:39:07 -0500 Subject: [PATCH 022/822] Changed Freeswitch core to return with error instead of abort when a critical module fails to load --- src/switch_loadable_module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/switch_loadable_module.c b/src/switch_loadable_module.c index d6796c8119..fe596bdf6b 100644 --- a/src/switch_loadable_module.c +++ b/src/switch_loadable_module.c @@ -1300,7 +1300,7 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_init(switch_bool_t autolo if (switch_loadable_module_load_module_ex((char *) path, (char *) val, SWITCH_FALSE, global, &err) == SWITCH_STATUS_GENERR) { if (critical && switch_true(critical)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to load critical module '%s', abort()\n", val); - abort(); + return SWITCH_STATUS_FALSE; } } count++; From 89a2ca8d008c4782d7e1895ead7f2d63d2b9036b Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 5 May 2011 18:17:30 -0400 Subject: [PATCH 023/822] rename to NBE SS7 --- libs/esl/fs_cli.c | 22 +++++++++++----------- src/mod/endpoints/mod_sofia/mod_sofia.h | 2 +- src/switch.c | 4 ++-- src/switch_core.c | 21 ++++++++++----------- 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/libs/esl/fs_cli.c b/libs/esl/fs_cli.c index 8006297ddd..d7130fd2d2 100644 --- a/libs/esl/fs_cli.c +++ b/libs/esl/fs_cli.c @@ -8,7 +8,7 @@ #include #define CMD_BUFLEN 1024 -#define PROMPT_PREFIX "sangoma-media-gateway" +#define PROMPT_PREFIX "netborder-ss7" static int WARN_STOP = 0; #ifdef WIN32 @@ -854,7 +854,7 @@ static void print_banner(FILE *stream) "\n" "*******************************************************\n" - "* Sangoma Media Gateway *\n" + "* Netborder SS7 Gateway *\n" "* Powered by FreeSWITCH (http://www.freeswitch.org) *\n" "*******************************************************\n" "\n" @@ -1002,13 +1002,13 @@ int main(int argc, char *argv[]) int rv = 0; #ifndef WIN32 - char hfile[512] = "/etc/smg_cli_history"; - char cfile[512] = "/etc/smg_cli.conf"; - char dft_cfile[512] = "/etc/smg_cli.conf"; + char hfile[512] = "/etc/nbess7_cli_history"; + char cfile[512] = "/etc/nbess7_cli.conf"; + char dft_cfile[512] = "/etc/nbess7_cli.conf"; #else - char hfile[512] = "smg_cli_history"; - char cfile[512] = "smg_cli.conf"; - char dft_cfile[512] = "smg_cli.conf"; + char hfile[512] = "nbess7_cli_history"; + char cfile[512] = "nbess7_cli.conf"; + char dft_cfile[512] = "nbess7_cli.conf"; #endif char *home = getenv("HOME"); /* Vars for optargs */ @@ -1054,8 +1054,8 @@ int main(int argc, char *argv[]) if (home) { - snprintf(hfile, sizeof(hfile), "%s/.smg_cli_history", home); - snprintf(cfile, sizeof(cfile), "%s/.smg_cli_conf", home); + snprintf(hfile, sizeof(hfile), "%s/.nbess7_cli_history", home); + snprintf(cfile, sizeof(cfile), "%s/.nbess7_cli_conf", home); } signal(SIGINT, handle_SIGINT); @@ -1368,7 +1368,7 @@ int main(int argc, char *argv[]) print_banner(stdout); - esl_log(ESL_LOG_INFO, "Sangoma Media Gateway CLI Ready.\nenter /help for a list of commands.\n"); + esl_log(ESL_LOG_INFO, "Netborder SS7 CLI Ready.\nenter /help for a list of commands.\n"); printf("%s\n", handle.last_sr_reply); while (running > 0) { diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 01aa8412a1..75efdd6e40 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -90,7 +90,7 @@ typedef struct private_object private_object_t; #define MULTICAST_EVENT "multicast::event" #define SOFIA_REPLACES_HEADER "_sofia_replaces_" -#define SOFIA_USER_AGENT "SangomaMediaGateway/" SWITCH_VERSION_MAJOR "." SWITCH_VERSION_MINOR "." SWITCH_VERSION_MICRO "-" SWITCH_VERSION_REVISION +#define SOFIA_USER_AGENT "NetborderSS7/" SWITCH_VERSION_MAJOR "." SWITCH_VERSION_MINOR "." SWITCH_VERSION_MICRO "-" SWITCH_VERSION_REVISION #define SOFIA_CHAT_PROTO "sip" #define SOFIA_MULTIPART_PREFIX "sip_mp_" #define SOFIA_MULTIPART_PREFIX_T "~sip_mp_" diff --git a/src/switch.c b/src/switch.c index de99a905e5..7633fcae9f 100644 --- a/src/switch.c +++ b/src/switch.c @@ -48,7 +48,7 @@ #include "private/switch_core_pvt.h" /* pid filename: Stores the process id of the freeswitch process */ -#define PIDFILE "sangoma-media-gateway.pid" +#define PIDFILE "netborder-ss7.pid" static char *pfile = PIDFILE; static int system_ready = 0; @@ -540,7 +540,7 @@ int main(int argc, char *argv[]) } if (local_argv[x] && !strcmp(local_argv[x], "-version")) { - fprintf(stdout, "Sangoma Media Gateway Version: %s\n", SWITCH_VERSION_FULL); + fprintf(stdout, "Netborder SS7 Version: %s\n", SWITCH_VERSION_FULL); return 0; known_opt++; } diff --git a/src/switch_core.c b/src/switch_core.c index 07aca5752e..0d7bfa8a11 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1758,17 +1758,16 @@ SWITCH_DECLARE(const char *) switch_core_banner(void) "* Brought to you by ClueCon http://www.cluecon.com/ *\n" "************************************************************\n" "\n"); #else return ( -"\n _____ ___ ___ _ _ _____ _ \n" -"/ ___| | \\/ | | (_) | __ \\ | | \n" -"\\ `--. __ _ _ __ __ _ ___ _ __ ___ __ _ | . . | ___ __| |_ __ _ | | \\/ __ _| |_ _____ ____ _ _ _ \n" -" `--. \\/ _` | '_ \\ / _` |/ _ \\| '_ ` _ \\ / _` | | |\\/| |/ _ \\/ _` | |/ _` | | | __ / _` | __|/ _ \\ \\ /\\ / / _` | | | |\n" -"/\\__/ / (_| | | | | (_| | (_) | | | | | | (_| | | | | | __/ (_| | | (_| | | |_\\ \\ (_| | |_| __/\\ V V / (_| | |_| |\n" -"\\____/ \\__,_|_| |_|\\__, |\\___/|_| |_| |_|\\__,_| \\_| |_/\\___|\\__,_|_|\\__,_| \\____/\\__,_|\\__|\\___| \\_/\\_/ \\__,_|\\__, |\n" -" __/ | __/ |\n" -" |___/ |___/ \n" - "************************************************************\n" - "* Powered by: FreeSWITCH (http://www.freeswitch.org) *\n" - "************************************************************\n" "\n"); + "************************************************************************\n" + "* .__ __. .______ _______ _______. _______. ______ *\n" + "* | \ | | | _ \ | ____| / | / ||____ |*\n" + "* | \| | | |_) | | |__ | (----` | (----` / / *\n" + "* | . ` | | _ < | __| \ \ \ \ / / *\n" + "* | |\ | | |_) | | |____ .----) | .----) | / / *\n" + "* |__| \__| |______/ |_______| |_______/ |_______/ /_/ *\n" + "* *\n" + "* Powered by: FreeSWITCH (http://www.freeswitch.org) *\n" + "**************************************************************************\n" "\n"); #endif } From 42d40227d93ca7500518161904e76757c6e7c5ba Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 5 May 2011 18:25:47 -0400 Subject: [PATCH 024/822] fix banner --- src/switch_core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/switch_core.c b/src/switch_core.c index 0d7bfa8a11..3c7f70c8dd 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1760,11 +1760,11 @@ SWITCH_DECLARE(const char *) switch_core_banner(void) return ( "************************************************************************\n" "* .__ __. .______ _______ _______. _______. ______ *\n" - "* | \ | | | _ \ | ____| / | / ||____ |*\n" - "* | \| | | |_) | | |__ | (----` | (----` / / *\n" - "* | . ` | | _ < | __| \ \ \ \ / / *\n" - "* | |\ | | |_) | | |____ .----) | .----) | / / *\n" - "* |__| \__| |______/ |_______| |_______/ |_______/ /_/ *\n" + "* | \\ | | | _ \\ | ____| / | / ||____ |*\n" + "* | \\| | | |_) | | |__ | (----` | (----` / / *\n" + "* | . ` | | _ < | __| \\ \\ \\ \\ / / *\n" + "* | |\\ | | |_) | | |____ .----) | .----) | / / *\n" + "* |__| \\__| |______/ |_______| |_______/ |_______/ /_/ *\n" "* *\n" "* Powered by: FreeSWITCH (http://www.freeswitch.org) *\n" "**************************************************************************\n" "\n"); From a8d1b80b83bb7a8ae66d883d5733351513065acd Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 5 May 2011 19:33:02 -0400 Subject: [PATCH 025/822] remove pid file when failing to load modules --- src/switch.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/switch.c b/src/switch.c index 7633fcae9f..f5ffe950e2 100644 --- a/src/switch.c +++ b/src/switch.c @@ -921,7 +921,10 @@ int main(int argc, char *argv[]) switch_file_write(fd, pid_buffer, &pid_len); if (switch_core_init_and_modload(flags, nc ? SWITCH_FALSE : SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { - fprintf(stderr, "Cannot Initialize [%s]\n", err); + fprintf(stderr, "Cannot Initialize [%s], deleting pid file [%s]\n", err, pid_path); + if (unlink(pid_path) != 0) { + fprintf(stderr, "Failed to delete pid file [%s]\n", pid_path); + } return 255; } From 034cb7a6870f4075ccc52c5c86cbdbf6ba08ea69 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 9 May 2011 12:39:53 -0400 Subject: [PATCH 026/822] Added modified build/modules.conf.in --- build/modules.conf.in | 114 ++---------------------------------------- 1 file changed, 4 insertions(+), 110 deletions(-) diff --git a/build/modules.conf.in b/build/modules.conf.in index d31bb31b76..1d27aaad1b 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -1,119 +1,13 @@ loggers/mod_console loggers/mod_logfile loggers/mod_syslog -#applications/mod_cidlookup -applications/mod_commands -applications/mod_conference applications/mod_dptools -applications/mod_enum -#applications/mod_osp -applications/mod_fifo -#applications/mod_curl -applications/mod_db +applications/mod_commands applications/mod_hash -#applications/mod_redis -applications/mod_voicemail -#applications/mod_directory -#applications/mod_lcr -applications/mod_expr -applications/mod_esf -#applications/mod_easyroute -applications/mod_fsv -#applications/mod_nibblebill -#applications/mod_soundtouch -#applications/mod_rss applications/mod_spandsp -#applications/mod_snom -#applications/mod_vmd -#applications/mod_avmd -#applications/mod_memcache -#applications/mod_spy -applications/mod_cluechoo -applications/mod_valet_parking -#applications/mod_distributor -#applications/mod_stress -#applications/mod_snapshot -#applications/mod_snipe_hunt -#applications/mod_callcenter -#applications/mod_fsk -#applications/mod_ladspa -codecs/mod_g723_1 -codecs/mod_amr -#codecs/mod_amrwb -#codecs/mod_silk -#codecs/mod_codec2 -codecs/mod_g729 -#codecs/mod_com_g729 -codecs/mod_h26x -codecs/mod_bv -codecs/mod_ilbc -codecs/mod_speex -codecs/mod_siren -#codecs/mod_celt -#codecs/mod_opus -#codecs/mod_sangoma_codec -#codecs/mod_dahdi_codec -#dialplans/mod_dialplan_directory dialplans/mod_dialplan_xml -dialplans/mod_dialplan_asterisk -#directories/mod_ldap -#endpoints/mod_dingaling -#endpoints/mod_portaudio endpoints/mod_sofia -endpoints/mod_loopback -#endpoints/mod_alsa -#endpoints/mod_opal -#endpoints/mod_skinny -#endpoints/mod_skypopen -#endpoints/mod_h323 -#endpoints/mod_khomp -#../../libs/openzap/mod_openzap -#../../libs/freetdm/mod_freetdm -#asr_tts/mod_unimrcp -#asr_tts/mod_flite -#asr_tts/mod_pocketsphinx -#asr_tts/mod_cepstral -#asr_tts/mod_tts_commandline -#event_handlers/mod_event_multicast -event_handlers/mod_event_socket -#event_handlers/mod_event_zmq -event_handlers/mod_cdr_csv -event_handlers/mod_cdr_sqlite -#event_handlers/mod_cdr_pg_csv -#event_handlers/mod_radius_cdr -#event_handlers/mod_erlang_event -#event_handlers/mod_snmp -formats/mod_native_file -formats/mod_sndfile -#formats/mod_shout -formats/mod_local_stream -formats/mod_tone_stream -#formats/mod_portaudio_stream -#formats/mod_shell_stream -#languages/mod_python -languages/mod_spidermonkey -languages/mod_lua -#languages/mod_perl -#languages/mod_yaml -#languages/mod_java -#languages/mod_managed -xml_int/mod_xml_rpc -#xml_int/mod_xml_curl +../../libs/freetdm/mod_freetdm xml_int/mod_xml_cdr -#xml_int/mod_xml_ldap -say/mod_say_en -#say/mod_say_de -#say/mod_say_es -#say/mod_say_fr -#say/mod_say_it -#say/mod_say_nl -#say/mod_say_pt -#say/mod_say_ru -#say/mod_say_zh -#say/mod_say_hu -#say/mod_say_th -#say/mod_say_he -#timers/mod_timerfd - -## Experimental Modules (don't cry if they're broken) -#../../contrib/mod/xml_int/mod_xml_odbc +event_handlers/mod_event_socket +codecs/mod_sangoma_codec From bced67d4f5da0a043e00885f1c09aa841fcce8fc Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 17 May 2011 17:13:38 -0400 Subject: [PATCH 027/822] chlog: freetdm - SS7: Support for Transparent IAM --- libs/freetdm/configure.ac | 13 + libs/freetdm/mod_freetdm/mod_freetdm.c | 30 +- libs/freetdm/src/ftdm_call_utils.c | 68 +++ libs/freetdm/src/ftdm_io.c | 4 +- .../ftmod_sangoma_isdn_support.c | 11 +- .../ftmod_sangoma_ss7_handle.c | 13 +- .../ftmod_sangoma_ss7_main.c | 9 +- .../ftmod_sangoma_ss7_main.h | 11 + .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 237 ++------ .../ftmod_sangoma_ss7_support.c | 526 +++++++++++++++++- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 34 +- libs/freetdm/src/include/freetdm.h | 12 +- libs/freetdm/src/include/ftdm_call_utils.h | 19 + 13 files changed, 753 insertions(+), 234 deletions(-) diff --git a/libs/freetdm/configure.ac b/libs/freetdm/configure.ac index 55185cb10d..493f0da3b0 100644 --- a/libs/freetdm/configure.ac +++ b/libs/freetdm/configure.ac @@ -294,6 +294,19 @@ if test "${HAVE_SNG_SS7}" = "yes"; then fi fi + +## +# zlib (required for Sangoma SS7 Transparent IAM) +# +HAVE_ZLIB="no" +AC_MSG_RESULT([${as_nl}<<>> zlib]) +AC_CHECK_LIB([z], [compress], [HAVE_ZLIB="yes"]) +AC_MSG_RESULT([checking whether zlib is installed... ${HAVE_ZLIB}]) +AM_CONDITIONAL([HAVE_ZLIB], [test "{HAVE_ZLIB]" = "yes"]) +if test "${HAVE_ZLIB}" = "yes"; then + CFLAGS="$CFLAGS -DHAVE_ZLIB" +fi + ## # libisdn # diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 954a568e6f..75b500d0f6 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1369,7 +1369,12 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-CPC"); if (sipvar) { - ftdm_set_calling_party_category(var, (uint8_t *)&caller_data.cpc); + ftdm_set_calling_party_category(sipvar, (uint8_t *)&caller_data.cpc); + } + + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-IAM"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_iam", sipvar); } } @@ -1443,7 +1448,13 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi if (!strncasecmp(h->name, FREETDM_VAR_PREFIX, FREETDM_VAR_PREFIX_LEN)) { char *v = h->name + FREETDM_VAR_PREFIX_LEN; if (!zstr(v)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding outbound freetdm variable %s=%s to channel %d:%d\n", v, h->value, span_id, chan_id); + if (!strcasecmp(v, "ss7_iam")) { + /* Do not print the value of ss7_iam as it is very long */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding outbound freetdm variable %s to channel %d:%d\n", v, span_id, chan_id); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding outbound freetdm variable %s=%s to channel %d:%d\n", v, h->value, span_id, chan_id); + } + ftdm_usrmsg_add_var(&usrmsg, v, h->value); } } @@ -1633,6 +1644,8 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS", "%s", channel_caller_data->rdnis.digits); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-NADI", "%d", channel_caller_data->rdnis.type); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-Plan", "%d", channel_caller_data->rdnis.plan); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-CPC", "%s", ftdm_calling_party_category2str(channel_caller_data->cpc)); + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdnis_screen_ind"); if (!ftdm_strlen_zero(var_value)) { @@ -1678,10 +1691,10 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-NumInComp", "%d", var_value); } } /* End - var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_gn_digits"); */ - - var_value = ftdm_sigmsg_get_var(sigmsg, "freetdm_calling_party_category"); + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_iam"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-CPC", "%s", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-IAM", "%s", var_value); } switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-Screen", "%d", channel_caller_data->screen); @@ -1694,7 +1707,12 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session ftdm_get_current_var(curr, &var_name, &var_value); snprintf(name, sizeof(name), FREETDM_VAR_PREFIX "%s", var_name); switch_channel_set_variable_printf(channel, name, "%s", var_value); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Call Variable: %s = %s\n", name, var_value); + if (!strcasecmp(var_name, "ss7_iam")) { + /* Do not print freetdm_ss7_iam as it is a very long variable */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Call Variable: %s is present\n", name); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Call Variable: %s = %s\n", name, var_value); + } } ftdm_iterator_free(iter); diff --git a/libs/freetdm/src/ftdm_call_utils.c b/libs/freetdm/src/ftdm_call_utils.c index 2b72f05b77..d23c95af4e 100644 --- a/libs/freetdm/src/ftdm_call_utils.c +++ b/libs/freetdm/src/ftdm_call_utils.c @@ -42,6 +42,74 @@ #include + + +FT_DECLARE(char *) ftdm_url_encode(const char *url, char *buf, ftdm_size_t len) +{ + /* This implementation of url_encode is slightly different compared to the + * Freeswitch one. This is because this implementation accepts the full + * range of values (0x00 - 0xFF) compared to the Freeswitch implementation + * that does not accept 0x00 */ + + const char *p; + size_t x = 0,y = 0; + const char urlunsafe[] = "\r\n \"#%&+:;<=>?@[\\]^`{|}"; + const char hex[] = "0123456789ABCDEF"; + + if (!buf) { + return 0; + } + + if (!url) { + return 0; + } + + len--; + + for (p = url; y <= len; p++) { + if (*p < ' ' || *p > '~' || strchr(urlunsafe, *p)) { + buf[x++] = '%'; + buf[x++] = hex[(*p >> 4) & 0x0f]; + buf[x++] = hex[*p & 0x0f]; + } else { + buf[x++] = *p; + } + y++; + } + buf[x] = '\0'; + return buf; +} + + +FT_DECLARE(char *) ftdm_url_decode(char *s, ftdm_size_t *len) +{ + /* This implementation of url_decode is slightly different compared to the + * Freeswitch one. This is because this implementation accepts the full + * range of values (0x00 - 0xFF) compared to the Freeswitch implementation + * that does not accept 0x00 */ + + char *o; + unsigned int tmp; + ftdm_size_t mylen = 0; + + if (ftdm_strlen_zero(s)) { + return s; + } + + for (o = s; *s; s++, o++) { + if (*s == '%' && strlen(s) > 2 && sscanf(s + 1, "%2x", &tmp) == 1) { + *o = (char) tmp; + s += 2; + } else { + *o = *s; + } + mylen++; + } + *o = '\0'; + *len = mylen; + return s; +} + FT_DECLARE(ftdm_status_t) ftdm_set_npi(const char *string, uint8_t *target) { uint8_t val; diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 1d7a0d1eb1..c7a3ec48f4 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -411,13 +411,13 @@ FT_DECLARE(void) ftdm_set_echocancel_call_begin(ftdm_channel_t *chan) if (ftdm_channel_test_feature(chan, FTDM_CHANNEL_FEATURE_HWEC)) { if (ftdm_channel_test_feature(chan, FTDM_CHANNEL_FEATURE_HWEC_DISABLED_ON_IDLE)) { /* If the ec is disabled on idle, we need to enable it unless is a digital call */ - if (caller_data->bearer_capability != FTDM_BEARER_CAP_64K_UNRESTRICTED) { + if (caller_data->bearer_capability != FTDM_BEARER_CAP_UNRESTRICTED) { ftdm_log_chan(chan, FTDM_LOG_DEBUG, "Enabling ec for call in channel state %s\n", ftdm_channel_state2str(chan->state)); ftdm_channel_command(chan, FTDM_COMMAND_ENABLE_ECHOCANCEL, NULL); } } else { /* If the ec is enabled on idle, we do nothing unless is a digital call that needs it disabled */ - if (caller_data->bearer_capability == FTDM_BEARER_CAP_64K_UNRESTRICTED) { + if (caller_data->bearer_capability == FTDM_BEARER_CAP_UNRESTRICTED) { ftdm_log_chan(chan, FTDM_LOG_DEBUG, "Disabling ec for digital call in channel state %s\n", ftdm_channel_state2str(chan->state)); ftdm_channel_command(chan, FTDM_COMMAND_DISABLE_ECHOCANCEL, NULL); } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c index a343809b4c..f4fee712c9 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c @@ -1069,18 +1069,20 @@ void get_memory_info(void) return; } + uint8_t sngisdn_get_infoTranCap_from_user(ftdm_bearer_cap_t bearer_capability) { switch(bearer_capability) { case FTDM_BEARER_CAP_SPEECH: return IN_ITC_SPEECH; - case FTDM_BEARER_CAP_64K_UNRESTRICTED: + case FTDM_BEARER_CAP_UNRESTRICTED: return IN_ITC_UNRDIG; case FTDM_BEARER_CAP_3_1KHZ_AUDIO: return IN_ITC_A31KHZ; case FTDM_BEARER_CAP_INVALID: return IN_ITC_SPEECH; - /* Do not put a default case here, so we can see compile warnings if we have unhandled cases */ + default: + return IN_ITC_SPEECH; } return FTDM_BEARER_CAP_SPEECH; } @@ -1096,7 +1098,8 @@ uint8_t sngisdn_get_usrInfoLyr1Prot_from_user(ftdm_user_layer1_prot_t layer1_pro return IN_UIL1_G711ALAW; case FTDM_USER_LAYER1_PROT_INVALID: return IN_UIL1_G711ULAW; - /* Do not put a default case here, so we can see compile warnings if we have unhandled cases */ + default: + return IN_UIL1_G711ULAW; } return IN_UIL1_G711ULAW; } @@ -1107,7 +1110,7 @@ ftdm_bearer_cap_t sngisdn_get_infoTranCap_from_stack(uint8_t bearer_capability) case IN_ITC_SPEECH: return FTDM_BEARER_CAP_SPEECH; case IN_ITC_UNRDIG: - return FTDM_BEARER_CAP_64K_UNRESTRICTED; + return FTDM_BEARER_CAP_UNRESTRICTED; case IN_ITC_A31KHZ: return FTDM_BEARER_CAP_3_1KHZ_AUDIO; default: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 596ae7c734..0520e9d163 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -33,12 +33,14 @@ /* INCLUDE ********************************************************************/ #include "ftmod_sangoma_ss7_main.h" + /******************************************************************************/ /* DEFINES ********************************************************************/ /******************************************************************************/ /* GLOBALS ********************************************************************/ + /******************************************************************************/ /* PROTOTYPES *****************************************************************/ @@ -79,14 +81,14 @@ ftdm_status_t handle_olm_msg(uint32_t suInstId, uint32_t spInstId, uint32_t circ /******************************************************************************/ /* FUNCTIONS ******************************************************************/ + ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt) { - SS7_FUNC_TRACE_ENTER(__FUNCTION__); - sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; char nadi[2]; - + + SS7_FUNC_TRACE_ENTER(__FUNCTION__); memset(nadi, '\0', sizeof(nadi)); /* get the ftdmchan and ss7_chan_data from the circuit */ @@ -208,6 +210,10 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sprintf(nadi, "%d", siConEvnt->cdPtyNum.natAddrInd.val); sngss7_add_var(sngss7_info, "ss7_cld_nadi", nadi); + if (sngss7_info->circuit->transparent_iam) { + sngss7_save_iam(ftdmchan, siConEvnt); + } + /* check if a COT test is requested */ if ((siConEvnt->natConInd.eh.pres) && (siConEvnt->natConInd.contChkInd.pres) && @@ -231,7 +237,6 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ siConEvnt->cgPtyNum.natAddrInd.val, ftdmchan->caller_data.dnis.digits, siConEvnt->cdPtyNum.natAddrInd.val); - } /* if (channel is usable */ break; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 59660765a1..53062b9d56 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -42,6 +42,7 @@ static sng_isup_event_interface_t sng_event; static ftdm_io_interface_t g_ftdm_sngss7_interface; ftdm_sngss7_data_t g_ftdm_sngss7_data; + /******************************************************************************/ /* PROTOTYPES *****************************************************************/ @@ -509,11 +510,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) SS7_DEBUG_CHAN(ftdmchan, "ftmod_sangoma_ss7 processing state %s\n", ftdm_channel_state2str (ftdmchan->state)); -#if 0 - /* clear the state change flag...since we might be setting a new state */ - ftdm_channel_complete_state(ftdmchan); -#endif - /*check what state we are supposed to be in */ switch (ftdmchan->state) { /**************************************************************************/ @@ -674,9 +670,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) } else { /*INBOUND...so FS told us it was going to answer...tell the stack */ ft_to_sngss7_anm(ftdmchan); -#if 1 /* DAVIDY */ - ft_to_sngss7_itx(ftdmchan); -#endif } break; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 04723048f6..f88202b1a8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -339,6 +339,7 @@ typedef struct sng_isup_ckt { uint32_t min_digits; uint8_t itx_auto_reply; + uint8_t transparent_iam; void *obj; uint16_t t3; uint16_t t12; @@ -406,6 +407,7 @@ typedef struct sng_ss7_cfg { uint32_t procId; char license[MAX_PATH]; char signature[MAX_PATH]; + uint32_t transparent_iam_max_size; uint32_t flags; sng_relay_t relay[MAX_RELAY_CHANNELS+1]; sng_mtp1_link_t mtp1Link[MAX_MTP_LINKS+1]; @@ -765,6 +767,10 @@ void sngss7_resm_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiR void sngss7_susp_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiSuspEvnt *siSuspEvnt); void sngss7_ssp_sta_cfm(uint32_t infId); +ftdm_status_t sngss7_bufferzero_iam(SiConEvnt *siConEvnt); +ftdm_status_t sngss7_retrieve_iam(ftdm_channel_t *ftdmchan, SiConEvnt *siConEvnt); +ftdm_status_t sngss7_save_iam(ftdm_channel_t *ftdmchan, SiConEvnt *siConEvnt); + /* in ftmod_sangoma_ss7_handle.c */ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt); ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiCnStEvnt *siCnStEvnt, uint8_t evntType); @@ -815,6 +821,11 @@ ftdm_status_t copy_genNmb_to_sngss7(ftdm_channel_t *ftdmchan, SiGenNum *genNmb); ftdm_status_t copy_genNmb_from_sngss7(ftdm_channel_t *ftdmchan, SiGenNum *genNmb); ftdm_status_t copy_cgPtyCat_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyCat *cgPtyCat); ftdm_status_t copy_cgPtyCat_from_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyCat *cgPtyCat); +ftdm_status_t copy_accTrnspt_to_sngss7(ftdm_channel_t *ftdmchan, SiAccTrnspt *accTrnspt); +ftdm_status_t copy_natConInd_to_sngss7(ftdm_channel_t *ftdmchan, SiNatConInd *natConInd); +ftdm_status_t copy_fwdCallInd_to_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd *fwdCallInd); +ftdm_status_t copy_txMedReq_to_sngss7(ftdm_channel_t *ftdmchan, SiTxMedReq *txMedReq); +ftdm_status_t copy_usrServInfoA_to_sngss7(ftdm_channel_t *ftdmchan, SiUsrServInfo *usrServInfoA); ftdm_status_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven); ftdm_status_t append_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index e1944513d1..91b8900fef 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -36,10 +36,8 @@ /******************************************************************************/ /* DEFINES ********************************************************************/ -/******************************************************************************/ /* GLOBALS ********************************************************************/ -/******************************************************************************/ /* PROTOTYPES *****************************************************************/ void ft_to_sngss7_iam(ftdm_channel_t * ftdmchan); @@ -66,219 +64,70 @@ void ft_to_sngss7_cgu(ftdm_channel_t * ftdmchan); void ft_to_sngss7_cgba(ftdm_channel_t * ftdmchan); void ft_to_sngss7_cgua(ftdm_channel_t * ftdmchan); -/******************************************************************************/ /* FUNCTIONS ******************************************************************/ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) -{ - SS7_FUNC_TRACE_ENTER (__FUNCTION__); - - sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;; - const char *clg_subAddr = NULL; - const char *cld_subAddr = NULL; - char subAddrIE[MAX_SIZEOF_SUBADDR_IE]; +{ SiConEvnt iam; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;; + + SS7_FUNC_TRACE_ENTER (__FUNCTION__); sngss7_info->suInstId = get_unique_id (); sngss7_info->spInstId = 0; sngss7_info->spId = 1; memset (&iam, 0x0, sizeof (iam)); - - /* copy down the nature of connection indicators */ - iam.natConInd.eh.pres = PRSNT_NODEF; - iam.natConInd.satInd.pres = PRSNT_NODEF; - iam.natConInd.satInd.val = 0; /* no satellite circuit */ - iam.natConInd.contChkInd.pres = PRSNT_NODEF; - iam.natConInd.contChkInd.val = CONTCHK_NOTREQ; - iam.natConInd.echoCntrlDevInd.pres = PRSNT_NODEF; - iam.natConInd.echoCntrlDevInd.val = ECHOCDEV_INCL; - - /* copy down the forward call indicators */ - iam.fwdCallInd.eh.pres = PRSNT_NODEF; - iam.fwdCallInd.natIntCallInd.pres = PRSNT_NODEF; - iam.fwdCallInd.natIntCallInd.val = 0x00; - iam.fwdCallInd.end2EndMethInd.pres = PRSNT_NODEF; - iam.fwdCallInd.end2EndMethInd.val = E2EMTH_NOMETH; - iam.fwdCallInd.intInd.pres = PRSNT_NODEF; - iam.fwdCallInd.intInd.val = INTIND_NOINTW; - iam.fwdCallInd.end2EndInfoInd.pres = PRSNT_NODEF; - iam.fwdCallInd.end2EndInfoInd.val = E2EINF_NOINFO; - iam.fwdCallInd.isdnUsrPrtInd.pres = PRSNT_NODEF; - iam.fwdCallInd.isdnUsrPrtInd.val = ISUP_USED; - iam.fwdCallInd.isdnUsrPrtPrfInd.pres = PRSNT_NODEF; - iam.fwdCallInd.isdnUsrPrtPrfInd.val = PREF_PREFAW; - iam.fwdCallInd.isdnAccInd.pres = PRSNT_NODEF; - iam.fwdCallInd.isdnAccInd.val = ISDNACC_ISDN; - iam.fwdCallInd.sccpMethInd.pres = PRSNT_NODEF; - iam.fwdCallInd.sccpMethInd.val = SCCPMTH_NOIND; + + if (sngss7_info->circuit->transparent_iam && + sngss7_retrieve_iam(ftdmchan, &iam) == FTDM_SUCCESS) { + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Transparent)\n", sngss7_info->circuit->cic); + } else { + /* Nature of Connection Indicators */ + copy_natConInd_to_sngss7(ftdmchan, &iam.natConInd); + + /* Forward Call Indicators */ + copy_fwdCallInd_to_sngss7(ftdmchan, &iam.fwdCallInd); + + /* Transmission medium requirements */ + copy_txMedReq_to_sngss7(ftdmchan, &iam.txMedReq); + + /* User Service Info A */ + copy_usrServInfoA_to_sngss7(ftdmchan, &iam.usrServInfoA); - /* copy down the transmission medium requirements */ - iam.txMedReq.eh.pres = PRSNT_NODEF; - iam.txMedReq.trMedReq.pres = PRSNT_NODEF; - iam.txMedReq.trMedReq.val = ftdmchan->caller_data.bearer_capability; - - if ((g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS88) || - (g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS92) || - (g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS95)) { - - /* include only if we're running ANSI */ - iam.fwdCallInd.transCallNInd.pres = PRSNT_NODEF; - iam.fwdCallInd.transCallNInd.val = 0x0; - - iam.usrServInfoA.eh.pres = PRSNT_NODEF; - - iam.usrServInfoA.infoTranCap.pres = PRSNT_NODEF; - switch (ftdmchan->caller_data.bearer_capability) { - /**********************************************************************/ - case (FTDM_BEARER_CAP_SPEECH): - iam.usrServInfoA.infoTranCap.val = 0x0; /* speech as per ATIS-1000113.3.2005 */ - break; - /**********************************************************************/ - case (FTDM_BEARER_CAP_64K_UNRESTRICTED): - iam.usrServInfoA.infoTranCap.val = 0x8; /* unrestricted digital as per ATIS-1000113.3.2005 */ - break; - /**********************************************************************/ - case (FTDM_BEARER_CAP_3_1KHZ_AUDIO): - iam.usrServInfoA.infoTranCap.val = 0x10; /* 3.1kHz audio as per ATIS-1000113.3.2005 */ - break; - /**********************************************************************/ - default: - SS7_ERROR_CHAN(ftdmchan, "Unknown Bearer capability falling back to speech%s\n", " "); - iam.usrServInfoA.infoTranCap.val = 0x0; /* speech as per ATIS-1000113.3.2005 */ - break; - /**********************************************************************/ - } /* switch (ftdmchan->caller_data.bearer_capability) */ - - iam.usrServInfoA.cdeStand.pres = PRSNT_NODEF; - iam.usrServInfoA.cdeStand.val = 0x0; /* ITU-T standardized coding */ - iam.usrServInfoA.tranMode.pres = PRSNT_NODEF; - iam.usrServInfoA.tranMode.val = 0x0; /* circuit mode */ - iam.usrServInfoA.infoTranRate0.pres = PRSNT_NODEF; - iam.usrServInfoA.infoTranRate0.val = 0x10; /* 64kbps origination to destination */ - iam.usrServInfoA.infoTranRate1.pres = PRSNT_NODEF; - iam.usrServInfoA.infoTranRate1.val = 0x10; /* 64kbps destination to origination */ - iam.usrServInfoA.chanStruct.pres = PRSNT_NODEF; - iam.usrServInfoA.chanStruct.val = 0x1; /* 8kHz integrity */ - iam.usrServInfoA.config.pres = PRSNT_NODEF; - iam.usrServInfoA.config.val = 0x0; /* point to point configuration */ - iam.usrServInfoA.establish.pres = PRSNT_NODEF; - iam.usrServInfoA.establish.val = 0x0; /* on demand */ - iam.usrServInfoA.symmetry.pres = PRSNT_NODEF; - iam.usrServInfoA.symmetry.val = 0x0; /* bi-directional symmetric */ - iam.usrServInfoA.usrInfLyr1Prot.pres = PRSNT_NODEF; - iam.usrServInfoA.usrInfLyr1Prot.val = 0x2; /* G.711 ulaw */ - iam.usrServInfoA.rateMultiplier.pres = PRSNT_NODEF; - iam.usrServInfoA.rateMultiplier.val = 0x1; /* 1x rate multipler */ - } /* if ANSI */ - - /* copy down the called number information */ - copy_cdPtyNum_to_sngss7 (ftdmchan, &iam.cdPtyNum); - - /* copy down the calling number information */ - copy_cgPtyNum_to_sngss7 (ftdmchan, &iam.cgPtyNum); - - /* copy down the generic number information */ - copy_genNmb_to_sngss7(ftdmchan, &iam.genNmb); - - /* copy down the calling party category */ - copy_cgPtyCat_to_sngss7(ftdmchan, &iam.cgPtyCat); - - /* TODO - move this to copy_clg_subAddr_to_sngss7 function */ - /* check if the user would like us to send a clg_sub-address */ - clg_subAddr = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_clg_subaddr"); - if (!ftdm_strlen_zero(clg_subAddr)) { - SS7_DEBUG_CHAN(ftdmchan,"Found user supplied Calling Sub-Address value \"%s\"\n", clg_subAddr); + /* Called Number information */ + copy_cdPtyNum_to_sngss7(ftdmchan, &iam.cdPtyNum); - /* clean out the subAddrIE */ - memset(subAddrIE, 0x0, sizeof(subAddrIE)); + /* Calling Number information */ + copy_cgPtyNum_to_sngss7(ftdmchan, &iam.cgPtyNum); - /* check the first character in the sub-address to see what type of encoding to use */ - switch (clg_subAddr[0]) { - case '0': /* NSAP */ - encode_subAddrIE_nsap(&clg_subAddr[1], subAddrIE, SNG_CALLING); - break; - case '1': /* national variant */ - encode_subAddrIE_nat(&clg_subAddr[1], subAddrIE, SNG_CALLING); - break; - default: - SS7_ERROR_CHAN(ftdmchan,"Invalid Calling Sub-Address encoding requested: %c\n", clg_subAddr[0]); - break; - } /* switch (cld_subAddr[0]) */ + /* Generic Number information */ + copy_genNmb_to_sngss7(ftdmchan, &iam.genNmb); + /* Calling Party's Category */ + copy_cgPtyCat_to_sngss7(ftdmchan, &iam.cgPtyCat); - /* if subaddIE is still empty don't copy it in */ - if (subAddrIE[0] != '0') { - /* check if the clg_subAddr has already been added */ - if (iam.accTrnspt.eh.pres == PRSNT_NODEF) { - /* append the subAddrIE */ - memcpy(&iam.accTrnspt.infoElmts.val[iam.accTrnspt.infoElmts.len], subAddrIE, (subAddrIE[1] + 2)); - iam.accTrnspt.infoElmts.len = iam.accTrnspt.infoElmts.len +subAddrIE[1] + 2; - } else { - /* fill in from the beginning */ - iam.accTrnspt.eh.pres = PRSNT_NODEF; - iam.accTrnspt.infoElmts.pres = PRSNT_NODEF; - memcpy(iam.accTrnspt.infoElmts.val, subAddrIE, (subAddrIE[1] + 2)); - iam.accTrnspt.infoElmts.len = subAddrIE[1] + 2; - } /* if (iam.accTrnspt.eh.pres */ - } /* if (subAddrIE[0] != '0') */ + /* Redirecting Number */ + copy_redirgNum_to_sngss7(ftdmchan, &iam.redirgNum); + + /* Access Transport */ + copy_accTrnspt_to_sngss7(ftdmchan, &iam.accTrnspt); + + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM clg = \"%s\" (NADI=%d), cld = \"%s\" (NADI=%d)\n", + sngss7_info->circuit->cic, + ftdmchan->caller_data.cid_num.digits, + iam.cgPtyNum.natAddrInd.val, + ftdmchan->caller_data.dnis.digits, + iam.cdPtyNum.natAddrInd.val); } - copy_redirgNum_to_sngss7(ftdmchan, &iam.redirgNum); - - /* check if the user would like us to send a cld_sub-address */ - cld_subAddr = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_cld_subaddr"); - if ((cld_subAddr != NULL) && (*cld_subAddr)) { - SS7_DEBUG_CHAN(ftdmchan,"Found user supplied Called Sub-Address value \"%s\"\n", cld_subAddr); - - /* clean out the subAddrIE */ - memset(subAddrIE, 0x0, sizeof(subAddrIE)); - - /* check the first character in the sub-address to see what type of encoding to use */ - switch (cld_subAddr[0]) { - case '0': /* NSAP */ - encode_subAddrIE_nsap(&cld_subAddr[1], subAddrIE, SNG_CALLED); - break; - case '1': /* national variant */ - encode_subAddrIE_nat(&cld_subAddr[1], subAddrIE, SNG_CALLED); - break; - default: - SS7_ERROR_CHAN(ftdmchan,"Invalid Called Sub-Address encoding requested: %c\n", cld_subAddr[0]); - break; - } /* switch (cld_subAddr[0]) */ - - /* if subaddIE is still empty don't copy it in */ - if (subAddrIE[0] != '0') { - /* check if the cld_subAddr has already been added */ - if (iam.accTrnspt.eh.pres == PRSNT_NODEF) { - /* append the subAddrIE */ - memcpy(&iam.accTrnspt.infoElmts.val[iam.accTrnspt.infoElmts.len], subAddrIE, (subAddrIE[1] + 2)); - iam.accTrnspt.infoElmts.len = iam.accTrnspt.infoElmts.len +subAddrIE[1] + 2; - } else { - /* fill in from the beginning */ - iam.accTrnspt.eh.pres = PRSNT_NODEF; - iam.accTrnspt.infoElmts.pres = PRSNT_NODEF; - memcpy(iam.accTrnspt.infoElmts.val, subAddrIE, (subAddrIE[1] + 2)); - iam.accTrnspt.infoElmts.len = subAddrIE[1] + 2; - } /* if (iam.accTrnspt.eh.pres */ - } /* if (subAddrIE[0] != '0') */ - } /* if ((cld_subAddr != NULL) && (*cld_subAddr)) */ - sng_cc_con_request (sngss7_info->spId, sngss7_info->suInstId, sngss7_info->spInstId, - sngss7_info->circuit->id, - &iam, + sngss7_info->circuit->id, + &iam, 0); - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM clg = \"%s\" (NADI=%d), cld = \"%s\" (NADI=%d)\n", - sngss7_info->circuit->cic, - ftdmchan->caller_data.cid_num.digits, - iam.cgPtyNum.natAddrInd.val, - ftdmchan->caller_data.dnis.digits, - iam.cdPtyNum.natAddrInd.val); - - SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -319,7 +168,7 @@ void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan) acm.bckCallInd.echoCtrlDevInd.val = 0x1; break; /**********************************************************************/ - case (FTDM_BEARER_CAP_64K_UNRESTRICTED): + case (FTDM_BEARER_CAP_UNRESTRICTED): acm.bckCallInd.echoCtrlDevInd.val = 0x0; break; /**********************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index a60a6c48ed..f82ca4d3ab 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -33,6 +33,9 @@ /* INCLUDE ********************************************************************/ #include "ftmod_sangoma_ss7_main.h" +#ifdef HAVE_ZLIB +#include +#endif /******************************************************************************/ /* DEFINES ********************************************************************/ @@ -111,6 +114,16 @@ ftdm2trillium_t cpc_codes[] = { {FTDM_CPC_PAYPHONE, CAT_PAYPHONE}, }; +ftdm2trillium_t bc_cap_codes[] = { + {FTDM_BEARER_CAP_SPEECH, ITC_SPEECH}, /* speech as per ATIS-1000113.3.2005 */ + {FTDM_BEARER_CAP_UNRESTRICTED, ITC_UNRDIG}, /* unrestricted digital as per ATIS-1000113.3.2005 */ + {FTDM_BEARER_CAP_RESTRICTED, ITC_UNRDIG}, /* Restricted Digital */ + {FTDM_BEARER_CAP_3_1KHZ_AUDIO, ITC_A31KHZ}, /* 3.1kHz audio as per ATIS-1000113.3.2005 */ + {FTDM_BEARER_CAP_7KHZ_AUDIO, ITC_A7KHZ}, /* 7Khz audio */ + {FTDM_BEARER_CAP_15KHZ_AUDIO, ITC_A15KHZ}, /* 15Khz audio */ + {FTDM_BEARER_CAP_VIDEO, ITC_VIDEO}, /* Video */ +}; + static uint8_t get_trillium_val(ftdm2trillium_t *vals, uint8_t ftdm_val, uint8_t default_val) { ftdm2trillium_t *val = vals; @@ -485,6 +498,187 @@ ftdm_status_t copy_cgPtyCat_from_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyCat *cg return FTDM_SUCCESS; } + +ftdm_status_t copy_accTrnspt_to_sngss7(ftdm_channel_t *ftdmchan, SiAccTrnspt *accTrnspt) +{ + const char *clg_subAddr = NULL; + const char *cld_subAddr = NULL; + char subAddrIE[MAX_SIZEOF_SUBADDR_IE]; + + /* check if the user would like us to send a clg_sub-address */ + clg_subAddr = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_clg_subaddr"); + if (!ftdm_strlen_zero(clg_subAddr)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Calling Sub-Address value \"%s\"\n", clg_subAddr); + + /* clean out the subAddrIE */ + memset(subAddrIE, 0x0, sizeof(subAddrIE)); + + /* check the first character in the sub-address to see what type of encoding to use */ + switch (clg_subAddr[0]) { + case '0': /* NSAP */ + encode_subAddrIE_nsap(&clg_subAddr[1], subAddrIE, SNG_CALLING); + break; + case '1': /* national variant */ + encode_subAddrIE_nat(&clg_subAddr[1], subAddrIE, SNG_CALLING); + break; + default: + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Invalid Calling Sub-Address encoding requested: %c\n", clg_subAddr[0]); + break; + } /* switch (cld_subAddr[0]) */ + + + /* if subaddIE is still empty don't copy it in */ + if (subAddrIE[0] != '0') { + /* check if the clg_subAddr has already been added */ + if (accTrnspt->eh.pres == PRSNT_NODEF) { + /* append the subAddrIE */ + memcpy(&accTrnspt->infoElmts.val[accTrnspt->infoElmts.len], subAddrIE, (subAddrIE[1] + 2)); + accTrnspt->infoElmts.len = accTrnspt->infoElmts.len +subAddrIE[1] + 2; + } else { + /* fill in from the beginning */ + accTrnspt->eh.pres = PRSNT_NODEF; + accTrnspt->infoElmts.pres = PRSNT_NODEF; + memcpy(accTrnspt->infoElmts.val, subAddrIE, (subAddrIE[1] + 2)); + accTrnspt->infoElmts.len = subAddrIE[1] + 2; + } + } + } + + /* check if the user would like us to send a cld_sub-address */ + cld_subAddr = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_cld_subaddr"); + if ((cld_subAddr != NULL) && (*cld_subAddr)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Called Sub-Address value \"%s\"\n", cld_subAddr); + + /* clean out the subAddrIE */ + memset(subAddrIE, 0x0, sizeof(subAddrIE)); + + /* check the first character in the sub-address to see what type of encoding to use */ + switch (cld_subAddr[0]) { + case '0': /* NSAP */ + encode_subAddrIE_nsap(&cld_subAddr[1], subAddrIE, SNG_CALLED); + break; + case '1': /* national variant */ + encode_subAddrIE_nat(&cld_subAddr[1], subAddrIE, SNG_CALLED); + break; + default: + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Invalid Called Sub-Address encoding requested: %c\n", cld_subAddr[0]); + break; + } /* switch (cld_subAddr[0]) */ + + /* if subaddIE is still empty don't copy it in */ + if (subAddrIE[0] != '0') { + /* check if the cld_subAddr has already been added */ + if (accTrnspt->eh.pres == PRSNT_NODEF) { + /* append the subAddrIE */ + memcpy(&accTrnspt->infoElmts.val[accTrnspt->infoElmts.len], subAddrIE, (subAddrIE[1] + 2)); + accTrnspt->infoElmts.len = accTrnspt->infoElmts.len +subAddrIE[1] + 2; + } else { + /* fill in from the beginning */ + accTrnspt->eh.pres = PRSNT_NODEF; + accTrnspt->infoElmts.pres = PRSNT_NODEF; + memcpy(accTrnspt->infoElmts.val, subAddrIE, (subAddrIE[1] + 2)); + accTrnspt->infoElmts.len = subAddrIE[1] + 2; + } + } + } /* if ((cld_subAddr != NULL) && (*cld_subAddr)) */ + return FTDM_SUCCESS; +} + +ftdm_status_t copy_natConInd_to_sngss7(ftdm_channel_t *ftdmchan, SiNatConInd *natConInd) +{ + /* copy down the nature of connection indicators */ + natConInd->eh.pres = PRSNT_NODEF; + natConInd->satInd.pres = PRSNT_NODEF; + natConInd->satInd.val = 0; /* no satellite circuit */ + natConInd->contChkInd.pres = PRSNT_NODEF; + natConInd->contChkInd.val = CONTCHK_NOTREQ; + natConInd->echoCntrlDevInd.pres = PRSNT_NODEF; + natConInd->echoCntrlDevInd.val = ECHOCDEV_INCL; + return FTDM_SUCCESS; +} + +ftdm_status_t copy_fwdCallInd_to_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd *fwdCallInd) +{ + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + fwdCallInd->eh.pres = PRSNT_NODEF; + fwdCallInd->natIntCallInd.pres = PRSNT_NODEF; + fwdCallInd->natIntCallInd.val = 0x00; + fwdCallInd->end2EndMethInd.pres = PRSNT_NODEF; + fwdCallInd->end2EndMethInd.val = E2EMTH_NOMETH; + fwdCallInd->intInd.pres = PRSNT_NODEF; + fwdCallInd->intInd.val = INTIND_NOINTW; + fwdCallInd->end2EndInfoInd.pres = PRSNT_NODEF; + fwdCallInd->end2EndInfoInd.val = E2EINF_NOINFO; + fwdCallInd->isdnUsrPrtInd.pres = PRSNT_NODEF; + fwdCallInd->isdnUsrPrtInd.val = ISUP_USED; + fwdCallInd->isdnUsrPrtPrfInd.pres = PRSNT_NODEF; + fwdCallInd->isdnUsrPrtPrfInd.val = PREF_PREFAW; + fwdCallInd->isdnAccInd.pres = PRSNT_NODEF; + fwdCallInd->isdnAccInd.val = ISDNACC_ISDN; + fwdCallInd->sccpMethInd.pres = PRSNT_NODEF; + fwdCallInd->sccpMethInd.val = SCCPMTH_NOIND; + + if ((g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS88) || + (g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS92) || + (g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS95)) { + + /* include only if we're running ANSI */ + fwdCallInd->transCallNInd.pres = PRSNT_NODEF; + fwdCallInd->transCallNInd.val = 0x0; + } + return FTDM_SUCCESS; +} + +ftdm_status_t copy_txMedReq_to_sngss7(ftdm_channel_t *ftdmchan, SiTxMedReq *txMedReq) +{ + txMedReq->eh.pres = PRSNT_NODEF; + txMedReq->trMedReq.pres = PRSNT_NODEF; + txMedReq->trMedReq.val = ftdmchan->caller_data.bearer_capability; + + return FTDM_SUCCESS; +} + +ftdm_status_t copy_usrServInfoA_to_sngss7(ftdm_channel_t *ftdmchan, SiUsrServInfo *usrServInfoA) +{ + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + if ((g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS88) || + (g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS92) || + (g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS95)) { + + usrServInfoA->eh.pres = PRSNT_NODEF; + + usrServInfoA->infoTranCap.pres = PRSNT_NODEF; + + usrServInfoA->infoTranCap.val = get_trillium_val(bc_cap_codes, ftdmchan->caller_data.bearer_capability, ITC_SPEECH); + + usrServInfoA->cdeStand.pres = PRSNT_NODEF; + usrServInfoA->cdeStand.val = 0x0; /* ITU-T standardized coding */ + usrServInfoA->tranMode.pres = PRSNT_NODEF; + usrServInfoA->tranMode.val = 0x0; /* circuit mode */ + usrServInfoA->infoTranRate0.pres = PRSNT_NODEF; + usrServInfoA->infoTranRate0.val = 0x10; /* 64kbps origination to destination */ + usrServInfoA->infoTranRate1.pres = PRSNT_NODEF; + usrServInfoA->infoTranRate1.val = 0x10; /* 64kbps destination to origination */ + usrServInfoA->chanStruct.pres = PRSNT_NODEF; + usrServInfoA->chanStruct.val = 0x1; /* 8kHz integrity */ + usrServInfoA->config.pres = PRSNT_NODEF; + usrServInfoA->config.val = 0x0; /* point to point configuration */ + usrServInfoA->establish.pres = PRSNT_NODEF; + usrServInfoA->establish.val = 0x0; /* on demand */ + usrServInfoA->symmetry.pres = PRSNT_NODEF; + usrServInfoA->symmetry.val = 0x0; /* bi-directional symmetric */ + usrServInfoA->usrInfLyr1Prot.pres = PRSNT_NODEF; + usrServInfoA->usrInfLyr1Prot.val = 0x2; /* G.711 ulaw */ + usrServInfoA->rateMultiplier.pres = PRSNT_NODEF; + usrServInfoA->rateMultiplier.val = 0x1; /* 1x rate multipler */ + } /* if ANSI */ + return FTDM_SUCCESS; +} + + + ftdm_status_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven) { uint8_t i; @@ -1710,7 +1904,7 @@ void sngss7_set_sig_status(sngss7_chan_data_t *sngss7_info, ftdm_signaling_statu sig.ev_data.sigstatus.status = status; if (ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS) { - SS7_ERROR_CHAN(ftdmchan, "Failed to change channel status to %s\n", + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to change channel status to %s\n", ftdm_signaling_status2str(status)); } return; @@ -1885,6 +2079,336 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) return FTDM_SUCCESS; } + +ftdm_status_t sngss7_bufferzero_iam(SiConEvnt *siConEvnt) +{ + if (siConEvnt->natConInd.eh.pres != PRSNT_NODEF) memset(&siConEvnt->natConInd, 0, sizeof(siConEvnt->natConInd)); + if (siConEvnt->fwdCallInd.eh.pres != PRSNT_NODEF) memset(&siConEvnt->fwdCallInd, 0, sizeof(siConEvnt->fwdCallInd)); + if (siConEvnt->cgPtyCat.eh.pres != PRSNT_NODEF) memset(&siConEvnt->cgPtyCat, 0, sizeof(siConEvnt->cgPtyCat)); + if (siConEvnt->txMedReq.eh.pres != PRSNT_NODEF) memset(&siConEvnt->txMedReq, 0, sizeof(siConEvnt->txMedReq)); +#if (SS7_ANS88 || SS7_ANS92 || SS7_ANS95 || SS7_BELL) + if (siConEvnt->usrServInfoA.eh.pres != PRSNT_NODEF) memset(&siConEvnt->usrServInfoA, 0, sizeof(siConEvnt->usrServInfoA)); +#endif + if (siConEvnt->cdPtyNum.eh.pres != PRSNT_NODEF) memset(&siConEvnt->cdPtyNum, 0, sizeof(siConEvnt->cdPtyNum)); +#if TNS_ANSI +#if (SS7_ANS92 || SS7_ANS95 || SS7_BELL) + if (siConEvnt->tranNetSel1.eh.pres != PRSNT_NODEF) memset(&siConEvnt->tranNetSel1, 0, sizeof(siConEvnt->tranNetSel1)); +#endif +#endif + if (siConEvnt->tranNetSel.eh.pres != PRSNT_NODEF) memset(&siConEvnt->tranNetSel, 0, sizeof(siConEvnt->tranNetSel)); +#if (SS7_ANS88 || SS7_ANS92 || SS7_ANS95 || SS7_BELL || SS7_CHINA) + if (siConEvnt->callRefA.eh.pres != PRSNT_NODEF) memset(&siConEvnt->callRefA, 0, sizeof(siConEvnt->callRefA)); +#endif + if (siConEvnt->callRef.eh.pres != PRSNT_NODEF) memset(&siConEvnt->callRef, 0, sizeof(siConEvnt->callRef)); + if (siConEvnt->cgPtyNum.eh.pres != PRSNT_NODEF) memset(&siConEvnt->cgPtyNum, 0, sizeof(siConEvnt->cgPtyNum)); +#if SS7_BELL + if (siConEvnt->cgPtyNumB.eh.pres != PRSNT_NODEF) memset(&siConEvnt->cgPtyNumB, 0, sizeof(siConEvnt->cgPtyNumB)); +#endif + if (siConEvnt->opFwdCalInd.eh.pres != PRSNT_NODEF) memset(&siConEvnt->opFwdCalInd, 0, sizeof(siConEvnt->opFwdCalInd)); +#if (SS7_Q767 || SS7_RUSSIA || SS7_NTT) + if (siConEvnt->opFwdCalIndQ.eh.pres != PRSNT_NODEF) memset(&siConEvnt->opFwdCalIndQ, 0, sizeof(siConEvnt->opFwdCalIndQ)); +#endif +#if SS7_Q767IT + if (siConEvnt->fwdVad.eh.pres != PRSNT_NODEF) memset(&siConEvnt->fwdVad, 0, sizeof(siConEvnt->fwdVad)); +#endif +#if SS7_ANS88 + if (siConEvnt->opFwdCalIndA.eh.pres != PRSNT_NODEF) memset(&siConEvnt->opFwdCalIndA, 0, sizeof(siConEvnt->opFwdCalIndA)); +#endif + if (siConEvnt->redirgNum.eh.pres != PRSNT_NODEF) memset(&siConEvnt->redirgNum, 0, sizeof(siConEvnt->redirgNum)); + if (siConEvnt->redirInfo.eh.pres != PRSNT_NODEF) memset(&siConEvnt->redirInfo, 0, sizeof(siConEvnt->redirInfo)); + if (siConEvnt->cugIntCode.eh.pres != PRSNT_NODEF) memset(&siConEvnt->cugIntCode, 0, sizeof(siConEvnt->cugIntCode)); +#if SS7_ANS88 + if (siConEvnt->cugIntCodeA.eh.pres != PRSNT_NODEF) memset(&siConEvnt->cugIntCodeA, 0, sizeof(siConEvnt->cugIntCodeA)); +#endif +#if (SS7_ANS88 || SS7_ANS92 || SS7_ANS95 || SS7_BELL || SS7_CHINA) + if (siConEvnt->connReqA.eh.pres != PRSNT_NODEF) memset(&siConEvnt->connReqA, 0, sizeof(siConEvnt->connReqA)); +#endif +#if SS7_ANS88 + if (siConEvnt->usr2UsrInfoA.eh.pres != PRSNT_NODEF) memset(&siConEvnt->usr2UsrInfoA, 0, sizeof(siConEvnt->usr2UsrInfoA)); +#endif + if (siConEvnt->connReq.eh.pres != PRSNT_NODEF) memset(&siConEvnt->connReq, 0, sizeof(siConEvnt->connReq)); + if (siConEvnt->origCdNum.eh.pres != PRSNT_NODEF) memset(&siConEvnt->origCdNum, 0, sizeof(siConEvnt->origCdNum)); + if (siConEvnt->usr2UsrInfo.eh.pres != PRSNT_NODEF) memset(&siConEvnt->usr2UsrInfo, 0, sizeof(siConEvnt->usr2UsrInfo)); + if (siConEvnt->accTrnspt.eh.pres != PRSNT_NODEF) memset(&siConEvnt->accTrnspt, 0, sizeof(siConEvnt->accTrnspt)); + if (siConEvnt->echoControl.eh.pres != PRSNT_NODEF) memset(&siConEvnt->echoControl, 0, sizeof(siConEvnt->echoControl)); +#if SS7_ANS88 + if (siConEvnt->redirInfoA.eh.pres != PRSNT_NODEF) memset(&siConEvnt->redirInfoA, 0, sizeof(siConEvnt->redirInfoA)); +#endif +#if (SS7_ANS88 || SS7_ANS92 || SS7_ANS95 || SS7_BELL) + if (siConEvnt->chargeNum.eh.pres != PRSNT_NODEF) memset(&siConEvnt->chargeNum, 0, sizeof(siConEvnt->chargeNum)); + if (siConEvnt->origLineInf.eh.pres != PRSNT_NODEF) memset(&siConEvnt->origLineInf, 0, sizeof(siConEvnt->origLineInf)); +#endif + if (siConEvnt->usrServInfo.eh.pres != PRSNT_NODEF) memset(&siConEvnt->usrServInfo, 0, sizeof(siConEvnt->usrServInfo)); + if (siConEvnt->usr2UsrInd.eh.pres != PRSNT_NODEF) memset(&siConEvnt->usr2UsrInd, 0, sizeof(siConEvnt->usr2UsrInd)); + if (siConEvnt->propDly.eh.pres != PRSNT_NODEF) memset(&siConEvnt->propDly, 0, sizeof(siConEvnt->propDly)); + if (siConEvnt->usrServInfo1.eh.pres != PRSNT_NODEF) memset(&siConEvnt->usrServInfo1, 0, sizeof(siConEvnt->usrServInfo1)); + if (siConEvnt->netFac.eh.pres != PRSNT_NODEF) memset(&siConEvnt->netFac, 0, sizeof(siConEvnt->netFac)); +#ifdef SS7_CHINA + if (siConEvnt->orgPteCdeA.eh.pres != PRSNT_NODEF) memset(&siConEvnt->orgPteCdeA, 0, sizeof(siConEvnt->orgPteCdeA)); +#endif + if (siConEvnt->orgPteCde.eh.pres != PRSNT_NODEF) memset(&siConEvnt->orgPteCde, 0, sizeof(siConEvnt->orgPteCde)); + if (siConEvnt->genDigits.eh.pres != PRSNT_NODEF) memset(&siConEvnt->genDigits, 0, sizeof(siConEvnt->genDigits)); + if (siConEvnt->genDigitsR.eh.pres != PRSNT_NODEF) memset(&siConEvnt->genDigitsR, 0, sizeof(siConEvnt->genDigitsR)); + if (siConEvnt->usrTSrvInfo.eh.pres != PRSNT_NODEF) memset(&siConEvnt->usrTSrvInfo, 0, sizeof(siConEvnt->usrTSrvInfo)); + if (siConEvnt->remotOper.eh.pres != PRSNT_NODEF) memset(&siConEvnt->remotOper, 0, sizeof(siConEvnt->remotOper)); + if (siConEvnt->parmCom.eh.pres != PRSNT_NODEF) memset(&siConEvnt->parmCom, 0, sizeof(siConEvnt->parmCom)); +#if (SS7_ANS92 || SS7_ANS95) + if (siConEvnt->servCode.eh.pres != PRSNT_NODEF) memset(&siConEvnt->servCode, 0, sizeof(siConEvnt->servCode)); +#endif +#if SS7_ANS92 + if (siConEvnt->serviceAct1.eh.pres != PRSNT_NODEF) memset(&siConEvnt->serviceAct1, 0, sizeof(siConEvnt->serviceAct1)); +#endif +#if SS7_CHINA + if (siConEvnt->serviceAct2.eh.pres != PRSNT_NODEF) memset(&siConEvnt->serviceAct2, 0, sizeof(siConEvnt->serviceAct2)); +#endif + if (siConEvnt->serviceAct2.eh.pres != PRSNT_NODEF) memset(&siConEvnt->serviceAct2, 0, sizeof(siConEvnt->serviceAct2)); + if (siConEvnt->serviceAct.eh.pres != PRSNT_NODEF) memset(&siConEvnt->serviceAct, 0, sizeof(siConEvnt->serviceAct)); + if (siConEvnt->mlppPrec.eh.pres != PRSNT_NODEF) memset(&siConEvnt->mlppPrec, 0, sizeof(siConEvnt->mlppPrec)); +#if (defined(SIT_PARAMETER) || defined(TDS_ROLL_UPGRADE_SUPPORT)) + if (siConEvnt->txMedUsPr.eh.pres != PRSNT_NODEF) memset(&siConEvnt->txMedUsPr, 0, sizeof(siConEvnt->txMedUsPr)); +#endif + if (siConEvnt->bckCallInd.eh.pres != PRSNT_NODEF) memset(&siConEvnt->bckCallInd, 0, sizeof(siConEvnt->bckCallInd)); + if (siConEvnt->cgPtyNum1.eh.pres != PRSNT_NODEF) memset(&siConEvnt->cgPtyNum1, 0, sizeof(siConEvnt->cgPtyNum1)); + if (siConEvnt->optBckCalInd.eh.pres != PRSNT_NODEF) memset(&siConEvnt->optBckCalInd, 0, sizeof(siConEvnt->optBckCalInd)); +#if (SS7_Q767 || SS7_RUSSIA || SS7_NTT) + if (siConEvnt->optBckCalIndQ.eh.pres != PRSNT_NODEF) memset(&siConEvnt->optBckCalIndQ, 0, sizeof(siConEvnt->optBckCalIndQ)); +#endif + if (siConEvnt->connNum.eh.pres != PRSNT_NODEF) memset(&siConEvnt->connNum, 0, sizeof(siConEvnt->connNum)); +#if (defined(SIT_PARAMETER) || defined(TDS_ROLL_UPGRADE_SUPPORT)) + if (siConEvnt->connNum2.eh.pres != PRSNT_NODEF) memset(&siConEvnt->connNum2, 0, sizeof(siConEvnt->connNum2)); +#endif + if (siConEvnt->accDelInfo.eh.pres != PRSNT_NODEF) memset(&siConEvnt->accDelInfo, 0, sizeof(siConEvnt->accDelInfo)); + if (siConEvnt->notifInd.eh.pres != PRSNT_NODEF) memset(&siConEvnt->notifInd, 0, sizeof(siConEvnt->notifInd)); + if (siConEvnt->notifIndR2.eh.pres != PRSNT_NODEF) memset(&siConEvnt->notifIndR2, 0, sizeof(siConEvnt->notifIndR2)); + if (siConEvnt->cllHstry.eh.pres != PRSNT_NODEF) memset(&siConEvnt->cllHstry, 0, sizeof(siConEvnt->cllHstry)); + if (siConEvnt->genNmb.eh.pres != PRSNT_NODEF) memset(&siConEvnt->genNmb, 0, sizeof(siConEvnt->genNmb)); + if (siConEvnt->genNmbR.eh.pres != PRSNT_NODEF) memset(&siConEvnt->genNmbR, 0, sizeof(siConEvnt->genNmbR)); + if (siConEvnt->redirNum.eh.pres != PRSNT_NODEF) memset(&siConEvnt->redirNum, 0, sizeof(siConEvnt->redirNum)); + if (siConEvnt->redirRstr.eh.pres != PRSNT_NODEF) memset(&siConEvnt->redirRstr, 0, sizeof(siConEvnt->redirRstr)); + +#if SS7_Q767IT + if (siConEvnt->backVad.eh.pres != PRSNT_NODEF) memset(&siConEvnt->backVad, 0, sizeof(siConEvnt->backVad)); +#endif +#if SS7_SINGTEL + if (siConEvnt->cgPtyNumS.eh.pres != PRSNT_NODEF) memset(&siConEvnt->cgPtyNumS, 0, sizeof(siConEvnt->cgPtyNumS)); +#endif +#if (SS7_ANS92 || SS7_ANS95 || SS7_BELL) + if (siConEvnt->businessGrp.eh.pres != PRSNT_NODEF) memset(&siConEvnt->businessGrp, 0, sizeof(siConEvnt->businessGrp)); + if (siConEvnt->infoInd.eh.pres != PRSNT_NODEF) memset(&siConEvnt->infoInd, 0, sizeof(siConEvnt->infoInd)); + if (siConEvnt->carrierId.eh.pres != PRSNT_NODEF) memset(&siConEvnt->carrierId, 0, sizeof(siConEvnt->carrierId)); + if (siConEvnt->carSelInf.eh.pres != PRSNT_NODEF) memset(&siConEvnt->carSelInf, 0, sizeof(siConEvnt->carSelInf)); + if (siConEvnt->egress.eh.pres != PRSNT_NODEF) memset(&siConEvnt->egress, 0, sizeof(siConEvnt->egress)); + if (siConEvnt->genAddr.eh.pres != PRSNT_NODEF) memset(&siConEvnt->genAddr, 0, sizeof(siConEvnt->genAddr)); + if (siConEvnt->genAddrR.eh.pres != PRSNT_NODEF) memset(&siConEvnt->genAddrR, 0, sizeof(siConEvnt->genAddrR)); + if (siConEvnt->infoReqInd.eh.pres != PRSNT_NODEF) memset(&siConEvnt->infoReqInd, 0, sizeof(siConEvnt->infoReqInd)); + if (siConEvnt->jurisInf.eh.pres != PRSNT_NODEF) memset(&siConEvnt->jurisInf, 0, sizeof(siConEvnt->jurisInf)); + if (siConEvnt->netTransport.eh.pres != PRSNT_NODEF) memset(&siConEvnt->netTransport, 0, sizeof(siConEvnt->netTransport)); + if (siConEvnt->specProcReq.eh.pres != PRSNT_NODEF) memset(&siConEvnt->specProcReq, 0, sizeof(siConEvnt->specProcReq)); + if (siConEvnt->transReq.eh.pres != PRSNT_NODEF) memset(&siConEvnt->transReq, 0, sizeof(siConEvnt->transReq)); +#endif +#if (defined(SIT_PARAMETER) || defined(TDS_ROLL_UPGRADE_SUPPORT)) +#if (SS7_ANS92 || SS7_ANS95) + if (siConEvnt->notifInd1.eh.pres != PRSNT_NODEF) memset(&siConEvnt->notifInd1, 0, sizeof(siConEvnt->notifInd1)); + if (siConEvnt->notifIndR1.eh.pres != PRSNT_NODEF) memset(&siConEvnt->notifIndR1, 0, sizeof(siConEvnt->notifIndR1)); +#endif /* SS7_ANS92 */ +#endif /* SIT_PARAMETER || TDS_ROLL_UPGRADE_SUPPORT */ +#if (SS7_BELL || SS7_ANS95) + if (siConEvnt->genName.eh.pres != PRSNT_NODEF) memset(&siConEvnt->genName, 0, sizeof(siConEvnt->genName)); +#endif +#if (SS7_ITU97 || SS7_RUSS2000 || SS7_ITU2000 || SS7_ETSIV3 || \ + SS7_BELL || SS7_ANS95 || SS7_INDIA || SS7_UK || SS7_NZL || SS7_KZ) + if (siConEvnt->hopCounter.eh.pres != PRSNT_NODEF) memset(&siConEvnt->hopCounter, 0, sizeof(siConEvnt->hopCounter)); +#endif +#if (SS7_BELL || SS7_ITU2000 || SS7_KZ) + if (siConEvnt->redirCap.eh.pres != PRSNT_NODEF) memset(&siConEvnt->redirCap, 0, sizeof(siConEvnt->redirCap)); + if (siConEvnt->redirCntr.eh.pres != PRSNT_NODEF) memset(&siConEvnt->redirCntr, 0, sizeof(siConEvnt->redirCntr)); +#endif +#if (SS7_ETSI || SS7_FTZ) + if (siConEvnt->ccbsParam.eh.pres != PRSNT_NODEF) memset(&siConEvnt->ccbsParam, 0, sizeof(siConEvnt->ccbsParam)); + if (siConEvnt->freePhParam.eh.pres != PRSNT_NODEF) memset(&siConEvnt->freePhParam, 0, sizeof(siConEvnt->freePhParam)); +#endif +#ifdef SS7_FTZ + if (siConEvnt->naPaFF.eh.pres != PRSNT_NODEF) memset(&siConEvnt->naPaFF, 0, sizeof(siConEvnt->naPaFF)); + if (siConEvnt->naPaFE.eh.pres != PRSNT_NODEF) memset(&siConEvnt->naPaFE, 0, sizeof(siConEvnt->naPaFE)); + if (siConEvnt->naPaSSP.eh.pres != PRSNT_NODEF) memset(&siConEvnt->naPaSSP, 0, sizeof(siConEvnt->naPaSSP)); + if (siConEvnt->naPaCdPNO.eh.pres != PRSNT_NODEF) memset(&siConEvnt->naPaCdPNO, 0, sizeof(siConEvnt->naPaCdPNO)); + if (siConEvnt->naPaSPV.eh.pres != PRSNT_NODEF) memset(&siConEvnt->naPaSPV, 0, sizeof(siConEvnt->naPaSPV)); + if (siConEvnt->naPaUKK.eh.pres != PRSNT_NODEF) memset(&siConEvnt->naPaUKK, 0, sizeof(siConEvnt->naPaUKK)); +#endif +#if SS7_NTT + if (siConEvnt->msgAreaInfo.eh.pres != PRSNT_NODEF) memset(&siConEvnt->msgAreaInfo, 0, sizeof(siConEvnt->msgAreaInfo)); + if (siConEvnt->subsNumber.eh.pres != PRSNT_NODEF) memset(&siConEvnt->subsNumber, 0, sizeof(siConEvnt->subsNumber)); + if (siConEvnt->rpCllngNo.eh.pres != PRSNT_NODEF) memset(&siConEvnt->rpCllngNo, 0, sizeof(siConEvnt->rpCllngNo)); + if (siConEvnt->supplUserType.eh.pres != PRSNT_NODEF) memset(&siConEvnt->supplUserType, 0, sizeof(siConEvnt->supplUserType)); + if (siConEvnt->carrierInfoTrans.eh.pres != PRSNT_NODEF) memset(&siConEvnt->carrierInfoTrans, 0, sizeof(siConEvnt->carrierInfoTrans)); + if (siConEvnt->nwFuncType.eh.pres != PRSNT_NODEF) memset(&siConEvnt->nwFuncType, 0, sizeof(siConEvnt->nwFuncType)); +#endif +#if SS7_ANS95 + if (siConEvnt->optrServicesInfo.eh.pres != PRSNT_NODEF) memset(&siConEvnt->optrServicesInfo, 0, sizeof(siConEvnt->optrServicesInfo)); +#endif +#if (SS7_ANS95 || SS7_ITU97 || SS7_RUSS2000|| SS7_ITU2000 || SS7_NZL || SS7_KZ) + if (siConEvnt->cirAsgnMap.eh.pres != PRSNT_NODEF) memset(&siConEvnt->cirAsgnMap, 0, sizeof(siConEvnt->cirAsgnMap)); +#endif +#if (SS7_ITU97 || SS7_RUSS2000 || SS7_ITU2000 || SS7_ETSIV3 || \ + SS7_INDIA || SS7_UK || SS7_NZL || SS7_KZ) + if (siConEvnt->displayInfo.eh.pres != PRSNT_NODEF) memset(&siConEvnt->displayInfo, 0, sizeof(siConEvnt->displayInfo)); + if (siConEvnt->confTrtInd.eh.pres != PRSNT_NODEF) memset(&siConEvnt->confTrtInd, 0, sizeof(siConEvnt->confTrtInd)); + if (siConEvnt->netMgmtControls.eh.pres != PRSNT_NODEF) memset(&siConEvnt->netMgmtControls, 0, sizeof(siConEvnt->netMgmtControls)); + if (siConEvnt->correlationId.eh.pres != PRSNT_NODEF) memset(&siConEvnt->correlationId, 0, sizeof(siConEvnt->correlationId)); + if (siConEvnt->callDivTrtInd.eh.pres != PRSNT_NODEF) memset(&siConEvnt->callDivTrtInd, 0, sizeof(siConEvnt->callDivTrtInd)); + if (siConEvnt->callInNmb.eh.pres != PRSNT_NODEF) memset(&siConEvnt->callInNmb, 0, sizeof(siConEvnt->callInNmb)); + if (siConEvnt->callOfferTrtInd.eh.pres != PRSNT_NODEF) memset(&siConEvnt->callOfferTrtInd, 0, sizeof(siConEvnt->callOfferTrtInd)); + if (siConEvnt->scfId.eh.pres != PRSNT_NODEF) memset(&siConEvnt->scfId, 0, sizeof(siConEvnt->scfId)); + if (siConEvnt->uidCapInd.eh.pres != PRSNT_NODEF) memset(&siConEvnt->uidCapInd, 0, sizeof(siConEvnt->uidCapInd)); + if (siConEvnt->collCallReq.eh.pres != PRSNT_NODEF) memset(&siConEvnt->collCallReq, 0, sizeof(siConEvnt->collCallReq)); + if (siConEvnt->ccss.eh.pres != PRSNT_NODEF) memset(&siConEvnt->ccss, 0, sizeof(siConEvnt->ccss)); +#endif +#if (SS7_ITU97 || SS7_RUSS2000 || SS7_ITU2000 || SS7_UK || SS7_NZL || SS7_KZ) + if (siConEvnt->backGVNS.eh.pres != PRSNT_NODEF) memset(&siConEvnt->backGVNS, 0, sizeof(siConEvnt->backGVNS)); + if (siConEvnt->forwardGVNS.eh.pres != PRSNT_NODEF) memset(&siConEvnt->forwardGVNS, 0, sizeof(siConEvnt->forwardGVNS)); +#endif +#if (SS7_ETSIV3 || SS7_ITU97 || SS7_RUSS2000 || SS7_ITU2000 || \ + SS7_INDIA || SS7_UK || SS7_NZL || SS7_KZ) + if (siConEvnt->appTransParam.eh.pres != PRSNT_NODEF) memset(&siConEvnt->appTransParam, 0, sizeof(siConEvnt->appTransParam)); +#endif +#if (SS7_ITU2000 || SS7_UK || SS7_NZL || SS7_KZ) + if (siConEvnt->htrInfo.eh.pres != PRSNT_NODEF) memset(&siConEvnt->htrInfo, 0, sizeof(siConEvnt->htrInfo)); + if (siConEvnt->pivotCap.eh.pres != PRSNT_NODEF) memset(&siConEvnt->pivotCap, 0, sizeof(siConEvnt->pivotCap)); + if (siConEvnt->cadDirNmb.eh.pres != PRSNT_NODEF) memset(&siConEvnt->cadDirNmb, 0, sizeof(siConEvnt->cadDirNmb)); + if (siConEvnt->origCallInNum.eh.pres != PRSNT_NODEF) memset(&siConEvnt->origCallInNum, 0, sizeof(siConEvnt->origCallInNum)); + if (siConEvnt->calgGeoLoc.eh.pres != PRSNT_NODEF) memset(&siConEvnt->calgGeoLoc, 0, sizeof(siConEvnt->calgGeoLoc)); + if (siConEvnt->netRoutNum.eh.pres != PRSNT_NODEF) memset(&siConEvnt->netRoutNum, 0, sizeof(siConEvnt->netRoutNum)); + if (siConEvnt->qonRelCap.eh.pres != PRSNT_NODEF) memset(&siConEvnt->qonRelCap, 0, sizeof(siConEvnt->qonRelCap)); + if (siConEvnt->pivotCntr.eh.pres != PRSNT_NODEF) memset(&siConEvnt->pivotCntr, 0, sizeof(siConEvnt->pivotCntr)); + if (siConEvnt->pivotRtgFwInfo.eh.pres != PRSNT_NODEF) memset(&siConEvnt->pivotRtgFwInfo, 0, sizeof(siConEvnt->pivotRtgFwInfo)); + if (siConEvnt->pivotRtgBkInfo.eh.pres != PRSNT_NODEF) memset(&siConEvnt->pivotRtgBkInfo, 0, sizeof(siConEvnt->pivotRtgBkInfo)); + if (siConEvnt->numPortFwdInfo.eh.pres != PRSNT_NODEF) memset(&siConEvnt->numPortFwdInfo, 0, sizeof(siConEvnt->numPortFwdInfo)); +#endif +#ifdef SS7_UK + if (siConEvnt->natFwdCalInd.eh.pres != PRSNT_NODEF) memset(&siConEvnt->natFwdCalInd, 0, sizeof(siConEvnt->natFwdCalInd)); + if (siConEvnt->presntNum.eh.pres != PRSNT_NODEF) memset(&siConEvnt->presntNum, 0, sizeof(siConEvnt->presntNum)); + if (siConEvnt->lstDvrtLineId.eh.pres != PRSNT_NODEF) memset(&siConEvnt->lstDvrtLineId, 0, sizeof(siConEvnt->lstDvrtLineId)); + if (siConEvnt->pcgLineId.eh.pres != PRSNT_NODEF) memset(&siConEvnt->pcgLineId, 0, sizeof(siConEvnt->pcgLineId)); + if (siConEvnt->natFwdCalIndLnk.eh.pres != PRSNT_NODEF) memset(&siConEvnt->natFwdCalIndLnk, 0, sizeof(siConEvnt->natFwdCalIndLnk)); + if (siConEvnt->cdBascSrvcMrk.eh.pres != PRSNT_NODEF) memset(&siConEvnt->cdBascSrvcMrk, 0, sizeof(siConEvnt->cdBascSrvcMrk)); +#endif /* SS7_UK */ +#if (defined(CGPN_CHK)) + if (siConEvnt->causeDgnCgPnChk.eh.pres != PRSNT_NODEF) memset(&siConEvnt->causeDgnCgPnChk, 0, sizeof(siConEvnt->causeDgnCgPnChk)); +#endif + return FTDM_SUCCESS; +} + +ftdm_status_t sngss7_save_iam(ftdm_channel_t *ftdmchan, SiConEvnt *siConEvnt) +{ +#ifndef HAVE_ZLIB + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Cannot perform transparent IAM because zlib is missing\n"); + return FTDM_FAIL; +#else + unsigned ret_val = FTDM_FAIL; + char *compressed_iam = NULL; + char *url_encoded_iam = NULL; + uLongf len = sizeof(*siConEvnt); + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + /* By default, Trillium does not memset their whole structure to zero for + * performance. But we want to memset all the IE's that are not present to + * optimize compressed size */ + sngss7_bufferzero_iam(siConEvnt); + + compressed_iam = ftdm_malloc(sizeof(*siConEvnt)); + if (!compressed_iam) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to allocate buffer for compressed_iam\n"); + goto done; + } + + /* Compress IAM structure to minimize buffer size */ + ret_val = compress((Bytef *)compressed_iam, &len, (const Bytef *)siConEvnt, (uLong)sizeof(*siConEvnt)); + if (ret_val != Z_OK) { + ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Failed to compress IAM (error:%d)\n", ret_val); + ret_val = FTDM_FAIL; + goto done; + } + + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Compressed IAM size:%d\n", len); + + /* Worst case: size will triple after url encode */ + url_encoded_iam = ftdm_malloc(3*sizeof(*siConEvnt)); + if (!url_encoded_iam) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to allocated buffer for url_encoded_iam\n"); + ret_val = FTDM_FAIL; + goto done; + } + memset(url_encoded_iam, 0, 2*sizeof(*siConEvnt)); + + /* URL encode buffer to that its safe to store it in a string */ + ftdm_url_encode((const char*)compressed_iam, url_encoded_iam, len); + + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "IAM variable length:%d\n", strlen(url_encoded_iam)); + + if (strlen(url_encoded_iam) > g_ftdm_sngss7_data.cfg.transparent_iam_max_size) { + ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "IAM variable length exceeds max size (len:%d max:%d) \n", strlen(url_encoded_iam), g_ftdm_sngss7_data.cfg.transparent_iam_max_size); + ret_val = FTDM_FAIL; + goto done; + } + + sngss7_add_var(sngss7_info, "ss7_iam", url_encoded_iam); +done: + ftdm_safe_free(compressed_iam); + ftdm_safe_free(url_encoded_iam); + return ret_val; +#endif +} + +ftdm_status_t sngss7_retrieve_iam(ftdm_channel_t *ftdmchan, SiConEvnt *siConEvnt) +{ +#ifndef HAVE_ZLIB + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Cannot perform transparent IAM because zlib is missing\n"); + return FTDM_FAIL; +#else + uLongf len = 3*sizeof(*siConEvnt); /* worst case: URL encoded buffer is 3x length of buffer */ + char *val = NULL; + unsigned ret_val = FTDM_FAIL; + void *uncompressed_buffer = NULL; + char *url_encoded_iam = NULL; + ftdm_size_t url_encoded_iam_len; + + val = (char*)ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam"); + if (ftdm_strlen_zero(val)) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No Transparent IAM info available\n"); + return FTDM_FAIL; + } + + url_encoded_iam = ftdm_strdup(val); + + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "IAM variable length:%d\n", strlen(val)); + ftdm_url_decode(url_encoded_iam, &url_encoded_iam_len); + + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Compressed IAM size:%d\n", url_encoded_iam_len); + + uncompressed_buffer = ftdm_malloc(sizeof(*siConEvnt)); + ftdm_assert_return(uncompressed_buffer, FTDM_FAIL, "Failed to allocate buffer for uncompressed buffer\n"); + + ret_val = uncompress(uncompressed_buffer, &len, (const Bytef *)url_encoded_iam, (uLong)url_encoded_iam_len); + if (ret_val != Z_OK) { + ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Failed to uncompress IAM (error:%d)\n", ret_val); + goto done; + } + + if (len != sizeof(*siConEvnt)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Incompatible IAM structure size (expected:%d size:%d)\n", sizeof(*siConEvnt), strlen(uncompressed_buffer)); + goto done; + } + + memcpy(siConEvnt, uncompressed_buffer, sizeof(*siConEvnt)); + ret_val = FTDM_SUCCESS; + +done: + ftdm_safe_free(uncompressed_buffer); + ftdm_safe_free(url_encoded_iam); + return ret_val; +#endif +} + /******************************************************************************/ /* For Emacs: * Local Variables: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 2df0a88edb..a891c50108 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -124,7 +124,8 @@ typedef struct sng_ccSpan uint32_t cld_nadi; uint32_t rdnis_nadi; uint32_t min_digits; - uint32_t itx_auto_reply; + uint8_t itx_auto_reply; + uint8_t transparent_iam; uint32_t t3; uint32_t t12; uint32_t t13; @@ -466,6 +467,9 @@ static int ftmod_ss7_parse_sng_gen(ftdm_conf_node_t *sng_gen) SS7_DEBUG("Found license file = %s\n", g_ftdm_sngss7_data.cfg.license); SS7_DEBUG("Found signature file = %s\n", g_ftdm_sngss7_data.cfg.signature); /**********************************************************************/ + } else if (!strcasecmp(parm->var, "transparent_iam_max_size")) { + g_ftdm_sngss7_data.cfg.transparent_iam_max_size = atoi(parm->val); + SS7_DEBUG("Found a transparent_iam max size = %d\n", g_ftdm_sngss7_data.cfg.transparent_iam_max_size); } else { /**********************************************************************/ SS7_ERROR("Found an invalid parameter \"%s\"!\n", parm->val); @@ -1896,6 +1900,13 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) } else if (!strcasecmp(parm->var, "itx_auto_reply")) { sng_ccSpan.itx_auto_reply = ftdm_true(parm->val); SS7_DEBUG("Found itx_auto_reply %d\n", sng_ccSpan.itx_auto_reply); + } else if (!strcasecmp(parm->var, "transparent_iam")) { +#ifndef HAVE_ZLIB + SS7_CRIT("Cannot enable transparent IAM becauze zlib not installed\n"); +#else + sng_ccSpan.transparent_iam = ftdm_true(parm->val); + SS7_DEBUG("Found transparent_iam %d\n", sng_ccSpan.transparent_iam); +#endif } else if (!strcasecmp(parm->var, "cicbase")) { /**********************************************************************/ sng_ccSpan.cicbase = atoi(parm->val); @@ -2907,16 +2918,17 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan) g_ftdm_sngss7_data.cfg.isupCkt[x].cic = 0; } - g_ftdm_sngss7_data.cfg.isupCkt[x].infId = ccSpan->isupInf; - g_ftdm_sngss7_data.cfg.isupCkt[x].typeCntrl = ccSpan->typeCntrl; - g_ftdm_sngss7_data.cfg.isupCkt[x].ssf = ccSpan->ssf; - g_ftdm_sngss7_data.cfg.isupCkt[x].cld_nadi = ccSpan->cld_nadi; - g_ftdm_sngss7_data.cfg.isupCkt[x].clg_nadi = ccSpan->clg_nadi; - g_ftdm_sngss7_data.cfg.isupCkt[x].rdnis_nadi = ccSpan->rdnis_nadi; - g_ftdm_sngss7_data.cfg.isupCkt[x].options = ccSpan->options; - g_ftdm_sngss7_data.cfg.isupCkt[x].switchType = ccSpan->switchType; - g_ftdm_sngss7_data.cfg.isupCkt[x].min_digits = ccSpan->min_digits; - g_ftdm_sngss7_data.cfg.isupCkt[x].itx_auto_reply = ccSpan->itx_auto_reply; + g_ftdm_sngss7_data.cfg.isupCkt[x].infId = ccSpan->isupInf; + g_ftdm_sngss7_data.cfg.isupCkt[x].typeCntrl = ccSpan->typeCntrl; + g_ftdm_sngss7_data.cfg.isupCkt[x].ssf = ccSpan->ssf; + g_ftdm_sngss7_data.cfg.isupCkt[x].cld_nadi = ccSpan->cld_nadi; + g_ftdm_sngss7_data.cfg.isupCkt[x].clg_nadi = ccSpan->clg_nadi; + g_ftdm_sngss7_data.cfg.isupCkt[x].rdnis_nadi = ccSpan->rdnis_nadi; + g_ftdm_sngss7_data.cfg.isupCkt[x].options = ccSpan->options; + g_ftdm_sngss7_data.cfg.isupCkt[x].switchType = ccSpan->switchType; + g_ftdm_sngss7_data.cfg.isupCkt[x].min_digits = ccSpan->min_digits; + g_ftdm_sngss7_data.cfg.isupCkt[x].itx_auto_reply = ccSpan->itx_auto_reply; + g_ftdm_sngss7_data.cfg.isupCkt[x].transparent_iam = ccSpan->transparent_iam; if (ccSpan->t3 == 0) { g_ftdm_sngss7_data.cfg.isupCkt[x].t3 = 1200; diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 6b14d14524..1d27b946e3 100755 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -276,12 +276,16 @@ FTDM_STR2ENUM_P(ftdm_str2ftdm_screening, ftdm_screening2str, ftdm_screening_t) /*! \brief bearer capability */ typedef enum { - FTDM_BEARER_CAP_SPEECH = 0x00, - FTDM_BEARER_CAP_64K_UNRESTRICTED = 0x02, - FTDM_BEARER_CAP_3_1KHZ_AUDIO = 0x03, + FTDM_BEARER_CAP_SPEECH = 0x00, /* Speech */ + FTDM_BEARER_CAP_UNRESTRICTED, /* Unrestricted Digital */ + FTDM_BEARER_CAP_RESTRICTED, /* Restricted Digital */ + FTDM_BEARER_CAP_3_1KHZ_AUDIO, /* 3.1 Khz Audio */ + FTDM_BEARER_CAP_7KHZ_AUDIO, /* 7 Khz Audio or Unrestricted digital w tones */ + FTDM_BEARER_CAP_15KHZ_AUDIO, /* 15 Khz Audio */ + FTDM_BEARER_CAP_VIDEO, /* Video */ FTDM_BEARER_CAP_INVALID } ftdm_bearer_cap_t; -#define BEARER_CAP_STRINGS "speech", "unrestricted-digital-information", "3.1-Khz-audio", "invalid" +#define BEARER_CAP_STRINGS "speech", "unrestricted-digital-information", "restricted-digital-information", "3.1-Khz-audio", "7-Khz-audio", "15-Khz-audio", "video", "invalid" FTDM_STR2ENUM_P(ftdm_str2ftdm_bearer_cap, ftdm_bearer_cap2str, ftdm_bearer_cap_t) /*! \brief user information layer 1 protocol */ diff --git a/libs/freetdm/src/include/ftdm_call_utils.h b/libs/freetdm/src/include/ftdm_call_utils.h index 2418273343..975e73e729 100644 --- a/libs/freetdm/src/include/ftdm_call_utils.h +++ b/libs/freetdm/src/include/ftdm_call_utils.h @@ -131,5 +131,24 @@ FT_DECLARE(ftdm_status_t) ftdm_is_number(const char *number); */ FT_DECLARE(ftdm_status_t) ftdm_set_calling_party_category(const char *string, uint8_t *target); +/*! + * \brief URL encode a buffer + * + * \param url buffer to convert + * \param buf target to save converted string to + * \param len size of buffer + * + * \retval pointer to converted string + */ +FT_DECLARE(char *) ftdm_url_encode(const char *url, char *buf, ftdm_size_t len); + +/*! + * \param s buffer to convert + * \param len size of buffer + * + * \retval pointer to converted string + */ +FT_DECLARE(char *) ftdm_url_decode(char *s, ftdm_size_t *len); + #endif /* __FTDM_CALL_UTILS_H__ */ From 0bdf79b17c8ed811b0a75f537e58bab63d7d0f94 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 17 May 2011 14:17:00 -0400 Subject: [PATCH 028/822] mod_sangoma_codec: AMR codec fixes - Set the proper RTP payload - Do not validate RTP reads when the size is dynamic (zero) --- src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c b/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c index dd97453c7a..5b12eb6448 100644 --- a/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c +++ b/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c @@ -96,7 +96,7 @@ vocallo_codec_t g_codec_map[] = /* manually initialized */ { SNGTC_CODEC_GSM_FR, IANA_GSM_A_8000_1, "GSM", "Sangoma GSM", 20, 13200, 20000, 160, 320, 33, 8000, 8000, 0 }, { SNGTC_CODEC_G723_1_63, IANA_G723_A_8000_1, "G723", "Sangoma G723", 90, 6300, 30000, 240, 480, 24, 8000, 8000, 0 }, - { SNGTC_CODEC_AMR_1220, IANA_AMR_WB_16000_1, "AMR", "Sangoma AMR", 20, 12200, 20000, 160, 320, 0, 8000, 8000, 0 }, + { SNGTC_CODEC_AMR_1220, IANA_AMR_A_8000_1, "AMR", "Sangoma AMR", 20, 12200, 20000, 160, 320, 0, 8000, 8000, 0 }, { SNGTC_CODEC_SIREN7_24, IANA_SIREN7, "G7221", "Sangoma G722.1", 20, 24000, 20000, 320, 640, 60, 16000, 16000, 0 }, { SNGTC_CODEC_SIREN7_32, IANA_SIREN7, "G7221", "Sangoma G722.1", 20, 32000, 20000, 320, 640, 80, 16000, 16000, 0 }, { SNGTC_CODEC_ILBC_133, IANA_ILBC_133_8000_1, "iLBC", "Sangoma iLBC", 30, 13300, 30000, 240, 480, 50, 8000, 8000, 0 }, @@ -131,6 +131,7 @@ struct codec_data { /* packet counters */ unsigned long tx; unsigned long rx; + unsigned long ticks; /* Lost packets */ long lastrxseqno; @@ -467,6 +468,8 @@ static switch_status_t switch_sangoma_encode(switch_codec_t *codec, switch_codec func_start_time = switch_micro_time_now(); } + sess->encoder.ticks++; + /* start assuming we will not encode anything */ *encoded_data_len = 0; @@ -547,7 +550,7 @@ static switch_status_t switch_sangoma_encode(switch_codec_t *codec, switch_codec continue; } - if (encoded_frame.datalen != codec->implementation->encoded_bytes_per_packet) { + if (codec->implementation->encoded_bytes_per_packet && encoded_frame.datalen != codec->implementation->encoded_bytes_per_packet) { /* seen when silence suppression is enabled */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Ignoring encoded frame of %d bytes intead of %d bytes\n", encoded_frame.datalen, codec->implementation->encoded_bytes_per_packet); continue; @@ -619,7 +622,7 @@ static switch_status_t switch_sangoma_encode(switch_codec_t *codec, switch_codec sess->encoder.rtp_queue[sess->encoder.queue_rindex].datalen = 0; SAFE_INDEX_INC(sess->encoder.rtp_queue, sess->encoder.queue_rindex); sess->encoder.queue_size--; - if (*encoded_data_len != codec->implementation->encoded_bytes_per_packet) { + if (codec->implementation->encoded_bytes_per_packet && *encoded_data_len != codec->implementation->encoded_bytes_per_packet) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Returning odd encoded frame of %d bytes intead of %d bytes\n", *encoded_data_len, codec->implementation->encoded_bytes_per_packet); } } else { @@ -667,6 +670,7 @@ static switch_status_t switch_sangoma_decode(switch_codec_t *codec, /* codec ses } dbuf_linear = decoded_data; + sess->decoder.ticks++; /* start assuming we will not decode anything */ *decoded_data_len = 0; @@ -989,6 +993,7 @@ SWITCH_STANDARD_API(sangoma_function) stream->write_function(stream, "Rx %s at %d.%d.%d.%d:%d from %d.%d.%d.%d:%d\n\n", sess->impl->iananame, SNGTC_NIPV4(sess->encoder.reply.b.host_ip), sess->encoder.reply.b.host_udp_port, SNGTC_NIPV4(sess->encoder.reply.b.codec_ip), sess->encoder.reply.b.codec_udp_port); + stream->write_function(stream, "Ticks: %lu\n", sess->encoder.ticks); stream->write_function(stream, "-- Inbound Stats --\n"); stream->write_function(stream, "Rx Discarded: %lu\n", sess->encoder.rxdiscarded); @@ -1008,6 +1013,7 @@ SWITCH_STANDARD_API(sangoma_function) SNGTC_NIPV4(sess->decoder.reply.a.codec_ip), sess->decoder.reply.a.codec_udp_port); stream->write_function(stream, "Rx L16 at %d.%d.%d.%d:%d from %d.%d.%d.%d:%d\n\n", SNGTC_NIPV4(sess->decoder.reply.b.host_ip), sess->decoder.reply.b.host_udp_port, SNGTC_NIPV4(sess->decoder.reply.b.codec_ip), sess->decoder.reply.b.codec_udp_port); + stream->write_function(stream, "Ticks: %lu\n", sess->decoder.ticks); stream->write_function(stream, "-- Inbound Stats --\n"); stream->write_function(stream, "Rx Discarded: %lu\n", sess->decoder.rxdiscarded); From 7db91251c8dbed559ca2b62e89daaf5a5c61d7b7 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 30 May 2011 18:49:15 -0400 Subject: [PATCH 029/822] modified switch.c to not create PID file until all modules are loaded this help init scripts to check when everything is really loaded. Also return 1 when loading modules fails, do not return 255 which can be confused with a segmentation fault or some other more violent code --- src/switch.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/switch.c b/src/switch.c index f5ffe950e2..5b71b64e8d 100644 --- a/src/switch.c +++ b/src/switch.c @@ -894,6 +894,11 @@ int main(int argc, char *argv[]) switch_dir_make_recursive(SWITCH_GLOBAL_dirs.run_dir, SWITCH_DEFAULT_DIR_PERMS, pool); + if (switch_core_init_and_modload(flags, nc ? SWITCH_FALSE : SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { + fprintf(stderr, "Failed to initialize modules: %s\n", err); + return 1; + } + if (switch_file_open(&fd, pid_path, SWITCH_FOPEN_READ, SWITCH_FPROT_UREAD | SWITCH_FPROT_UWRITE, pool) == SWITCH_STATUS_SUCCESS) { old_pid_len = sizeof(old_pid_buffer); @@ -920,14 +925,6 @@ int main(int argc, char *argv[]) switch_file_write(fd, pid_buffer, &pid_len); - if (switch_core_init_and_modload(flags, nc ? SWITCH_FALSE : SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { - fprintf(stderr, "Cannot Initialize [%s], deleting pid file [%s]\n", err, pid_path); - if (unlink(pid_path) != 0) { - fprintf(stderr, "Failed to delete pid file [%s]\n", pid_path); - } - return 255; - } - #ifndef WIN32 if (do_wait) { kill(getppid(), SIGUSR2); From cbb82ad6404b93781eec48983c04dc300bdfb789 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 30 May 2011 18:49:15 -0400 Subject: [PATCH 030/822] modified switch.c to not create PID file until all modules are loaded this help init scripts to check when everything is really loaded. Also return 1 when loading modules fails, do not return 255 which can be confused with a segmentation fault or some other more violent code --- src/switch.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/switch.c b/src/switch.c index 7e81ab01cf..fcc367c8c8 100644 --- a/src/switch.c +++ b/src/switch.c @@ -894,6 +894,11 @@ int main(int argc, char *argv[]) switch_dir_make_recursive(SWITCH_GLOBAL_dirs.run_dir, SWITCH_DEFAULT_DIR_PERMS, pool); + if (switch_core_init_and_modload(flags, nc ? SWITCH_FALSE : SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { + fprintf(stderr, "Failed to initialize modules: %s\n", err); + return 1; + } + if (switch_file_open(&fd, pid_path, SWITCH_FOPEN_READ, SWITCH_FPROT_UREAD | SWITCH_FPROT_UWRITE, pool) == SWITCH_STATUS_SUCCESS) { old_pid_len = sizeof(old_pid_buffer); @@ -920,11 +925,6 @@ int main(int argc, char *argv[]) switch_file_write(fd, pid_buffer, &pid_len); - if (switch_core_init_and_modload(flags, nc ? SWITCH_FALSE : SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { - fprintf(stderr, "Cannot Initialize [%s]\n", err); - return 255; - } - #ifndef WIN32 if (do_wait) { kill(getppid(), SIGUSR2); From 86072ad4edb1b1cee4bd91327ad6a334ef62fcb7 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 31 May 2011 19:56:50 -0400 Subject: [PATCH 031/822] freetdm: added fail-on-error global configuration to refuse to load the module if there is any error --- libs/freetdm/conf/freetdm.conf.xml | 5 + libs/freetdm/mod_freetdm/mod_freetdm.c | 192 +++++++------------------ 2 files changed, 59 insertions(+), 138 deletions(-) diff --git a/libs/freetdm/conf/freetdm.conf.xml b/libs/freetdm/conf/freetdm.conf.xml index 7d5de5a189..29232d927b 100644 --- a/libs/freetdm/conf/freetdm.conf.xml +++ b/libs/freetdm/conf/freetdm.conf.xml @@ -18,6 +18,11 @@ with the signaling protocols that you can run on top of your I/O interfaces. --> + + diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 8739c4c0bf..890ca504e5 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -88,6 +88,8 @@ static struct { switch_hash_t *ss7_configs; int sip_headers; uint8_t crash_on_assert; + uint8_t fail_on_error; + uint8_t config_error; } globals; /* private data attached to each fs session */ @@ -2302,6 +2304,10 @@ static uint32_t enable_analog_option(const char *str, uint32_t current_options) } +#define CONFIG_ERROR(...) do { \ + ftdm_log(FTDM_LOG_ERROR, __VA_ARGS__); \ + globals.config_error = 1; \ + } while(0) /* create ftdm_conf_node_t tree based on a fixed pattern XML configuration list * last 2 args are for limited aka dumb recursivity * */ @@ -2494,7 +2500,7 @@ static int add_profile_parameters(switch_xml_t cfg, const char *profname, ftdm_c profnode = switch_xml_child(cfg, "config_profiles"); if (!profnode) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cannot find profile '%s', there is no 'config_profiles' XML section\n", profname); + CONFIG_ERROR("cannot find profile '%s', there is no 'config_profiles' XML section\n", profname); return 0; } @@ -2510,7 +2516,7 @@ static int add_profile_parameters(switch_xml_t cfg, const char *profname, ftdm_c } if (!profile) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to find profile '%s'\n", profname); + CONFIG_ERROR("failed to find profile '%s'\n", profname); return 0; } @@ -2545,7 +2551,7 @@ static void parse_bri_pri_spans(switch_xml_t cfg, switch_xml_t spans) unsigned paramindex = 0; if (!name && !id) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sangoma isdn span missing required attribute 'id' or 'name', skipping ...\n"); + CONFIG_ERROR("sangoma isdn span missing required attribute 'id' or 'name', skipping ...\n"); continue; } @@ -2563,7 +2569,7 @@ static void parse_bri_pri_spans(switch_xml_t cfg, switch_xml_t spans) } if (zstatus != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + CONFIG_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); continue; } @@ -2590,7 +2596,7 @@ static void parse_bri_pri_spans(switch_xml_t cfg, switch_xml_t spans) char *val = (char *) switch_xml_attr_soft(param, "value"); if (ftdm_array_len(spanparameters) - 1 == paramindex) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Too many parameters for ss7 span, ignoring any parameter after %s\n", var); + CONFIG_ERROR("Too many parameters for ss7 span, ignoring any parameter after %s\n", var); break; } @@ -2605,10 +2611,10 @@ static void parse_bri_pri_spans(switch_xml_t cfg, switch_xml_t spans) int calls; int seconds; if (sscanf(val, "%d/%d", &calls, &seconds) != 2) { - ftdm_log(FTDM_LOG_ERROR, "Invalid %s parameter, format example: 3/1 for 3 calls per second\n", var); + CONFIG_ERROR("Invalid %s parameter, format example: 3/1 for 3 calls per second\n", var); } else { if (calls < 1 || seconds < 1) { - ftdm_log(FTDM_LOG_ERROR, "Invalid %s parameter value, minimum call limit must be 1 per second\n", var); + CONFIG_ERROR("Invalid %s parameter value, minimum call limit must be 1 per second\n", var); } else { SPAN_CONFIG[span_id].limit_calls = calls; SPAN_CONFIG[span_id].limit_seconds = seconds; @@ -2618,7 +2624,7 @@ static void parse_bri_pri_spans(switch_xml_t cfg, switch_xml_t spans) if (!strcasecmp(val, "answer")) { SPAN_CONFIG[span_id].limit_reset_event = FTDM_LIMIT_RESET_ON_ANSWER; } else { - ftdm_log(FTDM_LOG_ERROR, "Invalid %s parameter value, only accepted event is 'answer'\n", var); + CONFIG_ERROR("Invalid %s parameter value, only accepted event is 'answer'\n", var); } } else { spanparameters[paramindex].var = var; @@ -2631,7 +2637,7 @@ static void parse_bri_pri_spans(switch_xml_t cfg, switch_xml_t spans) "sangoma_isdn", on_clear_channel_signal, spanparameters) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error configuring Sangoma ISDN FreeTDM span %d\n", span_id); + CONFIG_ERROR("Error configuring Sangoma ISDN FreeTDM span %d\n", span_id); continue; } SPAN_CONFIG[span_id].span = span; @@ -2648,15 +2654,11 @@ static switch_status_t load_config(void) const char *cf = "freetdm.conf"; switch_xml_t cfg, xml, settings, param, spans, myspan; ftdm_conf_node_t *ss7confnode = NULL; - ftdm_span_t *boost_spans[FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN]; - ftdm_span_t *boost_span = NULL; - unsigned boosti = 0; unsigned int i = 0; ftdm_channel_t *fchan = NULL; ftdm_iterator_t *chaniter = NULL; ftdm_iterator_t *curr = NULL; - memset(boost_spans, 0, sizeof(boost_spans)); memset(&globals, 0, sizeof(globals)); switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, module_pool); if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) { @@ -2675,6 +2677,8 @@ static switch_status_t load_config(void) switch_set_string(globals.hold_music, val); } else if (!strcasecmp(var, "crash-on-assert")) { globals.crash_on_assert = switch_true(val); + } else if (!strcasecmp(var, "fail-on-error")) { + globals.fail_on_error = switch_true(val); } else if (!strcasecmp(var, "sip-headers")) { globals.sip_headers = switch_true(val); } else if (!strcasecmp(var, "enable-analog-option")) { @@ -2705,11 +2709,11 @@ static switch_status_t load_config(void) uint32_t span_id = 0; unsigned paramindex = 0; if (!name && !id) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ss7 span missing required attribute 'id' or 'name', skipping ...\n"); + CONFIG_ERROR("ss7 span missing required attribute 'id' or 'name', skipping ...\n"); continue; } if (!configname) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ss7 span missing required attribute, skipping ...\n"); + CONFIG_ERROR("ss7 span missing required attribute, skipping ...\n"); continue; } if (name) { @@ -2726,7 +2730,7 @@ static switch_status_t load_config(void) } if (zstatus != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + CONFIG_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); continue; } @@ -2736,7 +2740,7 @@ static switch_status_t load_config(void) ss7confnode = get_ss7_config_node(cfg, configname); if (!ss7confnode) { - ftdm_log(FTDM_LOG_ERROR, "Error finding ss7config '%s' for FreeTDM span id: %s\n", configname, switch_str_nil(id)); + CONFIG_ERROR("Error finding ss7config '%s' for FreeTDM span id: %s\n", configname, switch_str_nil(id)); continue; } @@ -2750,7 +2754,7 @@ static switch_status_t load_config(void) char *val = (char *) switch_xml_attr_soft(param, "value"); if (ftdm_array_len(spanparameters) - 1 == paramindex) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Too many parameters for ss7 span, ignoring any parameter after %s\n", var); + CONFIG_ERROR("Too many parameters for ss7 span, ignoring any parameter after %s\n", var); break; } @@ -2769,7 +2773,7 @@ static switch_status_t load_config(void) "sangoma_ss7", on_clear_channel_signal, spanparameters) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error configuring ss7 FreeTDM span %d\n", span_id); + CONFIG_ERROR("Error configuring ss7 FreeTDM span %d\n", span_id); continue; } SPAN_CONFIG[span_id].span = span; @@ -2820,7 +2824,7 @@ static switch_status_t load_config(void) } if (zstatus != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + CONFIG_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); continue; } @@ -2854,10 +2858,10 @@ static switch_status_t load_config(void) int calls; int seconds; if (sscanf(val, "%d/%d", &calls, &seconds) != 2) { - ftdm_log(FTDM_LOG_ERROR, "Invalid %s parameter, format example: 3/1 for 3 calls per second\n", var); + CONFIG_ERROR("Invalid %s parameter, format example: 3/1 for 3 calls per second\n", var); } else { if (calls < 1 || seconds < 1) { - ftdm_log(FTDM_LOG_ERROR, "Invalid %s parameter value, minimum call limit must be 1 per second\n", var); + CONFIG_ERROR("Invalid %s parameter value, minimum call limit must be 1 per second\n", var); } else { SPAN_CONFIG[span_id].limit_calls = calls; SPAN_CONFIG[span_id].limit_seconds = seconds; @@ -2867,7 +2871,7 @@ static switch_status_t load_config(void) if (!strcasecmp(val, "answer")) { SPAN_CONFIG[span_id].limit_reset_event = FTDM_LIMIT_RESET_ON_ANSWER; } else { - ftdm_log(FTDM_LOG_ERROR, "Invalid %s parameter value, only accepted event is 'answer'\n", var); + CONFIG_ERROR("Invalid %s parameter value, only accepted event is 'answer'\n", var); } } else if (!strcasecmp(var, "dial-regex")) { dial_regex = val; @@ -2895,7 +2899,7 @@ static switch_status_t load_config(void) } if (!id && !name) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n"); + CONFIG_ERROR("span missing required param 'id'\n"); continue; } @@ -2925,7 +2929,7 @@ static switch_status_t load_config(void) } if (zstatus != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + CONFIG_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); continue; } @@ -2945,7 +2949,7 @@ static switch_status_t load_config(void) "callwaiting", &callwaiting, "wait_dialtone_timeout", &dialtone_timeout, FTDM_TAG_END) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error configuring FreeTDM analog span %s\n", ftdm_span_get_name(span)); + CONFIG_ERROR("Error configuring FreeTDM analog span %s\n", ftdm_span_get_name(span)); continue; } @@ -3021,7 +3025,7 @@ static switch_status_t load_config(void) } if (!id && !name) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n"); + CONFIG_ERROR("span missing required param 'id'\n"); continue; } @@ -3053,7 +3057,7 @@ static switch_status_t load_config(void) } if (zstatus != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + CONFIG_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); continue; } @@ -3067,7 +3071,7 @@ static switch_status_t load_config(void) "digit_timeout", &to, "max_dialstr", &max, FTDM_TAG_END) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error starting FreeTDM span %d\n", span_id); + CONFIG_ERROR("Error starting FreeTDM span %d\n", span_id); continue; } @@ -3104,7 +3108,7 @@ static switch_status_t load_config(void) uint32_t span_id = 0; if (!name) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required attribute 'name'\n"); + CONFIG_ERROR("span missing required attribute 'name'\n"); continue; } @@ -3115,7 +3119,7 @@ static switch_status_t load_config(void) char *val = (char *) switch_xml_attr_soft(param, "value"); if (ftdm_array_len(spanparameters) - 1 == paramindex) { - ftdm_log(FTDM_LOG_ERROR, "Too many parameters for pri span '%s', ignoring everything after '%s'\n", name, var); + CONFIG_ERROR("Too many parameters for pri span '%s', ignoring everything after '%s'\n", name, var); break; } @@ -3137,13 +3141,13 @@ static switch_status_t load_config(void) zstatus = ftdm_span_find_by_name(name, &span); if (zstatus != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span %s\n", name); + CONFIG_ERROR("Error finding FreeTDM span %s\n", name); continue; } span_id = ftdm_span_get_id(span); if (ftdm_configure_span_signaling(span, "isdn", on_clear_channel_signal, spanparameters) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error configuring FreeTDM span %s\n", name); + CONFIG_ERROR("Error configuring FreeTDM span %s\n", name); continue; } @@ -3170,7 +3174,7 @@ static switch_status_t load_config(void) int span_id = 0; if (!name) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required attribute 'name'\n"); + CONFIG_ERROR("span missing required attribute 'name'\n"); continue; } @@ -3181,7 +3185,7 @@ static switch_status_t load_config(void) char *val = (char *) switch_xml_attr_soft(param, "value"); if (ftdm_array_len(spanparameters) - 1 == paramindex) { - ftdm_log(FTDM_LOG_ERROR, "Too many parameters for pritap span '%s', ignoring everything after '%s'\n", name, var); + CONFIG_ERROR("Too many parameters for pritap span '%s', ignoring everything after '%s'\n", name, var); break; } @@ -3198,13 +3202,13 @@ static switch_status_t load_config(void) zstatus = ftdm_span_find_by_name(name, &span); if (zstatus != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span %s\n", name); + CONFIG_ERROR("Error finding FreeTDM span %s\n", name); continue; } span_id = ftdm_span_get_id(span); if (ftdm_configure_span_signaling(span, "pritap", on_clear_channel_signal, spanparameters) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error configuring FreeTDM span %s\n", name); + CONFIG_ERROR("Error configuring FreeTDM span %s\n", name); continue; } @@ -3230,7 +3234,7 @@ static switch_status_t load_config(void) uint32_t span_id = 0; if (!name) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required attribute 'name'\n"); + CONFIG_ERROR("span missing required attribute 'name'\n"); continue; } @@ -3241,7 +3245,7 @@ static switch_status_t load_config(void) char *val = (char *) switch_xml_attr_soft(param, "value"); if (ftdm_array_len(spanparameters) - 1 == paramindex) { - ftdm_log(FTDM_LOG_ERROR, "Too many parameters for libpri span, ignoring everything after '%s'\n", var); + CONFIG_ERROR("Too many parameters for libpri span, ignoring everything after '%s'\n", var); break; } @@ -3263,13 +3267,13 @@ static switch_status_t load_config(void) zstatus = ftdm_span_find_by_name(name, &span); if (zstatus != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span %s\n", name); + CONFIG_ERROR("Error finding FreeTDM span %s\n", name); continue; } span_id = ftdm_span_get_id(span); if (ftdm_configure_span_signaling(span, "libpri", on_clear_channel_signal, spanparameters) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error configuring FreeTDM span %s\n", name); + CONFIG_ERROR("Error configuring FreeTDM span %s\n", name); continue; } @@ -3282,86 +3286,6 @@ static switch_status_t load_config(void) } } - if ((spans = switch_xml_child(cfg, "boost_spans"))) { - for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) { - char *id = (char *) switch_xml_attr(myspan, "id"); - char *name = (char *) switch_xml_attr(myspan, "name"); - char *sigmod = (char *) switch_xml_attr(myspan, "sigmod"); - ftdm_status_t zstatus = FTDM_FAIL; - const char *context = "default"; - const char *dialplan = "XML"; - uint32_t span_id = 0; - ftdm_span_t *span = NULL; - ftdm_conf_parameter_t spanparameters[30]; - unsigned paramindex = 0; - - if (!id && !name) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "boost span requires an id or name as attribute: \n"); - continue; - } - memset(spanparameters, 0, sizeof(spanparameters)); - if (sigmod) { - spanparameters[paramindex].var = "sigmod"; - spanparameters[paramindex].val = sigmod; - paramindex++; - } - - for (param = switch_xml_child(myspan, "param"); param; param = param->next) { - char *var = (char *) switch_xml_attr_soft(param, "name"); - char *val = (char *) switch_xml_attr_soft(param, "value"); - - if (ftdm_array_len(spanparameters) - 1 == paramindex) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Too many parameters for boost span, ignoring any parameter after %s\n", var); - break; - } - - if (!strcasecmp(var, "context")) { - context = val; - } else if (!strcasecmp(var, "dialplan")) { - dialplan = val; - } else { - spanparameters[paramindex].var = var; - spanparameters[paramindex].val = val; - paramindex++; - } - } - - if (name) { - zstatus = ftdm_span_find_by_name(name, &span); - } else { - if (switch_is_number(id)) { - span_id = atoi(id); - zstatus = ftdm_span_find(span_id, &span); - } - - if (zstatus != FTDM_SUCCESS) { - zstatus = ftdm_span_find_by_name(id, &span); - } - } - - if (zstatus != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); - continue; - } - - if (!span_id) { - span_id = ftdm_span_get_id(span); - } - - if (ftdm_configure_span_signaling(span, "sangoma_boost", on_clear_channel_signal, spanparameters) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error starting FreeTDM span %d error: %s\n", span_id, ftdm_span_get_last_error(span)); - continue; - } - - SPAN_CONFIG[span_id].span = span; - switch_copy_string(SPAN_CONFIG[span_id].context, context, sizeof(SPAN_CONFIG[span_id].context)); - switch_copy_string(SPAN_CONFIG[span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span_id].dialplan)); - - switch_copy_string(SPAN_CONFIG[span_id].type, "Sangoma (boost)", sizeof(SPAN_CONFIG[span_id].type)); - boost_spans[boosti++] = span; - } - } - if ((spans = switch_xml_child(cfg, "r2_spans"))) { for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) { char *name = (char *) switch_xml_attr(myspan, "name"); @@ -3380,7 +3304,7 @@ static switch_status_t load_config(void) unsigned paramindex = 0; if (!name) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "'name' attribute required for R2 spans!\n"); + CONFIG_ERROR("'name' attribute required for R2 spans!\n"); continue; } @@ -3415,14 +3339,13 @@ static switch_status_t load_config(void) zstatus = ftdm_span_find_by_name(name, &span); if (zstatus != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM R2 Span '%s'\n", name); + CONFIG_ERROR("Error finding FreeTDM R2 Span '%s'\n", name); continue; } span_id = ftdm_span_get_id(span); if (ftdm_configure_span_signaling(span, "r2", on_r2_signal, spanparameters) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error configuring FreeTDM R2 span %s, error: %s\n", - name, ftdm_span_get_last_error(span)); + CONFIG_ERROR("Error configuring FreeTDM R2 span %s, error: %s\n", name, ftdm_span_get_last_error(span)); continue; } @@ -3440,24 +3363,12 @@ static switch_status_t load_config(void) switch_copy_string(SPAN_CONFIG[span_id].type, "R2", sizeof(SPAN_CONFIG[span_id].type)); if (ftdm_span_start(span) == FTDM_FAIL) { - ftdm_log(FTDM_LOG_ERROR, "Error starting FreeTDM R2 span %s, error: %s\n", name, ftdm_span_get_last_error(span)); + CONFIG_ERROR("Error starting FreeTDM R2 span %s, error: %s\n", name, ftdm_span_get_last_error(span)); continue; } } } - /* start all boost spans now that we're done configuring. Unfortunately at this point boost modules have the limitation - * of needing all spans to be configured before starting them */ - for (i=0 ; i < boosti; i++) { - boost_span = boost_spans[i]; - ftdm_log(FTDM_LOG_DEBUG, "Starting boost span %d\n", ftdm_span_get_id(boost_span)); - if (ftdm_span_start(boost_span) == FTDM_FAIL) { - ftdm_log(FTDM_LOG_ERROR, "Error starting boost FreeTDM span %d, error: %s\n", - ftdm_span_get_id(boost_span), ftdm_span_get_last_error(boost_span)); - continue; - } - } - if (globals.crash_on_assert) { ftdm_log(FTDM_LOG_WARNING, "Crash on assert enabled\n"); ftdm_global_set_crash_policy(FTDM_CRASH_ON_ASSERT); @@ -3465,6 +3376,11 @@ static switch_status_t load_config(void) switch_xml_free(xml); + if (globals.fail_on_error && globals.config_error) { + ftdm_log(FTDM_LOG_ERROR, "Refusing to load module with errors\n"); + return SWITCH_STATUS_TERM; + } + return SWITCH_STATUS_SUCCESS; } From d19d4b96abd381e033d5d6a9d9a7a556e0a6512b Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 13 Jun 2011 13:33:25 -0400 Subject: [PATCH 032/822] use -base directory as the cwd for the process --- src/include/switch_apr.h | 1 + src/switch.c | 2 ++ src/switch_apr.c | 5 +++++ 3 files changed, 8 insertions(+) diff --git a/src/include/switch_apr.h b/src/include/switch_apr.h index 2306075e1f..9ec6f94496 100644 --- a/src/include/switch_apr.h +++ b/src/include/switch_apr.h @@ -854,6 +854,7 @@ SWITCH_DECLARE(switch_status_t) switch_queue_trypush(switch_queue_t *queue, void SWITCH_DECLARE(switch_status_t) switch_file_open(switch_file_t ** newf, const char *fname, int32_t flag, switch_fileperms_t perm, switch_memory_pool_t *pool); +SWITCH_DECLARE(switch_status_t) switch_filepath_set(const char *path, switch_memory_pool_t *pool); SWITCH_DECLARE(switch_status_t) switch_file_seek(switch_file_t *thefile, switch_seek_where_t where, int64_t *offset); diff --git a/src/switch.c b/src/switch.c index 7d4d1a8217..49ca107f67 100644 --- a/src/switch.c +++ b/src/switch.c @@ -875,6 +875,8 @@ int main(int argc, char *argv[]) apr_pool_create(&pool, NULL); + switch_filepath_set(SWITCH_GLOBAL_dirs.base_dir, pool); + switch_dir_make_recursive(SWITCH_GLOBAL_dirs.run_dir, SWITCH_DEFAULT_DIR_PERMS, pool); if (switch_file_open(&fd, pid_path, SWITCH_FOPEN_READ, SWITCH_FPROT_UREAD | SWITCH_FPROT_UWRITE, pool) == SWITCH_STATUS_SUCCESS) { diff --git a/src/switch_apr.c b/src/switch_apr.c index 495e0605a8..24c966e6dc 100644 --- a/src/switch_apr.c +++ b/src/switch_apr.c @@ -403,6 +403,11 @@ SWITCH_DECLARE(switch_status_t) switch_file_open(switch_file_t ** newf, const ch return apr_file_open(newf, fname, flag, perm, pool); } +SWITCH_DECLARE(switch_status_t) switch_filepath_set(const char *path, switch_memory_pool_t *pool) +{ + return apr_filepath_set(path, pool); +} + SWITCH_DECLARE(switch_status_t) switch_file_seek(switch_file_t *thefile, switch_seek_where_t where, int64_t *offset) { apr_status_t rv; From c23c3d87301cd17d1c62c0c224673748e0033dcf Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 13 Jun 2011 17:33:41 -0400 Subject: [PATCH 033/822] freetdm: set proper flags when a given layer (ISUP, MTP3 etc) is started and verify such flags on shutdown to avoid segfault when shutting down a layer that was never started - fix issue #741 --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c | 22 ++++++++----- .../ftmod_sangoma_ss7_main.c | 31 +++++++++++-------- .../ftmod_sangoma_ss7_main.h | 26 +++++++++++----- .../ftmod_sangoma_ss7_relay.c | 2 +- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 12 +++---- 5 files changed, 58 insertions(+), 35 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c index 34d79837f0..f340fa3833 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c @@ -99,17 +99,18 @@ int ft_to_sngss7_cfg_all(void) return 1; } else { SS7_INFO("Started Stack Manager!\n"); - sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_SM); + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_SM_STARTED); } /* check if the configuration had a Relay Channel */ - if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_RY)) { + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_RY_PRESENT)) { /* start up the relay task */ if (sng_isup_init_relay()) { SS7_CRITICAL("Failed to start Relay\n"); return 1; } else { SS7_INFO("Started Relay!\n"); + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_RY_STARTED); } /* run general configuration on the relay task */ @@ -122,12 +123,13 @@ int ft_to_sngss7_cfg_all(void) } /* if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_RY)) */ - if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_CC)) { + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_CC_PRESENT)) { if (sng_isup_init_cc()) { SS7_CRITICAL("Failed to start Call-Control\n"); return 1; } else { SS7_INFO("Started Call-Control!\n"); + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_CC_STARTED); } if (ftmod_ss7_cc_gen_config()) { SS7_CRITICAL("CC General configuration FAILED!\n"); @@ -143,12 +145,13 @@ int ft_to_sngss7_cfg_all(void) } } /* if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_CC)) */ - if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP)) { + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP_PRESENT)) { if (sng_isup_init_isup()) { SS7_CRITICAL("Failed to start ISUP\n"); return 1; } else { SS7_INFO("Started ISUP!\n"); + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP_STARTED); } if (ftmod_ss7_isup_gen_config()) { SS7_CRITICAL("ISUP General configuration FAILED!\n"); @@ -158,12 +161,13 @@ int ft_to_sngss7_cfg_all(void) } } /* if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP)) */ - if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP3)) { + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP3_PRESENT)) { if (sng_isup_init_mtp3()) { SS7_CRITICAL("Failed to start MTP3\n"); return 1; } else { SS7_INFO("Started MTP3!\n"); + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP3_STARTED); } if (ftmod_ss7_mtp3_gen_config()) { @@ -174,18 +178,20 @@ int ft_to_sngss7_cfg_all(void) } } /* if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP3)) */ - if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP2)) { + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP2_PRESENT)) { if (sng_isup_init_mtp2()) { SS7_CRITICAL("Failed to start MTP2\n"); return 1; } else { SS7_INFO("Started MTP2!\n"); + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP2_STARTED); } if (sng_isup_init_mtp1()) { - SS7_CRITICAL("Failed to start MTP2\n"); + SS7_CRITICAL("Failed to start MTP1\n"); return 1; } else { SS7_INFO("Started MTP1!\n"); + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP1_STARTED); } if (ftmod_ss7_mtp1_gen_config()) { SS7_CRITICAL("MTP1 General configuration FAILED!\n"); @@ -376,7 +382,7 @@ int ft_to_sngss7_cfg_all(void) x++; } /* while (x < (MAX_ISAPS)) */ - if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP)) { + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP_STARTED)) { x = 1; while (x < (MAX_ISUP_INFS)) { /* check if this link has been configured already */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 53062b9d56..0dec4e54d7 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1621,32 +1621,36 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_sangoma_ss7_unload) ftdm_log (FTDM_LOG_INFO, "Starting ftmod_sangoma_ss7 unload...\n"); - if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_CC)) { + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_CC_STARTED)) { sng_isup_free_cc(); - sngss7_clear_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_CC); + sngss7_clear_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_CC_STARTED); } - if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP)) { + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP_STARTED)) { ftmod_ss7_shutdown_isup(); sng_isup_free_isup(); - sngss7_clear_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP); + sngss7_clear_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP_STARTED); } - if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP3)) { + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP3_STARTED)) { ftmod_ss7_shutdown_mtp3(); sng_isup_free_mtp3(); - sngss7_clear_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP3); + sngss7_clear_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP3_STARTED); } - if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP2)) { + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP2_STARTED)) { ftmod_ss7_shutdown_mtp2(); sng_isup_free_mtp2(); - sng_isup_free_mtp1(); - sngss7_clear_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP2); + sngss7_clear_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP2_STARTED); } - if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_RY)) { - /* go through all the relays channels and configure it */ + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP1_STARTED)) { + sng_isup_free_mtp1(); + sngss7_clear_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP1_STARTED); + } + + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_RY_STARTED)) { + /* go through all the relays channels and disable them */ x = 1; while (x < (MAX_RELAY_CHANNELS)) { /* check if this relay channel has been configured already */ @@ -1668,11 +1672,12 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_sangoma_ss7_unload) ftmod_ss7_shutdown_relay(); sng_isup_free_relay(); - sngss7_clear_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_RY); + sngss7_clear_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_RY_STARTED); } - if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_SM)) { + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_SM_STARTED)) { sng_isup_free_sm(); + sngss7_clear_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_SM_STARTED); } sng_isup_free_gen(); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 11ff2318bb..e84c367f51 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -632,13 +632,25 @@ typedef enum { } sng_cfg_flag_t; typedef enum { - SNGSS7_SM = (1 << 0), - SNGSS7_RY = (1 << 1), - SNGSS7_MTP1 = (1 << 2), - SNGSS7_MTP2 = (1 << 3), - SNGSS7_MTP3 = (1 << 4), - SNGSS7_ISUP = (1 << 5), - SNGSS7_CC = (1 << 6) + SNGSS7_SM_STARTED = (1 << 0), + + SNGSS7_RY_PRESENT = (1 << 2), + SNGSS7_RY_STARTED = (1 << 3), + + SNGSS7_MTP1_PRESENT = (1 << 4), + SNGSS7_MTP1_STARTED = (1 << 5), + + SNGSS7_MTP2_PRESENT = (1 << 6), + SNGSS7_MTP2_STARTED = (1 << 7), + + SNGSS7_MTP3_PRESENT = (1 << 8), + SNGSS7_MTP3_STARTED = (1 << 9), + + SNGSS7_ISUP_PRESENT = (1 << 10), + SNGSS7_ISUP_STARTED = (1 << 11), + + SNGSS7_CC_PRESENT = (1 << 12), + SNGSS7_CC_STARTED = (1 << 13), } sng_task_flag_t; /******************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c index 1af538d727..890b222c64 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c @@ -300,7 +300,7 @@ ftdm_status_t disable_all_sigs_for_relay(uint32_t procId) ftdm_status_t disble_all_mtp2_sigs_for_relay(void) { /* check if there is a local mtp2 link*/ - if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP2)) { + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP2_STARTED)) { SS7_INFO("Disalbing all mtp2 sig links on local system\n"); ftmod_ss7_disable_grp_mtp2Link(1); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 8e327ea759..db372b0f97 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -2082,7 +2082,7 @@ static int ftmod_ss7_fill_in_relay_channel(sng_relay_t *relay_channel) relay_channel->port, relay_channel->procId, relay_channel->id); - sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_RY); + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_RY_PRESENT); } else { relay_channel->id = i; SS7_DEBUG("found existing relay channel on type:%d, hostname:%s, port:%d, procId:%d, id = %d\n", @@ -2116,7 +2116,7 @@ static int ftmod_ss7_fill_in_mtp1_link(sng_mtp1_link_t *mtp1Link) /* check if this id value has been used already */ if (g_ftdm_sngss7_data.cfg.mtp1Link[i].id == 0) { SS7_DEBUG("Found new MTP1 Link: id=%d, name=%s\n", mtp1Link->id, mtp1Link->name); - sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP1); + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP1_PRESENT); } else { SS7_DEBUG("Found an existing MTP1 Link: id=%d, name=%s (old name=%s)\n", mtp1Link->id, @@ -2142,7 +2142,7 @@ static int ftmod_ss7_fill_in_mtp2_link(sng_mtp2_link_t *mtp2Link) /* check if this id value has been used already */ if (g_ftdm_sngss7_data.cfg.mtp2Link[i].id == 0) { SS7_DEBUG("Found new MTP2 Link: id=%d, name=%s\n", mtp2Link->id, mtp2Link->name); - sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP2); + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP2_PRESENT); } else { SS7_DEBUG("Found an existing MTP2 Link: id=%d, name=%s (old name=%s)\n", mtp2Link->id, @@ -2219,7 +2219,7 @@ static int ftmod_ss7_fill_in_mtp3_link(sng_mtp3_link_t *mtp3Link) /* check if this id value has been used already */ if (g_ftdm_sngss7_data.cfg.mtp3Link[i].id == 0) { SS7_DEBUG("Found new MTP3 Link: id=%d, name=%s\n", mtp3Link->id, mtp3Link->name); - sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP3); + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP3_PRESENT); } else { SS7_DEBUG("Found an existing MTP3 Link: id=%d, name=%s (old name=%s)\n", mtp3Link->id, @@ -2560,7 +2560,7 @@ static int ftmod_ss7_fill_in_isup_interface(sng_isup_inf_t *sng_isup) /* check if this id value has been used already */ if (g_ftdm_sngss7_data.cfg.isupIntf[i].id == 0) { SS7_DEBUG("Found new ISUP Interface: id=%d, name=%s\n", sng_isup->id, sng_isup->name); - sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP); + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP_PRESENT); } else { SS7_DEBUG("Found an existing ISUP Interface: id=%d, name=%s (old name=%s)\n", sng_isup->id, @@ -2908,7 +2908,7 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan) g_ftdm_sngss7_data.cfg.isupCkt[x].type = VOICE; /* throw the flag to indicate that we need to start call control */ - sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_CC); + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_CC_PRESENT); } if (timeslot.channel) { From d6e3e7fcd7451234649b5f55843f3be39d13f326 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 14 Jun 2011 13:15:17 -0400 Subject: [PATCH 034/822] Changed libsng_isdn and libsng_ss7 include paths --- libs/freetdm/Makefile.am | 8 -------- .../src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h | 2 +- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h | 2 +- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/libs/freetdm/Makefile.am b/libs/freetdm/Makefile.am index b0398ef90c..6c2eae3ef8 100644 --- a/libs/freetdm/Makefile.am +++ b/libs/freetdm/Makefile.am @@ -40,14 +40,6 @@ library_includedir = $(prefix)/include INCS = -I$(FT_SRCDIR)/$(SRC)/include -I$(FT_SRCDIR)/$(SRC)/include/private -if HAVE_SNG_SS7 -INCS += -I/usr/include/sng_ss7 -endif - -if HAVE_SNG_ISDN -INCS += -I/usr/include/sng_isdn -endif - # we needed to separate CFLAGS in FTDM_COMPAT_CFLAGS and FTDM_CFLAGS due to -c99 which causes problems with wanpipe headers FTDM_COMPAT_CFLAGS = $(INCS) -DFTDM_CONFIG_DIR=\"@confdir@\" -DFTDM_MOD_DIR=\"$(moddir)\" @COMP_VENDOR_COMPAT_CFLAGS@ @DEFS@ FTDM_CFLAGS = $(INCS) -DFTDM_CONFIG_DIR=\"@confdir@\" -DFTDM_MOD_DIR=\"$(moddir)\" @COMP_VENDOR_CFLAGS@ @DEFS@ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h index 68e1371b79..9935b3e0ea 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h @@ -49,7 +49,7 @@ #include "private/ftdm_core.h" #include "ftmod_sangoma_isdn_user.h" -#include +#include /* Theoretical limit for MAX_SPANS_PER_NFAS_LINK is 31, but set to 8 for now to save some memory */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index e84c367f51..1bce70fb82 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -45,7 +45,7 @@ #include "private/ftdm_core.h" -#include "sng_ss7.h" +#include "sng_ss7/sng_ss7.h" /******************************************************************************/ From c2a1935850010a9f49c0bc3d09ece65a161fbc79 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 4 Jul 2011 11:25:18 -0400 Subject: [PATCH 035/822] skip initial space in switch console and API execution - resolve issue #778 --- src/switch_console.c | 8 +++++++- src/switch_loadable_module.c | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/switch_console.c b/src/switch_console.c index 7323a5f6a3..8f7238d257 100644 --- a/src/switch_console.c +++ b/src/switch_console.c @@ -346,7 +346,7 @@ SWITCH_DECLARE(switch_status_t) switch_console_execute(char *xcmd, int rec, swit int argc; char *argv[128]; int x; - char *dup = strdup(xcmd); + char *dup = NULL; char *cmd; switch_status_t status = SWITCH_STATUS_FALSE; @@ -357,6 +357,12 @@ SWITCH_DECLARE(switch_status_t) switch_console_execute(char *xcmd, int rec, swit goto end; } + while (xcmd && *xcmd == ' ') { + xcmd++; + } + + dup = strdup(xcmd); + if (!strncasecmp(xcmd, "alias", 5)) { argc = 1; argv[0] = xcmd; diff --git a/src/switch_loadable_module.c b/src/switch_loadable_module.c index f8a56d98bd..0938fd55ab 100644 --- a/src/switch_loadable_module.c +++ b/src/switch_loadable_module.c @@ -1789,6 +1789,10 @@ SWITCH_DECLARE(switch_status_t) switch_api_execute(const char *cmd, const char * switch_assert(stream->data != NULL); switch_assert(stream->write_function != NULL); + while (cmd && *cmd == ' ') { + cmd++; + } + if (strcasecmp(cmd, "console_complete")) { cmd_used = switch_strip_whitespace(cmd); arg_used = switch_strip_whitespace(arg); From fa2ef5e724e73c04e7f56a904d75a3524b0d9a83 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 23 Jun 2011 14:09:06 -0400 Subject: [PATCH 036/822] freetdm: change CLI parsing (ftdm_separate_string) to properly ignore white space (fixes Sangoma issue #778) minor change into SS7 CLI to use ftdm_array_len() instead of duplicating it --- libs/freetdm/src/ftdm_io.c | 18 +++++++----------- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index f7b4bb9a1c..1824fce04a 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -5771,6 +5771,9 @@ FT_DECLARE(uint32_t) ftdm_separate_string(char *buf, char delim, char **array, i ptr = buf; + /* we swallow separators that are contiguous */ + while (*ptr == delim) ptr++; + for (argc = 0; *ptr && (argc < arraylen - 1); argc++) { array[argc] = ptr; for (; *ptr; ptr++) { @@ -5782,6 +5785,8 @@ FT_DECLARE(uint32_t) ftdm_separate_string(char *buf, char delim, char **array, i } } else if ((*ptr == delim) && !quot) { *ptr++ = '\0'; + /* we swallow separators that are contiguous */ + while (*ptr == delim) ptr++; break; } } @@ -5791,22 +5796,13 @@ FT_DECLARE(uint32_t) ftdm_separate_string(char *buf, char delim, char **array, i array[argc++] = ptr; } - /* strip quotes and leading / trailing spaces */ + /* strip quotes */ for (x = 0; x < argc; x++) { - char *p; - - while(*(array[x]) == ' ') { - (array[x])++; - } - p = array[x]; + char *p = array[x]; while((p = strchr(array[x], qc))) { memmove(p, p+1, strlen(p)); p++; } - p = array[x] + (strlen(array[x]) - 1); - while(*p == ' ') { - *p-- = '\0'; - } } return argc; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index baed57e561..710b0c37a6 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -106,7 +106,7 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha if (data) { mycmd = ftdm_strdup(data); - argc = ftdm_separate_string(mycmd,' ',argv,(sizeof(argv) / sizeof(argv[0]))); + argc = ftdm_separate_string(mycmd, ' ', argv, ftdm_array_len(argv)); } if (check_arg_count(argc, 1)) goto handle_cli_error_argc; From bf41cc27a19a59d5b955bfd17a2b8fcd4e80790f Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Mon, 8 Aug 2011 12:35:41 -0400 Subject: [PATCH 037/822] chlog: freetdm: SS7 - added TX of CPG message in progress media state --- .../ftmod_sangoma_ss7_main.c | 4 +-- .../ftmod_sangoma_ss7_main.h | 1 + .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 29 +++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index cc922617af..ad1f638f54 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -656,10 +656,10 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) if (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_OUTBOUND)) { /* inform the user there is media avai */ sngss7_send_signal(sngss7_info, FTDM_SIGEVENT_PROGRESS_MEDIA); + } else { + ft_to_sngss7_cpg(ftdmchan); } - - /* nothing to do at this time */ break; /**************************************************************************/ case FTDM_CHANNEL_STATE_UP: /*call is accpeted...both incoming and outgoing */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index e61f1ee6df..cda6225217 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -751,6 +751,7 @@ int ftmod_ss7_isup_ckt_sta(uint32_t id, unsigned char *state); /* in ftmod_sangoma_ss7_out.c */ void ft_to_sngss7_iam(ftdm_channel_t *ftdmchan); void ft_to_sngss7_acm(ftdm_channel_t *ftdmchan); +void ft_to_sngss7_cpg (ftdm_channel_t *ftdmchan); void ft_to_sngss7_anm(ftdm_channel_t *ftdmchan); void ft_to_sngss7_rel(ftdm_channel_t *ftdmchan); void ft_to_sngss7_rlc(ftdm_channel_t *ftdmchan); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index 56238abdf9..11ac14891d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -36,6 +36,8 @@ /******************************************************************************/ /* DEFINES ********************************************************************/ +#define SNGSS7_EVNTINFO_IND_INBAND_AVAIL 0x03 +/******************************************************************************/ /* GLOBALS ********************************************************************/ @@ -171,6 +173,7 @@ void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan) acm.optBckCalInd.simpleSegmInd.pres = PRSNT_DEF; acm.optBckCalInd.mlppUserInd.pres = PRSNT_DEF; acm.optBckCalInd.usrNetIneractInd.pres = PRSNT_DEF; + acm.optBckCalInd.netExcDelInd.pres = PRSNT_DEF; } /* if (sngss7_test_options(isup_intf, SNGSS7_ACM_OBCI_BITA)) */ /* send the ACM request to LibSngSS7 */ @@ -187,6 +190,32 @@ void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan) return; } +void ft_to_sngss7_cpg (ftdm_channel_t *ftdmchan) +{ + SiCnStEvnt cpg; + SS7_FUNC_TRACE_ENTER (__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + + memset (&cpg, 0, sizeof (cpg)); + + cpg.evntInfo.eh.pres = PRSNT_NODEF; + + cpg.evntInfo.evntInd.pres = PRSNT_NODEF; + cpg.evntInfo.evntInd.val = SNGSS7_EVNTINFO_IND_INBAND_AVAIL; /* Event Indicator = In-band info is now available */ + + cpg.evntInfo.evntPresResInd.pres = PRSNT_NODEF; + cpg.evntInfo.evntPresResInd.val = 0; /* Event presentation restricted indicator = no indication */ + + /* send the CPG request to LibSngSS7 */ + sng_cc_con_status (1, sngss7_info->suInstId, sngss7_info->spInstId, sngss7_info->circuit->id, &cpg, PROGRESS); + + ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "[CIC:%d]Tx CPG\n", sngss7_info->circuit->cic); + ftdm_call_clear_vars(&ftdmchan->caller_data); + SS7_FUNC_TRACE_EXIT (__FUNCTION__); + return; +} void ft_to_sngss7_anm (ftdm_channel_t * ftdmchan) { SS7_FUNC_TRACE_ENTER (__FUNCTION__); From b2fa7e31393c196720f6a0695290f8352fbfbdd6 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 20 Sep 2011 19:15:05 -0400 Subject: [PATCH 038/822] freetdm: Fix for sending CPG without sending ACM prior to that --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index ad1f638f54..a849bf2f62 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -657,6 +657,10 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* inform the user there is media avai */ sngss7_send_signal(sngss7_info, FTDM_SIGEVENT_PROGRESS_MEDIA); } else { + if (!sngss7_test_ckt_flag(sngss7_info, FLAG_SENT_ACM)) { + sngss7_set_ckt_flag(sngss7_info, FLAG_SENT_ACM); + ft_to_sngss7_acm(ftdmchan); + } ft_to_sngss7_cpg(ftdmchan); } From d89f3afdc25cc8bd6d1f9e3684e231dc3edb7062 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Wed, 21 Sep 2011 15:15:19 -0400 Subject: [PATCH 039/822] freetdm: Manually merged relay code from branch jz.smg_ss7 (based on releases.3.3) - Added relay and other misc commands - Misc fixes in hardware blocks, hw alarm etc - Fix crash on shutdown in relay --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 833 ++++++++++++++---- .../ftmod_sangoma_ss7_handle.c | 16 +- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c | 68 +- .../ftmod_sangoma_ss7_logger.c | 8 +- .../ftmod_sangoma_ss7_main.c | 174 +++- .../ftmod_sangoma_ss7_main.h | 37 +- 6 files changed, 898 insertions(+), 238 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 5f87ffd877..9ff19bac02 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -31,6 +31,10 @@ * SOFTWARE|EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#if 0 +#define SMG_RELAY_DBG +#endif + /* INCLUDE ********************************************************************/ #include "ftmod_sangoma_ss7_main.h" /******************************************************************************/ @@ -44,7 +48,7 @@ /* PROTOTYPES *****************************************************************/ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const char *data); -static ftdm_status_t handle_print_usuage(ftdm_stream_handle_t *stream); +static ftdm_status_t handle_print_usage(ftdm_stream_handle_t *stream); static ftdm_status_t handle_show_procId(ftdm_stream_handle_t *stream); @@ -88,8 +92,31 @@ static ftdm_status_t handle_status_isup_ckt(ftdm_stream_handle_t *stream, char * static ftdm_status_t extract_span_chan(char *argv[10], int pos, int *span, int *chan); static ftdm_status_t check_arg_count(int args, int min); -/******************************************************************************/ + + +static ftdm_status_t cli_ss7_show_general(ftdm_stream_handle_t *stream); + +static ftdm_status_t cli_ss7_show_mtp2link_by_id(ftdm_stream_handle_t *stream, int rcId); +static ftdm_status_t cli_ss7_show_mtp2link_by_name(ftdm_stream_handle_t *stream, char *name); +static ftdm_status_t cli_ss7_show_all_mtp2link(ftdm_stream_handle_t *stream); + +static ftdm_status_t cli_ss7_show_mtp3link_by_id(ftdm_stream_handle_t *stream, int rcId); +static ftdm_status_t cli_ss7_show_mtp3link_by_name(ftdm_stream_handle_t *stream, char *name); +static ftdm_status_t cli_ss7_show_all_mtp3link(ftdm_stream_handle_t *stream); + +static ftdm_status_t cli_ss7_show_relay_by_id(ftdm_stream_handle_t *stream, int rcId); +static ftdm_status_t cli_ss7_show_relay_by_name(ftdm_stream_handle_t *stream, char *name); +static ftdm_status_t cli_ss7_show_all_relay(ftdm_stream_handle_t *stream); + +static ftdm_status_t cli_ss7_show_channel_detail_of_span(ftdm_stream_handle_t *stream, char *span_id, char *chan_id); +static ftdm_status_t cli_ss7_show_all_channels_of_span(ftdm_stream_handle_t *stream, char *span_id); + +static ftdm_status_t cli_ss7_show_span_by_id(ftdm_stream_handle_t *stream, char *span_id); +static ftdm_status_t cli_ss7_show_all_spans_general(ftdm_stream_handle_t *stream); +static ftdm_status_t cli_ss7_show_all_spans_detail(ftdm_stream_handle_t *stream); + +/******************************************************************************/ /* FUNCTIONS ******************************************************************/ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const char *data) { @@ -109,16 +136,72 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha argc = ftdm_separate_string(mycmd, ' ', argv, ftdm_array_len(argv)); } - if (check_arg_count(argc, 1)) goto handle_cli_error_argc; - + if (check_arg_count(argc, 1)) { + goto handle_cli_error_argc; + } + if (!strcasecmp(argv[c], "show")) { /**************************************************************************/ - if (check_arg_count(argc, 2)) goto handle_cli_error_argc; + if (check_arg_count(argc, 2)) { + cli_ss7_show_general(stream); + return FTDM_SUCCESS; + } c++; - if (!strcasecmp(argv[c], "status")) { + if (!strcasecmp(argv[c], "relay")) { /**********************************************************************/ - if (check_arg_count(argc, 3)) goto handle_cli_error_argc; + c++; + handle_status_relay(stream, argv[c]); + + } else if (!strcasecmp(argv[c], "span")) { + /**********************************************************************/ + switch (argc) { + case 2: + { + /* > ftdm ss7 show span */ + cli_ss7_show_all_spans_general(stream); + } + break; + + case 3: + { + if (!strcasecmp(argv[2], "all")) { + /* > ftdm ss7 show span all */ + cli_ss7_show_all_spans_detail(stream); + } else { + /* > ftdm ss7 show span 1 */ + cli_ss7_show_span_by_id(stream, argv[2]); + } + } + break; + + case 4: + { + /* > ftdm ss7 show span 1 chan */ + cli_ss7_show_all_channels_of_span(stream, argv[2]); + } + break; + + case 5: + default: + { + if (!strcasecmp(argv[3], "chan")) { + /* > ftdm ss7 show span 1 chan 2 */ + cli_ss7_show_channel_detail_of_span(stream, argv[2], argv[4]); + } else { + /* > ftdm ss7 show span 1 bla bla bla*/ + cli_ss7_show_all_channels_of_span(stream, argv[2]); + } + } + break; + } + } else if (!strcasecmp(argv[c], "status")) { + /**********************************************************************/ + if (check_arg_count(argc, 3)) { + cli_ss7_show_general(stream); + return FTDM_SUCCESS; + } + c++; if (!strcasecmp(argv[c], "mtp3")) { @@ -675,38 +758,40 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha handle_cli_error_argc: stream->write_function(stream, "Invalid # of arguments in command\n"); - handle_print_usuage(stream); + handle_print_usage(stream); return FTDM_SUCCESS; handle_cli_error_span_chan: stream->write_function(stream, "Unknown \"span\\chan\" command\n"); - handle_print_usuage(stream); + handle_print_usage(stream); return FTDM_SUCCESS; handle_cli_error: stream->write_function(stream, "Unknown command requested\n"); - handle_print_usuage(stream); + handle_print_usage(stream); return FTDM_SUCCESS; } /******************************************************************************/ -static ftdm_status_t handle_print_usuage(ftdm_stream_handle_t *stream) +static ftdm_status_t handle_print_usage(ftdm_stream_handle_t *stream) { - stream->write_function(stream, "Sangoma SS7 CLI usuage:\n\n"); + stream->write_function(stream, "Sangoma SS7 CLI usage:\n\n"); - stream->write_function(stream, "Ftmod_sangoma_ss7 general control:\n"); + stream->write_function(stream, "ftmod_sangoma_ss7 general control:\n"); stream->write_function(stream, "ftdm ss7 set ftrace X Y\n"); stream->write_function(stream, "ftdm ss7 set mtrace X Y\n"); stream->write_function(stream, "\n"); - stream->write_function(stream, "Ftmod_sangoma_ss7 information:\n"); + stream->write_function(stream, "ftmod_sangoma_ss7 information:\n"); stream->write_function(stream, "ftdm ss7 show status mtp3 X\n"); stream->write_function(stream, "ftdm ss7 show status mtp2 X\n"); stream->write_function(stream, "ftdm ss7 show status span X chan Y\n"); stream->write_function(stream, "ftdm ss7 show free span X chan Y\n"); + stream->write_function(stream, "ftdm ss7 show blocks span X chan Y\n"); + stream->write_function(stream, "ftdm ss7 show inuse span X chan Y\n"); stream->write_function(stream, "ftdm ss7 show inreset span X chan Y\n"); stream->write_function(stream, "\n"); - stream->write_function(stream, "Ftmod_sangoma_ss7 circuit control:\n"); + stream->write_function(stream, "ftmod_sangoma_ss7 circuit control:\n"); stream->write_function(stream, "ftdm ss7 blo span X chan Y\n"); stream->write_function(stream, "ftdm ss7 ubl span X chan Y\n"); stream->write_function(stream, "ftdm ss7 rsc span X chan Y\n"); @@ -714,7 +799,7 @@ static ftdm_status_t handle_print_usuage(ftdm_stream_handle_t *stream) stream->write_function(stream, "ftdm ss7 cgb span X chan Y range Z\n"); stream->write_function(stream, "ftdm ss7 cgu span X chan Y range Z\n"); stream->write_function(stream, "\n"); - stream->write_function(stream, "Ftmod_sangoma_ss7 link control:\n"); + stream->write_function(stream, "ftmod_sangoma_ss7 link control:\n"); stream->write_function(stream, "ftdm ss7 inhibit link X\n"); stream->write_function(stream, "ftdm ss7 uninhibit link X\n"); stream->write_function(stream, "ftdm ss7 activate link X\n"); @@ -724,8 +809,14 @@ static ftdm_status_t handle_print_usuage(ftdm_stream_handle_t *stream) stream->write_function(stream, "ftdm ss7 lpo link X\n"); stream->write_function(stream, "ftdm ss7 lpr link X\n"); stream->write_function(stream, "\n"); - stream->write_function(stream, "Ftmod_sangoma_ss7 Relay status:\n"); + + + stream->write_function(stream, "ftmod_sangoma_ss7 Relay status:\n"); stream->write_function(stream, "ftdm ss7 show status relay X\n"); + stream->write_function(stream, "ftdm ss7 show relay X\n"); + stream->write_function(stream, "ftdm ss7 show relay\n"); + stream->write_function(stream, "\n"); + stream->write_function(stream, "\n"); return FTDM_SUCCESS; @@ -1106,6 +1197,9 @@ static ftdm_status_t handle_show_blocks(ftdm_stream_handle_t *stream, int span, stream->write_function(stream, "l_ucic=N|"); } +#ifdef SMG_RELAY_DBG + stream->write_function(stream, " blk_flag= %x ckt_flag = %d", ss7_info->blk_flags, ss7_info->ckt_flags ); +#endif stream->write_function(stream, "\n"); } /* if ( span and chan) */ @@ -1217,6 +1311,9 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, } } +#ifdef SMG_RELAY_DBG + stream->write_function(stream," blk_flag= %x ckt_flag = %d", ss7_info->blk_flags, ss7_info->ckt_flags ); +#endif stream->write_function(stream, "\n"); } /* if ( hole, sig, voice) */ } /* if ( span and chan) */ @@ -1226,6 +1323,7 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, return FTDM_SUCCESS; } + /******************************************************************************/ static ftdm_status_t handle_tx_blo(ftdm_stream_handle_t *stream, int span, int chan, int verbose) { @@ -1263,7 +1361,7 @@ static ftdm_status_t handle_tx_blo(ftdm_stream_handle_t *stream, int span, int c if (check_for_state_change(ftdmchan)) { SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic); /* check if we need to die */ - SS7_ASSERT; + ftdm_assert(0, "State change not completed\n"); /* unlock the channel again before we exit */ ftdm_mutex_unlock(ftdmchan->mutex); /* move to the next channel */ @@ -1329,7 +1427,7 @@ static ftdm_status_t handle_tx_ubl(ftdm_stream_handle_t *stream, int span, int c if (check_for_state_change(ftdmchan)) { SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic); /* check if we need to die */ - SS7_ASSERT; + ftdm_assert(0, "State change not completed\n"); /* unlock the channel again before we exit */ ftdm_mutex_unlock(ftdmchan->mutex); /* move to the next channel */ @@ -1341,6 +1439,9 @@ static ftdm_status_t handle_tx_ubl(ftdm_stream_handle_t *stream, int span, int c /* clear the block flag */ sngss7_clear_ckt_blk_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX); + /* check group blocking */ + sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_MN_BLOCK_TX); + /* set the channel to suspended state */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); } @@ -1348,103 +1449,47 @@ static ftdm_status_t handle_tx_ubl(ftdm_stream_handle_t *stream, int span, int c /* unlock the channel again before we exit */ ftdm_mutex_unlock(ftdmchan->mutex); - } /* if ( span and chan) */ + } - } /* if ( cic != 0) */ + } /* go the next circuit */ x++; - } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x]id != 0) */ + } handle_show_blocks(stream, span, chan, verbose); return FTDM_SUCCESS; } + /******************************************************************************/ static ftdm_status_t handle_status_mtp3link(ftdm_stream_handle_t *stream, char *name) { - int x = 0; - SnMngmt sta; + SS7_RELAY_DBG_FUN(handle_status_mtp3link); - /* find the link request by it's name */ - x = 1; - while(x < (MAX_MTP_LINKS+1)) { - if (!strcasecmp(g_ftdm_sngss7_data.cfg.mtp3Link[x].name, name)) { + ftdm_assert_return(stream != NULL, FTDM_FAIL, "Invalid stream\n"); - /* send the status request */ - if (ftmod_ss7_mtp3link_sta(x, &sta)) { - stream->write_function(stream, "Failed to read link=%s status\n", name); - return FTDM_FAIL; - } + if (!name) { + return cli_ss7_show_all_mtp3link(stream); + } - /* print the results */ - stream->write_function(stream, "%s|span=%d|chan=%d|sap=%d|state=%s|l_blk=%s|r_blk=%s|l_inhbt=%s|r_inhbt=%s\n", - name, - g_ftdm_sngss7_data.cfg.mtp1Link[x].span, - g_ftdm_sngss7_data.cfg.mtp1Link[x].chan, - g_ftdm_sngss7_data.cfg.mtp3Link[x].id, - DECODE_LSN_LINK_STATUS(sta.t.ssta.s.snDLSAP.state), - (sta.t.ssta.s.snDLSAP.locBlkd) ? "Y":"N", - (sta.t.ssta.s.snDLSAP.remBlkd) ? "Y":"N", - (sta.t.ssta.s.snDLSAP.locInhbt) ? "Y":"N", - (sta.t.ssta.s.snDLSAP.rmtInhbt) ? "Y":"N"); - - goto success; - } - - /* move to the next link */ - x++; - } /* while (x < (MAX_MTP_LINKS+1)) */ - - stream->write_function(stream, "Failed to find link=\"%s\"\n", name); - -success: - return FTDM_SUCCESS; + return cli_ss7_show_mtp3link_by_name(stream, name); } + /******************************************************************************/ static ftdm_status_t handle_status_mtp2link(ftdm_stream_handle_t *stream, char *name) { - int x = 0; - SdMngmt sta; + SS7_RELAY_DBG_FUN(handle_status_mtp2link); - /* find the link request by it's name */ - x = 1; - while(x < (MAX_MTP_LINKS+1)) { - if (!strcasecmp(g_ftdm_sngss7_data.cfg.mtp2Link[x].name, name)) { + ftdm_assert_return(stream != NULL, FTDM_FAIL, "Invalid stream\n"); - /* send the status request */ - if (ftmod_ss7_mtp2link_sta(x, &sta)) { - stream->write_function(stream, "Failed to read link=%s status\n", name); - return FTDM_FAIL; - } + if (!name) { + return cli_ss7_show_all_mtp2link(stream); + } - /* print the results */ - stream->write_function(stream, "%s|span=%d|chan=%d|sap=%d|state=%s|outsFrm=%d|drpdFrm=%d|lclStatus=%s|rmtStatus=%s|fsn=%d|bsn=%d\n", - name, - g_ftdm_sngss7_data.cfg.mtp1Link[x].span, - g_ftdm_sngss7_data.cfg.mtp1Link[x].chan, - g_ftdm_sngss7_data.cfg.mtp2Link[x].id, - DECODE_LSD_LINK_STATUS(sta.t.ssta.s.sdDLSAP.hlSt), - sta.t.ssta.s.sdDLSAP.psOutsFrm, - sta.t.ssta.s.sdDLSAP.cntMaDrop, - (sta.t.ssta.s.sdDLSAP.lclBsy) ? "Y":"N", - (sta.t.ssta.s.sdDLSAP.remBsy) ? "Y":"N", - sta.t.ssta.s.sdDLSAP.fsn, - sta.t.ssta.s.sdDLSAP.bsn); - - goto success; - } - - /* move to the next link */ - x++; - } /* while (x < (MAX_MTP_LINKS+1)) */ - - stream->write_function(stream, "Failed to find link=\"%s\"\n", name); - -success: - return FTDM_SUCCESS; + return cli_ss7_show_mtp2link_by_name(stream, name); } /******************************************************************************/ @@ -1721,8 +1766,8 @@ static ftdm_status_t handle_tx_cgb(ftdm_stream_handle_t *stream, int span, int c memset (&sigev, 0, sizeof (sigev)); - if (range > 31) { - stream->write_function(stream, "Invalid range value %d", range); + if (range <= 1 || range > 31) { + stream->write_function(stream, "Invalid range value %d. Range value must be greater than 1 and less than 31. \n", range); return FTDM_SUCCESS; } @@ -1740,7 +1785,7 @@ static ftdm_status_t handle_tx_cgb(ftdm_stream_handle_t *stream, int span, int c ((ftdmchan->physical_chan_id >= chan) && (ftdmchan->physical_chan_id < (chan+range)))) { /* now that we have the right channel...put a lock on it so no-one else can use it */ - ftdm_mutex_lock(ftdmchan->mutex); + ftdm_channel_lock(ftdmchan); /* throw the grp maint. block flag */ sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_TX); @@ -1753,9 +1798,11 @@ static ftdm_status_t handle_tx_cgb(ftdm_stream_handle_t *stream, int span, int c /* attach the cgb information */ main_chan = ftdmchan; sngss7_span->tx_cgb.circuit = sngss7_info->circuit->id; - sngss7_span->tx_cgb.range = range-1; + sngss7_span->tx_cgb.range = 0; sngss7_span->tx_cgb.type = 0; /* maintenace block */ - } /* if (ftdmchan->physical_chan_id == chan) */ + } else { + ((sngss7_span_data_t*)(main_chan->span->signal_data))->tx_cgb.range++; + } /* update the status field */ sngss7_span->tx_cgb.status[byte] = (sngss7_span->tx_cgb.status[byte] | (1 << bit)); @@ -1768,12 +1815,12 @@ static ftdm_status_t handle_tx_cgb(ftdm_stream_handle_t *stream, int span, int c } /* unlock the channel again before we exit */ - ftdm_mutex_unlock(ftdmchan->mutex); - } /* if ( span and chan) */ - } /* if ( cic == voice) */ + ftdm_channel_unlock(ftdmchan); + } + } /* go the next circuit */ x++; - } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x]id != 0) */ + } if (!main_chan) { stream->write_function(stream, "Failed to find a voice cic in span %d chan %d range %d", span, chan, range); @@ -1794,7 +1841,7 @@ static ftdm_status_t handle_tx_cgb(ftdm_stream_handle_t *stream, int span, int c if ((ftdmchan->physical_span_id == span) && ((ftdmchan->physical_chan_id >= chan) && (ftdmchan->physical_chan_id < (chan+range)))) { - handle_show_status(stream, span, chan, verbose); + handle_show_status(stream, ftdmchan->physical_span_id, ftdmchan->physical_chan_id, verbose); } } /* if ( cic == voice) */ @@ -1809,24 +1856,48 @@ static ftdm_status_t handle_tx_cgb(ftdm_stream_handle_t *stream, int span, int c /******************************************************************************/ static ftdm_status_t handle_tx_cgu(ftdm_stream_handle_t *stream, int span, int chan, int range, int verbose) { - int x; - sngss7_chan_data_t *sngss7_info; - ftdm_channel_t *ftdmchan; - ftdm_channel_t *main_chan = NULL; - sngss7_span_data_t *sngss7_span; - int byte = 0; - int bit = 0; - ftdm_sigmsg_t sigev; + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + ftdm_channel_t *main_chan = NULL; + sngss7_span_data_t *sngss7_span = NULL; + sngss7_chan_data_t *ubl_sng_info[MAX_CIC_MAP_LENGTH+1]; + int x = 0; + int byte = 0; + int bit = 0; + int ubl_sng_info_idx = 1; + ftdm_sigmsg_t sigev; + memset(ubl_sng_info, 0, sizeof(ubl_sng_info)); memset (&sigev, 0, sizeof (sigev)); - - if (range > 31) { - stream->write_function(stream, "Invalid range value %d", range); + if (range <= 1 || range > 31) { + stream->write_function(stream, "Invalid range value %d. Range value must be greater than 1 and less than 31.\n", range); return FTDM_SUCCESS; } - x = (g_ftdm_sngss7_data.cfg.procId * 1000) + 1; + /* verify that there is not hardware block in the range. + * if there is any channel within the group unblock range, do not execute the group unblock */ + x = (g_ftdm_sngss7_data.cfg.procId * MAX_CIC_MAP_LENGTH) + 1; + while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == SNG_CKT_VOICE) { + sngss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCkt[x].obj; + ftdmchan = sngss7_info->ftdmchan; + sngss7_span = ftdmchan->span->signal_data; + + if ( (ftdmchan->physical_span_id == span) + && (ftdmchan->physical_chan_id >= chan) + && (ftdmchan->physical_chan_id < (chan+range)) + && sngss7_test_ckt_blk_flag(sngss7_info, (FLAG_GRP_HW_BLOCK_TX | FLAG_GRP_HW_BLOCK_TX_DN)) + ) { + stream->write_function(stream, "There is at least one channel with hardware block. Group unblock operation not allowed at this time.\n"); + return FTDM_SUCCESS; + } + } + x++; + } + + + x = (g_ftdm_sngss7_data.cfg.procId * MAX_CIC_MAP_LENGTH) + 1; while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) { if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == SNG_CKT_VOICE) { @@ -1840,10 +1911,15 @@ static ftdm_status_t handle_tx_cgu(ftdm_stream_handle_t *stream, int span, int c ((ftdmchan->physical_chan_id >= chan) && (ftdmchan->physical_chan_id < (chan+range)))) { /* now that we have the right channel...put a lock on it so no-one else can use it */ - ftdm_mutex_lock(ftdmchan->mutex); + ftdm_channel_lock(ftdmchan); /* throw the grp maint. block flag */ sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_TX); + + if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX_DN)) { + ubl_sng_info[ubl_sng_info_idx] = sngss7_info; + ubl_sng_info_idx++; + } /* bring the sig status up */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); @@ -1853,9 +1929,11 @@ static ftdm_status_t handle_tx_cgu(ftdm_stream_handle_t *stream, int span, int c /* attach the cgb information */ main_chan = ftdmchan; sngss7_span->tx_cgu.circuit = sngss7_info->circuit->id; - sngss7_span->tx_cgu.range = range-1; + sngss7_span->tx_cgu.range = 0; sngss7_span->tx_cgu.type = 0; /* maintenace block */ - } /* if (ftdmchan->physical_chan_id == chan) */ + } else { + ((sngss7_span_data_t*)(main_chan->span->signal_data))->tx_cgu.range++; + } /* update the status field */ sngss7_span->tx_cgu.status[byte] = (sngss7_span->tx_cgu.status[byte] | (1 << bit)); @@ -1868,12 +1946,12 @@ static ftdm_status_t handle_tx_cgu(ftdm_stream_handle_t *stream, int span, int c } /* unlock the channel again before we exit */ - ftdm_mutex_unlock(ftdmchan->mutex); - } /* if ( span and chan) */ - } /* if ( cic == voice) */ + ftdm_channel_unlock(ftdmchan); + } + } /* go the next circuit */ x++; - } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x]id != 0) */ + } if (!main_chan) { stream->write_function(stream, "Failed to find a voice cic in span %d chan %d range %d", span, chan, range); @@ -1883,6 +1961,13 @@ static ftdm_status_t handle_tx_cgu(ftdm_stream_handle_t *stream, int span, int c /* send the circuit group block */ ft_to_sngss7_cgu(main_chan); + /* clearing blocking flags */ + for (x = 1; ubl_sng_info[x]; x++) { + sngss7_info = ubl_sng_info[x]; + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX_DN); + } + x = (g_ftdm_sngss7_data.cfg.procId * 1000) + 1; while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) { if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == SNG_CKT_VOICE) { @@ -1894,7 +1979,8 @@ static ftdm_status_t handle_tx_cgu(ftdm_stream_handle_t *stream, int span, int c if ((ftdmchan->physical_span_id == span) && ((ftdmchan->physical_chan_id >= chan) && (ftdmchan->physical_chan_id < (chan+range)))) { - handle_show_status(stream, span, chan, verbose); + handle_show_status(stream, ftdmchan->physical_span_id, ftdmchan->physical_chan_id, verbose); + } } /* if ( cic == voice) */ @@ -2158,42 +2244,11 @@ success: /******************************************************************************/ static ftdm_status_t handle_status_relay(ftdm_stream_handle_t *stream, char *name) { - RyMngmt sta; - int x = 0; - - memset(&sta, 0x0, sizeof(sta)); - - - /* find the channel request by it's name */ - x = 1; - while(x < (MAX_RELAY_CHANNELS)) { - if (!strcasecmp(g_ftdm_sngss7_data.cfg.relay[x].name, name)) { - - if (ftmod_ss7_relay_status(g_ftdm_sngss7_data.cfg.relay[x].id, &sta)) { - stream->write_function(stream, "Failed to read relay =%s status\n", name); - return FTDM_FAIL; - } - - /* print the results */ - stream->write_function(stream, "%s|sap=%d|type=%d|port=%d|hostname=%s|procId=%d|status=%s\n", - name, - g_ftdm_sngss7_data.cfg.relay[x].id, - g_ftdm_sngss7_data.cfg.relay[x].type, - g_ftdm_sngss7_data.cfg.relay[x].port, - g_ftdm_sngss7_data.cfg.relay[x].hostname, - g_ftdm_sngss7_data.cfg.relay[x].procId, - DECODE_LRY_CHAN_STATUS(sta.t.ssta.rySta.cStatus)); - - goto success; - } - - /* move to the next link */ - x++; - - } /* x < (MAX_RELAY_CHANNELS) */ - -success: - return FTDM_SUCCESS; + SS7_RELAY_DBG_FUN(handle_status_relay); + if (!name) { + return cli_ss7_show_all_relay(stream); + } + return cli_ss7_show_relay_by_name(stream, name); } /******************************************************************************/ @@ -2426,6 +2481,468 @@ static ftdm_status_t check_arg_count(int args, int min) } } + +/****************************************************************************** +* Fun: cli_ss7_show_mtp2link_by_id() +* Desc: display mtp3 link information with id +* Param: +* stream : output stream object +* rcId : mtp2 link's id +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: James Zhang +*******************************************************************************/ +static ftdm_status_t cli_ss7_show_mtp2link_by_id(ftdm_stream_handle_t *stream, int rcId) +{ + SdMngmt sta; + + SS7_RELAY_DBG_FUN(cli_ss7_show_mtp2link_by_id); + + ftdm_assert_return(stream != NULL, FTDM_FAIL, "Null stream\n"); + + if (ftmod_ss7_mtp2link_sta(rcId, &sta)) { + stream->write_function(stream, "Failed to read status of MTP2 link, id=%d \n", rcId); + return FTDM_FAIL; + } + + stream->write_function(stream, "name=%s|span=%d|chan=%d|sap=%d|state=%s|outsFrm=%d|drpdFrm=%d|lclStatus=%s|rmtStatus=%s|fsn=%d|bsn=%d\n", + g_ftdm_sngss7_data.cfg.mtp2Link[rcId].name, + g_ftdm_sngss7_data.cfg.mtp1Link[rcId].span, + g_ftdm_sngss7_data.cfg.mtp1Link[rcId].chan, + g_ftdm_sngss7_data.cfg.mtp2Link[rcId].id, + DECODE_LSD_LINK_STATUS(sta.t.ssta.s.sdDLSAP.hlSt), + sta.t.ssta.s.sdDLSAP.psOutsFrm, + sta.t.ssta.s.sdDLSAP.cntMaDrop, + (sta.t.ssta.s.sdDLSAP.lclBsy) ? "Y":"N", + (sta.t.ssta.s.sdDLSAP.remBsy) ? "Y":"N", + sta.t.ssta.s.sdDLSAP.fsn, + sta.t.ssta.s.sdDLSAP.bsn + ); + + return FTDM_SUCCESS; +} + +/****************************************************************************** +* Fun: cli_ss7_show_mtp2link_by_name() +* Desc: display all relay channels information +* Param: +* stream : output stream object +* rcName: mtp2 link's name +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: James Zhang +*******************************************************************************/ +static ftdm_status_t cli_ss7_show_mtp2link_by_name(ftdm_stream_handle_t *stream, char *name) +{ + int x = 0; + SS7_RELAY_DBG_FUN(cli_ss7_show_mtp2link_by_name); + + ftdm_assert_return(stream != NULL, FTDM_FAIL, "Null stream\n"); + ftdm_assert_return(!ftdm_strlen_zero(name), FTDM_FAIL, "Null MTP2 link name\n"); + + for (x = 0; x < (MAX_MTP_LINKS + 1); x++) { + if (0 == strcasecmp(g_ftdm_sngss7_data.cfg.mtp2Link[x].name, name)) { + return cli_ss7_show_mtp2link_by_id( stream, x ); + } + } + + stream->write_function (stream, "The MTP2 link with name \'%s\' is not found. \n", name); + return FTDM_FAIL; +} + +/****************************************************************************** +* Fun: cli_ss7_show_all_mtp2link() +* Desc: display all mtp2 links information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: James Zhang +*******************************************************************************/ +static ftdm_status_t cli_ss7_show_all_mtp2link(ftdm_stream_handle_t *stream) +{ + int x = 0; + + SS7_RELAY_DBG_FUN(cli_ss7_show_all_mtp2link); + + ftdm_assert_return(stream != NULL, FTDM_FAIL, "Null stream\n"); + + for (x = 0; x < (MAX_MTP_LINKS + 1); x++) { + if (!ftdm_strlen_zero( g_ftdm_sngss7_data.cfg.mtp2Link[x].name)) { + cli_ss7_show_mtp2link_by_id(stream, x ); + } + } + + return FTDM_SUCCESS; +} + +/****************************************************************************** +* Fun: cli_ss7_show_mtp3link_by_id() +* Desc: display mtp3 link information with id +* Param: +* stream : output stream object +* rcId : mtp3 link's id +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: James Zhang +*******************************************************************************/ +static ftdm_status_t cli_ss7_show_mtp3link_by_id(ftdm_stream_handle_t *stream, int rcId) +{ + SnMngmt sta; + + SS7_RELAY_DBG_FUN(cli_ss7_show_mtp3link_by_id); + + ftdm_assert_return(stream != NULL, FTDM_FAIL, "Null stream\n"); + + memset(&sta, 0, sizeof(sta)); + if (ftmod_ss7_mtp3link_sta(rcId, &sta)) { + stream->write_function(stream, "Failed to read status of MTP3 link, id=%d \n", rcId); + return FTDM_FAIL; + } + + stream->write_function(stream, "name=%s|span=%d|chan=%d|sap=%d|state=%s|l_blk=%s|r_blk=%s|l_inhbt=%s|r_inhbt=%s\n", + g_ftdm_sngss7_data.cfg.mtp3Link[rcId].name, + g_ftdm_sngss7_data.cfg.mtp1Link[rcId].span, + g_ftdm_sngss7_data.cfg.mtp1Link[rcId].chan, + g_ftdm_sngss7_data.cfg.mtp3Link[rcId].id, + DECODE_LSN_LINK_STATUS(sta.t.ssta.s.snDLSAP.state), + (sta.t.ssta.s.snDLSAP.locBlkd) ? "Y":"N", + (sta.t.ssta.s.snDLSAP.remBlkd) ? "Y":"N", + (sta.t.ssta.s.snDLSAP.locInhbt) ? "Y":"N", + (sta.t.ssta.s.snDLSAP.rmtInhbt) ? "Y":"N" + ); + + return FTDM_SUCCESS; +} + +/****************************************************************************** +* Fun: cli_ss7_show_mtp3link_by_name() +* Desc: display all relay channels information +* Param: +* stream : output stream object +* rcName: mtp3 link's name +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: James Zhang +*******************************************************************************/ +static ftdm_status_t cli_ss7_show_mtp3link_by_name(ftdm_stream_handle_t *stream, char *name) +{ + int x=0; + SS7_RELAY_DBG_FUN(cli_ss7_show_mtp3link_by_name); + + ftdm_assert_return(stream != NULL, FTDM_FAIL, "Null stream\n"); + ftdm_assert_return(!ftdm_strlen_zero(name), FTDM_FAIL, "Null MTP3 link name\n"); + + for (x = 0; x < (MAX_MTP_LINKS + 1); x++) { + if (!strcasecmp(g_ftdm_sngss7_data.cfg.mtp3Link[x].name, name)) { + return cli_ss7_show_mtp3link_by_id(stream, x ); + } + } + + stream->write_function(stream, "The MTP3 link with name \'%s\' is not found. \n", name); + return FTDM_FAIL; +} +/****************************************************************************** +* Fun: cli_ss7_show_all_mtp3link() +* Desc: display all mtp3 links information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: James Zhang +*******************************************************************************/ +static ftdm_status_t cli_ss7_show_all_mtp3link(ftdm_stream_handle_t *stream) +{ + int x = 0; + + SS7_RELAY_DBG_FUN(cli_ss7_show_all_mtp3link); + ftdm_assert_return(stream != NULL, FTDM_FAIL, "Null stream\n"); + + for (x = 0; x < (MAX_MTP_LINKS + 1); x++) { + if (!ftdm_strlen_zero(g_ftdm_sngss7_data.cfg.mtp3Link[x].name)) { + cli_ss7_show_mtp3link_by_id(stream, x); + } + } + + return FTDM_SUCCESS; +} + + +/****************************************************************************** +* Fun: cli_ss7_show_all_linkset() +* Desc: display all mtp3 linksets information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: James Zhang +*******************************************************************************/ +static ftdm_status_t cli_ss7_show_all_linkset(ftdm_stream_handle_t *stream) +{ + int x = 0; + SnMngmt sta; + + SS7_RELAY_DBG_FUN(cli_ss7_show_all_linkset); + ftdm_assert_return(stream != NULL, FTDM_FAIL, "Null stream\n"); + + x = 1; + while(x < (MAX_MTP_LINKSETS+1)) { + if (!ftdm_strlen_zero(g_ftdm_sngss7_data.cfg.mtpLinkSet[x].name)) { + if (ftmod_ss7_mtplinkSet_sta(x, &sta)) { + stream->write_function(stream, "Failed to read linkset=%s status\n", g_ftdm_sngss7_data.cfg.mtpLinkSet[x].name); + } else { + stream->write_function(stream, "name=%s|state=%s|nmbActLnk=%d\n", + g_ftdm_sngss7_data.cfg.mtpLinkSet[x].name, + DECODE_LSN_LINKSET_STATUS(sta.t.ssta.s.snLnkSet.state), sta.t.ssta.s.snLnkSet.nmbActLnks + ); + } + } + x++; + } + return FTDM_SUCCESS; +} + + +/****************************************************************************** +* Fun: cli_ss7_show_general() +* Desc: display all general information about ss7 +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: James Zhang +*******************************************************************************/ +static ftdm_status_t cli_ss7_show_general(ftdm_stream_handle_t *stream) +{ + SS7_RELAY_DBG_FUN(cli_ss7_show_general); + + ftdm_assert_return(stream != NULL, FTDM_FAIL, "Null stream\n"); + + stream->write_function(stream, "MTP2 status: \n"); + cli_ss7_show_all_mtp2link(stream); + + stream->write_function(stream, "\nMTP3 status: \n"); + cli_ss7_show_all_mtp3link(stream); + + stream->write_function(stream, "\nMTP3 linkset status: \n"); + cli_ss7_show_all_linkset(stream); + +#if 0 + stream->write_function(stream, "\nMTP3 link route status: \n"); + + stream->write_function(stream, "\nISUP status: \n"); +#endif + + stream->write_function(stream, "\nRelay status: \n"); + cli_ss7_show_all_relay(stream); + + return FTDM_SUCCESS; +} + +/****************************************************************************** +* Fun: cli_ss7_show_relay_by_id() +* Desc: display all relay channels information +* Param: +* stream : output stream object +* rcId : channel's id +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: James Zhang +*******************************************************************************/ +static ftdm_status_t cli_ss7_show_relay_by_id(ftdm_stream_handle_t *stream, int rcId) +{ + RyMngmt sta; + + SS7_RELAY_DBG_FUN(cli_ss7_show_relay_by_id); + ftdm_assert_return(stream != NULL, FTDM_FAIL, "Null stream\n"); + + memset(&sta, 0x0, sizeof(sta)); + if (ftmod_ss7_relay_status(g_ftdm_sngss7_data.cfg.relay[rcId].id, &sta)) { + stream->write_function(stream, "Failed to read relay =%s status\n", g_ftdm_sngss7_data.cfg.relay[rcId].name); + return FTDM_FAIL; + } + + stream->write_function(stream, "name=%s|sap=%d|type=%d|port=%d|hostname=%s|procId=%d|status=%s\n", + g_ftdm_sngss7_data.cfg.relay[rcId].name, + g_ftdm_sngss7_data.cfg.relay[rcId].id, + g_ftdm_sngss7_data.cfg.relay[rcId].type, + g_ftdm_sngss7_data.cfg.relay[rcId].port, + g_ftdm_sngss7_data.cfg.relay[rcId].hostname, + g_ftdm_sngss7_data.cfg.relay[rcId].procId, + DECODE_LRY_CHAN_STATUS(sta.t.ssta.rySta.cStatus) + ); + + return FTDM_SUCCESS; +} +/****************************************************************************** +* Fun: cli_ss7_show_relay_by_name() +* Desc: display all relay channels information +* Param: +* stream : output stream object +* rcName: channel's name +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: James Zhang +*******************************************************************************/ +static ftdm_status_t cli_ss7_show_relay_by_name(ftdm_stream_handle_t *stream, char *name) +{ + int x = 0; + + SS7_RELAY_DBG_FUN(cli_ss7_show_relay_by_name); + + ftdm_assert_return(stream != NULL, FTDM_FAIL, "Null stream\n"); + ftdm_assert_return(!ftdm_strlen_zero(name), FTDM_FAIL, "Null relay link name\n"); + + for (x = 1; x < MAX_RELAY_CHANNELS; x++) { + if (!strcasecmp(g_ftdm_sngss7_data.cfg.relay[x].name, name)) { + return cli_ss7_show_relay_by_id(stream, x); + } + } + + stream->write_function( stream, "The relay channel with name \'%s\' is not found. \n", name); + return FTDM_FAIL; + +} +/****************************************************************************** +* Fun: cli_ss7_show_all_relay() +* Desc: display all relay channels information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: James Zhang +*******************************************************************************/ +static ftdm_status_t cli_ss7_show_all_relay(ftdm_stream_handle_t *stream) +{ + int x = 0; + SS7_RELAY_DBG_FUN(cli_ss7_show_relay_by_name); + + ftdm_assert_return(stream != NULL, FTDM_FAIL, "Null stream\n"); + + for (x = 1; x < MAX_RELAY_CHANNELS; x++) { + if (!ftdm_strlen_zero(g_ftdm_sngss7_data.cfg.relay[x].name)) { + cli_ss7_show_relay_by_id (stream, x); + } + } + + return FTDM_SUCCESS; +} + + +/****************************************************************************** +* Fun: cli_ss7_show_channel_detail_of_span() +* Desc: display span information of a given id +* Param: +* stream : output stream object +* span_id : span id string received from cli +* chan_id : channel id string received from cli +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: James Zhang +*******************************************************************************/ +static ftdm_status_t cli_ss7_show_channel_detail_of_span(ftdm_stream_handle_t *stream, char *span_id, char *chan_id) +{ + int x, y; + + SS7_RELAY_DBG_FUN(cli_ss7_show_channel_detail_of_span); + + ftdm_assert_return(stream != NULL, FTDM_FAIL, "Null stream\n"); + ftdm_assert_return(span_id != 0, FTDM_FAIL, "Invalid span id\n"); + ftdm_assert_return(chan_id != 0, FTDM_FAIL, "Invalid chan id\n"); + + x = atoi(span_id); + y = atoi(chan_id); + if (!x) { + stream->write_function( stream, "Span \'%s\' does not exist. \n", span_id); + return FTDM_FAIL; + } + + return handle_show_status(stream, x, y, 1); +} + +/****************************************************************************** +* Fun: cli_ss7_show_all_channels_of_span() +* Desc: display span information of a given id +* Param: +* stream : output stream object +* span_id : span id string received from cli +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: James Zhang +*******************************************************************************/ +static ftdm_status_t cli_ss7_show_all_channels_of_span(ftdm_stream_handle_t *stream, char *span_id) +{ + int x=-1; + SS7_RELAY_DBG_FUN(cli_ss7_show_all_channels_of_span); + + ftdm_assert_return(stream != NULL, FTDM_FAIL, "Null stream\n"); + ftdm_assert_return(span_id != 0, FTDM_FAIL, "Invalid span id\n"); + + x = atoi(span_id); + if (!x) { + stream->write_function( stream, "Span \'%s\' does not exist. \n", span_id); + return FTDM_FAIL; + } + return handle_show_status(stream, x, 0, 1); +} + +/****************************************************************************** +* Fun: cli_ss7_show_span_by_id() +* Desc: display span information of a given id +* Param: +* stream : output stream object +* span_id : span id string received from cli +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: James Zhang +*******************************************************************************/ +static ftdm_status_t cli_ss7_show_span_by_id(ftdm_stream_handle_t *stream, char *span_id) +{ + int x = -1; + + SS7_RELAY_DBG_FUN(cli_ss7_show_span_by_id); + + ftdm_assert_return(stream != NULL, FTDM_FAIL, "Null stream\n"); + ftdm_assert_return(span_id != 0, FTDM_FAIL, "Invalid span id\n"); + + x = atoi(span_id); + if (!x) { + stream->write_function(stream, "Span \'%s\' does not exist. \n", span_id); + return FTDM_FAIL; + } + +#if 0 + stream->write_function( stream, "JZ: we should display span details here \n" ); +#endif + + cli_ss7_show_all_channels_of_span(stream, span_id); + + return FTDM_FAIL; +} + + +/****************************************************************************** +* Fun: cli_ss7_show_all_spans_detail() +* Desc: display all spans information in detail +* Param: +* stream : output stream object +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: James Zhang +*******************************************************************************/ +static ftdm_status_t cli_ss7_show_all_spans_detail(ftdm_stream_handle_t *stream) +{ + SS7_RELAY_DBG_FUN(cli_ss7_show_all_spans_detail); + ftdm_assert_return(stream != NULL, FTDM_FAIL, "Null stream\n"); + return handle_show_status(stream, 0, 0, 1); +} + +/****************************************************************************** +* Fun: cli_ss7_show_all_spans_general() +* Desc: display all spans information in general +* Param: +* stream : output stream object +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: James Zhang +*******************************************************************************/ +static ftdm_status_t cli_ss7_show_all_spans_general(ftdm_stream_handle_t *stream) +{ + SS7_RELAY_DBG_FUN(cli_ss7_show_all_spans_general); + ftdm_assert_return(stream != NULL, FTDM_FAIL, "Null stream\n"); + return FTDM_FAIL; +} + /******************************************************************************/ /* For Emacs: * Local Variables: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index b541e1b551..26356220ec 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -1643,8 +1643,8 @@ ftdm_status_t handle_ubl_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ ftdm_mutex_lock(ftdmchan->mutex); /* check if the channel is blocked */ - if (!(sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX))) { - SS7_WARN("Received UBL on circuit that is not blocked!\n"); + if (!(sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX)) && !sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX)) { + SS7_WARN("Received UBL on circuit that is not blocked! span= %d, chan= %d , flag = %x \n", g_ftdm_sngss7_data.cfg.isupCkt[circuit].span, g_ftdm_sngss7_data.cfg.isupCkt[circuit].chan,sngss7_info->blk_flags ); } /* throw the unblock flag */ @@ -1652,6 +1652,8 @@ ftdm_status_t handle_ubl_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* clear the block flag */ sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX_DN); /* set the channel to suspended state */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); @@ -1692,14 +1694,6 @@ ftdm_status_t handle_ubl_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circ DECODE_LCC_EVENT(evntType)); } - /* lock the channel */ - ftdm_mutex_lock(ftdmchan->mutex); - - /* KONRAD FIX ME */ - - /* unlock the channel again before we exit */ - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); return FTDM_SUCCESS; } @@ -2453,6 +2447,8 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ /**********************************************************************/ case 0: /* maintenance oriented */ sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); break; /**********************************************************************/ case 1: /* hardware failure oriented */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c index 4c6c16350d..b13c98b1e6 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c @@ -486,47 +486,47 @@ void sngss7_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint g_ftdm_sngss7_data.cfg.isupCkt[circuit].cic); } - x = (g_ftdm_sngss7_data.cfg.procId * 1000) + 1; + x = (g_ftdm_sngss7_data.cfg.procId * MAX_CIC_MAP_LENGTH) + 1; while ((g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) && - (g_ftdm_sngss7_data.cfg.isupCkt[x].id < ((g_ftdm_sngss7_data.cfg.procId +1) * 1000))) { - /**********************************************************************/ + (g_ftdm_sngss7_data.cfg.isupCkt[x].id < ((g_ftdm_sngss7_data.cfg.procId + 1) * MAX_CIC_MAP_LENGTH))) { + /**********************************************************************/ /* confirm this is a voice channel and not a gap/sig (no ftdmchan there) */ - if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != SNG_CKT_VOICE) goto move_along; + if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == SNG_CKT_VOICE) { + /* compare the intfIds */ + if (g_ftdm_sngss7_data.cfg.isupCkt[x].infId == intfId) { + /* we have a match, setup the pointers to the correct values */ + circuit = x; - /* compare the intfIds */ - if (g_ftdm_sngss7_data.cfg.isupCkt[x].infId == intfId) { - /* we have a match, setup the pointers to the correct values */ - circuit = x; + /* confirm that the circuit is active on our side otherwise move to the next circuit */ + if (!sngss7_test_flag(&g_ftdm_sngss7_data.cfg.isupCkt[circuit], SNGSS7_ACTIVE)) { + SS7_DEBUG("[CIC:%d]Rx %s but circuit is not active yet, skipping!\n", + g_ftdm_sngss7_data.cfg.isupCkt[circuit].cic, + DECODE_LCC_EVENT(evntType)); + x++; + continue; + } - /* confirm that the circuit is active on our side otherwise move to the next circuit */ - if (!sngss7_test_flag(&g_ftdm_sngss7_data.cfg.isupCkt[circuit], SNGSS7_ACTIVE)) { - SS7_DEBUG("[CIC:%d]Rx %s but circuit is not active yet, skipping!\n", - g_ftdm_sngss7_data.cfg.isupCkt[circuit].cic, - DECODE_LCC_EVENT(evntType)); - continue; - } - - if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { - SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - return; + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; + } + + /* bounce out of the loop */ + break; } + } - /* bounce out of the loop */ - break; - } /* if (g_ftdm_sngss7_data.cfg.isupCkt[x].intfId == intfId) */ - -move_along: - /* move along ... nothing to see here */ x++; - - /**********************************************************************/ - } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) */ + /**********************************************************************/ + } /* check if we found any circuits that are on the intfId, drop the message - * if none are found - */ - if (ftdmchan == NULL) goto sta_ind_end; + * if none are found */ + if (!ftdmchan) { + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; + } break; /**************************************************************************/ @@ -544,7 +544,6 @@ move_along: SS7_FUNC_TRACE_EXIT(__FUNCTION__); return; } - break; /**************************************************************************/ } /* switch (evntType) */ @@ -571,9 +570,6 @@ move_along: /* enqueue this event */ ftdm_queue_enqueue(((sngss7_span_data_t*)sngss7_info->ftdmchan->span->signal_data)->event_queue, sngss7_event); - -sta_ind_end: - SS7_FUNC_TRACE_EXIT(__FUNCTION__); } /******************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c index 4b5787c0cb..bddcd39eca 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c @@ -31,6 +31,7 @@ * SOFTWARE|EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + /* INCLUDE ********************************************************************/ #include "ftmod_sangoma_ss7_main.h" /******************************************************************************/ @@ -353,6 +354,8 @@ void handle_sng_mtp3_alarm(Pst *pst, SnMngmt *sta) char buf[50]; int x = 1; + SS7_RELAY_DBG_FUN(handle_sng_mtp3_alarm); + memset(buf, '\0', sizeof(buf)); switch (sta->hdr.elmId.elmnt) { @@ -492,6 +495,8 @@ void handle_sng_isup_alarm(Pst *pst, SiMngmt *sta) char tmp[25]; char *p = NULL; int x = 0; + + SS7_RELAY_DBG_FUN(handle_sng_isup_alarm); /* initalize the msg variable to NULLs */ memset(&msg[0], '\0', sizeof(&msg)); @@ -502,7 +507,6 @@ void handle_sng_isup_alarm(Pst *pst, SiMngmt *sta) return; } - /* point p to the first spot in msg */ p = &msg[0]; @@ -742,6 +746,7 @@ void handle_sng_isup_alarm(Pst *pst, SiMngmt *sta) void handle_sng_cc_alarm(Pst *pst, CcMngmt *sta) { + SS7_RELAY_DBG_FUN(handle_sng_cc_alarm); return; } /* handle_cc_alarm */ @@ -749,6 +754,7 @@ void handle_sng_cc_alarm(Pst *pst, CcMngmt *sta) void handle_sng_relay_alarm(Pst *pst, RyMngmt *sta) { + SS7_RELAY_DBG_FUN(handle_sng_relay_alarm); switch (sta->hdr.elmId.elmnt) { /**************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index a849bf2f62..9f2cbbac25 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -60,6 +60,7 @@ static ftdm_status_t ftdm_sangoma_ss7_stop (ftdm_span_t * span); static ftdm_status_t ftdm_sangoma_ss7_start (ftdm_span_t * span); /******************************************************************************/ + /* STATE MAP ******************************************************************/ ftdm_state_map_t sangoma_ss7_state_map = { { @@ -281,7 +282,37 @@ ftdm_state_map_t sangoma_ss7_state_map = { } }; -/******************************************************************************/ +static void handle_hw_alarm(ftdm_event_t *e) +{ + sngss7_chan_data_t *ss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + int x = 0; + + ftdm_assert(e != NULL, "Null event!\n"); + + for (x = (g_ftdm_sngss7_data.cfg.procId * MAX_CIC_MAP_LENGTH) + 1; g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0; x++) { + if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == SNG_CKT_VOICE) { + ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCkt[x].obj; + ftdmchan = ss7_info->ftdmchan; + + if (e->channel->span_id == ftdmchan->physical_span_id && + e->channel->chan_id == ftdmchan->physical_chan_id) { + if (e->enum_id == FTDM_OOB_ALARM_TRAP) { + sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX); + if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + } + } else { + sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); + sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX); + if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + } + } + } + } + } +} /* MONITIOR THREADS ***********************************************************/ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) @@ -293,6 +324,9 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) sngss7_event_data_t *sngss7_event = NULL; sngss7_span_data_t *sngss7_span = (sngss7_span_data_t *)ftdmspan->signal_data; + int b_alarm_test = 1; + sngss7_chan_data_t *ss7_info=NULL; + ftdm_log (FTDM_LOG_INFO, "ftmod_sangoma_ss7 monitor thread for span=%u started.\n", ftdmspan->span_id); /* set IN_THREAD flag so that we know this thread is running */ @@ -311,6 +345,30 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) } while (ftdm_running () && !(ftdm_test_flag (ftdmspan, FTDM_SPAN_STOP_THREAD))) { + int x = 0; + if (b_alarm_test) { + b_alarm_test = 0; + for (x = (g_ftdm_sngss7_data.cfg.procId * MAX_CIC_MAP_LENGTH) + 1; + g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0; x++) { + if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == SNG_CKT_VOICE) { + ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCkt[x].obj; + ftdmchan = ss7_info->ftdmchan; + if (!ftdmchan) { + continue; + } + + if (ftdmchan->alarm_flags != 0) { /* we'll send out block */ + sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX ); + } else { /* we'll send out reset */ + sngss7_clear_ckt_blk_flag( ss7_info, FLAG_GRP_HW_BLOCK_TX ); + sngss7_clear_ckt_blk_flag( ss7_info, FLAG_GRP_HW_BLOCK_TX_DN ); + sngss7_set_ckt_blk_flag (ss7_info, FLAG_GRP_HW_UNBLK_TX); + } + } + usleep(50); + } + ftdmchan = NULL; + } /* check the channel state queue for an event*/ switch ((ftdm_interrupt_multiple_wait(ftdm_sangoma_ss7_int, 2, 100))) { @@ -388,7 +446,11 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) switch (ftdm_span_poll_event(ftdmspan, 0, NULL)) { /**********************************************************************/ case FTDM_SUCCESS: - while (ftdm_span_next_event(ftdmspan, &event) == FTDM_SUCCESS); + while (ftdm_span_next_event(ftdmspan, &event) == FTDM_SUCCESS) { + if (event->e_type == FTDM_EVENT_OOB) { + handle_hw_alarm(event); + } + } break; /**********************************************************************/ case FTDM_TIMEOUT: @@ -1106,16 +1168,97 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* clear the unblock flag */ sngss7_clear_ckt_blk_flag (sngss7_info, FLAG_CKT_MN_UNBLK_RX); - /* bring the sig status up */ - sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + /* not bring the cic up if there is a hardware block */ + if( !sngss7_test_ckt_blk_flag(sngss7_info, (FLAG_GRP_HW_BLOCK_TX | FLAG_GRP_HW_BLOCK_TX_DN) ) ) { + /* bring the sig status up */ + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); - /* send a uba */ - ft_to_sngss7_uba (ftdmchan); + /* send a uba */ + ft_to_sngss7_uba (ftdmchan); + } /* check the last state and return to it to allow the call to finish */ goto suspend_goto_last; } + + /**********************************************************************/ + /* hardware block/unblock tx */ + if (sngss7_test_ckt_blk_flag (sngss7_info, FLAG_GRP_HW_BLOCK_TX ) && + !sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX_DN )) { + + SS7_DEBUG_CHAN(ftdmchan, "Processing FLAG_GRP_HW_BLOCK_TX flag %s\n", ""); + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); + + /* dont send block again if the channel is already blocked by maintenance */ + if( !sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX) && + !sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX_DN) + ) { + ft_to_sngss7_blo(ftdmchan); + } + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX_DN); + + goto suspend_goto_last; + } + + if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_UNBLK_TX)) { + SS7_DEBUG_CHAN(ftdmchan, "Processing FLAG_GRP_HW_UNBLK_TX flag %s\n", ""); + + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX_DN); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_UNBLK_TX); + + /* do not set the channel up if it's blocked by blo/cgb command OR blocked by receiving blo/cgb */ + if (!sngss7_test_ckt_blk_flag(sngss7_info, ( FLAG_CKT_MN_BLOCK_TX + | FLAG_CKT_MN_BLOCK_TX + | FLAG_GRP_MN_BLOCK_TX + | FLAG_GRP_MN_BLOCK_TX_DN + | FLAG_CKT_MN_BLOCK_RX + | FLAG_CKT_MN_BLOCK_RX_DN + | FLAG_GRP_MN_BLOCK_RX + | FLAG_GRP_MN_BLOCK_RX_DN + ) + ) + ) { + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + ft_to_sngss7_ubl(ftdmchan); + } + + goto suspend_goto_last; + } +#if 0 +//jz: there is no such thing of "remote hw block". for receiver, there are only block and unblock + + /**********************************************************************/ + // jz: hardware block/unblock rx + if (sngss7_test_ckt_blk_flag (sngss7_info, FLAG_GRP_HW_BLOCK_RX ) && + !sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX_DN )) { + + SS7_DEBUG_CHAN(ftdmchan, "Processing FLAG_GRP_HW_BLOCK_RX flag %s\n", ""); + + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); + ft_to_sngss7_bla(ftdmchan); + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX_DN); + + goto suspend_goto_last; + } + + if (sngss7_test_ckt_blk_flag (sngss7_info, FLAG_GRP_HW_UNBLK_RX )){ + SS7_DEBUG_CHAN(ftdmchan, "Processing FLAG_GRP_HW_UNBLK_RX flag %s\n", ""); + + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX_DN); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_UNBLK_RX); + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + + ft_to_sngss7_uba(ftdmchan); + + goto suspend_goto_last; + } +#endif + + + /**********************************************************************/ if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX) && !sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX_DN)) { @@ -1146,11 +1289,14 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* clear the unblock flag */ sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_UNBLK_TX); - /* bring the sig status up */ - sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + /* not bring the cic up if there is a hardware block */ + if (!sngss7_test_ckt_blk_flag(sngss7_info, (FLAG_GRP_HW_BLOCK_TX | FLAG_GRP_HW_BLOCK_TX_DN))) { + /* bring the sig status up */ + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); - /* send a ubl */ - ft_to_sngss7_ubl (ftdmchan); + /* send a ubl */ + ft_to_sngss7_ubl(ftdmchan); + } /* check the last state and return to it to allow the call to finish */ goto suspend_goto_last; @@ -1628,6 +1774,7 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_sangoma_ss7_unload) ftdm_log (FTDM_LOG_INFO, "Starting ftmod_sangoma_ss7 unload...\n"); + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_CC_STARTED)) { sng_isup_free_cc(); sngss7_clear_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_CC_STARTED); @@ -1666,13 +1813,15 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_sangoma_ss7_unload) /* send the specific configuration */ if (ftmod_ss7_disable_relay_channel(x)) { SS7_CRITICAL("Relay Channel %d disable failed!\n", x); - return 1; + /* jz: dont leave like this + * return 1; + * */ } else { SS7_INFO("Relay Channel %d disable DONE!\n", x); } /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.relay[x].flags &= !SNGSS7_CONFIGURED; + g_ftdm_sngss7_data.cfg.relay[x].flags &= ~(SNGSS7_CONFIGURED); } /* if !SNGSS7_CONFIGURED */ x++; } /* while (x < (MAX_RELAY_CHANNELS)) */ @@ -1682,6 +1831,7 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_sangoma_ss7_unload) sngss7_clear_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_RY_STARTED); } + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_SM_STARTED)) { sng_isup_free_sm(); sngss7_clear_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_SM_STARTED); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index cda6225217..7a116ecbb4 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -64,12 +64,10 @@ (switchtype == LSI_SW_ANS92) || \ (switchtype == LSI_SW_ANS95) -typedef struct ftdm2trillium -{ +typedef struct ftdm2trillium { uint8_t ftdm_val; uint8_t trillium_val; -}ftdm2trillium_t; - +} ftdm2trillium_t; typedef enum { SNGSS7_CON_IND_EVENT = 0, @@ -609,22 +607,20 @@ typedef enum { "TX CKT BLK DN", \ "TX CKT UNBLK", \ "TX CKT UNBLK DN", \ - "RX GRP MN BLK", \ - "RX GRP MN BLK DN", \ - "RX GRP MN UNBLK", \ - "RX GRP MN UNBLK DN", \ - "TX GRP MN BLK", \ - "TX GRP MN BLK DN", \ - "TX GRP MN UNBLK", \ - "TX GRP MN UNBLK DN", \ "RX GRP HW BLK", \ "RX GRP HW BLK DN", \ - "RX GRP HW UNBLK", \ - "RX GRP HW UNBLK DN", \ "TX GRP HW BLK", \ "TX GRP HW BLK DN", \ + "RX GRP MN BLK", \ + "RX GRP MN BLK DN", \ + "TX GRP MN BLK", \ + "TX GRP MN BLK DN", \ "TX GRP HW UNBLK", \ - "TX GRP HW UNBLK DN" + "TX GRP HW UNBLK DN", \ + "TX GRP MN UNBLK", \ + "TX GRP MN UNBLK DN", \ + "RX GRP HW UNBLK", \ + "RX GRP HW UNBLK DN" FTDM_STR2ENUM_P(ftmod_ss7_blk_state2flag, ftmod_ss7_blk_flag2str, sng_ckt_block_flag_t) /* valid for every cfg array except circuits */ @@ -1042,13 +1038,12 @@ if (ftdmchan->state == new_state) { \ #define sngss7_set_options(obj, option) ((obj)->options |= (option)) -#ifdef SS7_PRODUCTION -# define SS7_ASSERT \ - SS7_INFO_CHAN(ftdmchan,"Production Mode, continuing%s\n", ""); +#ifdef SMG_RELAY_DBG +#define SS7_RELAY_DBG(a,...) printf(a"\n", ##__VA_ARGS__) +#define SS7_RELAY_DBG_FUN(a) printf(#a"\n") #else -# define SS7_ASSERT \ - SS7_ERROR_CHAN(ftdmchan, "Debugging Mode, ending%s\n", ""); \ - *(int*)0=0; +#define SS7_RELAY_DBG(a, ...) +#define SS7_RELAY_DBG_FUN(a) #endif /******************************************************************************/ From 5ca31e9fbf712e721481718d57b11484b189e731 Mon Sep 17 00:00:00 2001 From: yannick Date: Tue, 27 Sep 2011 15:44:20 -0400 Subject: [PATCH 040/822] freetdm: resolve mtp2 on relay always down problem --- .../ftmod_sangoma_ss7_relay.c | 49 +++++++------------ 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c index bfb6971297..c99a14a7e7 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c @@ -49,7 +49,7 @@ ftdm_status_t handle_relay_disconnect(RyMngmt *sta); static ftdm_status_t reconfig_all_ckts_for_relay(void); static ftdm_status_t disable_all_ckts_for_relay(void); static ftdm_status_t block_all_ckts_for_relay(uint32_t procId); -static ftdm_status_t unblock_all_ckts_for_relay(uint32_t procId); +/* static ftdm_status_t unblock_all_ckts_for_relay(uint32_t procId); */ static ftdm_status_t disable_all_sigs_for_relay(uint32_t procId); static ftdm_status_t disble_all_mtp2_sigs_for_relay(void); /******************************************************************************/ @@ -59,43 +59,26 @@ ftdm_status_t handle_relay_connect(RyMngmt *sta) { sng_relay_t *sng_relay = &g_ftdm_sngss7_data.cfg.relay[sta->t.usta.s.ryUpUsta.id]; - - /* test if this is the first time the channel comes up */ if (!sngss7_test_flag(sng_relay, SNGSS7_RELAY_INIT)) { - SS7_INFO("Relay Channel %d initial connection UP\n", sng_relay->id); - - /* mark the channel as being up */ + /* SS7_INFO("Relay Channel %d initial connection UP\n", sng_relay->id); */ sngss7_set_flag(sng_relay, SNGSS7_RELAY_INIT); - } else { - SS7_INFO("Relay Channel %d connection UP\n", sng_relay->id); - - /* react based on type of channel */ - switch (sng_relay->type) { - /******************************************************************/ - case (LRY_CT_TCP_CLIENT): - /* reconfigure all ISUP ckts, since the main system would have lost all configs */ + } + + SS7_INFO("Relay Channel %d connection UP\n", sng_relay->id); + if (sng_relay->type == LRY_CT_TCP_CLIENT) { + if (!sngss7_test_flag(sng_relay, SNGSS7_RELAY_INIT)) { if (reconfig_all_ckts_for_relay()) { SS7_ERROR("Failed to reconfigure ISUP Ckts!\n"); /* we're done....this is very bad! */ } - break; - /******************************************************************/ - case (LRY_CT_TCP_SERVER): - /* bring the sig links on the client system back up */ - ftmod_ss7_enable_grp_mtp3Link(sta->t.usta.s.ryUpUsta.id); - - /* unbloock the ckts on the client system */ - unblock_all_ckts_for_relay(sta->t.usta.s.ryUpUsta.id); - - break; - /******************************************************************/ - default: - break; - /******************************************************************/ - } /* switch (g_ftdm_sngss7_data.cfg.relay[sta->t.usta.s.ryUpUsta.id].type) */ - } /* intial up? */ - - return FTDM_SUCCESS; + } + return FTDM_SUCCESS; + } else if (sng_relay->type == LRY_CT_TCP_SERVER) { + ftmod_ss7_enable_grp_mtp3Link(sta->t.usta.s.ryUpUsta.id); + /* unbloock the ckts on the client system */ + return FTDM_SUCCESS; + } + return FTDM_FAIL; } /******************************************************************************/ @@ -310,6 +293,7 @@ ftdm_status_t disble_all_mtp2_sigs_for_relay(void) } +#if 0 /******************************************************************************/ static ftdm_status_t unblock_all_ckts_for_relay(uint32_t procId) { @@ -345,6 +329,7 @@ static ftdm_status_t unblock_all_ckts_for_relay(uint32_t procId) return FTDM_SUCCESS; } +#endif /******************************************************************************/ /* For Emacs: From d9fe71f02485efcdd1147096023d17d7cd4ba431 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Tue, 27 Sep 2011 15:46:40 -0400 Subject: [PATCH 041/822] freetdm: changing git user to be James Zhang - last commit of mtp2 relay fixing was mine --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c index c99a14a7e7..1d85dfffbb 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c @@ -331,6 +331,7 @@ static ftdm_status_t unblock_all_ckts_for_relay(uint32_t procId) } #endif + /******************************************************************************/ /* For Emacs: * Local Variables: From b7199839338d812a3c5c9335885932bdcc57daac Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Wed, 28 Sep 2011 11:56:19 -0400 Subject: [PATCH 042/822] mod_sofia: Resolved issue #1547 - SIP INFO not working The dtmf_type member was incorrectly being set to NONE if the SDP does not advertise RFC2833 support (which has nothing to do with SIP INFO) --- src/mod/endpoints/mod_sofia/mod_sofia.c | 5 +++++ src/mod/endpoints/mod_sofia/sofia_glue.c | 10 ++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index d77f298588..0fc8c3acfb 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1359,10 +1359,12 @@ static switch_status_t sofia_send_dtmf(switch_core_session_t *session, const swi switch (dtmf_type) { case DTMF_2833: { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Enqueuing RFC2833 DTMF %c of length %d\n", dtmf->digit, dtmf->duration); return switch_rtp_queue_rfc2833(tech_pvt->rtp_session, dtmf); } case DTMF_INFO: { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Sending INFO DTMF %c of length %d\n", dtmf->digit, dtmf->duration); snprintf(message, sizeof(message), "Signal=%c\r\nDuration=%d\r\n", dtmf->digit, dtmf->duration / 8); switch_mutex_lock(tech_pvt->sofia_mutex); nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("application/dtmf-relay"), SIPTAG_PAYLOAD_STR(message), TAG_END()); @@ -1370,6 +1372,9 @@ static switch_status_t sofia_send_dtmf(switch_core_session_t *session, const swi } break; case DTMF_NONE: + { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Discarding DTMF %c of length %d, DTMF type is NONE\n", dtmf->digit, dtmf->duration); + } break; default: switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Unhandled DTMF type!\n"); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 062da61a98..ae10ccc0aa 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -4847,10 +4847,12 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s } } } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Disable 2833 dtmf\n"); - switch_channel_set_variable(tech_pvt->channel, "dtmf_type", "none"); - tech_pvt->dtmf_type = DTMF_NONE; - te = tech_pvt->recv_te = 0; + if (tech_pvt->dtmf_type == DTMF_2833) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Disable 2833 dtmf\n"); + switch_channel_set_variable(tech_pvt->channel, "dtmf_type", "none"); + tech_pvt->dtmf_type = DTMF_NONE; + te = tech_pvt->recv_te = 0; + } } From 4ec5c66c0ccaaf27b6ac90cc3e4086cae06a0c4c Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Wed, 28 Sep 2011 12:33:03 -0400 Subject: [PATCH 043/822] fixed problems with previous master merge in fs_cli.c --- libs/esl/fs_cli.c | 95 +---------------------------------------------- 1 file changed, 1 insertion(+), 94 deletions(-) diff --git a/libs/esl/fs_cli.c b/libs/esl/fs_cli.c index 6ef6d8953d..0f432f464f 100644 --- a/libs/esl/fs_cli.c +++ b/libs/esl/fs_cli.c @@ -867,8 +867,6 @@ static const char *basic_gets(int *cnt) } #endif -<<<<<<< HEAD - static void print_banner(FILE *stream) { fprintf(stream, @@ -884,27 +882,6 @@ static void print_banner(FILE *stream) ); } -======= -static const char *banner = - " _____ ____ ____ _ ___ \n" - " | ___/ ___| / ___| | |_ _| \n" - " | |_ \\___ \\ | | | | | | \n" - " | _| ___) | | |___| |___ | | \n" - " |_| |____/ \\____|_____|___| \n" - "\n" - "*******************************************************\n" - "* Anthony Minessale II, Ken Rice, *\n" - "* Michael Jerris, Travis Cross *\n" - "* FreeSWITCH (http://www.freeswitch.org) *\n" - "* Paypal Donations Appreciated: paypal@freeswitch.org *\n" - "* Brought to you by ClueCon http://www.cluecon.com/ *\n" - "*******************************************************\n" - "\n" - "Type /help to see a list of commands\n\n\n"; - -static void print_banner(FILE *stream) { fprintf(stream, "%s%s", output_text_color, banner); } ->>>>>>> master - static void set_fn_keys(cli_profile_t *profile) { profile->console_fnkeys[0] = "help"; @@ -1126,15 +1103,9 @@ int main(int argc, char *argv[]) char cmd_str[1024] = ""; cli_profile_t *profile = NULL; #ifndef WIN32 -<<<<<<< HEAD char hfile[512] = "/etc/nbess7_cli_history"; char cfile[512] = "/etc/nbess7_cli.conf"; char dft_cfile[512] = "/etc/nbess7_cli.conf"; -======= - char hfile[512] = "/tmp/fs_cli_history"; - char cfile[512] = "/etc/fs_cli.conf"; - char dft_cfile[512] = "/etc/fs_cli.conf"; ->>>>>>> master #else char hfile[512] = "nbess7_cli_history"; char cfile[512] = "nbess7_cli.conf"; @@ -1265,66 +1236,7 @@ int main(int argc, char *argv[]) printf("\n"); return usage(argv[0]); } -<<<<<<< HEAD - - if (!(rv = esl_config_open_file(&cfg, cfile))) { - rv = esl_config_open_file(&cfg, dft_cfile); - } - - if (rv) { - char *var, *val; - char cur_cat[128] = ""; - - while (esl_config_next_pair(&cfg, &var, &val)) { - if (strcmp(cur_cat, cfg.category)) { - esl_set_string(cur_cat, cfg.category); - esl_set_string(profiles[pcount].name, cur_cat); - esl_set_string(profiles[pcount].host, "localhost"); - esl_set_string(profiles[pcount].pass, "ClueCon"); - profiles[pcount].port = 8821; - set_fn_keys(&profiles[pcount]); - esl_log(ESL_LOG_DEBUG, "Found Profile [%s]\n", profiles[pcount].name); - pcount++; - } - - if (!strcasecmp(var, "host")) { - esl_set_string(profiles[pcount-1].host, val); - } else if (!strcasecmp(var, "user")) { - esl_set_string(profiles[pcount-1].user, val); - } else if (!strcasecmp(var, "password")) { - esl_set_string(profiles[pcount-1].pass, val); - } else if (!strcasecmp(var, "port")) { - int pt = atoi(val); - if (pt > 0) { - profiles[pcount-1].port = (esl_port_t)pt; - } - } else if (!strcasecmp(var, "debug")) { - int dt = atoi(val); - if (dt > -1 && dt < 8){ - profiles[pcount-1].debug = dt; - } - } else if(!strcasecmp(var, "loglevel")) { - esl_set_string(profiles[pcount-1].loglevel, val); - } else if(!strcasecmp(var, "quiet")) { - profiles[pcount-1].quiet = esl_true(val); - } else if (!strncasecmp(var, "key_F", 5)) { - char *key = var + 5; - - if (key) { - int i = atoi(key); - - if (i > 0 && i < 13) { - profiles[pcount-1].console_fnkeys[i - 1] = strdup(val); - } - } - } - } - esl_config_close_file(&cfg); - } - -======= read_config(dft_cfile, cfile); ->>>>>>> master if (optind < argc) { get_profile(argv[optind], &profile); } @@ -1485,15 +1397,10 @@ int main(int argc, char *argv[]) esl_send_recv(&handle, cmd_str); } print_banner(stdout); -<<<<<<< HEAD esl_log(ESL_LOG_INFO, "Netborder SS7 CLI Ready.\nenter /help for a list of commands.\n"); - printf("%s\n", handle.last_sr_reply); - -======= - esl_log(ESL_LOG_INFO, "FS CLI Ready.\nenter /help for a list of commands.\n"); output_printf("%s\n", handle.last_sr_reply); ->>>>>>> master + while (running > 0) { int r; #ifdef HAVE_EDITLINE From 1ba6d277fa03694d1b626bb325ff894a7ed7d5ad Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Wed, 28 Sep 2011 13:23:30 -0400 Subject: [PATCH 044/822] freetdm: Fix SS7 T35 timer --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c | 7 ++++--- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c index ff66cc6b41..10afc65bc9 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c @@ -56,21 +56,22 @@ void handle_isup_t35(void *userdata) ftdm_channel_t *ftdmchan = sngss7_info->ftdmchan; /* now that we have the right channel...put a lock on it so no-one else can use it */ - ftdm_mutex_lock(ftdmchan->mutex); + ftdm_channel_lock(ftdmchan); + /* Q.764 2.2.5 Address incomplete (T35 expiry action is hangup with cause 28 according to Table A.1/Q.764) */ SS7_ERROR("[Call-Control] Timer 35 expired on CIC = %d\n", sngss7_info->circuit->cic); /* set the flag to indicate this hangup is started from the local side */ sngss7_set_ckt_flag(sngss7_info, FLAG_LOCAL_REL); /* hang up on timer expiry */ - ftdmchan->caller_data.hangup_cause = 28; + ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_INVALID_NUMBER_FORMAT; /* end the call */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); /*unlock*/ - ftdm_mutex_unlock(ftdmchan->mutex); + ftdm_channel_unlock(ftdmchan); SS7_FUNC_TRACE_EXIT(__FUNCTION__); return; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 2794eb497c..d7fc553e2f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -2966,9 +2966,10 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan) g_ftdm_sngss7_data.cfg.isupCkt[x].t17 = ccSpan->t17; } if (ccSpan->t35 == 0) { - g_ftdm_sngss7_data.cfg.isupCkt[x].t17 = 170; + /* Q.764 2.2.5 Address incomplete (T35 is 15-20 seconds according to Table A.1/Q.764) */ + g_ftdm_sngss7_data.cfg.isupCkt[x].t35 = 170; } else { - g_ftdm_sngss7_data.cfg.isupCkt[x].t17 = ccSpan->t35; + g_ftdm_sngss7_data.cfg.isupCkt[x].t35 = ccSpan->t35; } if (ccSpan->tval == 0) { g_ftdm_sngss7_data.cfg.isupCkt[x].tval = 10; From 1aad77a0d332b05b11557c6620def53deb6353c5 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Wed, 28 Sep 2011 13:40:55 -0400 Subject: [PATCH 045/822] Fix issue #1545 - Wrong branding Conflicts: src/switch_console.c --- src/mod/applications/mod_commands/mod_commands.c | 2 +- src/switch_console.c | 2 +- src/switch_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 785861457e..4e114ad5d7 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -283,7 +283,7 @@ SWITCH_STANDARD_API(shutdown_function) SWITCH_STANDARD_API(version_function) { - stream->write_function(stream, "Sangoma Media Gateway Version %s\n", SWITCH_VERSION_FULL); + stream->write_function(stream, "NSG Version %s\n", SWITCH_VERSION_FULL); return SWITCH_STATUS_SUCCESS; } diff --git a/src/switch_console.c b/src/switch_console.c index 8f7238d257..876e9386a4 100644 --- a/src/switch_console.c +++ b/src/switch_console.c @@ -1004,7 +1004,7 @@ static unsigned char console_f12key(EditLine * el, int ch) char *prompt(EditLine * e) { if (*prompt_str == '\0') { - switch_snprintf(prompt_str, sizeof(prompt_str), "sangoma-media-gateway@%s> ", switch_core_get_switchname()); + switch_snprintf(prompt_str, sizeof(prompt_str), "nsg@%s> ", switch_core_get_switchname()); } return prompt_str; diff --git a/src/switch_core.c b/src/switch_core.c index 2aa40f9188..bc4974b995 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1859,7 +1859,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_init_and_modload(switch_core_flag_t switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, - "\nSangoma Media Gateway Version %s Started.\nMax Sessions[%u]\nSession Rate[%d]\nSQL [%s]\n", SWITCH_VERSION_FULL, + "\nNSG Version %s Started.\nMax Sessions[%u]\nSession Rate[%d]\nSQL [%s]\n", SWITCH_VERSION_FULL, switch_core_session_limit(0), switch_core_sessions_per_second(0), switch_test_flag((&runtime), SCF_USE_SQL) ? "Enabled" : "Disabled"); From fd55b32ad18322d88e861b20529c2a444c806f40 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Wed, 28 Sep 2011 13:40:55 -0400 Subject: [PATCH 046/822] Fix issue #1545 - Wrong branding Conflicts: src/switch_console.c --- src/mod/applications/mod_commands/mod_commands.c | 2 +- src/switch_console.c | 2 +- src/switch_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 638fd1588a..1513743018 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -283,7 +283,7 @@ SWITCH_STANDARD_API(shutdown_function) SWITCH_STANDARD_API(version_function) { - stream->write_function(stream, "Sangoma Media Gateway Version %s\n", SWITCH_VERSION_FULL); + stream->write_function(stream, "NSG Version %s\n", SWITCH_VERSION_FULL); return SWITCH_STATUS_SUCCESS; } diff --git a/src/switch_console.c b/src/switch_console.c index 8f7238d257..876e9386a4 100644 --- a/src/switch_console.c +++ b/src/switch_console.c @@ -1004,7 +1004,7 @@ static unsigned char console_f12key(EditLine * el, int ch) char *prompt(EditLine * e) { if (*prompt_str == '\0') { - switch_snprintf(prompt_str, sizeof(prompt_str), "sangoma-media-gateway@%s> ", switch_core_get_switchname()); + switch_snprintf(prompt_str, sizeof(prompt_str), "nsg@%s> ", switch_core_get_switchname()); } return prompt_str; diff --git a/src/switch_core.c b/src/switch_core.c index 2d256177c7..8bdf3e59b5 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1894,7 +1894,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_init_and_modload(switch_core_flag_t switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, - "\nSangoma Media Gateway Version %s Started.\nMax Sessions[%u]\nSession Rate[%d]\nSQL [%s]\n", SWITCH_VERSION_FULL, + "\nNSG Version %s Started.\nMax Sessions[%u]\nSession Rate[%d]\nSQL [%s]\n", SWITCH_VERSION_FULL, switch_core_session_limit(0), switch_core_sessions_per_second(0), switch_test_flag((&runtime), SCF_USE_SQL) ? "Enabled" : "Disabled"); From b8284420523f88820ca0eedc2463ed1903c88bc6 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Wed, 28 Sep 2011 19:15:35 -0400 Subject: [PATCH 047/822] freetdm: Fix SS7 ISUP T10 (Overlap digit timeout) - issue #1445 --- .../ftmod_sangoma_ss7_handle.c | 2 ++ .../ftmod_sangoma_ss7_main.c | 35 ++++++++++++++++--- .../ftmod_sangoma_ss7_main.h | 4 ++- .../ftmod_sangoma_ss7_timers.c | 35 ++++++++++++++++++- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 30 +++++++++------- 5 files changed, 87 insertions(+), 19 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 26356220ec..213c4c8d4d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -405,6 +405,8 @@ ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circ append_tknStr_from_sngss7(siCnStEvnt->subNum.addrSig, ftdmchan->caller_data.dnis.digits, siCnStEvnt->subNum.oddEven); + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Rx SAM (digits = %s)\n", sngss7_info->circuit->cic, + ftdmchan->caller_data.dnis.digits); } else { SS7_INFO_CHAN(ftdmchan,"No Called party (DNIS) information in SAM!%s\n", " "); } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 9f2cbbac25..5341983e46 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -592,6 +592,11 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) i++; } + /* kill t10 if active */ + if (sngss7_info->t10.hb_timer_id) { + ftdm_sched_cancel_timer (sngss7_info->t10.sched, sngss7_info->t10.hb_timer_id); + } + /* check if the end of pulsing (ST) character has arrived or the right number of digits */ if (ftdmchan->caller_data.dnis.digits[i-1] == 'F') { SS7_DEBUG_CHAN(ftdmchan, "Received the end of pulsing character %s\n", ""); @@ -613,7 +618,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) } else { /* if we are coming from idle state then we have already been here once before */ if (ftdmchan->last_state != FTDM_CHANNEL_STATE_IDLE) { - SS7_INFO_CHAN(ftdmchan,"Received %d out of %d so far: %s...starting T35\n", + SS7_INFO_CHAN(ftdmchan, "Received %d out of %d so far: %s...starting T35\n", i, sngss7_info->circuit->min_digits, ftdmchan->caller_data.dnis.digits); @@ -628,7 +633,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) SS7_ERROR ("Unable to schedule timer, hanging up call!\n"); - ftdmchan->caller_data.hangup_cause = 41; + ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_TEMPORARY_FAILURE; /* set the flag to indicate this hangup is started from the local side */ sngss7_set_ckt_flag (sngss7_info, FLAG_LOCAL_REL); @@ -636,9 +641,29 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* end the call */ state_flag = 0; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); - } /* if (ftdm_sched_timer(sngss7_info->t35.sched, */ - } /* if (ftdmchan->last_state != FTDM_CHANNEL_STATE_IDLE) */ - } /* checking ST/#digits */ + } + } + + /* start ISUP t10 */ + if (ftdm_sched_timer (sngss7_info->t10.sched, + "t10", + sngss7_info->t10.beat, + sngss7_info->t10.callback, + &sngss7_info->t10, + &sngss7_info->t10.hb_timer_id)) { + + SS7_ERROR ("Unable to schedule timer, hanging up call!\n"); + + ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_TEMPORARY_FAILURE; + + /* set the flag to indicate this hangup is started from the local side */ + sngss7_set_ckt_flag (sngss7_info, FLAG_LOCAL_REL); + + /* end the call */ + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); + } + } break; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 7a116ecbb4..d58d2a5331 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -288,7 +288,6 @@ typedef struct sng_isup_intf { uint32_t ssf; uint32_t isap; uint16_t t4; - uint32_t t10; uint32_t t11; uint32_t t18; uint32_t t19; @@ -344,6 +343,7 @@ typedef struct sng_isup_ckt { uint8_t transparent_iam; void *obj; uint16_t t3; + uint32_t t10; uint16_t t12; uint16_t t13; uint16_t t14; @@ -471,6 +471,7 @@ typedef struct sngss7_chan_data { void *raw_data; /* send on next sigevent */ sngss7_glare_data_t glare; sngss7_timer_data_t t35; + sngss7_timer_data_t t10; sngss7_group_data_t rx_grs; sngss7_group_data_t rx_gra; sngss7_group_data_t tx_grs; @@ -887,6 +888,7 @@ ftdm_status_t sngss7_add_raw_data(sngss7_chan_data_t *sngss7_info, uint8_t* data /* in ftmod_sangoma_ss7_timers.c */ void handle_isup_t35(void *userdata); +void handle_isup_t10(void *userdata); /******************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c index 10afc65bc9..6138ea34b0 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2009, Konrad Hammel + * Copyright (c) 2009, Sangoma Technologies + * Konrad Hammel * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,6 +30,11 @@ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contributors: + * + * Moises Silva + * */ /* INCLUDE ********************************************************************/ @@ -70,12 +76,39 @@ void handle_isup_t35(void *userdata) /* end the call */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); + /* kill t10 if active */ + if (sngss7_info->t10.hb_timer_id) { + ftdm_sched_cancel_timer (sngss7_info->t10.sched, sngss7_info->t10.hb_timer_id); + } + /*unlock*/ ftdm_channel_unlock(ftdmchan); SS7_FUNC_TRACE_EXIT(__FUNCTION__); return; } + + +void handle_isup_t10(void *userdata) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_timer_data_t *timer = userdata; + sngss7_chan_data_t *sngss7_info = timer->sngss7_info; + ftdm_channel_t *ftdmchan = sngss7_info->ftdmchan; + + ftdm_channel_lock(ftdmchan); + + SS7_DEBUG("[Call-Control] Timer 10 expired on CIC = %d\n", sngss7_info->circuit->cic); + + /* send the call to the user */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); + + ftdm_channel_unlock(ftdmchan); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); +} + /******************************************************************************/ /* For Emacs: * Local Variables: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index d7fc553e2f..acb29ba385 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -127,6 +127,7 @@ typedef struct sng_ccSpan uint8_t itx_auto_reply; uint8_t transparent_iam; uint32_t t3; + uint32_t t10; uint32_t t12; uint32_t t13; uint32_t t14; @@ -1570,11 +1571,6 @@ static int ftmod_ss7_parse_isup_interface(ftdm_conf_node_t *isup_interface) sng_isap.t9 = atoi(parm->val); SS7_DEBUG("Found isup t9 = %d\n",sng_isap.t9); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "isup.t10")) { - /**********************************************************************/ - sng_isup.t10 = atoi(parm->val); - SS7_DEBUG("Found isup t10 = %d\n",sng_isup.t10); - /**********************************************************************/ } else if (!strcasecmp(parm->var, "isup.t11")) { /**********************************************************************/ sng_isup.t11 = atoi(parm->val); @@ -1965,6 +1961,10 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) /**********************************************************************/ sng_ccSpan.t3 = atoi(parm->val); SS7_DEBUG("Found isup t3 = %d\n", sng_ccSpan.t3); + } else if (!strcasecmp(parm->var, "isup.t10")) { + /**********************************************************************/ + sng_ccSpan.t10 = atoi(parm->val); + SS7_DEBUG("Found isup t10 = %d\n", sng_ccSpan.t10); /**********************************************************************/ } else if (!strcasecmp(parm->var, "isup.t12")) { /**********************************************************************/ @@ -2584,11 +2584,6 @@ static int ftmod_ss7_fill_in_isup_interface(sng_isup_inf_t *sng_isup) } else { g_ftdm_sngss7_data.cfg.isupIntf[i].t4 = 3000; } - if (sng_isup->t10 != 0) { - g_ftdm_sngss7_data.cfg.isupIntf[i].t10 = sng_isup->t10; - } else { - g_ftdm_sngss7_data.cfg.isupIntf[i].t10 = 50; - } if (sng_isup->t11 != 0) { g_ftdm_sngss7_data.cfg.isupIntf[i].t11 = sng_isup->t11; } else { @@ -2935,6 +2930,11 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan) } else { g_ftdm_sngss7_data.cfg.isupCkt[x].t3 = ccSpan->t3; } + if (ccSpan->t10 == 0) { + g_ftdm_sngss7_data.cfg.isupCkt[x].t10 = 50; + } else { + g_ftdm_sngss7_data.cfg.isupCkt[x].t10 = ccSpan->t10; + } if (ccSpan->t12 == 0) { g_ftdm_sngss7_data.cfg.isupCkt[x].t12 = 300; } else { @@ -3063,12 +3063,18 @@ static int ftmod_ss7_fill_in_circuits(sng_span_t *sngSpan) ftdmchan->call_data = ss7_info; /* prepare the timer structures */ - ss7_info->t35.sched = ((sngss7_span_data_t *)(ftdmspan->signal_data))->sched; + ss7_info->t35.sched = ((sngss7_span_data_t *)(ftdmspan->signal_data))->sched; ss7_info->t35.counter = 1; - ss7_info->t35.beat = (isupCkt->t35) * 100; /* beat is in ms, t35 is in 100ms */ + ss7_info->t35.beat = (isupCkt->t35) * 100; /* beat is in ms, t35 is in 100ms */ ss7_info->t35.callback = handle_isup_t35; ss7_info->t35.sngss7_info = ss7_info; + ss7_info->t10.sched = ((sngss7_span_data_t *)(ftdmspan->signal_data))->sched; + ss7_info->t10.counter = 1; + ss7_info->t10.beat = (isupCkt->t10) * 100; /* beat is in ms, t10 is in 100ms */ + ss7_info->t10.callback = handle_isup_t10; + ss7_info->t10.sngss7_info = ss7_info; + /**************************************************************************/ } /* for (i == 1; i < ftdmspan->chan_count; i++) */ From f43eecbab3cd171bd81b41e403d304c6ae65a76e Mon Sep 17 00:00:00 2001 From: James Zhang Date: Fri, 30 Sep 2011 10:25:21 -0400 Subject: [PATCH 048/822] ftdm_ss7: Adding OPC and Call Reference Number to SIP x-headers --- libs/freetdm/mod_freetdm/mod_freetdm.c | 15 +++++++++++++++ .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index caee4dcec9..8501bb1ce2 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1760,6 +1760,21 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-Screen", "%d", channel_caller_data->screen); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-Presentation", "%d", channel_caller_data->pres); + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_opc"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OPC", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_lac"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-LAC", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_crn"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-CRN", "%s", var_value); + } } /* Add any call variable to the dial plan */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 213c4c8d4d..41e0129919 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -219,6 +219,14 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sprintf(var, "%d", sngss7_info->circuit->cic); sngss7_add_var(sngss7_info, "ss7_cic", var); + sprintf(var, "%d", g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].spc ); + sngss7_add_var(sngss7_info, "ss7_opc", var); + + if (siConEvnt->callRef.callId.pres) { + sprintf(var, "%u", (unsigned int)siConEvnt->callRef.callId.val); + sngss7_add_var(sngss7_info, "ss7_crn", var); + } + if (sngss7_info->circuit->transparent_iam) { sngss7_save_iam(ftdmchan, siConEvnt); } From dbd6bb9a83d9858ec09a6075de2c68ec1b07859e Mon Sep 17 00:00:00 2001 From: James Zhang Date: Fri, 30 Sep 2011 11:52:33 -0400 Subject: [PATCH 049/822] fixing bug 1625 - relay status not reported properly in the cli --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 9ff19bac02..00a563962c 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -1304,7 +1304,9 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, stream->write_function(stream, "r_hw=N|"); } - if (sngss7_test_ckt_blk_flag(ss7_info, FLAG_RELAY_DOWN)) { + + if (g_ftdm_sngss7_data.cfg.procId != 1) { + /* if (sngss7_test_ckt_blk_flag(ss7_info, FLAG_RELAY_DOWN)) { */ stream->write_function(stream, "relay=Y|"); }else { stream->write_function(stream, "relay=N"); From 595454126b3aa04643e52c661d2948b3caa5e15e Mon Sep 17 00:00:00 2001 From: root Date: Fri, 30 Sep 2011 13:09:13 -0400 Subject: [PATCH 050/822] freetdm: changing call reference to generic header; removing location area code --- libs/freetdm/mod_freetdm/mod_freetdm.c | 13 ++----------- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c | 5 +++-- libs/freetdm/src/include/freetdm.h | 1 + 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 8501bb1ce2..5a28076fb1 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1760,21 +1760,12 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-Screen", "%d", channel_caller_data->screen); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-Presentation", "%d", channel_caller_data->pres); - + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-CallReference", "%d", channel_caller_data->call_reference); + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_opc"); if (!ftdm_strlen_zero(var_value)) { switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OPC", "%s", var_value); } - - var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_lac"); - if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-LAC", "%s", var_value); - } - - var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_crn"); - if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-CRN", "%s", var_value); - } } /* Add any call variable to the dial plan */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 41e0129919..75c5357a8c 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -223,8 +223,9 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_add_var(sngss7_info, "ss7_opc", var); if (siConEvnt->callRef.callId.pres) { - sprintf(var, "%u", (unsigned int)siConEvnt->callRef.callId.val); - sngss7_add_var(sngss7_info, "ss7_crn", var); + ftdmchan->caller_data.call_reference = (unsigned int)siConEvnt->callRef.callId.val; + } else { + ftdmchan->caller_data.call_reference = 0; } if (sngss7_info->circuit->transparent_iam) { diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 0948f16e29..c9c1b2e687 100755 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -362,6 +362,7 @@ typedef struct ftdm_caller_data { /* user information layer 1 protocol */ ftdm_user_layer1_prot_t bearer_layer1; ftdm_calling_party_category_t cpc; /*!< Calling party category */ + uint32_t call_reference; ftdm_channel_t *fchan; /*!< FreeTDM channel associated (can be NULL) */ From ccc81f320713e8b2e4248735f1eaf7e4340787c9 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Fri, 30 Sep 2011 16:03:08 -0400 Subject: [PATCH 051/822] ftdm: change max_path length from 255 to 4096 --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index d58d2a5331..caef19af12 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -51,7 +51,7 @@ /* DEFINES ********************************************************************/ #define MAX_NAME_LEN 25 -#define MAX_PATH 255 +#define MAX_PATH 4096 #define MAX_CIC_LENGTH 5 #define MAX_CIC_MAP_LENGTH 1000 From b89a072a4691988da077720d0cfb3f11c0a4ae01 Mon Sep 17 00:00:00 2001 From: wadam Date: Wed, 13 Jul 2011 10:57:09 -0400 Subject: [PATCH 052/822] Fix pid file name - Still hardcoded but to nsg. --- src/switch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/switch.c b/src/switch.c index c0f4b5c2d3..038dd2c759 100644 --- a/src/switch.c +++ b/src/switch.c @@ -48,7 +48,7 @@ #include "private/switch_core_pvt.h" /* pid filename: Stores the process id of the freeswitch process */ -#define PIDFILE "netborder-ss7.pid" +#define PIDFILE "nsg.pid" static char *pfile = PIDFILE; static int system_ready = 0; From c82f1ecabdcc3428a8bbd74d27e62e2ce7842709 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 6 Oct 2011 12:45:00 -0400 Subject: [PATCH 053/822] freetdm: Added SS7 variables for location number (pending SIP-X header integration) --- .../ftmod_sangoma_ss7_handle.c | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 75c5357a8c..dab2035450 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -93,7 +93,7 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; - char var[10]; + char var[FTDM_DIGITS_LIMIT]; memset(var, '\0', sizeof(var)); @@ -216,6 +216,34 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sprintf(var, "%d", siConEvnt->cdPtyNum.natAddrInd.val); sngss7_add_var(sngss7_info, "ss7_cld_nadi", var); + /* Retrieve the Location Number if present (see ITU Q.763, 3.30) */ + if (siConEvnt->cgPtyNum1.eh.pres) { + if (siConEvnt->cgPtyNum1.addrSig.pres) { + /* fill in the ss7 location address number */ + copy_tknStr_from_sngss7(siConEvnt->cgPtyNum1.addrSig, var, siConEvnt->cgPtyNum1.oddEven); + sngss7_add_var(sngss7_info, "ss7_loc_digits", var); + } + + if (siConEvnt->cgPtyNum1.scrnInd.pres) { + /* fill in the screening indication value */ + sprintf(var, "%d", siConEvnt->cgPtyNum1.scrnInd.val); + sngss7_add_var(sngss7_info, "ss7_loc_screen_ind", var); + } + + if (siConEvnt->cgPtyNum1.presRest.pres) { + /* fill in the presentation value */ + sprintf(var, "%d", siConEvnt->cgPtyNum1.presRest.val); + sngss7_add_var(sngss7_info, "ss7_loc_pres_ind", var); + } + + if (siConEvnt->cgPtyNum1.natAddrInd.pres) { + sprintf(var, "%d", siConEvnt->cgPtyNum1.natAddrInd.val); + sngss7_add_var(sngss7_info, "ss7_loc_nadi", var); + } + } else { + SS7_DEBUG_CHAN(ftdmchan, "No Location Number information in IAM%s\n", " "); + } + sprintf(var, "%d", sngss7_info->circuit->cic); sngss7_add_var(sngss7_info, "ss7_cic", var); From f1257ab8b510295a30ff2083cc6d4a11bef2a794 Mon Sep 17 00:00:00 2001 From: yannick Date: Thu, 6 Oct 2011 17:36:50 -0400 Subject: [PATCH 054/822] ftdm: fixing reset on in-use channel causing infinite state loop. --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 8 +++++-- .../ftmod_sangoma_ss7_main.c | 24 ++++++++++++++----- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 00a563962c..9eb737a7f3 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -29,6 +29,10 @@ * LIABILITY|WHETHER IN CONTRACT|STRICT LIABILITY|OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE|EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contributors: + * James Zhang + * */ #if 0 @@ -1198,7 +1202,7 @@ static ftdm_status_t handle_show_blocks(ftdm_stream_handle_t *stream, int span, } #ifdef SMG_RELAY_DBG - stream->write_function(stream, " blk_flag= %x ckt_flag = %d", ss7_info->blk_flags, ss7_info->ckt_flags ); + stream->write_function(stream," blk_flag=%x | ckt_flag=%x | chan_flag=%x", ss7_info->blk_flags, ss7_info->ckt_flags, ftdmchan->flags); #endif stream->write_function(stream, "\n"); } /* if ( span and chan) */ @@ -1314,7 +1318,7 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, } #ifdef SMG_RELAY_DBG - stream->write_function(stream," blk_flag= %x ckt_flag = %d", ss7_info->blk_flags, ss7_info->ckt_flags ); + stream->write_function(stream," blk_flag=%x | ckt_flag=%x | chan_flag=%x", ss7_info->blk_flags, ss7_info->ckt_flags, ftdmchan->flags); #endif stream->write_function(stream, "\n"); } /* if ( hole, sig, voice) */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 5341983e46..44870a69a9 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -842,9 +842,18 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) if (sngss7_test_ckt_flag (sngss7_info, FLAG_REMOTE_REL)) { /* check if this hangup is from a tx RSC */ if (sngss7_test_ckt_flag (sngss7_info, FLAG_RESET_TX)) { - /* go to RESTART State until RSCa is received */ - state_flag = 0; - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + if (!sngss7_test_ckt_flag(sngss7_info, FLAG_RESET_SENT)) { + ft_to_sngss7_rsc (ftdmchan); + sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_SENT); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + } else if (sngss7_test_ckt_flag(sngss7_info, FLAG_RESET_TX_RSP)) { + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + } else { + /* go to RESTART State until RSCa is received */ + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + } } else { /* if the hangup is from a rx RSC, rx GRS, or glare don't sent RLC */ if (!(sngss7_test_ckt_flag(sngss7_info, FLAG_RESET_RX)) && @@ -1040,9 +1049,12 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) if ((sngss7_test_ckt_flag(sngss7_info, FLAG_RESET_TX)) && !(sngss7_test_ckt_flag(sngss7_info, FLAG_RESET_SENT))) { - /* send a reset request */ - ft_to_sngss7_rsc (ftdmchan); - sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_SENT); + /* don't send out reset before finished hanging up if I'm in-use. */ + if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) { + /* send a reset request */ + ft_to_sngss7_rsc (ftdmchan); + sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_SENT); + } } /* if (sngss7_test_ckt_flag(sngss7_info, FLAG_RESET_TX)) */ From 4ece7e6ffde58e140ce3b562f54d170a243ef6ca Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 6 Oct 2011 17:54:46 -0400 Subject: [PATCH 055/822] freetdm: ftmod_wanpipe - remove debug idle messages for good, not worth the noise --- libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index 0f6f7db939..a2eed92b4e 100644 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -857,12 +857,6 @@ static void wanpipe_write_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_tx_hdr_t *t } if (ftdmchan->iostats.tx.idle_packets < tx_stats->wp_api_tx_hdr_tx_idle_packets) { - /* HDLC channels do not always transmit, so its ok for drivers to fill with idle - * also do not report idle warning when we just started transmitting */ - if (ftdmchan->iostats.tx.packets && FTDM_IS_VOICE_CHANNEL(ftdmchan)) { - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Tx idle changed from %d to %d\n", - ftdmchan->iostats.tx.idle_packets, tx_stats->wp_api_tx_hdr_tx_idle_packets); - } ftdmchan->iostats.tx.idle_packets = tx_stats->wp_api_tx_hdr_tx_idle_packets; } From 8ccd5f0e1304cd8dadd4bb0663b4cb8848e96b99 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 6 Oct 2011 18:53:38 -0400 Subject: [PATCH 056/822] freetdm: ss7 - fixing reset on in-use channel causing signaling down in the receiving side --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 44870a69a9..049aa1546d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -944,7 +944,9 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* check if we came from reset (aka we just processed a reset) */ if ((ftdmchan->last_state == FTDM_CHANNEL_STATE_RESTART) || - (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED)) { + (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) || + (ftdmchan->last_state == FTDM_CHANNEL_STATE_HANGUP_COMPLETE)) { + /* check if reset flags are up indicating there is more processing to do yet */ if (!(sngss7_test_ckt_flag (sngss7_info, FLAG_RESET_TX)) && From 4aa0285a226d10b83ec310fd5e0dadb3aad6109e Mon Sep 17 00:00:00 2001 From: James Zhang Date: Wed, 12 Oct 2011 17:44:52 -0400 Subject: [PATCH 057/822] freetdm: CDR - location number implementation (for incoming and outgoing calls) --- libs/freetdm/mod_freetdm/mod_freetdm.c | 26 +++++++++ .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c | 13 ++++- .../ftmod_sangoma_ss7_handle.c | 3 - .../ftmod_sangoma_ss7_main.h | 3 + .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 9 ++- .../ftmod_sangoma_ss7_support.c | 56 +++++++++++++++++++ .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 26 +++++++-- libs/freetdm/src/include/freetdm.h | 1 + 8 files changed, 125 insertions(+), 12 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 5a28076fb1..f7b64a02a3 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1337,6 +1337,11 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi ftdm_set_string(caller_data.dnis.digits, sipvar); } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-LOC"); + if (sipvar) { + ftdm_set_string(caller_data.loc.digits, sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-DNIS-TON"); if (sipvar) { caller_data.dnis.type = (uint8_t)atoi(sipvar); @@ -1703,6 +1708,7 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-Plan", "%d", channel_caller_data->rdnis.plan); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-CPC", "%s", ftdm_calling_party_category2str(channel_caller_data->cpc)); + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdnis_screen_ind"); if (!ftdm_strlen_zero(var_value)) { switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-Screen", "%d", var_value); @@ -1766,6 +1772,26 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session if (!ftdm_strlen_zero(var_value)) { switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OPC", "%s", var_value); } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_loc_digits"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-LOC", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_loc_screen_ind"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-LOC-Screen", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_loc_pres_ind"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-LOC-Presentation", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_loc_pres_nadi"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-LOC-NADI", "%s", var_value); + } } /* Add any call variable to the dial plan */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c index dd1058f420..a9b4136665 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c @@ -78,6 +78,8 @@ int ft_to_sngss7_cfg_all(void) /* check if we have done gen_config already */ if (!(g_ftdm_sngss7_data.gen_config)) { + /* update the global gen_config so we don't do it again */ + g_ftdm_sngss7_data.gen_config = 1; /* start of by checking if the license and sig file are valid */ if (sng_validate_license(g_ftdm_sngss7_data.cfg.license, @@ -207,10 +209,17 @@ int ft_to_sngss7_cfg_all(void) } } /* if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP2)) */ - /* update the global gen_config so we don't do it again */ - g_ftdm_sngss7_data.gen_config = 1; + g_ftdm_sngss7_data.gen_config = 2; + } /* if (!(g_ftdm_sngss7_data.gen_config)) */ + + /* FIXME: Please change number 2 to an ENUM that is more explanatory */ + if (g_ftdm_sngss7_data.gen_config != 2) { + SS7_CRITICAL("General configuration FAILED!\n"); + return 1; + } + /* go through all the relays channels and configure it */ x = 1; while (x < (MAX_RELAY_CHANNELS)) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index dab2035450..59a226d738 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -213,9 +213,6 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sprintf(var, "%d", siConEvnt->cgPtyNum.natAddrInd.val); sngss7_add_var(sngss7_info, "ss7_clg_nadi", var); - sprintf(var, "%d", siConEvnt->cdPtyNum.natAddrInd.val); - sngss7_add_var(sngss7_info, "ss7_cld_nadi", var); - /* Retrieve the Location Number if present (see ITU Q.763, 3.30) */ if (siConEvnt->cgPtyNum1.eh.pres) { if (siConEvnt->cgPtyNum1.addrSig.pres) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index caef19af12..9bf24aada3 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -328,6 +328,7 @@ typedef struct sng_isup_ckt { uint32_t clg_nadi; uint32_t cld_nadi; uint8_t rdnis_nadi; + uint32_t loc_nadi; /* Generic Number defaults */ uint8_t gn_nmbqual; /* Number Qualifier */ @@ -835,6 +836,8 @@ ftdm_status_t copy_cdPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cd ftdm_status_t copy_cdPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cdPtyNum); ftdm_status_t copy_redirgNum_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *redirgNum); ftdm_status_t copy_redirgNum_from_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *redirgNum); +ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum); +ftdm_status_t copy_locPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum); ftdm_status_t copy_genNmb_to_sngss7(ftdm_channel_t *ftdmchan, SiGenNum *genNmb); ftdm_status_t copy_genNmb_from_sngss7(ftdm_channel_t *ftdmchan, SiGenNum *genNmb); ftdm_status_t copy_cgPtyCat_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyCat *cgPtyCat); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index b729552092..5aed5f49a4 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -79,6 +79,9 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* Calling Number information */ copy_cgPtyNum_to_sngss7(ftdmchan, &iam.cgPtyNum); + /* Location Number information */ + copy_locPtyNum_to_sngss7(ftdmchan, &iam.cgPtyNum1); + /* Generic Number information */ copy_genNmb_to_sngss7(ftdmchan, &iam.genNmb); @@ -91,12 +94,14 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* Access Transport */ copy_accTrnspt_to_sngss7(ftdmchan, &iam.accTrnspt); - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM clg = \"%s\" (NADI=%d), cld = \"%s\" (NADI=%d)\n", + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM clg = \"%s\" (NADI=%d), cld = \"%s\" (NADI=%d), loc = %s (NADI=%d)\n", sngss7_info->circuit->cic, ftdmchan->caller_data.cid_num.digits, iam.cgPtyNum.natAddrInd.val, ftdmchan->caller_data.dnis.digits, - iam.cdPtyNum.natAddrInd.val); + iam.cdPtyNum.natAddrInd.val, + ftdmchan->caller_data.loc.digits, + iam.cgPtyNum1.natAddrInd.val); } sng_cc_con_request (sngss7_info->spId, diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 613ad6d95e..167de57bb8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -225,6 +225,62 @@ ftdm_status_t copy_cdPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cdPt return copy_tknStr_to_sngss7(caller_data->dnis.digits, &cdPtyNum->addrSig, &cdPtyNum->oddEven); } +ftdm_status_t copy_locPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum) +{ + return FTDM_SUCCESS; +} + +ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum) +{ + const char *val = NULL; + const char *loc_nadi = NULL; + + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; + + locPtyNum->eh.pres = PRSNT_NODEF; + locPtyNum->natAddrInd.pres = PRSNT_NODEF; + locPtyNum->natAddrInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].loc_nadi; + + locPtyNum->scrnInd.pres = PRSNT_NODEF; + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_loc_screen_ind"); + if (!ftdm_strlen_zero(val)) { + locPtyNum->scrnInd.val = atoi(val); + } else { + locPtyNum->scrnInd.val = caller_data->screen; + } + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Location Reference Code Screening Ind %d\n", locPtyNum->scrnInd.val); + + locPtyNum->presRest.pres = PRSNT_NODEF; + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_pres_ind"); + if (!ftdm_strlen_zero(val)) { + locPtyNum->presRest.val = atoi(val); + } else { + locPtyNum->presRest.val = caller_data->pres; + } + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Calling Party Number Presentation Ind %d\n", locPtyNum->presRest.val); + + locPtyNum->numPlan.pres = PRSNT_NODEF; + locPtyNum->numPlan.val = 0x01; + + locPtyNum->niInd.pres = PRSNT_NODEF; + locPtyNum->niInd.val = 0x00; + + /* check if the user would like a custom NADI value for the Location Reference */ + loc_nadi = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_loc_nadi"); + if (!ftdm_strlen_zero(loc_nadi)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Reference NADI value \"%s\"\n", loc_nadi); + locPtyNum->natAddrInd.val = atoi(loc_nadi); + } else { + locPtyNum->natAddrInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].loc_nadi; + locPtyNum->natAddrInd.val = 0x03; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied NADI value found for LOC, using \"%d\"\n", locPtyNum->natAddrInd.val); + } + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Location Reference Presentation Ind %d\n", locPtyNum->presRest.val); + + return copy_tknStr_to_sngss7(caller_data->loc.digits, &locPtyNum->addrSig, &locPtyNum->oddEven); +} + ftdm_status_t copy_genNmb_to_sngss7(ftdm_channel_t *ftdmchan, SiGenNum *genNmb) { const char *val = NULL; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index acb29ba385..30d215a14d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -123,6 +123,7 @@ typedef struct sng_ccSpan uint32_t clg_nadi; uint32_t cld_nadi; uint32_t rdnis_nadi; + uint32_t loc_nadi; uint32_t min_digits; uint8_t itx_auto_reply; uint8_t transparent_iam; @@ -1844,6 +1845,7 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) int flag_clg_nadi = 0; int flag_cld_nadi = 0; int flag_rdnis_nadi = 0; + int flag_loc_nadi = 0; int i; int ret; @@ -1945,6 +1947,14 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) SS7_DEBUG("Invalid parm->value for obci_bita option\n"); } /**********************************************************************/ + } else if (!strcasecmp(parm->var, "loc_nadi")) { + /* add location reference number */ + flag_loc_nadi = 1; + sng_ccSpan.loc_nadi = atoi(parm->val); + SS7_DEBUG("Found default LOC_NADI parm->value = %d\n", sng_ccSpan.loc_nadi); + printf( " --- jz: we got loc nadi from XML, val = %d \n" , sng_ccSpan.loc_nadi); + + /**********************************************************************/ } else if (!strcasecmp(parm->var, "lpa_on_cot")) { /**********************************************************************/ if (*parm->val == '1') { @@ -2034,6 +2044,11 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) sng_ccSpan.rdnis_nadi = 0x03; } + if (!flag_loc_nadi) { + /* default the nadi value to national */ + sng_ccSpan.loc_nadi = 0x03; + } + /* pull up the SSF and Switchtype from the isup interface */ sng_ccSpan.ssf = g_ftdm_sngss7_data.cfg.isupIntf[sng_ccSpan.isupInf].ssf; sng_ccSpan.switchType = g_ftdm_sngss7_data.cfg.isupIntf[sng_ccSpan.isupInf].switchType; @@ -2918,12 +2933,13 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan) g_ftdm_sngss7_data.cfg.isupCkt[x].ssf = ccSpan->ssf; g_ftdm_sngss7_data.cfg.isupCkt[x].cld_nadi = ccSpan->cld_nadi; g_ftdm_sngss7_data.cfg.isupCkt[x].clg_nadi = ccSpan->clg_nadi; - g_ftdm_sngss7_data.cfg.isupCkt[x].rdnis_nadi = ccSpan->rdnis_nadi; + g_ftdm_sngss7_data.cfg.isupCkt[x].rdnis_nadi = ccSpan->rdnis_nadi; + g_ftdm_sngss7_data.cfg.isupCkt[x].loc_nadi = ccSpan->loc_nadi; g_ftdm_sngss7_data.cfg.isupCkt[x].options = ccSpan->options; - g_ftdm_sngss7_data.cfg.isupCkt[x].switchType = ccSpan->switchType; - g_ftdm_sngss7_data.cfg.isupCkt[x].min_digits = ccSpan->min_digits; - g_ftdm_sngss7_data.cfg.isupCkt[x].itx_auto_reply = ccSpan->itx_auto_reply; - g_ftdm_sngss7_data.cfg.isupCkt[x].transparent_iam = ccSpan->transparent_iam; + g_ftdm_sngss7_data.cfg.isupCkt[x].switchType = ccSpan->switchType; + g_ftdm_sngss7_data.cfg.isupCkt[x].min_digits = ccSpan->min_digits; + g_ftdm_sngss7_data.cfg.isupCkt[x].itx_auto_reply = ccSpan->itx_auto_reply; + g_ftdm_sngss7_data.cfg.isupCkt[x].transparent_iam = ccSpan->transparent_iam; if (ccSpan->t3 == 0) { g_ftdm_sngss7_data.cfg.isupCkt[x].t3 = 1200; diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index c9c1b2e687..966e875842 100755 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -351,6 +351,7 @@ typedef struct ftdm_caller_data { ftdm_number_t ani; /*!< ANI (Automatic Number Identification) */ ftdm_number_t dnis; /*!< DNIS (Dialed Number Identification Service) */ ftdm_number_t rdnis; /*!< RDNIS (Redirected Dialed Number Identification Service) */ + ftdm_number_t loc; /*!< LOC (Location Reference Code) */ char aniII[FTDM_DIGITS_LIMIT]; /*! ANI II */ uint8_t screen; /*!< Screening */ uint8_t pres; /*!< Presentation*/ From d79f95f2d62503d122d65706e7c47f192627b47b Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 24 Oct 2011 12:43:54 -0400 Subject: [PATCH 058/822] freetdm: * Avoid acquiring the span mutex if the pendingchans queue is available for use * * FreeTDM modules using the old FTDM_SPAN_STATE_CHANGE flag should be updated * * until then, they are still vulnerable to deadlock situations * * Modules pending update: (ftmod_analog, ftmod_libpri, ftmod_isdn) * * Fixes Sangoma redmine ticket #1791 0 FTDM span stop deadlock * --- libs/freetdm/src/ftdm_state.c | 13 ++++++++++--- libs/freetdm/src/include/private/ftdm_types.h | 6 ++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/libs/freetdm/src/ftdm_state.c b/libs/freetdm/src/ftdm_state.c index 54ecde530d..d3f99f6074 100644 --- a/libs/freetdm/src/ftdm_state.c +++ b/libs/freetdm/src/ftdm_state.c @@ -370,12 +370,19 @@ end: } ftdm_set_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); - ftdm_mutex_lock(ftdmchan->span->mutex); - ftdm_set_flag(ftdmchan->span, FTDM_SPAN_STATE_CHANGE); if (ftdmchan->span->pendingchans) { ftdm_queue_enqueue(ftdmchan->span->pendingchans, ftdmchan); + } else { + /* there is a potential deadlock here, if a signaling module is processing + * state changes while the ftdm_span_stop() function is called, the signaling + * thread will block until it can acquire the span lock, but the thread calling + * ftdm_span_stop() which holds the span lock is waiting on the signaling thread + * to finish ... The only reason to acquire the span lock is this flag, new + * signaling modules should use the pendingchans queue instead of this flag, + * as of today a few modules need still to be updated before we can get rid of + * this flag (ie, ftmod_libpri, ftmod_isdn, ftmod_analog) */ + ftdm_set_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE); } - ftdm_mutex_unlock(ftdmchan->span->mutex); if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NONBLOCK)) { /* the channel should not block waiting for state processing */ diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h index 2ed9fd04c5..6df25fe4d2 100755 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -173,6 +173,12 @@ typedef enum { FTDM_SPAN_SUSPENDED = (1 << 3), FTDM_SPAN_IN_THREAD = (1 << 4), FTDM_SPAN_STOP_THREAD = (1 << 5), + /*! Signaling modules set this flag to use fchan->pendingchans queue instead + * of the FTDM_SPAN_STATE_CHANGE flag to detect when there is channels with + * a state change pending in the span. If you set this member you can't rely + * on FTDM_SPAN_STATE_CHANGE anymore and must use the queue only instead. This + * is the new way of detecting state changes, new modules should always set this + * flag, the old modules still relying on FTDM_SPAN_STATE_CHANGE should be updated */ FTDM_SPAN_USE_CHAN_QUEUE = (1 << 6), FTDM_SPAN_SUGGEST_CHAN_ID = (1 << 7), FTDM_SPAN_USE_AV_RATE = (1 << 8), From 5fdbda54796521674599eb9981668dc715f0c4e5 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 24 Oct 2011 12:43:54 -0400 Subject: [PATCH 059/822] freetdm: * Avoid acquiring the span mutex if the pendingchans queue is available for use * * FreeTDM modules using the old FTDM_SPAN_STATE_CHANGE flag should be updated * * until then, they are still vulnerable to deadlock situations * * Modules pending update: (ftmod_analog, ftmod_libpri, ftmod_isdn) * * Fixes Sangoma redmine ticket #1791 0 FTDM span stop deadlock * --- libs/freetdm/src/ftdm_state.c | 13 ++++++++++--- libs/freetdm/src/include/private/ftdm_types.h | 6 ++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/libs/freetdm/src/ftdm_state.c b/libs/freetdm/src/ftdm_state.c index 54ecde530d..d3f99f6074 100644 --- a/libs/freetdm/src/ftdm_state.c +++ b/libs/freetdm/src/ftdm_state.c @@ -370,12 +370,19 @@ end: } ftdm_set_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); - ftdm_mutex_lock(ftdmchan->span->mutex); - ftdm_set_flag(ftdmchan->span, FTDM_SPAN_STATE_CHANGE); if (ftdmchan->span->pendingchans) { ftdm_queue_enqueue(ftdmchan->span->pendingchans, ftdmchan); + } else { + /* there is a potential deadlock here, if a signaling module is processing + * state changes while the ftdm_span_stop() function is called, the signaling + * thread will block until it can acquire the span lock, but the thread calling + * ftdm_span_stop() which holds the span lock is waiting on the signaling thread + * to finish ... The only reason to acquire the span lock is this flag, new + * signaling modules should use the pendingchans queue instead of this flag, + * as of today a few modules need still to be updated before we can get rid of + * this flag (ie, ftmod_libpri, ftmod_isdn, ftmod_analog) */ + ftdm_set_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE); } - ftdm_mutex_unlock(ftdmchan->span->mutex); if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NONBLOCK)) { /* the channel should not block waiting for state processing */ diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h index 2ed9fd04c5..6df25fe4d2 100755 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -173,6 +173,12 @@ typedef enum { FTDM_SPAN_SUSPENDED = (1 << 3), FTDM_SPAN_IN_THREAD = (1 << 4), FTDM_SPAN_STOP_THREAD = (1 << 5), + /*! Signaling modules set this flag to use fchan->pendingchans queue instead + * of the FTDM_SPAN_STATE_CHANGE flag to detect when there is channels with + * a state change pending in the span. If you set this member you can't rely + * on FTDM_SPAN_STATE_CHANGE anymore and must use the queue only instead. This + * is the new way of detecting state changes, new modules should always set this + * flag, the old modules still relying on FTDM_SPAN_STATE_CHANGE should be updated */ FTDM_SPAN_USE_CHAN_QUEUE = (1 << 6), FTDM_SPAN_SUGGEST_CHAN_ID = (1 << 7), FTDM_SPAN_USE_AV_RATE = (1 << 8), From 563460ce15d333d5a9e1878ee0bf0d95458075b9 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 24 Oct 2011 13:21:15 -0400 Subject: [PATCH 060/822] freetdm: mod_freetdm - add SIP x header for FreeTDM-NADI value --- libs/freetdm/mod_freetdm/mod_freetdm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index f7b64a02a3..ae167ccef2 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1708,6 +1708,10 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-Plan", "%d", channel_caller_data->rdnis.plan); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-CPC", "%s", ftdm_calling_party_category2str(channel_caller_data->cpc)); + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_clg_nadi"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-NADI", "%d", var_value); + } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdnis_screen_ind"); if (!ftdm_strlen_zero(var_value)) { From fc997aaea4b2555b12afef00867c14c125767672 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Mon, 24 Oct 2011 19:40:45 -0400 Subject: [PATCH 061/822] freetdm: logging fixes, ss7 events sanity checks --- .../ftmod_sangoma_ss7_logger.c | 2 +- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 16 +++++++++++++--- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h | 2 +- .../ftmod_sangoma_ss7_support.c | 18 ++++++++++++------ .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 4 ++-- 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c index bddcd39eca..790b893a8d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c @@ -791,7 +791,7 @@ void handle_sng_relay_alarm(Pst *pst, RyMngmt *sta) break; /**************************************************************************/ case (LRY_USTA_UP): /* channel up */ - ftdm_log(FTDM_LOG_ERROR,"[RELAY] Channel UP: tx procId %d: channel %d\n", + ftdm_log(FTDM_LOG_INFO,"[RELAY] Channel UP: tx procId %d: channel %d\n", sta->t.usta.s.ryUpUsta.sendPid, sta->t.usta.s.ryUpUsta.id); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 049aa1546d..759fd2871f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1651,6 +1651,7 @@ static ftdm_status_t ftdm_sangoma_ss7_start(ftdm_span_t * span) static ftdm_status_t ftdm_sangoma_ss7_stop(ftdm_span_t * span) { /*this function is called by the FT-Core to stop this span */ + int timeout=0; ftdm_log (FTDM_LOG_INFO, "Stopping span %s:%u.\n", span->name,span->span_id); @@ -1659,10 +1660,17 @@ static ftdm_status_t ftdm_sangoma_ss7_stop(ftdm_span_t * span) /* wait for the thread to stop */ while (ftdm_test_flag (span, FTDM_SPAN_IN_THREAD)) { - ftdm_log (FTDM_LOG_DEBUG,"Waiting for monitor thread to end for %s:%u.\n", + ftdm_set_flag (span, FTDM_SPAN_STOP_THREAD); + ftdm_log (FTDM_LOG_DEBUG,"Waiting for monitor thread to end for %s:%u. [flags=0x%08X]\n", span->name, - span->span_id); - ftdm_sleep (1); + span->span_id, + span->flags); + /* Wait 50ms */ + ftdm_sleep (50); + timeout++; + + /* timeout after 5 sec, better to crash than hang */ + ftdm_assert_return(timeout < 100, FTDM_FALSE, "SS7 Span stop timeout!\n"); } /* KONRAD FIX ME - deconfigure any circuits, links, attached to this span */ @@ -1725,12 +1733,14 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config) /* parse the configuration and apply to the global config structure */ if (ftmod_ss7_parse_xml(ftdm_parameters, span)) { ftdm_log (FTDM_LOG_CRIT, "Failed to parse configuration!\n"); + ftdm_sleep (1000); return FTDM_FAIL; } /* configure libsngss7 */ if (ft_to_sngss7_cfg_all()) { ftdm_log (FTDM_LOG_CRIT, "Failed to configure LibSngSS7!\n"); + ftdm_sleep (1000); return FTDM_FAIL; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 9bf24aada3..3fd5c6e468 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -915,7 +915,7 @@ if (ftdmchan->state == new_state) { \ #define SS7_ERROR_CHAN(fchan, msg, args...) ftdm_log_chan(fchan, FTDM_LOG_ERROR, msg , ##args) #define SS7_CTRIT_CHAN(fchan, msg, args...) ftdm_log_chan(fchan, FTDM_LOG_CRIT, msg , ##args) -#ifdef KONRAD_DEVEL +#ifdef SS7_CODE_DEVEL #define SS7_DEVEL_DEBUG(a,...) ftdm_log(FTDM_LOG_DEBUG,a,##__VA_ARGS__ ); #else #define SS7_DEVEL_DEBUG(a,...) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 167de57bb8..3c1124b3d8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -922,11 +922,6 @@ int check_for_state_change(ftdm_channel_t *ftdmchan) /******************************************************************************/ ftdm_status_t extract_chan_data(uint32_t circuit, sngss7_chan_data_t **sngss7_info, ftdm_channel_t **ftdmchan) { - if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].obj == NULL) { - SS7_ERROR("sngss7_info is Null for circuit #%d\n", circuit); - return FTDM_FAIL; - } - if (!g_ftdm_sngss7_data.cfg.isupCkt[circuit].obj) { SS7_ERROR("No ss7 info for circuit #%d\n", circuit); return FTDM_FAIL; @@ -935,10 +930,21 @@ ftdm_status_t extract_chan_data(uint32_t circuit, sngss7_chan_data_t **sngss7_in *sngss7_info = g_ftdm_sngss7_data.cfg.isupCkt[circuit].obj; if (!(*sngss7_info)->ftdmchan) { - SS7_ERROR("No channel for circuit #%d\n", circuit); + SS7_ERROR("No ftdmchan for circuit #%d\n", circuit); return FTDM_FAIL; } + if (!(*sngss7_info)->ftdmchan->span) { + SS7_CRITICAL("ftdmchan->span = NULL for circuit #%d\n",circuit); + return FTDM_FAIL; + + } + if (!(*sngss7_info)->ftdmchan->span->signal_data) { + SS7_CRITICAL("ftdmchan->span->signal_data = NULL for circuit #%d\n",circuit); + return FTDM_FAIL; + + } + *ftdmchan = (*sngss7_info)->ftdmchan; return FTDM_SUCCESS; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 30d215a14d..8edea31399 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -2877,7 +2877,7 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan) (g_ftdm_sngss7_data.cfg.isupCkt[x].chan == count)) { /* we are processing a circuit that already exists */ - SS7_DEBUG("Found an existing circuit %d, ccSpanId=%d, chan%d\n", + SS7_DEVEL_DEBUG("Found an existing circuit %d, ccSpanId=%d, chan%d\n", x, ccSpan->id, count); @@ -2886,7 +2886,7 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan) flag = 1; /* not supporting reconfig at this time */ - SS7_DEBUG("Not supporting ckt reconfig at this time!\n"); + SS7_DEVEL_DEBUG("Not supporting ckt reconfig at this time!\n"); goto move_along; } else { /* this is not the droid you are looking for */ From 13e6e7bb04ac16209f0ea2ccfeac1ea63c125525 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 25 Oct 2011 17:13:07 -0400 Subject: [PATCH 062/822] freetdm: added debug ftdm_print_stack macro --- libs/freetdm/src/include/private/ftdm_core.h | 25 ++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 9c5c9ad468..65ffad677c 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -104,6 +104,10 @@ #include #endif +#ifdef __linux__ +#include +#endif + #include #include #include @@ -220,6 +224,27 @@ extern "C" { #define ftdm_is_dtmf(key) ((key > 47 && key < 58) || (key > 64 && key < 69) || (key > 96 && key < 101) || key == 35 || key == 42 || key == 87 || key == 119) +#ifdef __linux__ +#define ftdm_print_stack(level) \ + do { \ + void *__stacktrace[100] = { 0 }; \ + char **__symbols = NULL; \ + int __size = 0; \ + int __i = 0; \ + __size = backtrace(__stacktrace, ftdm_array_len(__stacktrace)); \ + __symbols = backtrace_symbols(__stacktrace, __size); \ + if (__symbols) { \ + for (__i = 0; __i < __size; __i++) { \ + ftdm_log(__level, "%s\n", __symbols[i]); \ + } \ + free(__symbols); \ + } \ + } while (0); +#else +#define ftdm_print_stack(level) ftdm_log(level, "FTDM_PRINT_STACK is not implemented in this operating system!\n"); +#endif + + #define FTDM_SPAN_IS_BRI(x) ((x)->trunk_type == FTDM_TRUNK_BRI || (x)->trunk_type == FTDM_TRUNK_BRI_PTMP) /*! \brief Copy flags from one arbitrary object to another From 1d3d1658223474eb12d8086e1006e19c0b9112fa Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Tue, 25 Oct 2011 18:05:41 -0400 Subject: [PATCH 063/822] freetdm: ftdm_running checks on handle, implemented no wait block --- .../ftmod_sangoma_ss7_cntrl.c | 36 ++-------- .../ftmod_sangoma_ss7_handle.c | 65 +++++++++++++++++++ .../ftmod_sangoma_ss7_main.h | 4 +- .../ftmod_sangoma_ss7_relay.c | 2 +- 4 files changed, 75 insertions(+), 32 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c index b0a2163fdd..d57526b267 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c @@ -48,35 +48,7 @@ static int ftmod_ss7_enable_isap(int suId); static int ftmod_ss7_enable_nsap(int suId); static int ftmod_ss7_enable_mtpLinkSet(int lnkSetId); -int ftmod_ss7_inhibit_mtp3link(uint32_t id); -int ftmod_ss7_uninhibit_mtp3link(uint32_t id); -int ftmod_ss7_bind_mtp3link(uint32_t id); -int ftmod_ss7_unbind_mtp3link(uint32_t id); -int ftmod_ss7_activate_mtp3link(uint32_t id); -int ftmod_ss7_deactivate_mtp3link(uint32_t id); -int ftmod_ss7_deactivate2_mtp3link(uint32_t id); - -int ftmod_ss7_activate_mtplinkSet(uint32_t id); -int ftmod_ss7_deactivate_mtplinkSet(uint32_t id); -int ftmod_ss7_deactivate2_mtplinkSet(uint32_t id); - -int ftmod_ss7_lpo_mtp3link(uint32_t id); -int ftmod_ss7_lpr_mtp3link(uint32_t id); - -int ftmod_ss7_shutdown_isup(void); -int ftmod_ss7_shutdown_mtp3(void); -int ftmod_ss7_shutdown_mtp2(void); -int ftmod_ss7_shutdown_relay(void); -int ftmod_ss7_disable_relay_channel(uint32_t chanId); - -int ftmod_ss7_disable_grp_mtp3Link(uint32_t procId); -int ftmod_ss7_enable_grp_mtp3Link(uint32_t procId); - -int ftmod_ss7_disable_grp_mtp2Link(uint32_t procId); - -int ftmod_ss7_block_isup_ckt(uint32_t cktId); -int ftmod_ss7_unblock_isup_ckt(uint32_t cktId); /******************************************************************************/ /* FUNCTIONS ******************************************************************/ @@ -848,7 +820,7 @@ int ftmod_ss7_disable_grp_mtp2Link(uint32_t procId) } /******************************************************************************/ -int ftmod_ss7_block_isup_ckt(uint32_t cktId) +int __ftmod_ss7_block_isup_ckt(uint32_t cktId, ftdm_bool_t wait) { SiMngmt cntrl; Pst pst; @@ -876,7 +848,11 @@ int ftmod_ss7_block_isup_ckt(uint32_t cktId) cntrl.t.cntrl.action = ADISIMM; /* block via BLO */ cntrl.t.cntrl.subAction = SAELMNT; /* specificed element */ - return (sng_cntrl_isup(&pst, &cntrl)); + if (wait == FTDM_TRUE) { + return (sng_cntrl_isup(&pst, &cntrl)); + } else { + return (sng_cntrl_isup_nowait(&pst, &cntrl)); + } } /******************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 59a226d738..8d01a6d97e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -87,6 +87,8 @@ ftdm_status_t handle_olm_msg(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* FUNCTIONS ******************************************************************/ +#define ftdm_running_return(var) if (!ftdm_running()) { SS7_ERROR("Error: ftdm_running is not set! Ignoring\n"); return var; } + ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt) { SS7_FUNC_TRACE_ENTER(__FUNCTION__); @@ -97,6 +99,8 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ memset(var, '\0', sizeof(var)); + ftdm_running_return(FTDM_FAIL); + /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); @@ -341,6 +345,8 @@ ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -596,6 +602,8 @@ ftdm_status_t handle_con_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -671,6 +679,8 @@ ftdm_status_t handle_rel_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -793,6 +803,8 @@ ftdm_status_t handle_rel_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -844,6 +856,8 @@ ftdm_status_t handle_dat_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -871,6 +885,8 @@ ftdm_status_t handle_fac_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -898,6 +914,8 @@ ftdm_status_t handle_fac_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -925,6 +943,8 @@ ftdm_status_t handle_umsg_ind(uint32_t suInstId, uint32_t spInstId, uint32_t cir sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -952,6 +972,8 @@ ftdm_status_t handle_susp_ind(uint32_t suInstId, uint32_t spInstId, uint32_t cir sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -979,6 +1001,8 @@ ftdm_status_t handle_resm_ind(uint32_t suInstId, uint32_t spInstId, uint32_t cir sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -1003,6 +1027,8 @@ ftdm_status_t handle_resm_ind(uint32_t suInstId, uint32_t spInstId, uint32_t cir ftdm_status_t handle_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) { SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is active on our side otherwise move to the next circuit */ if (!sngss7_test_flag(&g_ftdm_sngss7_data.cfg.isupCkt[circuit], SNGSS7_ACTIVE)) { @@ -1203,6 +1229,8 @@ ftdm_status_t handle_reattempt(uint32_t suInstId, uint32_t spInstId, uint32_t ci sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1266,6 +1294,8 @@ ftdm_status_t handle_pause(uint32_t suInstId, uint32_t spInstId, uint32_t circui int infId; int i; + ftdm_running_return(FTDM_FAIL); + /* extract the affected infId from the circuit structure */ infId = g_ftdm_sngss7_data.cfg.isupCkt[circuit].infId; @@ -1330,6 +1360,8 @@ ftdm_status_t handle_resume(uint32_t suInstId, uint32_t spInstId, uint32_t circu ftdm_channel_t *ftdmchan = NULL; int infId; int i; + + ftdm_running_return(FTDM_FAIL); /* extract the affect infId from the circuit structure */ infId = g_ftdm_sngss7_data.cfg.isupCkt[circuit].infId; @@ -1394,6 +1426,8 @@ ftdm_status_t handle_cot_start(uint32_t suInstId, uint32_t spInstId, uint32_t ci sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1449,6 +1483,8 @@ ftdm_status_t handle_cot_stop(uint32_t suInstId, uint32_t spInstId, uint32_t cir sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1494,6 +1530,8 @@ ftdm_status_t handle_cot(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1562,6 +1600,8 @@ ftdm_status_t handle_blo_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1612,6 +1652,8 @@ ftdm_status_t handle_blo_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1653,6 +1695,8 @@ ftdm_status_t handle_ubl_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1741,6 +1785,8 @@ ftdm_status_t handle_rsc_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1800,6 +1846,8 @@ ftdm_status_t handle_local_rsc_req(uint32_t suInstId, uint32_t spInstId, uint32_ sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1858,6 +1906,8 @@ ftdm_status_t handle_rsc_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1948,6 +1998,8 @@ ftdm_status_t handle_grs_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ ftdm_channel_t *ftdmchan = NULL; sngss7_span_data_t *sngss7_span = NULL; int range = 0; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -2005,6 +2057,8 @@ ftdm_status_t handle_grs_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circ ftdm_channel_t *ftdmchan = NULL; sngss7_span_data_t *sngss7_span = NULL; int range = 0; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -2069,6 +2123,8 @@ ftdm_status_t handle_local_blk(uint32_t suInstId, uint32_t spInstId, uint32_t ci sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -2119,6 +2175,8 @@ ftdm_status_t handle_local_ubl(uint32_t suInstId, uint32_t spInstId, uint32_t ci sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -2174,6 +2232,7 @@ ftdm_status_t handle_ucic(uint32_t suInstId, uint32_t spInstId, uint32_t circuit sngss7_span_data_t *sngss7_span = NULL; ftdm_channel_t *ftdmchan = NULL; + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -2255,6 +2314,8 @@ ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ int bit = 0; int x; + ftdm_running_return(FTDM_FAIL); + memset(&status[0], '\0', sizeof(status)); /* confirm that the circuit is voice channel */ @@ -2401,6 +2462,8 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ int bit = 0; int x; ftdm_sigmsg_t sigev; + + ftdm_running_return(FTDM_FAIL); memset(&sigev, 0, sizeof (sigev)); memset(&status[0], '\0', sizeof(status)); @@ -2538,6 +2601,8 @@ ftdm_status_t handle_olm_msg(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 3fd5c6e468..cdef894232 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -732,7 +732,9 @@ int ftmod_ss7_enable_grp_mtp3Link(uint32_t procId); int ftmod_ss7_disable_grp_mtp2Link(uint32_t procId); -int ftmod_ss7_block_isup_ckt(uint32_t cktId); +#define ftmod_ss7_block_isup_ckt(x) __ftmod_ss7_block_isup_ckt(x,FTDM_TRUE) +#define ftmod_ss7_block_isup_ckt_nowait(x) __ftmod_ss7_block_isup_ckt(x,FTDM_FALSE) +int __ftmod_ss7_block_isup_ckt(uint32_t cktId, ftdm_bool_t wait); int ftmod_ss7_unblock_isup_ckt(uint32_t cktId); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c index 1d85dfffbb..f58aad4ca7 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c @@ -248,7 +248,7 @@ ftdm_status_t block_all_ckts_for_relay(uint32_t procId) if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == SNG_CKT_VOICE) { /* send a block request via stack manager */ - ret = ftmod_ss7_block_isup_ckt(g_ftdm_sngss7_data.cfg.isupCkt[x].id); + ret = ftmod_ss7_block_isup_ckt_nowait(g_ftdm_sngss7_data.cfg.isupCkt[x].id); if (ret) { SS7_INFO("Successfully BLOcked CIC:%d(ckt:%d) due to Relay failure\n", g_ftdm_sngss7_data.cfg.isupCkt[x].cic, From 7f746b4298a5b70e461ac64ce4064d463982aba0 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Tue, 25 Oct 2011 18:36:37 -0400 Subject: [PATCH 064/822] freetdm: added nowait mtp3 commands if proc ids dont match --- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c index d57526b267..1fcf1fcfbe 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c @@ -751,7 +751,14 @@ int ftmod_ss7_disable_grp_mtp3Link(uint32_t procId) cntrl.t.cntrl.action = AUBND_DIS; /* disable and unbind */ cntrl.t.cntrl.subAction = SAGR_DSTPROCID; /* specificed element */ - return (sng_cntrl_mtp3(&pst, &cntrl)); + if (g_ftdm_sngss7_data.cfg.procId == procId) { + SS7_DEBUG("Executing MTP3 cntrl command local pid =%i\n",procId); + return (sng_cntrl_mtp3(&pst, &cntrl)); + } else { + SS7_WARN("Executing MTP3 cntrl command different local=%i target=%i\n", + g_ftdm_sngss7_data.cfg.procId,procId); + return (sng_cntrl_mtp3_nowait(&pst, &cntrl)); + } } From f8ae7e7464254d03742595c7828aab14e07ffc16 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Tue, 25 Oct 2011 18:44:28 -0400 Subject: [PATCH 065/822] freetdm: ftmod_ss7_enable_grp_mtp3Link - wait no wait based on proc --- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c index 1fcf1fcfbe..c5aca9aa73 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c @@ -790,7 +790,14 @@ int ftmod_ss7_enable_grp_mtp3Link(uint32_t procId) cntrl.t.cntrl.action = ABND_ENA; /* bind and enable */ cntrl.t.cntrl.subAction = SAGR_DSTPROCID; /* specificed element */ - return (sng_cntrl_mtp3(&pst, &cntrl)); + if (g_ftdm_sngss7_data.cfg.procId == procId) { + SS7_DEBUG("Executing MTP3 cntrl command local pid =%i\n",procId); + return (sng_cntrl_mtp3(&pst, &cntrl)); + } else { + SS7_WARN("Executing MTP3 cntrl command different local=%i target=%i\n", + g_ftdm_sngss7_data.cfg.procId,procId); + return (sng_cntrl_mtp3_nowait(&pst, &cntrl)); + } } From 982bcf41460ac39150485288ab750ba5f28cf56d Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Tue, 25 Oct 2011 19:04:50 -0400 Subject: [PATCH 066/822] freetdm: added debugging - changed order of block/unblock --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c index f58aad4ca7..a96dae5cdd 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c @@ -42,8 +42,6 @@ /******************************************************************************/ /* PROTOTYPES *****************************************************************/ -ftdm_status_t handle_relay_connect(RyMngmt *sta); -ftdm_status_t handle_relay_disconnect(RyMngmt *sta); /*static ftdm_status_t enable_all_ckts_for_relay(void);*/ static ftdm_status_t reconfig_all_ckts_for_relay(void); @@ -84,23 +82,24 @@ ftdm_status_t handle_relay_connect(RyMngmt *sta) /******************************************************************************/ ftdm_status_t handle_relay_disconnect_on_error(RyMngmt *sta) { + SS7_DEBUG("SS7 relay disconnect on error\n"); /* check which procId is in error, if it is 1, disable the ckts */ if (sta->t.usta.s.ryErrUsta.errPid == 1 ) { - /* we've lost the server, bring down the mtp2 links */ - disble_all_mtp2_sigs_for_relay(); - /* we've lost the server, bring the sig status down on all ckts */ disable_all_ckts_for_relay(); + + /* we've lost the server, bring down the mtp2 links */ + disble_all_mtp2_sigs_for_relay(); } /* check if the channel is a server, means we just lost a MGW */ if (g_ftdm_sngss7_data.cfg.relay[sta->t.usta.s.ryErrUsta.errPid].type == LRY_CT_TCP_SERVER) { - /* we've lost the client, bring down all mtp3 links for this procId */ - disable_all_sigs_for_relay(sta->t.usta.s.ryErrUsta.errPid); - /* we've lost the client, bring down all the ckts for this procId */ block_all_ckts_for_relay(sta->t.usta.s.ryErrUsta.errPid); + + /* we've lost the client, bring down all mtp3 links for this procId */ + disable_all_sigs_for_relay(sta->t.usta.s.ryErrUsta.errPid); } return FTDM_SUCCESS; @@ -110,6 +109,8 @@ ftdm_status_t handle_relay_disconnect_on_error(RyMngmt *sta) ftdm_status_t handle_relay_disconnect_on_down(RyMngmt *sta) { + SS7_DEBUG("SS7 relay disconnect on down\n"); + /* check if the channel is a server, means we just lost a MGW */ if (g_ftdm_sngss7_data.cfg.relay[sta->t.usta.s.ryUpUsta.id].type == LRY_CT_TCP_SERVER) { block_all_ckts_for_relay(sta->t.usta.s.ryUpUsta.id); From 79c1ed7dc15154fc1c32087ade26766bec82d825 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Tue, 25 Oct 2011 20:29:22 -0400 Subject: [PATCH 067/822] freetdm: fixed reset tx after unequiped cic; reset sent flag was not being cleared --- .../freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 759fd2871f..4f0d021228 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1410,6 +1410,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_UCIC_UNBLK); /* throw the channel into reset to sync states */ + clear_tx_rsc_flags(sngss7_info); sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); /* bring the channel into restart again */ From 859d3b0ed5fec36c667d8bddfa3571fe74d6b3df Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Wed, 26 Oct 2011 13:05:12 -0400 Subject: [PATCH 068/822] Added GRS on startup by default --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 4f0d021228..ed076925b8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1568,6 +1568,7 @@ static ftdm_status_t ftdm_sangoma_ss7_start(ftdm_span_t * span) sngss7_span_data_t *sngss7_span = NULL; sng_isup_inf_t *sngss7_intf = NULL; int x; + int first_channel=0; SS7_INFO ("Starting span %s:%u.\n", span->name, span->span_id); @@ -1612,13 +1613,15 @@ static ftdm_status_t ftdm_sangoma_ss7_start(ftdm_span_t * span) sngss7_clear_ckt_flag(sngss7_info, FLAG_INFID_PAUSED); sngss7_set_ckt_flag(sngss7_info, FLAG_INFID_RESUME); } -#if 0 +#if 1 /* throw the grp reset flag */ sngss7_set_ckt_flag(sngss7_info, FLAG_GRP_RESET_TX); - if (x == 1) { - sngss7_set_flag(sngss7_info, FLAG_GRP_RESET_BASE); - sngss7_span->tx_grs.circuit = sngss7_info->circuit->id; - sngss7_span->tx_grs.range = span->chan_count -1; + if (first_channel == 0) { + sngss7_chan_data_t *cinfo = ftdmchan->call_data; + sngss7_set_ckt_flag(sngss7_info, FLAG_GRP_RESET_BASE); + cinfo->tx_grs.circuit = sngss7_info->circuit->id; + cinfo->tx_grs.range = span->chan_count -1; + first_channel=1; } #else /* throw the channel into reset */ From fd6d18d56c7a3b026eb670d307fe6020f392a8ae Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Wed, 26 Oct 2011 14:33:28 -0400 Subject: [PATCH 069/822] freetdm: Fixed GRA - added group reset by default on startup --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c | 3 +++ .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 16 +++++++++++++++- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 2 -- .../ftmod_sangoma_ss7_support.c | 2 +- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 8d01a6d97e..3733a619a7 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -2271,6 +2271,8 @@ ftdm_status_t handle_ucic(uint32_t suInstId, uint32_t spInstId, uint32_t circuit cinfo->ucic.range = cinfo->tx_grs.range; ftdm_set_flag(sngss7_span, SNGSS7_UCIC_PENDING); + SS7_WARN("Set span SNGSS7_UCIC_PENDING for ISUP circuit = %d!\n", circuit); + ftdm_channel_unlock(fchan); goto done; @@ -2283,6 +2285,7 @@ ftdm_status_t handle_ucic(uint32_t suInstId, uint32_t spInstId, uint32_t circuit ftdm_mutex_lock(ftdmchan->mutex); /* throw the ckt block flag */ + SS7_DEBUG("Set FLAG_CKT_UCIC_BLOCK for ISUP circuit = %d!\n", circuit); sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_UCIC_BLOCK); /* set the channel to suspended state */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index ed076925b8..2cb59ca36e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1024,6 +1024,10 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) break; /**************************************************************************/ case FTDM_CHANNEL_STATE_RESTART: /* CICs needs a Reset */ + + SS7_DEBUG_CHAN(ftdmchan,"RESTART: Current flags: ckt=0x%X, blk=0x%X\n", + sngss7_info->ckt_flags, + sngss7_info->blk_flags); if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_UCIC_BLOCK)) { if ((sngss7_test_ckt_flag(sngss7_info, FLAG_RESET_RX)) || @@ -1139,7 +1143,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /**************************************************************************/ case FTDM_CHANNEL_STATE_SUSPENDED: /* circuit has been blocked */ - SS7_DEBUG_CHAN(ftdmchan,"Current flags: ckt=0x%X, blk=0x%X\n", + SS7_DEBUG_CHAN(ftdmchan,"SUSPEND: Current flags: ckt=0x%X, blk=0x%X\n", sngss7_info->ckt_flags, sngss7_info->blk_flags); @@ -1256,6 +1260,8 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) | FLAG_CKT_MN_BLOCK_RX_DN | FLAG_GRP_MN_BLOCK_RX | FLAG_GRP_MN_BLOCK_RX_DN + | FLAG_CKT_UCIC_BLOCK + | FLAG_CKT_UCIC_BLOCK_DN ) ) ) { @@ -1410,6 +1416,14 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_UCIC_UNBLK); /* throw the channel into reset to sync states */ + + clear_rx_grs_flags(sngss7_info); + clear_rx_grs_data(sngss7_info); + clear_tx_grs_flags(sngss7_info); + clear_tx_grs_data(sngss7_info); + clear_rx_rsc_flags(sngss7_info); + clear_tx_rsc_flags(sngss7_info); + clear_tx_rsc_flags(sngss7_info); sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index 5aed5f49a4..4c7bbf084c 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -523,8 +523,6 @@ void ft_to_sngss7_grs (ftdm_channel_t *fchan) cinfo->circuit->cic, (cinfo->circuit->cic + cinfo->tx_grs.range)); - memset(&cinfo->tx_grs, 0, sizeof(cinfo->tx_grs)); - sngss7_set_ckt_flag(cinfo, FLAG_GRP_RESET_SENT); SS7_FUNC_TRACE_EXIT (__FUNCTION__); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 3c1124b3d8..7b53a18eba 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -1428,7 +1428,7 @@ ftdm_status_t process_span_ucic(ftdm_span_t *ftdmspan) /* lock the channel */ ftdm_channel_lock(ftdmchan); - SS7_INFO_CHAN(ftdmchan, "[CIC:%d]Rx UCIC\n", sngss7_info->circuit->cic); + SS7_INFO_CHAN(ftdmchan, "[CIC:%d]Rx Span UCIC\n", sngss7_info->circuit->cic); /* clear up any pending state changes */ while (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { From de2836e76a0f9f925bda95db3782a49e010cff1c Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Wed, 26 Oct 2011 14:57:27 -0400 Subject: [PATCH 070/822] freetdm: Its possible to get HW ALARM clear even though we never got the initial alarm. Only send out an unblock if block was sent from hw alarm and there are no maintenance blocks pending. --- .../ftmod_sangoma_ss7_main.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 2cb59ca36e..177af00733 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1247,6 +1247,25 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_UNBLK_TX)) { SS7_DEBUG_CHAN(ftdmchan, "Processing FLAG_GRP_HW_UNBLK_TX flag %s\n", ""); + if (sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX) && + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX_DN)) { + + /* Block was sent out we must send an unblock */ + /* Do not send an unblock if we also have Management block + enabled */ + + if (!sngss7_test_ckt_blk_flag(sngss7_info, ( FLAG_CKT_MN_BLOCK_TX + | FLAG_CKT_MN_BLOCK_TX + | FLAG_GRP_MN_BLOCK_TX + | FLAG_GRP_MN_BLOCK_TX_DN + ) + ) + ) { + ft_to_sngss7_ubl(ftdmchan); + } + + } + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX); sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX_DN); sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_UNBLK_TX); From 0e2b85ddf4582f0d702035cd89fcbe0d64e20a18 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Wed, 26 Oct 2011 16:09:32 -0400 Subject: [PATCH 071/822] freetdm: Add debugging --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 177af00733..dc8ed7dbc2 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -289,6 +289,8 @@ static void handle_hw_alarm(ftdm_event_t *e) int x = 0; ftdm_assert(e != NULL, "Null event!\n"); + + SS7_DEBUG("handle_hw_alarm event\n"); for (x = (g_ftdm_sngss7_data.cfg.procId * MAX_CIC_MAP_LENGTH) + 1; g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0; x++) { if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == SNG_CKT_VOICE) { @@ -298,11 +300,13 @@ static void handle_hw_alarm(ftdm_event_t *e) if (e->channel->span_id == ftdmchan->physical_span_id && e->channel->chan_id == ftdmchan->physical_chan_id) { if (e->enum_id == FTDM_OOB_ALARM_TRAP) { + SS7_DEBUG("handle_hw_alarm: Set \n"); sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX); if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); } } else { + SS7_DEBUG("handle_hw_alarm: Clear\n"); sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX); if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { @@ -363,6 +367,7 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) sngss7_clear_ckt_blk_flag( ss7_info, FLAG_GRP_HW_BLOCK_TX ); sngss7_clear_ckt_blk_flag( ss7_info, FLAG_GRP_HW_BLOCK_TX_DN ); sngss7_set_ckt_blk_flag (ss7_info, FLAG_GRP_HW_UNBLK_TX); + SS7_DEBUG("b_alarm_test FLAG_GRP_HW_UNBLK_TX\n"); } } usleep(50); From d0188836f8717da029d7c0b4072cadbba66e4786 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Wed, 26 Oct 2011 16:17:11 -0400 Subject: [PATCH 072/822] freetdm: Do not set hw block clear flag on startup if port is already up --- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index dc8ed7dbc2..fbe5889615 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -307,10 +307,12 @@ static void handle_hw_alarm(ftdm_event_t *e) } } else { SS7_DEBUG("handle_hw_alarm: Clear\n"); - sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); - sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX); - if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + if (sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX)) { + sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); + sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX); + if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + } } } } From 44895d738d23a8b46550a10a1b83abf50b8b0713 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Wed, 26 Oct 2011 16:34:56 -0400 Subject: [PATCH 073/822] freetdm: On alarm off event make sure that we had alarm on before issuing HW UNBLOCK --- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index fbe5889615..37be742793 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -366,10 +366,12 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) if (ftdmchan->alarm_flags != 0) { /* we'll send out block */ sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX ); } else { /* we'll send out reset */ - sngss7_clear_ckt_blk_flag( ss7_info, FLAG_GRP_HW_BLOCK_TX ); - sngss7_clear_ckt_blk_flag( ss7_info, FLAG_GRP_HW_BLOCK_TX_DN ); - sngss7_set_ckt_blk_flag (ss7_info, FLAG_GRP_HW_UNBLK_TX); - SS7_DEBUG("b_alarm_test FLAG_GRP_HW_UNBLK_TX\n"); + if (sngss7_test_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX )) { + sngss7_clear_ckt_blk_flag( ss7_info, FLAG_GRP_HW_BLOCK_TX ); + sngss7_clear_ckt_blk_flag( ss7_info, FLAG_GRP_HW_BLOCK_TX_DN ); + sngss7_set_ckt_blk_flag (ss7_info, FLAG_GRP_HW_UNBLK_TX); + SS7_DEBUG("b_alarm_test FLAG_GRP_HW_UNBLK_TX\n"); + } } } usleep(50); From d442c188eb97524ec027c21ee7112ce599dd3c7a Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Wed, 26 Oct 2011 16:37:44 -0400 Subject: [PATCH 074/822] freetdm: More debugging --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 37be742793..da37f485c3 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -300,7 +300,7 @@ static void handle_hw_alarm(ftdm_event_t *e) if (e->channel->span_id == ftdmchan->physical_span_id && e->channel->chan_id == ftdmchan->physical_chan_id) { if (e->enum_id == FTDM_OOB_ALARM_TRAP) { - SS7_DEBUG("handle_hw_alarm: Set \n"); + SS7_DEBUG("handle_hw_alarm: Set FLAG_GRP_HW_BLOCK_TX\n"); sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX); if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); @@ -310,6 +310,7 @@ static void handle_hw_alarm(ftdm_event_t *e) if (sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX)) { sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX); + SS7_DEBUG("handle_hw_alarm: Setting FLAG_GRP_HW_BLOCK_TX\n"); if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); } From 08768608e66e28ea0398204f5b58a8006e8e8737 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Wed, 26 Oct 2011 16:56:47 -0400 Subject: [PATCH 075/822] freetdm: on handle alarm must check TRAP or CLEAR cannot use default case --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index da37f485c3..9a7f36792f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -305,12 +305,12 @@ static void handle_hw_alarm(ftdm_event_t *e) if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); } - } else { + } else if (e->enum_id == FTDM_OOB_ALARM_CLEAR) { SS7_DEBUG("handle_hw_alarm: Clear\n"); if (sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX)) { sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX); - SS7_DEBUG("handle_hw_alarm: Setting FLAG_GRP_HW_BLOCK_TX\n"); + SS7_DEBUG("handle_hw_alarm: Setting FLAG_GRP_HW_UNBLK_TX\n"); if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); } From acfdddabbb32935da98c5acebad778eba408ed06 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 28 Oct 2011 09:35:49 -0400 Subject: [PATCH 076/822] freetdm: ss7 - add china switchtype to the configuration options --- libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 30d215a14d..3807595183 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -62,6 +62,7 @@ sng_switch_type_t sng_switch_type_map[] = { 1, "india" , LSI_SW_INDIA , LSI_SW_INDIA }, { 1, "uk" , LSI_SW_UK , LSI_SW_UK }, { 1, "russia" , LSI_SW_RUSSIA , LSI_SW_RUSSIA }, + { 1, "china" , LSI_SW_CHINA , LSI_SW_CHINA }, { 0, "", 0, 0 }, }; From c98d8b49d93eb9a8a203417d8574d13ccf059ab8 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Mon, 31 Oct 2011 23:56:39 -0400 Subject: [PATCH 077/822] freetdm: Default to individual reset not GRS --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 9a7f36792f..2cc723d618 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1656,7 +1656,7 @@ static ftdm_status_t ftdm_sangoma_ss7_start(ftdm_span_t * span) sngss7_clear_ckt_flag(sngss7_info, FLAG_INFID_PAUSED); sngss7_set_ckt_flag(sngss7_info, FLAG_INFID_RESUME); } -#if 1 +#if 0 /* throw the grp reset flag */ sngss7_set_ckt_flag(sngss7_info, FLAG_GRP_RESET_TX); if (first_channel == 0) { From 429b2944e53f5853b1ca411a093261d215cd149a Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Mon, 31 Oct 2011 23:57:45 -0400 Subject: [PATCH 078/822] freetdm: reset to reset not GRS - take2 --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 2cc723d618..bb909488d4 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1610,8 +1610,10 @@ static ftdm_status_t ftdm_sangoma_ss7_start(ftdm_span_t * span) sngss7_chan_data_t *sngss7_info = NULL; sngss7_span_data_t *sngss7_span = NULL; sng_isup_inf_t *sngss7_intf = NULL; - int x; - int first_channel=0; + int x; + int first_channel; + + first_channel=0; SS7_INFO ("Starting span %s:%u.\n", span->name, span->span_id); From 953cd77f956415e8905c067a3cc1e0a81cf32c99 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Wed, 2 Nov 2011 20:53:14 -0400 Subject: [PATCH 079/822] freetdm: Fixed blocks/unblocks resets. Performed conformance tests Fixed hw alarm handling: physical ids were not used which caused alarms read wrong. Tested sip hold Group blocks/unblock Group reset Link down-> block -> unblock FS start with link down then link up FS start with link up, take link down and up -> make incoming call --- .../ftmod_sangoma_ss7_main.c | 132 +++++++++--------- .../ftmod_sangoma_ss7_main.h | 16 +++ 2 files changed, 84 insertions(+), 64 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index bb909488d4..1453581214 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -290,15 +290,16 @@ static void handle_hw_alarm(ftdm_event_t *e) ftdm_assert(e != NULL, "Null event!\n"); - SS7_DEBUG("handle_hw_alarm event\n"); + SS7_DEBUG("handle_hw_alarm event [%d/%d]\n",e->channel->physical_span_id,e->channel->physical_chan_id); for (x = (g_ftdm_sngss7_data.cfg.procId * MAX_CIC_MAP_LENGTH) + 1; g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0; x++) { if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == SNG_CKT_VOICE) { ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCkt[x].obj; ftdmchan = ss7_info->ftdmchan; - if (e->channel->span_id == ftdmchan->physical_span_id && - e->channel->chan_id == ftdmchan->physical_chan_id) { + if (e->channel->physical_span_id == ftdmchan->physical_span_id && + e->channel->physical_chan_id == ftdmchan->physical_chan_id) { + SS7_DEBUG("handle_hw_alarm: span=%i chan=%i ckt=%i x=%i\n",ftdmchan->physical_span_id,ftdmchan->physical_chan_id,g_ftdm_sngss7_data.cfg.isupCkt[x].id,x); if (e->enum_id == FTDM_OOB_ALARM_TRAP) { SS7_DEBUG("handle_hw_alarm: Set FLAG_GRP_HW_BLOCK_TX\n"); sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX); @@ -307,13 +308,10 @@ static void handle_hw_alarm(ftdm_event_t *e) } } else if (e->enum_id == FTDM_OOB_ALARM_CLEAR) { SS7_DEBUG("handle_hw_alarm: Clear\n"); - if (sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX)) { - sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); - sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX); - SS7_DEBUG("handle_hw_alarm: Setting FLAG_GRP_HW_UNBLK_TX\n"); - if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); - } + sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); + SS7_DEBUG("handle_hw_alarm: Setting FLAG_GRP_HW_UNBLK_TX\n"); + if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); } } } @@ -963,16 +961,12 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) !(sngss7_test_ckt_flag (sngss7_info, FLAG_RESET_RX)) && !(sngss7_test_ckt_flag (sngss7_info, FLAG_GRP_RESET_TX)) && !(sngss7_test_ckt_flag (sngss7_info, FLAG_GRP_RESET_RX))) { + + SS7_DEBUG_CHAN(ftdmchan,"Current flags: ckt=0x%X, blk=0x%X\n", + sngss7_info->ckt_flags, + sngss7_info->blk_flags); - /* now check if there is an active block */ - if (!(sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX)) && - !(sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX)) && - !(sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX)) && - !(sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX)) && - !(sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX)) && - !(sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX)) && - !(sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_TX))) { - + if (sngss7_channel_status_clear(sngss7_info)) { /* check if the sig status is down, and bring it up if it isn't */ if (!ftdm_test_flag (ftdmchan, FTDM_CHANNEL_SIG_UP)) { SS7_DEBUG_CHAN(ftdmchan,"All reset flags cleared %s\n", ""); @@ -1038,6 +1032,13 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) SS7_DEBUG_CHAN(ftdmchan,"RESTART: Current flags: ckt=0x%X, blk=0x%X\n", sngss7_info->ckt_flags, sngss7_info->blk_flags); + +#if 0 + if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_UNBLK_TX) && sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_RESUME)) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + break; + } +#endif if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_UCIC_BLOCK)) { if ((sngss7_test_ckt_flag(sngss7_info, FLAG_RESET_RX)) || @@ -1169,13 +1170,15 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_clear_ckt_flag(sngss7_info, FLAG_INFID_PAUSED); /* if there are any resets present */ - if ((sngss7_test_ckt_flag (sngss7_info, FLAG_RESET_TX)) || - (sngss7_test_ckt_flag (sngss7_info, FLAG_RESET_RX)) || - (sngss7_test_ckt_flag (sngss7_info, FLAG_GRP_RESET_TX)) || - (sngss7_test_ckt_flag (sngss7_info, FLAG_GRP_RESET_RX))) { - + if (!sngss7_channel_status_clear(sngss7_info)) { /* don't bring up the sig status but also move to reset */ - goto suspend_goto_restart; + if (!sngss7_reset_status_clear(sngss7_info)) { + goto suspend_goto_restart; + } else if (!sngss7_block_status_clear(sngss7_info)) { + /* Do nothing just go and handle blocks */ + } else { + goto suspend_goto_restart; + } } else { /* bring the sig status back up */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); @@ -1190,6 +1193,9 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* bring the sig status down */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); } + + /* Wait for RESUME */ + goto suspend_goto_last; } /* if (sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_PAUSED)) { */ /**********************************************************************/ @@ -1221,14 +1227,17 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* clear the unblock flag */ sngss7_clear_ckt_blk_flag (sngss7_info, FLAG_CKT_MN_UNBLK_RX); + SS7_DEBUG_CHAN(ftdmchan,"Current flags: ckt=0x%X, blk=0x%X\n", + sngss7_info->ckt_flags, + sngss7_info->blk_flags); /* not bring the cic up if there is a hardware block */ - if( !sngss7_test_ckt_blk_flag(sngss7_info, (FLAG_GRP_HW_BLOCK_TX | FLAG_GRP_HW_BLOCK_TX_DN) ) ) { + if (sngss7_channel_status_clear(sngss7_info)) { /* bring the sig status up */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); - /* send a uba */ - ft_to_sngss7_uba (ftdmchan); } + /* send a uba */ + ft_to_sngss7_uba (ftdmchan); /* check the last state and return to it to allow the call to finish */ goto suspend_goto_last; @@ -1255,46 +1264,27 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) } if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_UNBLK_TX)) { + int skip_unblock=0; SS7_DEBUG_CHAN(ftdmchan, "Processing FLAG_GRP_HW_UNBLK_TX flag %s\n", ""); - if (sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX) && - sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX_DN)) { - - /* Block was sent out we must send an unblock */ - /* Do not send an unblock if we also have Management block - enabled */ - - if (!sngss7_test_ckt_blk_flag(sngss7_info, ( FLAG_CKT_MN_BLOCK_TX - | FLAG_CKT_MN_BLOCK_TX - | FLAG_GRP_MN_BLOCK_TX - | FLAG_GRP_MN_BLOCK_TX_DN - ) - ) - ) { - ft_to_sngss7_ubl(ftdmchan); - } - + if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX) || + sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX_DN)) { + /* Real unblock */ + } else { + SS7_ERROR_CHAN(ftdmchan, "FLAG_GRP_HW_UNBLK_TX set while FLAG_GRP_HW_BLOCK_TX is not %s\n", ""); + skip_unblock=1; } - + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX); sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX_DN); sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_UNBLK_TX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_UNBLK_TX_DN); - /* do not set the channel up if it's blocked by blo/cgb command OR blocked by receiving blo/cgb */ - if (!sngss7_test_ckt_blk_flag(sngss7_info, ( FLAG_CKT_MN_BLOCK_TX - | FLAG_CKT_MN_BLOCK_TX - | FLAG_GRP_MN_BLOCK_TX - | FLAG_GRP_MN_BLOCK_TX_DN - | FLAG_CKT_MN_BLOCK_RX - | FLAG_CKT_MN_BLOCK_RX_DN - | FLAG_GRP_MN_BLOCK_RX - | FLAG_GRP_MN_BLOCK_RX_DN - | FLAG_CKT_UCIC_BLOCK - | FLAG_CKT_UCIC_BLOCK_DN - ) - ) - ) { + if (sngss7_channel_status_clear(sngss7_info)) { sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + } + + if (sngss7_tx_block_status_clear(sngss7_info) && !skip_unblock) { ft_to_sngss7_ubl(ftdmchan); } @@ -1302,6 +1292,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) } #if 0 //jz: there is no such thing of "remote hw block". for receiver, there are only block and unblock +//nc: yes there is: its part of the CGB - however its handled in ss7_handle.c /**********************************************************************/ // jz: hardware block/unblock rx @@ -1323,9 +1314,14 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX_DN); sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_UNBLK_RX); - sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); - ft_to_sngss7_uba(ftdmchan); + if (sngss7_channel_status_clear(sngs7_info)) { + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + } + + if (sngss7_tx_block_status_clear(sngss7_info)) { + ft_to_sngss7_uba(ftdmchan); + } goto suspend_goto_last; } @@ -1363,11 +1359,12 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* clear the unblock flag */ sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_UNBLK_TX); - /* not bring the cic up if there is a hardware block */ - if (!sngss7_test_ckt_blk_flag(sngss7_info, (FLAG_GRP_HW_BLOCK_TX | FLAG_GRP_HW_BLOCK_TX_DN))) { + if (sngss7_channel_status_clear(sngss7_info)) { /* bring the sig status up */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + } + if (sngss7_tx_block_status_clear(sngss7_info)) { /* send a ubl */ ft_to_sngss7_ubl(ftdmchan); } @@ -1388,6 +1385,9 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* throw the done flag */ sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX_DN); + /* bring the sig status down */ + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); + /* check the last state and return to it to allow the call to finish */ goto suspend_goto_last; } @@ -1405,6 +1405,10 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* send a uba */ /*ft_to_sngss7_uba(ftdmchan);*/ + + if (sngss7_channel_status_clear(sngss7_info)) { + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + } /* check the last state and return to it to allow the call to finish */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index cdef894232..4a0f6026c7 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -1044,6 +1044,22 @@ if (ftdmchan->state == new_state) { \ #define sngss7_clear_options(obj, option) ((obj)->options &= ~(option)) #define sngss7_set_options(obj, option) ((obj)->options |= (option)) +#define sngss7_tx_block_status_clear(obj) (!sngss7_test_ckt_blk_flag(obj, (FLAG_CKT_MN_BLOCK_TX | \ + FLAG_CKT_MN_BLOCK_TX_DN | \ + FLAG_GRP_MN_BLOCK_TX | \ + FLAG_GRP_MN_BLOCK_TX_DN | \ + FLAG_GRP_HW_BLOCK_TX | \ + FLAG_GRP_HW_BLOCK_TX_DN ))) + +#define sngss7_block_status_clear(obj) (obj->blk_flags == 0) + +#define sngss7_reset_status_clear(obj) (!sngss7_test_ckt_flag(obj, (FLAG_RESET_TX | \ + FLAG_RESET_RX | \ + FLAG_GRP_RESET_TX | \ + FLAG_GRP_RESET_RX ))) + +#define sngss7_channel_status_clear(obj) ((sngss7_block_status_clear(obj)) && (sngss7_reset_status_clear(obj))) + #ifdef SMG_RELAY_DBG #define SS7_RELAY_DBG(a,...) printf(a"\n", ##__VA_ARGS__) From 69f6f20fd22a7bda09c1ea21932fafeba4ab6e88 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Thu, 3 Nov 2011 14:29:47 -0400 Subject: [PATCH 080/822] freetdm: on hander do not go up unless all channel blocks/restes are cleared Added more documentation in main --- .../ftmod_sangoma_ss7_handle.c | 4 ++- .../ftmod_sangoma_ss7_main.c | 32 +++++++------------ 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 3733a619a7..0f3515097b 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -2571,7 +2571,9 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ sigev.channel = ftdmchan; /* bring the sig status down */ - sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + if (sngss7_channel_status_clear(sngss7_info)) { + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + } /* unlock the channel again before we exit */ ftdm_mutex_unlock(ftdmchan->mutex); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 1453581214..c4854f860c 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1032,13 +1032,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) SS7_DEBUG_CHAN(ftdmchan,"RESTART: Current flags: ckt=0x%X, blk=0x%X\n", sngss7_info->ckt_flags, sngss7_info->blk_flags); - -#if 0 - if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_UNBLK_TX) && sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_RESUME)) { - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); - break; - } -#endif if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_UCIC_BLOCK)) { if ((sngss7_test_ckt_flag(sngss7_info, FLAG_RESET_RX)) || @@ -1175,8 +1168,11 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) if (!sngss7_reset_status_clear(sngss7_info)) { goto suspend_goto_restart; } else if (!sngss7_block_status_clear(sngss7_info)) { - /* Do nothing just go and handle blocks */ + /* Do nothing just go through and handle blocks below */ } else { + /* This should not happen as above function tests + * for reset and blocks */ + SS7_ERROR_CHAN(ftdmchan, "Invalid code path: sngss7_channel_status_clear reset and block are both cleared%s\n", ""); goto suspend_goto_restart; } } else { @@ -1195,6 +1191,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) } /* Wait for RESUME */ + /* FIXME: Check if this is a correct action to wait for RESUME */ goto suspend_goto_last; } /* if (sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_PAUSED)) { */ @@ -1290,19 +1287,20 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) goto suspend_goto_last; } -#if 0 -//jz: there is no such thing of "remote hw block". for receiver, there are only block and unblock -//nc: yes there is: its part of the CGB - however its handled in ss7_handle.c /**********************************************************************/ - // jz: hardware block/unblock rx +#if 0 + /* This logic is handled in the handle_cgu_req and handle_cgb_req */ + if (sngss7_test_ckt_blk_flag (sngss7_info, FLAG_GRP_HW_BLOCK_RX ) && !sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX_DN )) { SS7_DEBUG_CHAN(ftdmchan, "Processing FLAG_GRP_HW_BLOCK_RX flag %s\n", ""); sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); - ft_to_sngss7_bla(ftdmchan); + + /* FIXME: Transmit CRG Ack */ + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX_DN); goto suspend_goto_last; @@ -1319,16 +1317,13 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); } - if (sngss7_tx_block_status_clear(sngss7_info)) { - ft_to_sngss7_uba(ftdmchan); - } + /* Transmit CRU Ack */ goto suspend_goto_last; } #endif - /**********************************************************************/ if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX) && !sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX_DN)) { @@ -1861,9 +1856,6 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_ss7_init) sng_isup_version(&major, &minor, &build); SS7_INFO("Loaded LibSng-SS7 %d.%d.%d\n", major, minor, build); - /* crash on assert fail */ - ftdm_global_set_crash_policy (FTDM_CRASH_ON_ASSERT); - return FTDM_SUCCESS; } From 4b25044ac6043b4a411a62d0d28ceb4b50cc95b2 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Thu, 3 Nov 2011 20:04:26 -0400 Subject: [PATCH 081/822] freetdm: Made CPG optional on configuration file Fixes in hw alarm - no need to set hw unblock if hw block did not execute yet. Minor bug fixes --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c | 2 +- .../ftmod_sangoma_ss7_main.c | 47 ++++++++++++++++--- .../ftmod_sangoma_ss7_main.h | 12 ++++- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 12 +++++ 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c index a9b4136665..e51428acaa 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c @@ -94,7 +94,7 @@ int ft_to_sngss7_cfg_all(void) /* set the desired procID value */ sng_set_procId((uint16_t)g_ftdm_sngss7_data.cfg.procId); } - + /* start up the stack manager */ if (sng_isup_init_sm()) { SS7_CRITICAL("Failed to start Stack Manager\n"); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index c4854f860c..cd7f3ad58e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -308,10 +308,14 @@ static void handle_hw_alarm(ftdm_event_t *e) } } else if (e->enum_id == FTDM_OOB_ALARM_CLEAR) { SS7_DEBUG("handle_hw_alarm: Clear\n"); - sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); - SS7_DEBUG("handle_hw_alarm: Setting FLAG_GRP_HW_UNBLK_TX\n"); - if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX); + sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); + if (sngss7_test_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX_DN)) { + sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); + SS7_DEBUG("handle_hw_alarm: Setting FLAG_GRP_HW_UNBLK_TX\n"); + if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + } } } } @@ -737,6 +741,12 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_set_ckt_flag(sngss7_info, FLAG_SENT_ACM); ft_to_sngss7_acm(ftdmchan); } + if (g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].cpg_on_progress == FTDM_TRUE) { + if (!sngss7_test_ckt_flag(sngss7_info, FLAG_SENT_CPG)) { + sngss7_set_ckt_flag(sngss7_info, FLAG_SENT_CPG); + ft_to_sngss7_cpg(ftdmchan); + } + } } break; @@ -756,7 +766,12 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_set_ckt_flag(sngss7_info, FLAG_SENT_ACM); ft_to_sngss7_acm(ftdmchan); } - ft_to_sngss7_cpg(ftdmchan); + if (g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].cpg_on_progress_media == FTDM_TRUE) { + if (!sngss7_test_ckt_flag(sngss7_info, FLAG_SENT_CPG)) { + sngss7_set_ckt_flag(sngss7_info, FLAG_SENT_CPG); + ft_to_sngss7_cpg(ftdmchan); + } + } } break; @@ -973,7 +988,10 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* all flags are down so we can bring up the sig status */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); } /* if (!ftdm_test_flag (ftdmchan, FTDM_CHANNEL_SIG_UP)) */ - } /* if !blocked */ + } else { + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + } /* if !blocked */ } else { SS7_DEBUG_CHAN(ftdmchan,"Reset flags present (0x%X)\n", sngss7_info->ckt_flags); @@ -998,6 +1016,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_clear_ckt_flag (sngss7_info, FLAG_REMOTE_REL); sngss7_clear_ckt_flag (sngss7_info, FLAG_LOCAL_REL); sngss7_clear_ckt_flag (sngss7_info, FLAG_SENT_ACM); + sngss7_clear_ckt_flag (sngss7_info, FLAG_SENT_CPG); if (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_OPEN)) { @@ -1162,6 +1181,22 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* clear the PAUSE flag */ sngss7_clear_ckt_flag(sngss7_info, FLAG_INFID_PAUSED); + /* We have transmitted Reset/GRS but have not gotten a + * Response. In mean time we got a RESUME. We cannot be sure + * that our reset has been trasmitted, thus restart reset procedure. */ + if (sngss7_tx_reset_status_pending(sngss7_info)) { + SS7_DEBUG_CHAN(ftdmchan, "Channel transmitted RSC/GRS before RESUME, restart Reset procedure%s\n", ""); + clear_rx_grs_flags(sngss7_info); + clear_rx_grs_data(sngss7_info); + clear_tx_grs_flags(sngss7_info); + clear_tx_grs_data(sngss7_info); + clear_rx_rsc_flags(sngss7_info); + clear_tx_rsc_flags(sngss7_info); + + clear_tx_rsc_flags(sngss7_info); + sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); + } + /* if there are any resets present */ if (!sngss7_channel_status_clear(sngss7_info)) { /* don't bring up the sig status but also move to reset */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 4a0f6026c7..4a0a331594 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -342,6 +342,8 @@ typedef struct sng_isup_ckt { uint32_t min_digits; uint8_t itx_auto_reply; uint8_t transparent_iam; + uint8_t cpg_on_progress_media; + uint8_t cpg_on_progress; void *obj; uint16_t t3; uint32_t t10; @@ -534,6 +536,7 @@ typedef enum { FLAG_INFID_RESUME = (1 << 14), FLAG_INFID_PAUSED = (1 << 15), FLAG_SENT_ACM = (1 << 16), + FLAG_SENT_CPG = (1 << 17), FLAG_RELAY_DOWN = (1 << 30), FLAG_CKT_RECONFIG = (1 << 31) } sng_ckt_flag_t; @@ -542,14 +545,14 @@ typedef enum { "RX_RSC", \ "TX_RSC", \ "TX_RSC_REQ_SENT", \ - "TX_RSC_RSP_RECIEVED", \ + "TX_RSC_RSP_RECEIVED", \ "RX_GRS", \ "RX_GRS_DONE", \ "RX_GRS_CMPLT", \ "GRS_BASE", \ "TX_GRS", \ "TX_GRS_REQ_SENT", \ - "TX_GRS_RSP_RECIEVED", \ + "TX_GRS_RSP_RECEIVED", \ "REMOTE_REL", \ "LOCAL_REL", \ "GLARE", \ @@ -1058,6 +1061,11 @@ if (ftdmchan->state == new_state) { \ FLAG_GRP_RESET_TX | \ FLAG_GRP_RESET_RX ))) +#define sngss7_tx_reset_status_pending(obj) ((sngss7_test_ckt_flag(obj, (FLAG_RESET_TX)) && \ + sngss7_test_ckt_flag(obj, (FLAG_RESET_SENT))) || \ + (sngss7_test_ckt_flag(obj, (FLAG_GRP_RESET_TX)) && \ + sngss7_test_ckt_flag(obj, (FLAG_GRP_RESET_SENT)))) + #define sngss7_channel_status_clear(obj) ((sngss7_block_status_clear(obj)) && (sngss7_reset_status_clear(obj))) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 8f29c55efe..045c1835ef 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -128,6 +128,8 @@ typedef struct sng_ccSpan uint32_t min_digits; uint8_t itx_auto_reply; uint8_t transparent_iam; + uint8_t cpg_on_progress_media; + uint8_t cpg_on_progress; uint32_t t3; uint32_t t10; uint32_t t12; @@ -1906,6 +1908,14 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) sng_ccSpan.transparent_iam = ftdm_true(parm->val); SS7_DEBUG("Found transparent_iam %d\n", sng_ccSpan.transparent_iam); #endif + } else if (!strcasecmp(parm->var, "cpg_on_progress_media")) { + sng_ccSpan.cpg_on_progress_media = ftdm_true(parm->val); + SS7_DEBUG("Found cpg_on_progress_media %d\n", sng_ccSpan.cpg_on_progress_media); + + } else if (!strcasecmp(parm->var, "cpg_on_progress")) { + sng_ccSpan.cpg_on_progress = ftdm_true(parm->val); + SS7_DEBUG("Found cpg_on_progress_media %d\n", sng_ccSpan.cpg_on_progress); + } else if (!strcasecmp(parm->var, "cicbase")) { /**********************************************************************/ sng_ccSpan.cicbase = atoi(parm->val); @@ -2941,6 +2951,8 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan) g_ftdm_sngss7_data.cfg.isupCkt[x].min_digits = ccSpan->min_digits; g_ftdm_sngss7_data.cfg.isupCkt[x].itx_auto_reply = ccSpan->itx_auto_reply; g_ftdm_sngss7_data.cfg.isupCkt[x].transparent_iam = ccSpan->transparent_iam; + g_ftdm_sngss7_data.cfg.isupCkt[x].cpg_on_progress_media = ccSpan->cpg_on_progress_media; + g_ftdm_sngss7_data.cfg.isupCkt[x].cpg_on_progress = ccSpan->cpg_on_progress; if (ccSpan->t3 == 0) { g_ftdm_sngss7_data.cfg.isupCkt[x].t3 = 1200; From 5dd076c81f8b4506006c38ac6d6a228a5508cec3 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Mon, 7 Nov 2011 00:08:38 -0500 Subject: [PATCH 082/822] freetdm: Allow for backward compatibility. cpg_on_progress_media is default to TRUE if not xml option exists. transparent_iam_max_size added to ccspan. Gloal value is used if transparent_iam_max_size is not in ccSpan. --- .../ftmod_sangoma_ss7_main.h | 3 ++- .../ftmod_sangoma_ss7_support.c | 5 ++-- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 25 ++++++++++++++++--- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 4a0a331594..b25b21f0ef 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -340,10 +340,11 @@ typedef struct sng_isup_ckt { /* END - Generic Number defaults */ uint32_t min_digits; - uint8_t itx_auto_reply; + uint32_t transparent_iam_max_size; uint8_t transparent_iam; uint8_t cpg_on_progress_media; uint8_t cpg_on_progress; + uint8_t itx_auto_reply; void *obj; uint16_t t3; uint32_t t10; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 7b53a18eba..4d81e6b1f4 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -2532,8 +2532,9 @@ ftdm_status_t sngss7_save_iam(ftdm_channel_t *ftdmchan, SiConEvnt *siConEvnt) ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "IAM variable length:%d\n", strlen(url_encoded_iam)); - if (strlen(url_encoded_iam) > g_ftdm_sngss7_data.cfg.transparent_iam_max_size) { - ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "IAM variable length exceeds max size (len:%d max:%d) \n", strlen(url_encoded_iam), g_ftdm_sngss7_data.cfg.transparent_iam_max_size); + if (strlen(url_encoded_iam) > sngss7_info->circuit->transparent_iam_max_size) { + ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "IAM variable length exceeds max size (len:%d max:%d) \n", + strlen(url_encoded_iam), sngss7_info->circuit->transparent_iam_max_size); ret_val = FTDM_FAIL; goto done; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 045c1835ef..2fbd2e5631 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -126,10 +126,11 @@ typedef struct sng_ccSpan uint32_t rdnis_nadi; uint32_t loc_nadi; uint32_t min_digits; - uint8_t itx_auto_reply; + uint32_t transparent_iam_max_size; uint8_t transparent_iam; uint8_t cpg_on_progress_media; uint8_t cpg_on_progress; + uint8_t itx_auto_reply; uint32_t t3; uint32_t t10; uint32_t t12; @@ -194,6 +195,7 @@ static int ftmod_ss7_next_timeslot(char *ch_map, sng_timeslot_t *timeslot); /******************************************************************************/ /* FUNCTIONS ******************************************************************/ + int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *span) { int i = 0; @@ -203,6 +205,7 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa sng_route_t self_route; sng_span_t sngSpan; + /* clean out the isup ckt */ memset(&sngSpan, 0x0, sizeof(sngSpan)); @@ -455,6 +458,9 @@ static int ftmod_ss7_parse_sng_gen(ftdm_conf_node_t *sng_gen) int num_parms = sng_gen->n_parameters; int i = 0; + /* Set the transparent_iam_max_size to default value */ + g_ftdm_sngss7_data.cfg.transparent_iam_max_size=800; + /* extract all the information from the parameters */ for (i = 0; i < num_parms; i++) { /**************************************************************************/ @@ -1855,6 +1861,7 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) /* initalize the ccSpan structure */ memset(&sng_ccSpan, 0x0, sizeof(sng_ccSpan)); + /* confirm that we are looking at an mtp_link */ if (strcasecmp(cc_span->name, "cc_span")) { SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"cc_span\"!\n",cc_span->name); @@ -1863,6 +1870,14 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) SS7_DEBUG("Parsing \"cc_span\"...\n"); } + /* Backward compatible. + * If cpg_on_progress_media is not in the config file + * default the cpg on progress_media to TRUE */ + sng_ccSpan.cpg_on_progress_media=FTDM_TRUE; + /* If transparent_iam_max_size is not set in cc spans + * use the global value */ + sng_ccSpan.transparent_iam_max_size=g_ftdm_sngss7_data.cfg.transparent_iam_max_size; + for (i = 0; i < num_parms; i++) { /**************************************************************************/ @@ -1908,14 +1923,15 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) sng_ccSpan.transparent_iam = ftdm_true(parm->val); SS7_DEBUG("Found transparent_iam %d\n", sng_ccSpan.transparent_iam); #endif + } else if (!strcasecmp(parm->var, "transparent_iam_max_size")) { + sng_ccSpan.transparent_iam_max_size = ftdm_true(parm->val); + SS7_DEBUG("Found transparent_iam_max_size %d\n", sng_ccSpan.transparent_iam_max_size); } else if (!strcasecmp(parm->var, "cpg_on_progress_media")) { sng_ccSpan.cpg_on_progress_media = ftdm_true(parm->val); SS7_DEBUG("Found cpg_on_progress_media %d\n", sng_ccSpan.cpg_on_progress_media); - } else if (!strcasecmp(parm->var, "cpg_on_progress")) { sng_ccSpan.cpg_on_progress = ftdm_true(parm->val); - SS7_DEBUG("Found cpg_on_progress_media %d\n", sng_ccSpan.cpg_on_progress); - + SS7_DEBUG("Found cpg_on_progress %d\n", sng_ccSpan.cpg_on_progress); } else if (!strcasecmp(parm->var, "cicbase")) { /**********************************************************************/ sng_ccSpan.cicbase = atoi(parm->val); @@ -2951,6 +2967,7 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan) g_ftdm_sngss7_data.cfg.isupCkt[x].min_digits = ccSpan->min_digits; g_ftdm_sngss7_data.cfg.isupCkt[x].itx_auto_reply = ccSpan->itx_auto_reply; g_ftdm_sngss7_data.cfg.isupCkt[x].transparent_iam = ccSpan->transparent_iam; + g_ftdm_sngss7_data.cfg.isupCkt[x].transparent_iam_max_size = ccSpan->transparent_iam_max_size; g_ftdm_sngss7_data.cfg.isupCkt[x].cpg_on_progress_media = ccSpan->cpg_on_progress_media; g_ftdm_sngss7_data.cfg.isupCkt[x].cpg_on_progress = ccSpan->cpg_on_progress; From 3552e329ca7b7477e862bb4c09b4edfe59c26373 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 7 Nov 2011 12:53:32 -0500 Subject: [PATCH 083/822] freetdm: fix sip header wrong value of NADI error was caused by printing string value to integer --- libs/freetdm/mod_freetdm/mod_freetdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index ae167ccef2..ba0389a1cc 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1710,7 +1710,7 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_clg_nadi"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-NADI", "%d", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-NADI", "%s", var_value); } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdnis_screen_ind"); From f0631fc87e9261819449195b309888485e93bd9d Mon Sep 17 00:00:00 2001 From: root Date: Mon, 7 Nov 2011 16:37:11 -0500 Subject: [PATCH 084/822] freetdm: change call reference number to HEX string format --- libs/freetdm/mod_freetdm/mod_freetdm.c | 6 +++++- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c | 7 +++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index ba0389a1cc..866fb74bec 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1770,7 +1770,11 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-Screen", "%d", channel_caller_data->screen); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-Presentation", "%d", channel_caller_data->pres); - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-CallReference", "%d", channel_caller_data->call_reference); + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_callref"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-CallReference", "%s", var_value); + } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_opc"); if (!ftdm_strlen_zero(var_value)) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 0f3515097b..f351d8ab8d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -252,10 +252,9 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_add_var(sngss7_info, "ss7_opc", var); if (siConEvnt->callRef.callId.pres) { - ftdmchan->caller_data.call_reference = (unsigned int)siConEvnt->callRef.callId.val; - } else { - ftdmchan->caller_data.call_reference = 0; - } + sprintf(var, "%x", siConEvnt->callRef.callId.val); + sngss7_add_var(sngss7_info, "ss7_callref", var); + } if (sngss7_info->circuit->transparent_iam) { sngss7_save_iam(ftdmchan, siConEvnt); From 08e01bb5a202082295e19f98333a42e1456797cf Mon Sep 17 00:00:00 2001 From: root Date: Mon, 7 Nov 2011 17:32:02 -0500 Subject: [PATCH 085/822] freetdm: fix generic number --- libs/freetdm/mod_freetdm/mod_freetdm.c | 14 +++++++------- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 866fb74bec..be55d2b7ff 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1725,36 +1725,36 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_gn_digits"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN", "%d", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN", "%s", var_value); var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_gn_numqual"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-NumQual", "%d", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-NumQual", "%s", var_value); } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_gn_nadi"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-NADI", "%d", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-NADI", "%s", var_value); } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_gn_screen_ind"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-Screen", "%d", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-Screen", "%s", var_value); } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_gn_pres_ind"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-Presentation", "%d", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-Presentation", "%s", var_value); } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_gn_npi"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-Plan", "%d", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-Plan", "%s", var_value); } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_gn_num_inc_ind"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-NumInComp", "%d", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-NumInComp", "%s", var_value); } } /* End - var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_gn_digits"); */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 4d81e6b1f4..aa50ce2264 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -375,7 +375,7 @@ ftdm_status_t copy_genNmb_from_sngss7(ftdm_channel_t *ftdmchan, SiGenNum *genNmb if (genNmb->nmbQual.pres == PRSNT_NODEF) { snprintf(val, sizeof(val), "%d", genNmb->nmbQual.val); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Generic Number \"number qualifier\" \n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Generic Number \"number qualifier\" \"%s\" \n", val); sngss7_add_var(sngss7_info, "ss7_gn_numqual", val); } From 5c4a3f81a2e5c2077eb5949dfbc54101a17d3bdc Mon Sep 17 00:00:00 2001 From: wadam Date: Mon, 7 Nov 2011 22:26:02 -0500 Subject: [PATCH 086/822] Fix error in call reference conversion to string. src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c cc1: warnings being treated as errors src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c: In function 'handle_con_ind': src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c:255: warning: format '%x' expects type 'unsigned int', but argument 3 has type 'U32' make[6]: *** [ftmod_sangoma_ss7_la-ftmod_sangoma_ss7_handle.lo] Error 1 --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index f351d8ab8d..25967e5977 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -252,7 +252,9 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_add_var(sngss7_info, "ss7_opc", var); if (siConEvnt->callRef.callId.pres) { - sprintf(var, "%x", siConEvnt->callRef.callId.val); + /* %x expect an unsigned int so as callId is a U32, casting to uint32_t + * is safe */ + sprintf(var, "%x", (uint32_t)siConEvnt->callRef.callId.val); sngss7_add_var(sngss7_info, "ss7_callref", var); } From dcdb5f18eb017d52dc556a62b956d1d397482591 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Mon, 14 Nov 2011 16:42:23 -0500 Subject: [PATCH 087/822] freetdm: fixing RDNIS-Screen value mis-displaying string in decimal format --- libs/freetdm/mod_freetdm/mod_freetdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index be55d2b7ff..b2df0e40ac 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1715,7 +1715,7 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdnis_screen_ind"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-Screen", "%d", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-Screen", "%s", var_value); } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdnis_pres_ind"); From 552405024afbc40ecf57c97052f13aa37c759f39 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Tue, 15 Nov 2011 14:46:57 -0500 Subject: [PATCH 088/822] freetdm: fixing relay must start after master. relay - configuring circuits only when resume is recieved. master - configuring relay after all the others are configured. --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c | 322 +++++++++--------- .../ftmod_sangoma_ss7_logger.c | 5 + .../ftmod_sangoma_ss7_main.c | 22 +- .../ftmod_sangoma_ss7_support.c | 1 + 4 files changed, 189 insertions(+), 161 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c index e51428acaa..25510e8c7a 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c @@ -220,27 +220,6 @@ int ft_to_sngss7_cfg_all(void) return 1; } - /* go through all the relays channels and configure it */ - x = 1; - while (x < (MAX_RELAY_CHANNELS)) { - /* check if this relay channel has been configured already */ - if ((g_ftdm_sngss7_data.cfg.relay[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.relay[x].flags & SNGSS7_CONFIGURED))) { - - /* send the specific configuration */ - if (ftmod_ss7_relay_chan_config(x)) { - SS7_CRITICAL("Relay Channel %d configuration FAILED!\n", x); - return 1; - } else { - SS7_INFO("Relay Channel %d configuration DONE!\n", x); - } - - /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.relay[x].flags |= SNGSS7_CONFIGURED; - } /* if !SNGSS7_CONFIGURED */ - x++; - } /* while (x < (MAX_RELAY_CHANNELS)) */ - x = 1; while (x < (MAX_MTP_LINKS)) { /* check if this link has been configured already */ @@ -281,160 +260,189 @@ int ft_to_sngss7_cfg_all(void) x++; } /* while (x < (MAX_MTP_LINKS+1)) */ - x = 1; - while (x < (MAX_MTP_LINKS)) { - /* check if this link has been configured already */ - if ((g_ftdm_sngss7_data.cfg.mtp3Link[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.mtp3Link[x].flags & SNGSS7_CONFIGURED))) { - - /* configure mtp3 */ - if (ftmod_ss7_mtp3_dlsap_config(x)) { - SS7_CRITICAL("MTP3 DLSAP %d configuration FAILED!\n", x); - return 1;; - } else { - SS7_INFO("MTP3 DLSAP %d configuration DONE!\n", x); - } - - /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.mtp3Link[x].flags |= SNGSS7_CONFIGURED; - } - - x++; - } /* while (x < (MAX_MTP_LINKS+1)) */ - - x = 1; - while (x < (MAX_NSAPS)) { - /* check if this link has been configured already */ - if ((g_ftdm_sngss7_data.cfg.nsap[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.nsap[x].flags & SNGSS7_CONFIGURED))) { - - ret = ftmod_ss7_mtp3_nsap_config(x); - if (ret) { - SS7_CRITICAL("MTP3 NSAP %d configuration FAILED!(%s)\n", x, DECODE_LCM_REASON(ret)); - return 1; - } else { - SS7_INFO("MTP3 NSAP %d configuration DONE!\n", x); - } - - ret = ftmod_ss7_isup_nsap_config(x); - if (ret) { - SS7_CRITICAL("ISUP NSAP %d configuration FAILED!(%s)\n", x, DECODE_LCM_REASON(ret)); - return 1; - } else { - SS7_INFO("ISUP NSAP %d configuration DONE!\n", x); - } - - /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.nsap[x].flags |= SNGSS7_CONFIGURED; - } /* if !SNGSS7_CONFIGURED */ - - x++; - } /* while (x < (MAX_NSAPS)) */ - - x = 1; - while (x < (MAX_MTP_LINKSETS+1)) { - /* check if this link has been configured already */ - if ((g_ftdm_sngss7_data.cfg.mtpLinkSet[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags & SNGSS7_CONFIGURED))) { - - if (ftmod_ss7_mtp3_linkset_config(x)) { - SS7_CRITICAL("MTP3 LINKSET %d configuration FAILED!\n", x); - return 1; - } else { - SS7_INFO("MTP3 LINKSET %d configuration DONE!\n", x); - } - - /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags |= SNGSS7_CONFIGURED; - } /* if !SNGSS7_CONFIGURED */ - - x++; - } /* while (x < (MAX_MTP_LINKSETS+1)) */ - - x = 1; - while (x < (MAX_MTP_ROUTES+1)) { - /* check if this link has been configured already */ - if ((g_ftdm_sngss7_data.cfg.mtpRoute[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.mtpRoute[x].flags & SNGSS7_CONFIGURED))) { - - if (ftmod_ss7_mtp3_route_config(x)) { - SS7_CRITICAL("MTP3 ROUTE %d configuration FAILED!\n", x); - return 1; - } else { - SS7_INFO("MTP3 ROUTE %d configuration DONE!\n",x); - } - - /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.mtpRoute[x].flags |= SNGSS7_CONFIGURED; - } /* if !SNGSS7_CONFIGURED */ - - x++; - } /* while (x < (MAX_MTP_ROUTES+1)) */ - - x = 1; - while (x < (MAX_ISAPS)) { - /* check if this link has been configured already */ - if ((g_ftdm_sngss7_data.cfg.isap[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.isap[x].flags & SNGSS7_CONFIGURED))) { - - if (ftmod_ss7_isup_isap_config(x)) { - SS7_CRITICAL("ISUP ISAP %d configuration FAILED!\n", x); - return 1; - } else { - SS7_INFO("ISUP ISAP %d configuration DONE!\n", x); - } - - /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.isap[x].flags |= SNGSS7_CONFIGURED; - } /* if !SNGSS7_CONFIGURED */ - - x++; - } /* while (x < (MAX_ISAPS)) */ - - if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP_STARTED)) { + /* no configs above mtp2 for relay */ + if (g_ftdm_sngss7_data.cfg.procId == 1) { x = 1; - while (x < (MAX_ISUP_INFS)) { + while (x < (MAX_MTP_LINKS)) { /* check if this link has been configured already */ - if ((g_ftdm_sngss7_data.cfg.isupIntf[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.isupIntf[x].flags & SNGSS7_CONFIGURED))) { - - if (ftmod_ss7_isup_intf_config(x)) { - SS7_CRITICAL("ISUP INTF %d configuration FAILED!\n", x); + if ((g_ftdm_sngss7_data.cfg.mtp3Link[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.mtp3Link[x].flags & SNGSS7_CONFIGURED))) { + + /* configure mtp3 */ + if (ftmod_ss7_mtp3_dlsap_config(x)) { + SS7_CRITICAL("MTP3 DLSAP %d configuration FAILED!\n", x); + return 1;; + } else { + SS7_INFO("MTP3 DLSAP %d configuration DONE!\n", x); + } + + /* set the SNGSS7_CONFIGURED flag */ + g_ftdm_sngss7_data.cfg.mtp3Link[x].flags |= SNGSS7_CONFIGURED; + } + + x++; + } /* while (x < (MAX_MTP_LINKS+1)) */ + + x = 1; + while (x < (MAX_NSAPS)) { + /* check if this link has been configured already */ + if ((g_ftdm_sngss7_data.cfg.nsap[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.nsap[x].flags & SNGSS7_CONFIGURED))) { + + ret = ftmod_ss7_mtp3_nsap_config(x); + if (ret) { + SS7_CRITICAL("MTP3 NSAP %d configuration FAILED!(%s)\n", x, DECODE_LCM_REASON(ret)); return 1; } else { - SS7_INFO("ISUP INTF %d configuration DONE!\n", x); - /* set the interface to paused */ - sngss7_set_flag(&g_ftdm_sngss7_data.cfg.isupIntf[x], SNGSS7_PAUSED); + SS7_INFO("MTP3 NSAP %d configuration DONE!\n", x); } - + + ret = ftmod_ss7_isup_nsap_config(x); + if (ret) { + SS7_CRITICAL("ISUP NSAP %d configuration FAILED!(%s)\n", x, DECODE_LCM_REASON(ret)); + return 1; + } else { + SS7_INFO("ISUP NSAP %d configuration DONE!\n", x); + } + /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.isupIntf[x].flags |= SNGSS7_CONFIGURED; + g_ftdm_sngss7_data.cfg.nsap[x].flags |= SNGSS7_CONFIGURED; } /* if !SNGSS7_CONFIGURED */ x++; - } /* while (x < (MAX_ISUP_INFS)) */ - } /* if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP)) */ + } /* while (x < (MAX_NSAPS)) */ - x = (g_ftdm_sngss7_data.cfg.procId * 1000) + 1; - while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) { - /* check if this link has been configured already */ - if ((g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.isupCkt[x].flags & SNGSS7_CONFIGURED))) { + x = 1; + while (x < (MAX_MTP_LINKSETS+1)) { + /* check if this link has been configured already */ + if ((g_ftdm_sngss7_data.cfg.mtpLinkSet[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags & SNGSS7_CONFIGURED))) { - if (ftmod_ss7_isup_ckt_config(x)) { - SS7_CRITICAL("ISUP CKT %d configuration FAILED!\n", x); + if (ftmod_ss7_mtp3_linkset_config(x)) { + SS7_CRITICAL("MTP3 LINKSET %d configuration FAILED!\n", x); + return 1; + } else { + SS7_INFO("MTP3 LINKSET %d configuration DONE!\n", x); + } + + /* set the SNGSS7_CONFIGURED flag */ + g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags |= SNGSS7_CONFIGURED; + } /* if !SNGSS7_CONFIGURED */ + + x++; + } /* while (x < (MAX_MTP_LINKSETS+1)) */ + + x = 1; + while (x < (MAX_MTP_ROUTES+1)) { + /* check if this link has been configured already */ + if ((g_ftdm_sngss7_data.cfg.mtpRoute[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.mtpRoute[x].flags & SNGSS7_CONFIGURED))) { + + if (ftmod_ss7_mtp3_route_config(x)) { + SS7_CRITICAL("MTP3 ROUTE %d configuration FAILED!\n", x); + return 1; + } else { + SS7_INFO("MTP3 ROUTE %d configuration DONE!\n",x); + } + + /* set the SNGSS7_CONFIGURED flag */ + g_ftdm_sngss7_data.cfg.mtpRoute[x].flags |= SNGSS7_CONFIGURED; + } /* if !SNGSS7_CONFIGURED */ + + x++; + } /* while (x < (MAX_MTP_ROUTES+1)) */ + + x = 1; + while (x < (MAX_ISAPS)) { + /* check if this link has been configured already */ + if ((g_ftdm_sngss7_data.cfg.isap[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.isap[x].flags & SNGSS7_CONFIGURED))) { + + if (ftmod_ss7_isup_isap_config(x)) { + SS7_CRITICAL("ISUP ISAP %d configuration FAILED!\n", x); + return 1; + } else { + SS7_INFO("ISUP ISAP %d configuration DONE!\n", x); + } + + /* set the SNGSS7_CONFIGURED flag */ + g_ftdm_sngss7_data.cfg.isap[x].flags |= SNGSS7_CONFIGURED; + } /* if !SNGSS7_CONFIGURED */ + + x++; + } /* while (x < (MAX_ISAPS)) */ + + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP_STARTED)) { + x = 1; + while (x < (MAX_ISUP_INFS)) { + /* check if this link has been configured already */ + if ((g_ftdm_sngss7_data.cfg.isupIntf[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.isupIntf[x].flags & SNGSS7_CONFIGURED))) { + + if (ftmod_ss7_isup_intf_config(x)) { + SS7_CRITICAL("ISUP INTF %d configuration FAILED!\n", x); + return 1; + } else { + SS7_INFO("ISUP INTF %d configuration DONE!\n", x); + /* set the interface to paused */ + sngss7_set_flag(&g_ftdm_sngss7_data.cfg.isupIntf[x], SNGSS7_PAUSED); + } + + /* set the SNGSS7_CONFIGURED flag */ + g_ftdm_sngss7_data.cfg.isupIntf[x].flags |= SNGSS7_CONFIGURED; + } /* if !SNGSS7_CONFIGURED */ + + x++; + } /* while (x < (MAX_ISUP_INFS)) */ + } /* if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP)) */ + + x = (g_ftdm_sngss7_data.cfg.procId * 1000) + 1; + while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) { + + if (g_ftdm_sngss7_data.cfg.procId > 1) { + break; + } + + /* check if this link has been configured already */ + if ((g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.isupCkt[x].flags & SNGSS7_CONFIGURED))) { + + if (ftmod_ss7_isup_ckt_config(x)) { + SS7_CRITICAL("ISUP CKT %d configuration FAILED!\n", x); + return 1; + } else { + SS7_INFO("ISUP CKT %d configuration DONE!\n", x); + } + + /* set the SNGSS7_CONFIGURED flag */ + g_ftdm_sngss7_data.cfg.isupCkt[x].flags |= SNGSS7_CONFIGURED; + } /* if !SNGSS7_CONFIGURED */ + + x++; + } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) */ + } + + /* go through all the relays channels and configure it */ + x = 1; + while (x < (MAX_RELAY_CHANNELS)) { + /* check if this relay channel has been configured already */ + if ((g_ftdm_sngss7_data.cfg.relay[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.relay[x].flags & SNGSS7_CONFIGURED))) { + + /* send the specific configuration */ + if (ftmod_ss7_relay_chan_config(x)) { + SS7_CRITICAL("Relay Channel %d configuration FAILED!\n", x); return 1; } else { - SS7_INFO("ISUP CKT %d configuration DONE!\n", x); + SS7_INFO("Relay Channel %d configuration DONE!\n", x); } /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.isupCkt[x].flags |= SNGSS7_CONFIGURED; + g_ftdm_sngss7_data.cfg.relay[x].flags |= SNGSS7_CONFIGURED; } /* if !SNGSS7_CONFIGURED */ - x++; - } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) */ - + } /* while (x < (MAX_RELAY_CHANNELS)) */ + return 0; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c index 790b893a8d..176de9e627 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c @@ -810,6 +810,11 @@ void handle_sng_relay_alarm(Pst *pst, RyMngmt *sta) break; /**************************************************************************/ + case (LRY_USTA_TCP_CONN_FAILED): + ftdm_log(FTDM_LOG_ERROR,"[RELAY] TCP connection failed \n" ); + + break; + /**************************************************************************/ default: ftdm_log(FTDM_LOG_ERROR,"Unknown Relay Alram\n"); break; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index cd7f3ad58e..93d76fc8e7 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1166,10 +1166,24 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /**************************************************************************/ case FTDM_CHANNEL_STATE_SUSPENDED: /* circuit has been blocked */ - SS7_DEBUG_CHAN(ftdmchan,"SUSPEND: Current flags: ckt=0x%X, blk=0x%X\n", - sngss7_info->ckt_flags, - sngss7_info->blk_flags); - + SS7_DEBUG_CHAN(ftdmchan,"SUSPEND: Current flags: ckt=0x%X, blk=0x%X, circuit->flag=0x%X\n", + sngss7_info->ckt_flags, sngss7_info->blk_flags, + sngss7_info->circuit->flags ); + + if (!(sngss7_info->circuit->flags & SNGSS7_CONFIGURED)) { + if ( !sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_PAUSED) + ||(sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_RESUME))) { + if (ftmod_ss7_isup_ckt_config(sngss7_info->circuit->id)) { + SS7_CRITICAL("ISUP CKT %d configuration FAILED!\n", sngss7_info->circuit->id); + *(int*)0=0; + return 1; + } else { + SS7_INFO("ISUP CKT %d configuration DONE!\n", sngss7_info->circuit->id); + } + sngss7_info->circuit->flags |= SNGSS7_CONFIGURED; + } + } + /**********************************************************************/ if (sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_RESUME)) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index aa50ce2264..4f18459018 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -1943,6 +1943,7 @@ ftdm_status_t check_status_of_all_isup_intf(void) if (ftmod_ss7_isup_intf_sta(sngss7_intf->id, &status)) { SS7_ERROR("Failed to get status of ISUP intf %d\n", sngss7_intf->id); + sngss7_set_flag(sngss7_intf, SNGSS7_PAUSED); continue; } From e293c1253583a97a5e6b3358213bfb62f88eadf2 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Tue, 15 Nov 2011 18:26:13 -0500 Subject: [PATCH 089/822] freetdm: fix loc_nadi value --- libs/freetdm/mod_freetdm/mod_freetdm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index b2df0e40ac..2d946f3c59 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1796,7 +1796,8 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-LOC-Presentation", "%s", var_value); } - var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_loc_pres_nadi"); + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_loc_nadi"); + printf ( "ss7_loc_nadi = %s \n " , var_value ); if (!ftdm_strlen_zero(var_value)) { switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-LOC-NADI", "%s", var_value); } From cb1d5be5e6ce84a89c00026b97c64bbadee9362f Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 17 Nov 2011 15:43:40 -0500 Subject: [PATCH 090/822] freetdm: fix redirection presentation number in X-header --- libs/freetdm/mod_freetdm/mod_freetdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 2d946f3c59..c9daadac12 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1720,7 +1720,7 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdnis_pres_ind"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-Presentation", "%d", channel_caller_data->rdnis.plan); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-Presentation", "%s", var_value); } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_gn_digits"); From 69c62f7b388ceaae3d16ff2d26b5f0d94e119a06 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Thu, 24 Nov 2011 19:19:58 -0500 Subject: [PATCH 091/822] Fixed the out of sequence frame condition Redmine Bug#1966 IAM -> <-REL <-ACM <-ANM ACM sets the reset flag ANM sets the group reset flag when both reset flags are set we got into infinite loop --- .../ftmod_sangoma_ss7_handle.c | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 25967e5977..cacbf15170 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -322,12 +322,14 @@ handle_glare: default: /* should not have gotten an IAM while in this state */ SS7_ERROR_CHAN(ftdmchan, "Got IAM on channel in invalid state(%s)...reset!\n", ftdm_channel_state2str (ftdmchan->state)); - /* reset the cic */ - sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); - - /* move the state of the channel to RESTART to force a reset */ - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + /* throw the TX reset flag */ + if (!sngss7_tx_reset_status_pending(sngss7_info)) { + sngss7_info->ckt_flags=0; + sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); + /* go to RESTART */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + } break; /**************************************************************************/ } /* switch (ftdmchan->state) */ @@ -393,11 +395,14 @@ ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circ SS7_ERROR_CHAN(ftdmchan, "RX ACM in invalid state :%s...resetting CIC\n", ftdm_channel_state2str (ftdmchan->state)); - /* reset the cic */ - sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); + /* throw the TX reset flag */ + if (!sngss7_tx_reset_status_pending(sngss7_info)) { + sngss7_info->ckt_flags=0; + sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); - /* go to RESTART */ - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + /* go to RESTART */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + } break; /**********************************************************************/ } /* switch (ftdmchan->state) */ @@ -657,10 +662,13 @@ ftdm_status_t handle_con_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circ SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx ANM/CON\n", sngss7_info->circuit->cic); /* throw the TX reset flag */ - sngss7_set_ckt_flag(sngss7_info, FLAG_GRP_RESET_TX); + if (!sngss7_tx_reset_status_pending(sngss7_info)) { + sngss7_info->ckt_flags=0; + sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); - /* go to RESTART */ - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + /* go to RESTART */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + } break; /**************************************************************************/ From 5b8af78a897ea2716da18e5be913eca71e72f7f1 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Fri, 25 Nov 2011 21:05:39 -0500 Subject: [PATCH 092/822] Fixed 5 relay conditions M UP -> S UP M Down -> S UP -> M UP M UP -> S UP -> relay down -> relay up M UP -> S UP -> Kill M -> M UP M Up -> S UP -> relay down -> M link down -> relay up -> M link up --- .../ftmod_sangoma_ss7_main.c | 15 ++++++++------ .../ftmod_sangoma_ss7_relay.c | 8 +++----- .../ftmod_sangoma_ss7_support.c | 20 ++++++++++++++++--- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 93d76fc8e7..468c8b0a83 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1171,16 +1171,19 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_info->circuit->flags ); if (!(sngss7_info->circuit->flags & SNGSS7_CONFIGURED)) { - if ( !sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_PAUSED) - ||(sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_RESUME))) { + /* Configure the circuit if RESUME and PAUSED are not set. + And also in a case when RESUME is set */ + if (!sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_PAUSED) || + sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_RESUME)) { if (ftmod_ss7_isup_ckt_config(sngss7_info->circuit->id)) { SS7_CRITICAL("ISUP CKT %d configuration FAILED!\n", sngss7_info->circuit->id); - *(int*)0=0; - return 1; + sngss7_set_ckt_flag(sngss7_info, FLAG_INFID_PAUSED); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INFID_RESUME); } else { SS7_INFO("ISUP CKT %d configuration DONE!\n", sngss7_info->circuit->id); + sngss7_info->circuit->flags |= SNGSS7_CONFIGURED; + sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); } - sngss7_info->circuit->flags |= SNGSS7_CONFIGURED; } } @@ -1391,7 +1394,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* check the last state and return to it to allow the call to finish */ goto suspend_goto_last; } - + if (sngss7_test_ckt_blk_flag (sngss7_info, FLAG_CKT_MN_UNBLK_TX)) { SS7_DEBUG_CHAN(ftdmchan, "Processing CKT_MN_UNBLK_TX flag %s\n", ""); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c index a96dae5cdd..0fb496843f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c @@ -64,11 +64,9 @@ ftdm_status_t handle_relay_connect(RyMngmt *sta) SS7_INFO("Relay Channel %d connection UP\n", sng_relay->id); if (sng_relay->type == LRY_CT_TCP_CLIENT) { - if (!sngss7_test_flag(sng_relay, SNGSS7_RELAY_INIT)) { - if (reconfig_all_ckts_for_relay()) { - SS7_ERROR("Failed to reconfigure ISUP Ckts!\n"); - /* we're done....this is very bad! */ - } + if (reconfig_all_ckts_for_relay()) { + SS7_ERROR("Failed to reconfigure ISUP Ckts!\n"); + /* we're done....this is very bad! */ } return FTDM_SUCCESS; } else if (sng_relay->type == LRY_CT_TCP_SERVER) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 4f18459018..6d5880073d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -2110,6 +2110,7 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) uint8_t bits_ef = 0; int x; int ret; + ret=0; for (x = 1; x < (ftdmspan->chan_count + 1); x++) { /**************************************************************************/ @@ -2147,6 +2148,10 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) /* query for the status of the ckt */ if (ftmod_ss7_isup_ckt_sta(sngss7_info->circuit->id, &state)) { + /* NC: Circuit statistic failed: does not exist. Must re-configure circuit + Reset the circuit CONFIGURED flag so that RESUME will reconfigure + this circuit. */ + sngss7_info->circuit->flags &= ~SNGSS7_CONFIGURED; SS7_ERROR("Failed to read isup ckt = %d status\n", sngss7_info->circuit->id); continue; } @@ -2159,6 +2164,14 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) if (bits_cd == 0x0) { /* check if circuit is UCIC or transient */ if (bits_ab == 0x3) { + SS7_INFO("ISUP CKT %d re-configuration pending!\n", x); + sngss7_info->circuit->flags &= ~SNGSS7_CONFIGURED; + SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + + /* NC: The code below should be deleted. Its here for hitorical + reason. The RESUME code will reconfigure the channel since + the CONFIGURED flag has been reset */ +#if 0 /* bit a and bit b are set, unequipped */ ret = ftmod_ss7_isup_ckt_config(sngss7_info->circuit->id); if (ret) { @@ -2181,6 +2194,7 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) /* unlock the channel */ ftdm_mutex_unlock(ftdmchan->mutex); +#endif } /* if (bits_ab == 0x3) */ } else { @@ -2192,8 +2206,8 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) break; /**************************************************************************/ case (1): - /* locally blocked */ - sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX); + /* locally blocked: Therefore we need to state machine to send an unblock */ + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_UNBLK_TX); /* set the channel to suspended state */ SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); @@ -2209,7 +2223,7 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) /**************************************************************************/ case (3): /* both locally and remotely blocked */ - sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX); + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_UNBLK_TX); sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); /* set the channel to suspended state */ From 96068d901de9a0250762e39faa53e2908950c103 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Tue, 29 Nov 2011 13:11:38 -0500 Subject: [PATCH 093/822] Fixed case S UP - Place Call - relay down - Hangup - relay up - Confirm Call hangsup up properly and unblock is set. Fixed unexpeced reset condidtions. --- .../ftmod_sangoma_ss7_handle.c | 16 ++++++-- .../ftmod_sangoma_ss7_main.c | 9 ++++- .../ftmod_sangoma_ss7_support.c | 39 ++++++++++++++----- 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index cacbf15170..e61dc9426e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -325,6 +325,7 @@ handle_glare: /* throw the TX reset flag */ if (!sngss7_tx_reset_status_pending(sngss7_info)) { sngss7_info->ckt_flags=0; + sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); /* go to RESTART */ @@ -398,6 +399,7 @@ ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* throw the TX reset flag */ if (!sngss7_tx_reset_status_pending(sngss7_info)) { sngss7_info->ckt_flags=0; + sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); /* go to RESTART */ @@ -664,6 +666,7 @@ ftdm_status_t handle_con_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* throw the TX reset flag */ if (!sngss7_tx_reset_status_pending(sngss7_info)) { sngss7_info->ckt_flags=0; + sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); /* go to RESTART */ @@ -788,11 +791,15 @@ ftdm_status_t handle_rel_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ /**************************************************************************/ default: - /* throw the reset flag */ - sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_RX); + /* throw the TX reset flag */ + if (!sngss7_tx_reset_status_pending(sngss7_info)) { + sngss7_info->ckt_flags=0; + sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); + sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); - /* set the state to RESTART */ - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + /* go to RESTART */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + } break; /**************************************************************************/ } /* switch (ftdmchan->state) */ @@ -1836,6 +1843,7 @@ ftdm_status_t handle_rsc_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ default: /* set the state of the channel to restart...the rest is done by the chan monitor */ + sngss7_set_ckt_flag(sngss7_info, FLAG_REMOTE_REL); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); break; /**************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 468c8b0a83..7350a478ef 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -588,7 +588,11 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) int state_flag = 1; int i = 0; - SS7_DEBUG_CHAN(ftdmchan, "ftmod_sangoma_ss7 processing state %s\n", ftdm_channel_state2str (ftdmchan->state)); + SS7_DEBUG_CHAN(ftdmchan, "ftmod_sangoma_ss7 processing state %s: ckt=0x%X, blk=0x%X\n", + ftdm_channel_state2str (ftdmchan->state), + sngss7_info->ckt_flags, + sngss7_info->blk_flags); + /*check what state we are supposed to be in */ switch (ftdmchan->state) { @@ -863,6 +867,9 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) } if (sngss7_test_ckt_flag (sngss7_info, FLAG_REMOTE_REL)) { + + sngss7_clear_ckt_flag (sngss7_info, FLAG_LOCAL_REL); + /* check if this hangup is from a tx RSC */ if (sngss7_test_ckt_flag (sngss7_info, FLAG_RESET_TX)) { if (!sngss7_test_ckt_flag(sngss7_info, FLAG_RESET_SENT)) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 6d5880073d..47fdd47728 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -2135,12 +2135,12 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) /* check if the interface is paused or resumed */ if (sngss7_test_flag(sngss7_intf, SNGSS7_PAUSED)) { - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "ISUP intf %d is PAUSED\n", sngss7_intf->id); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Circuit set to PAUSED %s\n"," "); /* throw the pause flag */ sngss7_clear_ckt_flag(sngss7_info, FLAG_INFID_RESUME); sngss7_set_ckt_flag(sngss7_info, FLAG_INFID_PAUSED); } else { - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "ISUP intf %d is RESUMED\n", sngss7_intf->id); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Circuit set to RESUMED %s\n"," "); /* throw the resume flag */ sngss7_clear_ckt_flag(sngss7_info, FLAG_INFID_PAUSED); sngss7_set_ckt_flag(sngss7_info, FLAG_INFID_RESUME); @@ -2152,7 +2152,7 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) Reset the circuit CONFIGURED flag so that RESUME will reconfigure this circuit. */ sngss7_info->circuit->flags &= ~SNGSS7_CONFIGURED; - SS7_ERROR("Failed to read isup ckt = %d status\n", sngss7_info->circuit->id); + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR,"Failed to read isup ckt = %d status\n", sngss7_info->circuit->id); continue; } @@ -2160,6 +2160,8 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) bits_ab = (state & (SNG_BIT_A + SNG_BIT_B)) >> 0; bits_cd = (state & (SNG_BIT_C + SNG_BIT_D)) >> 2; bits_ef = (state & (SNG_BIT_E + SNG_BIT_F)) >> 4; + + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Circuit state=0x%X ab=0x%X cd=0x%X ef=0x%X\n",state,bits_ab,bits_cd,bits_ef); if (bits_cd == 0x0) { /* check if circuit is UCIC or transient */ @@ -2196,7 +2198,20 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) ftdm_mutex_unlock(ftdmchan->mutex); #endif - } /* if (bits_ab == 0x3) */ + } else { /* if (bits_ab == 0x3) */ + /* The stack status is not blocked. However this is possible if + the circuit state was UP. So even though Master sent out the BLO + the status command is not showing it. + + As a kudge. We will try to send out an UBL even though the status + indicates that there is no BLO. */ + if (!sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX)) { + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_UNBLK_TX); + + /* set the channel to suspended state */ + SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + } + } } else { /* check the maintenance block status in bits A and B */ switch (bits_ab) { @@ -2206,11 +2221,17 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) break; /**************************************************************************/ case (1): - /* locally blocked: Therefore we need to state machine to send an unblock */ - sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_UNBLK_TX); + /* The stack status is Blocked. Check if the block was sent + by user via console. If the block was not sent by user then, it + was sent out by Master due to relay down. + Therefore send out the unblock to clear it */ + if (!sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX)) { + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_UNBLK_TX); + + /* set the channel to suspended state */ + SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + } - /* set the channel to suspended state */ - SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); break; /**************************************************************************/ case (2): @@ -2276,7 +2297,7 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) /* clear the re-config flag ... no matter what */ sngss7_clear_ckt_flag(sngss7_info, FLAG_CKT_RECONFIG); - } /* if ((sngss7_test_ckt_flag(sngss7_info, FLAG_CKT_RECONFIG)) */ + } } /* for (x = 1; x < (span->chan_count + 1); x++) */ return FTDM_SUCCESS; From fa64d3954d0eac9667c63d992fac6b4364e8c912 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Wed, 30 Nov 2011 19:11:33 -0500 Subject: [PATCH 094/822] Sigificant changes to the core state machine :) Visually status of channels will only be DOWN once all resets/blocks are cleared. Therefore if any reset/block is active on a channel, the channel state will be in RESTART not DOWN. Logic Change SUSPENDED -> Originally used as intermediate state. Purpose is to handle a condition from any state and go back to the previous state. Conditions: such as block/ucic. -> Updated logic is that SUSPEND will be smart enough not to go back to just any state. SUSPEND will only go back to UP - if call is still up RESTART - if for any reason singaling is not up due to blocks/resets/etc... DOWN - if signaling is UP - no resets/blocks In this case we avoid infinite loops due to state jumping from STATE->SUSPEND->STATE->SUSPEND HANGUP_COMPLETE -> If call is in use and a RESET comes on a call the RESTART state will first try the HANGUP_COMPLETE state. HANGUP_COMPLETE will Tx RSC and wait for it. Reset Response handle was updated if current state HANGUP/HANGUP_COMPLETE go back to RESTART state. Which will call HANGUP COMPLETE due to channel in usage and HANDLE_COMPLETE will clear RESET condition and go back to DOWN TERMINATING -> This state is used to hangup a call. Sends a signal to FS. -> Usually TERMINATING state stays in TERMINATING until FS comes back. -> I added a condition in case of RESET on the line though TERMINATING will go back to RESTART. This allows us to process RESET commands even though we are in the middle of hanging up. Block Handler If BLO is received on circuit is already blocked, we failed to trasmit BLA. We should always ack the BLO even though it was alrady in blocked state. Fixed & Tested S UP --> place call --> relay down --> hangup --> relay up--> Confirm that call is hungup properly. In this condition, on relay up the circuit is put into RESET. Since circuit is still in use, it will HANGUP first, then RESET then clear pending BLOCK. S UP --> place call -> Tx RSC on call. Used to cause infitie loop Confirm call is cleard properly Re-Tested S UP --> place call -> Rx RSC on call Confirm call is cleard properly S UP --> place call -> Rx BLO -> hangup -> place call Confirm call cannot be placed Tx UBL Confirm call can be placed S UP --> place call -> Rx BLO -> Tx BLO -> hangup -> place call Confirm call cannot be placed Tx UBL Confirm call cannot be placed Rx UBL Confirm call can be placed S UP --> place call -> relay down --> Rx BLO on channel from telco --> relay up Confirm that relay detects the BLO channels even though relay was down Tx AIS -> S Start -> Confirm HW block -> Tx AIS off -> Confirm hw block clear and UP S UP -> Tx AIS -> Confirm HW block -> Tx AIS off -> confirm hw block clear and UP S UP -> relay down -> Tx AIS -> relay up -> Tx AIS off -> confirm all back up -> In this condition BLO will not go out due to PAUSE S UP -> Tx AIS -> relay down -> Tx AIS off -> relay up -> confirm all back up -> In this condition UBL will not go out due to PAUSE --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 2 + .../ftmod_sangoma_ss7_handle.c | 4 +- .../ftmod_sangoma_ss7_main.c | 75 ++++++++++++------- .../ftmod_sangoma_ss7_main.h | 16 ++-- .../ftmod_sangoma_ss7_support.c | 3 + 5 files changed, 67 insertions(+), 33 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 9eb737a7f3..1b24b9f8da 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -1632,6 +1632,8 @@ static ftdm_status_t handle_tx_rsc(ftdm_stream_handle_t *stream, int span, int c ftdm_mutex_lock(ftdmchan->mutex); /* throw the reset flag */ + sngss7_set_ckt_flag (sngss7_info, FLAG_LOCAL_REL); + sngss7_clear_ckt_flag (sngss7_info, FLAG_REMOTE_REL); sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); switch (ftdmchan->state) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index e61dc9426e..64c4c9252d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -1646,10 +1646,12 @@ ftdm_status_t handle_blo_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* check if the circuit is already blocked or not */ if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX)) { SS7_WARN("Received BLO on circuit that is already blocked!\n"); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); } /* throw the ckt block flag */ sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); /* set the channel to suspended state */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); @@ -1981,7 +1983,7 @@ ftdm_status_t handle_rsc_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX_RSP); /* go to DOWN */ - /*ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);*/ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); break; /**********************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 7350a478ef..1b7af43bc8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -453,7 +453,7 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) /* check each channel on the span to see if it needs to be reconfigured */ check_for_reconfig_flag(ftdmspan); - + /* Poll for events, e.g HW DTMF */ switch (ftdm_span_poll_event(ftdmspan, 0, NULL)) { /**********************************************************************/ @@ -825,6 +825,14 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /*this state is set when the line is hanging up */ sngss7_send_signal(sngss7_info, FTDM_SIGEVENT_STOP); + + /* If the RESET flag is set, do not say in TERMINATING state. + Go back to RESTART state and wait for RESET Confirmation */ + if (sngss7_tx_reset_status_pending(sngss7_info)) { + SS7_DEBUG_CHAN(ftdmchan,"Reset pending in Terminating state!%s\n", ""); + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + } break; /**************************************************************************/ @@ -880,9 +888,9 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) state_flag = 0; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); } else { - /* go to RESTART State until RSCa is received */ - state_flag = 0; - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + /* Stay in hangup complete until RSC is received */ + /* Channel is in use if we go to RESTART we will + restart will just come back to HANGUP_COMPLETE */ } } else { /* if the hangup is from a rx RSC, rx GRS, or glare don't sent RLC */ @@ -901,6 +909,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) SS7_DEBUG_CHAN(ftdmchan,"Completing remotely requested hangup!%s\n", ""); } else if (sngss7_test_ckt_flag (sngss7_info, FLAG_LOCAL_REL)) { + /* if this hang up is do to a rx RESET we need to sit here till the RSP arrives */ if (sngss7_test_ckt_flag (sngss7_info, FLAG_RESET_TX_RSP)) { @@ -923,10 +932,12 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /**************************************************************************/ case FTDM_CHANNEL_STATE_DOWN: /*the call is finished and removed */ - - if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { - SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n"); - break; + + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { + if (!ftdm_test_flag (ftdmchan, FTDM_CHANNEL_OPEN)) { + SS7_DEBUG_CHAN(ftdmchan,"Down came from SUSPEND - break %s\n", ""); + break; + } } /* check if there is a reset response that needs to be sent */ @@ -997,7 +1008,10 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) } /* if (!ftdm_test_flag (ftdmchan, FTDM_CHANNEL_SIG_UP)) */ } else { state_flag = 0; + SS7_DEBUG_CHAN(ftdmchan,"Down detected blocked flags go to SUSPEND %s\n", " "); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + break; + } /* if !blocked */ } else { SS7_DEBUG_CHAN(ftdmchan,"Reset flags present (0x%X)\n", sngss7_info->ckt_flags); @@ -1029,6 +1043,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) if (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_OPEN)) { ftdm_channel_t *close_chan = ftdmchan; /* close the channel */ + SS7_DEBUG_CHAN(ftdmchan,"FTDM Channel Close %s\n", ""); ftdm_channel_close (&close_chan); } @@ -1205,6 +1220,14 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* clear the PAUSE flag */ sngss7_clear_ckt_flag(sngss7_info, FLAG_INFID_PAUSED); + if (sngss7_test_ckt_flag (sngss7_info, FLAG_LOCAL_REL)) { + SS7_DEBUG_CHAN(ftdmchan, "Channel local release on RESUME, restart Reset procedure%s\n", ""); + /* By setting RESET_TX flag the check below sngss7_tx_reset_status_pending() will + be true, and will restart the RESET TX procedure */ + sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); + sngss7_set_ckt_flag (sngss7_info, FLAG_RESET_TX); + } + /* We have transmitted Reset/GRS but have not gotten a * Response. In mean time we got a RESUME. We cannot be sure * that our reset has been trasmitted, thus restart reset procedure. */ @@ -1250,7 +1273,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) } /* Wait for RESUME */ - /* FIXME: Check if this is a correct action to wait for RESUME */ goto suspend_goto_last; } /* if (sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_PAUSED)) { */ @@ -1269,8 +1291,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* throw the done flag */ sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); - /* check the last state and return to it to allow the call to finish */ - goto suspend_goto_last; } if (sngss7_test_ckt_blk_flag (sngss7_info, FLAG_CKT_MN_UNBLK_RX)){ @@ -1283,7 +1303,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* clear the unblock flag */ sngss7_clear_ckt_blk_flag (sngss7_info, FLAG_CKT_MN_UNBLK_RX); - SS7_DEBUG_CHAN(ftdmchan,"Current flags: ckt=0x%X, blk=0x%X\n", + SS7_DEBUG_CHAN(ftdmchan,"Current flags: ckt=0x%X, blk=0x%X\n", sngss7_info->ckt_flags, sngss7_info->blk_flags); /* not bring the cic up if there is a hardware block */ @@ -1295,8 +1315,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* send a uba */ ft_to_sngss7_uba (ftdmchan); - /* check the last state and return to it to allow the call to finish */ - goto suspend_goto_last; } @@ -1316,7 +1334,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) } sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX_DN); - goto suspend_goto_last; } if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_UNBLK_TX)) { @@ -1344,7 +1361,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) ft_to_sngss7_ubl(ftdmchan); } - goto suspend_goto_last; } /**********************************************************************/ @@ -1398,8 +1414,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* throw the done flag */ sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX_DN); - /* check the last state and return to it to allow the call to finish */ - goto suspend_goto_last; } if (sngss7_test_ckt_blk_flag (sngss7_info, FLAG_CKT_MN_UNBLK_TX)) { @@ -1423,8 +1437,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) ft_to_sngss7_ubl(ftdmchan); } - /* check the last state and return to it to allow the call to finish */ - goto suspend_goto_last; } /**********************************************************************/ @@ -1442,8 +1454,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* bring the sig status down */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); - /* check the last state and return to it to allow the call to finish */ - goto suspend_goto_last; } if (sngss7_test_ckt_blk_flag (sngss7_info, FLAG_CKT_LC_UNBLK_RX)) { @@ -1465,8 +1475,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) } - /* check the last state and return to it to allow the call to finish */ - goto suspend_goto_last; } /**********************************************************************/ if (sngss7_test_ckt_blk_flag (sngss7_info, FLAG_CKT_UCIC_BLOCK) && @@ -1488,8 +1496,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* throw the done flag */ sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_UCIC_BLOCK_DN); - /* bring the channel down */ - goto suspend_goto_last; } if (sngss7_test_ckt_blk_flag (sngss7_info, FLAG_CKT_UCIC_UNBLK)) { @@ -1521,6 +1527,23 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) SS7_DEBUG_CHAN(ftdmchan,"No block flag processed!%s\n", ""); suspend_goto_last: + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_UP) { + /* proceed to UP */ + } else if (!sngss7_channel_status_clear(sngss7_info)) { + SS7_DEBUG_CHAN(ftdmchan,"Channel opted to stay in RESTART due to blocks!%s\n", ""); + SS7_DEBUG_CHAN(ftdmchan,"Current flags: ckt=0x%X, blk=0x%X, circuit->flag=0x%X\n", + sngss7_info->ckt_flags, sngss7_info->blk_flags, + sngss7_info->circuit->flags ); + + goto suspend_goto_restart; + } else { + SS7_DEBUG_CHAN(ftdmchan,"Channel signaling is up proceed to DOWN! [Last State=%i]\n", ftdmchan->last_state); + SS7_DEBUG_CHAN(ftdmchan,"Current flags: ckt=0x%X, blk=0x%X, circuit->flag=0x%X\n", + sngss7_info->ckt_flags, sngss7_info->blk_flags, + sngss7_info->circuit->flags ); + ftdmchan->last_state = FTDM_CHANNEL_STATE_DOWN; + } + state_flag = 0; ftdm_set_state(ftdmchan, ftdmchan->last_state); break; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index b25b21f0ef..697da825cb 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -1049,11 +1049,13 @@ if (ftdmchan->state == new_state) { \ #define sngss7_set_options(obj, option) ((obj)->options |= (option)) #define sngss7_tx_block_status_clear(obj) (!sngss7_test_ckt_blk_flag(obj, (FLAG_CKT_MN_BLOCK_TX | \ - FLAG_CKT_MN_BLOCK_TX_DN | \ - FLAG_GRP_MN_BLOCK_TX | \ - FLAG_GRP_MN_BLOCK_TX_DN | \ - FLAG_GRP_HW_BLOCK_TX | \ - FLAG_GRP_HW_BLOCK_TX_DN ))) + FLAG_CKT_MN_BLOCK_TX_DN | \ + FLAG_GRP_MN_BLOCK_TX | \ + FLAG_GRP_MN_BLOCK_TX_DN | \ + FLAG_GRP_HW_BLOCK_TX | \ + FLAG_GRP_HW_BLOCK_TX_DN | \ + FLAG_GRP_HW_UNBLK_TX | \ + FLAG_CKT_MN_UNBLK_TX ))) #define sngss7_block_status_clear(obj) (obj->blk_flags == 0) @@ -1062,10 +1064,12 @@ if (ftdmchan->state == new_state) { \ FLAG_GRP_RESET_TX | \ FLAG_GRP_RESET_RX ))) -#define sngss7_tx_reset_status_pending(obj) ((sngss7_test_ckt_flag(obj, (FLAG_RESET_TX)) && \ +#define sngss7_tx_reset_sent(obj) ((sngss7_test_ckt_flag(obj, (FLAG_RESET_TX)) && \ sngss7_test_ckt_flag(obj, (FLAG_RESET_SENT))) || \ (sngss7_test_ckt_flag(obj, (FLAG_GRP_RESET_TX)) && \ sngss7_test_ckt_flag(obj, (FLAG_GRP_RESET_SENT)))) + +#define sngss7_tx_reset_status_pending(obj) (sngss7_test_ckt_flag(obj, (FLAG_RESET_TX)) || sngss7_test_ckt_flag(obj, (FLAG_GRP_RESET_TX))) #define sngss7_channel_status_clear(obj) ((sngss7_block_status_clear(obj)) && (sngss7_reset_status_clear(obj))) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 47fdd47728..7a68fe318f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -2232,6 +2232,9 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); } + /* Only locally blocked, thus remove a remote block */ + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); + break; /**************************************************************************/ case (2): From 997c127a9405af27f041c07a87395d10bcef63c4 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Wed, 30 Nov 2011 20:02:25 -0500 Subject: [PATCH 095/822] Fixed following two secnarios From previous commit, failed to clear the done flag _DN which cause SUSPEND to think that there was a block pending, causing state to remain in RESTART S UP -> relay down -> Tx AIS -> relay up -> Tx AIS off -> confirm all back up -> In this condition BLO will not go out due to PAUSE S UP -> Tx AIS -> relay down -> Tx AIS off -> relay up -> confirm all back up -> In this condition UBL will not go out due to PAUSE --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c | 4 +++- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 64c4c9252d..e7cc9db573 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -122,8 +122,11 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* as per Q.764, 2.8.2.3 xiv ... remove the block from this channel */ sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX_DN); sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX_DN); /* KONRAD FIX ME : check in case there is a ckt and grp block */ } @@ -1646,7 +1649,6 @@ ftdm_status_t handle_blo_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* check if the circuit is already blocked or not */ if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX)) { SS7_WARN("Received BLO on circuit that is already blocked!\n"); - sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); } /* throw the ckt block flag */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 7a68fe318f..eb1eb12961 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -2234,12 +2234,14 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) /* Only locally blocked, thus remove a remote block */ sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); break; /**************************************************************************/ case (2): /* remotely blocked */ sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); /* set the channel to suspended state */ SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); @@ -2247,8 +2249,11 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) /**************************************************************************/ case (3): /* both locally and remotely blocked */ - sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_UNBLK_TX); + if (!sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX)) { + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_UNBLK_TX); + } sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); /* set the channel to suspended state */ SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); From 7b83dd4c968f9769c58b8ef89a83eb55a8218df3 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 1 Dec 2011 03:16:59 -0500 Subject: [PATCH 096/822] Fixed the exception condition - trigger reset used to clear ckt_flags, this was wrong. if ctk_flags are blindly cleard a PAUSE might be cleared. changed the code to clear only TX RESET and try to reset again. Release Collision If we get out of sync with other side we must reset the circuit. This condition occoured at 1+3 test box Local Management Block Its possible for stack to send us a BLO indicating to us that we are local blocked. This case never worked and we would get stuck there forever. If we never manaully sent a LOCAL block, the BLO from the stack will be acked and then unblocked. This condition occoured at 1+3 test box --- libs/freetdm/src/ftdm_state.c | 1 + .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 2 +- .../ftmod_sangoma_ss7_handle.c | 19 +++---- .../ftmod_sangoma_ss7_main.c | 24 ++++++--- .../ftmod_sangoma_ss7_main.h | 11 ++++- .../ftmod_sangoma_ss7_support.c | 49 +++++++++++++++++++ libs/freetdm/src/include/private/ftdm_core.h | 1 + 7 files changed, 89 insertions(+), 18 deletions(-) diff --git a/libs/freetdm/src/ftdm_state.c b/libs/freetdm/src/ftdm_state.c index d3f99f6074..6572ab75a4 100644 --- a/libs/freetdm/src/ftdm_state.c +++ b/libs/freetdm/src/ftdm_state.c @@ -87,6 +87,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const c ftdm_assert(!fchan->history[hindex].end_time, "End time should be zero!\n"); fchan->history[hindex].end_time = ftdm_current_time_in_ms(); + fchan->last_state_change_time = ftdm_current_time_in_ms(); fchan->state_status = FTDM_STATE_STATUS_COMPLETED; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 1b24b9f8da..2c8f5172b9 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -1634,7 +1634,7 @@ static ftdm_status_t handle_tx_rsc(ftdm_stream_handle_t *stream, int span, int c /* throw the reset flag */ sngss7_set_ckt_flag (sngss7_info, FLAG_LOCAL_REL); sngss7_clear_ckt_flag (sngss7_info, FLAG_REMOTE_REL); - sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); + sngss7_tx_reset_restart(sngss7_info); switch (ftdmchan->state) { /**************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index e7cc9db573..295d127064 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -327,9 +327,8 @@ handle_glare: /* throw the TX reset flag */ if (!sngss7_tx_reset_status_pending(sngss7_info)) { - sngss7_info->ckt_flags=0; + sngss7_tx_reset_restart(sngss7_info); sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); - sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); /* go to RESTART */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); @@ -401,9 +400,8 @@ ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* throw the TX reset flag */ if (!sngss7_tx_reset_status_pending(sngss7_info)) { - sngss7_info->ckt_flags=0; + sngss7_tx_reset_restart(sngss7_info); sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); - sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); /* go to RESTART */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); @@ -668,9 +666,8 @@ ftdm_status_t handle_con_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* throw the TX reset flag */ if (!sngss7_tx_reset_status_pending(sngss7_info)) { - sngss7_info->ckt_flags=0; + sngss7_tx_reset_restart(sngss7_info); sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); - sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); /* go to RESTART */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); @@ -772,6 +769,10 @@ ftdm_status_t handle_rel_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* send out the release complete */ ft_to_sngss7_rlc (ftdmchan); + } else { + SS7_DEBUG_CHAN(ftdmchan, "Collision of REL messages - resetting state.\n", " "); + ft_to_sngss7_rlc (ftdmchan); + goto rel_ind_reset; } break; /**************************************************************************/ @@ -794,11 +795,11 @@ ftdm_status_t handle_rel_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ /**************************************************************************/ default: +rel_ind_reset: /* throw the TX reset flag */ if (!sngss7_tx_reset_status_pending(sngss7_info)) { - sngss7_info->ckt_flags=0; - sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); - sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); + sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); + sngss7_tx_reset_restart(sngss7_info); /* go to RESTART */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 1b7af43bc8..4c6992e61f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1358,6 +1358,8 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) } if (sngss7_tx_block_status_clear(sngss7_info) && !skip_unblock) { + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX_DN); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX); ft_to_sngss7_ubl(ftdmchan); } @@ -1434,6 +1436,8 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) if (sngss7_tx_block_status_clear(sngss7_info)) { /* send a ubl */ + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX_DN); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX); ft_to_sngss7_ubl(ftdmchan); } @@ -1446,13 +1450,19 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) SS7_DEBUG_CHAN(ftdmchan, "Processing CKT_LC_BLOCK_RX flag %s\n", ""); /* send a BLA */ - /*ft_to_sngss7_bla(ftdmchan);*/ + ft_to_sngss7_bla(ftdmchan); /* throw the done flag */ sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX_DN); - - /* bring the sig status down */ - sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); + + if (sngss7_tx_block_status_clear(sngss7_info)) { + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX_DN); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX); + ft_to_sngss7_ubl(ftdmchan); + } else { + /* bring the sig status down */ + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); + } } @@ -1468,7 +1478,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_UNBLK_RX); /* send a uba */ - /*ft_to_sngss7_uba(ftdmchan);*/ + ft_to_sngss7_uba(ftdmchan); if (sngss7_channel_status_clear(sngss7_info)) { sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); @@ -1530,14 +1540,14 @@ suspend_goto_last: if (ftdmchan->last_state == FTDM_CHANNEL_STATE_UP) { /* proceed to UP */ } else if (!sngss7_channel_status_clear(sngss7_info)) { - SS7_DEBUG_CHAN(ftdmchan,"Channel opted to stay in RESTART due to blocks!%s\n", ""); + SS7_DEBUG_CHAN(ftdmchan,"Channel opted to stay in RESTART due to reset/blocks!%s\n", ""); SS7_DEBUG_CHAN(ftdmchan,"Current flags: ckt=0x%X, blk=0x%X, circuit->flag=0x%X\n", sngss7_info->ckt_flags, sngss7_info->blk_flags, sngss7_info->circuit->flags ); goto suspend_goto_restart; } else { - SS7_DEBUG_CHAN(ftdmchan,"Channel signaling is up proceed to DOWN! [Last State=%i]\n", ftdmchan->last_state); + SS7_DEBUG_CHAN(ftdmchan,"Channel signaling is up proceed to DOWN! [Last State=%s]\n", ftdm_channel_state2str(ftdmchan->last_state)); SS7_DEBUG_CHAN(ftdmchan,"Current flags: ckt=0x%X, blk=0x%X, circuit->flag=0x%X\n", sngss7_info->ckt_flags, sngss7_info->blk_flags, sngss7_info->circuit->flags ); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 697da825cb..631dadf007 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -1071,7 +1071,16 @@ if (ftdmchan->state == new_state) { \ #define sngss7_tx_reset_status_pending(obj) (sngss7_test_ckt_flag(obj, (FLAG_RESET_TX)) || sngss7_test_ckt_flag(obj, (FLAG_GRP_RESET_TX))) -#define sngss7_channel_status_clear(obj) ((sngss7_block_status_clear(obj)) && (sngss7_reset_status_clear(obj))) +#define sngss7_channel_status_clear(obj) ((sngss7_block_status_clear(obj)) && \ + (sngss7_reset_status_clear(obj)) && \ + (!sngss7_test_ckt_flag((obj),FLAG_INFID_PAUSED))) + +#define sngss7_tx_reset_restart(obj) do { clear_tx_grs_flags((obj)); \ + clear_tx_grs_data((obj)); \ + clear_tx_rsc_flags((obj)); \ + sngss7_set_ckt_flag((obj), (FLAG_RESET_TX)); \ + } while (0); + #ifdef SMG_RELAY_DBG diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index eb1eb12961..7696974807 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -2098,6 +2098,55 @@ void sngss7_set_sig_status(sngss7_chan_data_t *sngss7_info, ftdm_signaling_statu return; } +#if 0 +ftdm_status_t check_for_invalid_states(ftdm_channel_t *ftmchan) +{ + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + if (!sngss7_info) { + SS7_WARN_CHAN(ftdmchan, "Found ftdmchan with no sig module data!%s\n", " "); + return FTDM_FAIL; + } + + if (sngss7_test_flag(sngss7_intf, SNGSS7_PAUSED)) { + return FTDM_SUCCESS; + } + + switch (ftdmchan->state) { + case UP: + case DOWN: + return FTDM_SUCCESS; + + default: + if ((ftdm_current_time_in_ms() - ftdmchan->last_state_change_time) > 30000) { + SS7_WARN_CHAN(ftdmchan, "Circuite in state=%s too long - resetting!%s\n", + ftdm_channel_state2str(ftdmchan->state)); + + ftdm_channel_lock(ftdmchan); + + if (sngss7_channel_status_clear(sngss7_info)) { + sngss7_tx_reset_restart(sngss7_info); + + if (ftdmchan->state == FTDM_CHANNEL_STATE_RESTART) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + } else { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + } + } else { + + } + + + + ftdm_channel_unlock(ftdmchan); + } + } + + return FTDM_SUCCESS; +} +#endif + + /******************************************************************************/ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) { diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 65ffad677c..f27be789e2 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -469,6 +469,7 @@ struct ftdm_channel { int32_t txdrops; int32_t rxdrops; ftdm_usrmsg_t *usrmsg; + ftdm_time_t last_state_change_time; }; struct ftdm_span { From 6dabe5409bf7fb88f17b4580d7bcf0d3151f67fc Mon Sep 17 00:00:00 2001 From: wadam Date: Thu, 1 Dec 2011 11:40:18 -0500 Subject: [PATCH 097/822] Fixed Bug#2018 - The threshold of cpu warning message should be increased --- libs/freetdm/src/ftdm_io.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 0205ab36b1..8ec6a3344f 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -5594,15 +5594,15 @@ static void *ftdm_cpu_monitor_run(ftdm_thread_t *me, void *obj) if (monitor->alarm) { if ((int)time >= (100 - monitor->set_alarm_threshold)) { - ftdm_log(FTDM_LOG_DEBUG, "CPU alarm OFF (idle:%d)\n", (int) time); + ftdm_log(FTDM_LOG_DEBUG, "CPU alarm is OFF (cpu usage:%d)\n", (int) (100-time)); monitor->alarm = 0; } - if (monitor->alarm_action_flags & FTDM_CPU_ALARM_ACTION_WARN) { + if (monitor->alarm && (monitor->alarm_action_flags & FTDM_CPU_ALARM_ACTION_WARN)) { ftdm_log(FTDM_LOG_WARNING, "CPU alarm is ON (cpu usage:%d)\n", (int) (100-time)); } } else { if ((int)time <= (100-monitor->reset_alarm_threshold)) { - ftdm_log(FTDM_LOG_DEBUG, "CPU alarm ON (idle:%d)\n", (int) time); + ftdm_log(FTDM_LOG_DEBUG, "CPU alarm is ON (cpu usage:%d)\n", (int) (100-time)); monitor->alarm = 1; } } From 3432dccfc2b01b095e561d5467c76d20a094bc69 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 1 Dec 2011 12:13:12 -0500 Subject: [PATCH 098/822] freetdm: fix cpu monitor inconsistent messages, variable names etc changed parameter name from cpu_reset_alarm_threshold to cpu_clear_alarm_threshold (old parameter name still valid for backwards compatibility in configuration files) --- libs/freetdm/conf/freetdm.conf | 2 +- libs/freetdm/src/ftdm_io.c | 51 ++++++++++++++++++++-------------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/libs/freetdm/conf/freetdm.conf b/libs/freetdm/conf/freetdm.conf index eb506bef8d..0d53992979 100644 --- a/libs/freetdm/conf/freetdm.conf +++ b/libs/freetdm/conf/freetdm.conf @@ -13,7 +13,7 @@ cpu_monitoring_interval => 1000 cpu_set_alarm_threshold => 80 ; At what CPU percentage stop the CPU alarm -cpu_reset_alarm_threshold => 70 +cpu_clear_alarm_threshold => 70 ; Which action to take when the CPU alarm is raised ; it can be warn and/or reject calls diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 8ec6a3344f..bb866610a2 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -223,7 +223,7 @@ typedef struct { uint32_t interval; uint8_t alarm_action_flags; uint8_t set_alarm_threshold; - uint8_t reset_alarm_threshold; + uint8_t clear_alarm_threshold; ftdm_interrupt_t *interrupt; } cpu_monitor_t; @@ -4834,14 +4834,15 @@ static ftdm_status_t load_config(void) } else { ftdm_log(FTDM_LOG_ERROR, "Invalid cpu alarm set threshold %s\n", val); } - } else if (!strncasecmp(var, "cpu_reset_alarm_threshold", sizeof("cpu_reset_alarm_threshold")-1)) { + } else if (!strncasecmp(var, "cpu_reset_alarm_threshold", sizeof("cpu_reset_alarm_threshold")-1) || + !strncasecmp(var, "cpu_clear_alarm_threshold", sizeof("cpu_clear_alarm_threshold")-1)) { intparam = atoi(val); if (intparam > 0 && intparam < 100) { - globals.cpu_monitor.reset_alarm_threshold = (uint8_t)intparam; - if (globals.cpu_monitor.reset_alarm_threshold > globals.cpu_monitor.set_alarm_threshold) { - globals.cpu_monitor.reset_alarm_threshold = globals.cpu_monitor.set_alarm_threshold - 10; - ftdm_log(FTDM_LOG_ERROR, "Cpu alarm reset threshold must be lower than set threshold" - ", setting threshold to %d\n", globals.cpu_monitor.reset_alarm_threshold); + globals.cpu_monitor.clear_alarm_threshold = (uint8_t)intparam; + if (globals.cpu_monitor.clear_alarm_threshold > globals.cpu_monitor.set_alarm_threshold) { + globals.cpu_monitor.clear_alarm_threshold = globals.cpu_monitor.set_alarm_threshold - 10; + ftdm_log(FTDM_LOG_ERROR, "Cpu alarm clear threshold must be lower than set threshold, " + "setting clear threshold to %d\n", globals.cpu_monitor.clear_alarm_threshold); } } else { ftdm_log(FTDM_LOG_ERROR, "Invalid cpu alarm reset threshold %s\n", val); @@ -5581,28 +5582,32 @@ static void *ftdm_cpu_monitor_run(ftdm_thread_t *me, void *obj) { cpu_monitor_t *monitor = (cpu_monitor_t *)obj; struct ftdm_cpu_monitor_stats *cpu_stats = ftdm_new_cpu_monitor(); + + ftdm_log(FTDM_LOG_DEBUG, "CPU monitor thread is now running\n"); if (!cpu_stats) { - return NULL; + goto done; } monitor->running = 1; - while(ftdm_running()) { - double time; - if (ftdm_cpu_get_system_idle_time(cpu_stats, &time)) { + while (ftdm_running()) { + double idle_time = 0.0; + int cpu_usage = 0; + + if (ftdm_cpu_get_system_idle_time(cpu_stats, &idle_time)) { break; } + cpu_usage = (int)(100 - idle_time); if (monitor->alarm) { - if ((int)time >= (100 - monitor->set_alarm_threshold)) { - ftdm_log(FTDM_LOG_DEBUG, "CPU alarm is OFF (cpu usage:%d)\n", (int) (100-time)); + if (cpu_usage <= monitor->clear_alarm_threshold) { + ftdm_log(FTDM_LOG_DEBUG, "CPU alarm is now OFF (cpu usage: %d)\n", cpu_usage); monitor->alarm = 0; - } - if (monitor->alarm && (monitor->alarm_action_flags & FTDM_CPU_ALARM_ACTION_WARN)) { - ftdm_log(FTDM_LOG_WARNING, "CPU alarm is ON (cpu usage:%d)\n", (int) (100-time)); + } else if (monitor->alarm_action_flags & FTDM_CPU_ALARM_ACTION_WARN) { + ftdm_log(FTDM_LOG_WARNING, "CPU alarm is still ON (cpu usage: %d)\n", cpu_usage); } } else { - if ((int)time <= (100-monitor->reset_alarm_threshold)) { - ftdm_log(FTDM_LOG_DEBUG, "CPU alarm is ON (cpu usage:%d)\n", (int) (100-time)); + if (cpu_usage >= monitor->set_alarm_threshold) { + ftdm_log(FTDM_LOG_WARNING, "CPU alarm is now ON (cpu usage: %d)\n", cpu_usage); monitor->alarm = 1; } } @@ -5611,7 +5616,11 @@ static void *ftdm_cpu_monitor_run(ftdm_thread_t *me, void *obj) ftdm_delete_cpu_monitor(cpu_stats); monitor->running = 0; + +done: + ftdm_log(FTDM_LOG_DEBUG, "CPU monitor thread is now terminating\n"); return NULL; + #ifdef __WINDOWS__ UNREFERENCED_PARAMETER(me); #endif @@ -5714,7 +5723,7 @@ FT_DECLARE(ftdm_status_t) ftdm_global_configuration(void) globals.cpu_monitor.interval = 1000; globals.cpu_monitor.alarm_action_flags = 0; globals.cpu_monitor.set_alarm_threshold = 80; - globals.cpu_monitor.reset_alarm_threshold = 70; + globals.cpu_monitor.clear_alarm_threshold = 70; if (load_config() != FTDM_SUCCESS) { globals.running = 0; @@ -5723,10 +5732,10 @@ FT_DECLARE(ftdm_status_t) ftdm_global_configuration(void) } if (globals.cpu_monitor.enabled) { - ftdm_log(FTDM_LOG_INFO, "CPU Monitor is running interval:%d lo-thres:%d hi-thres:%d\n", + ftdm_log(FTDM_LOG_INFO, "CPU Monitor is running interval:%d set-thres:%d clear-thres:%d\n", globals.cpu_monitor.interval, globals.cpu_monitor.set_alarm_threshold, - globals.cpu_monitor.reset_alarm_threshold); + globals.cpu_monitor.clear_alarm_threshold); if (ftdm_cpu_monitor_start() != FTDM_SUCCESS) { return FTDM_FAIL; From 35df4f468c2ba3d5e6e184e2882c2b2f72a0279e Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 1 Dec 2011 19:18:54 -0500 Subject: [PATCH 099/822] Update to the SUSPEND state machine updated 2 commits ago. SUSPEND will not only change the return state in few cases. I have retested all test cases from previous 2 commits. What is missing is timer for each Tx Event. RSC,BLO,UBL. Its possible to loose a message from Slave via relay to Master. If that ever occours we will not know what state we are in. Thus we need a timer that will re-transmit a packet if it does not get acknowledged. --- .../ftmod_sangoma_ss7_main.c | 49 ++++++++++++++++--- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 4c6992e61f..280cc1a428 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -883,7 +883,9 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) if (!sngss7_test_ckt_flag(sngss7_info, FLAG_RESET_SENT)) { ft_to_sngss7_rsc (ftdmchan); sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_SENT); - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + + /* Wait for Reset in HANGUP Complete nothing to do until we + get reset response back */ } else if (sngss7_test_ckt_flag(sngss7_info, FLAG_RESET_TX_RSP)) { state_flag = 0; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); @@ -910,7 +912,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) SS7_DEBUG_CHAN(ftdmchan,"Completing remotely requested hangup!%s\n", ""); } else if (sngss7_test_ckt_flag (sngss7_info, FLAG_LOCAL_REL)) { - /* if this hang up is do to a rx RESET we need to sit here till the RSP arrives */ if (sngss7_test_ckt_flag (sngss7_info, FLAG_RESET_TX_RSP)) { /* go to the down state as we have already received RSC-RLC */ @@ -926,6 +927,9 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); } else { SS7_DEBUG_CHAN(ftdmchan,"Completing requested hangup for unknown reason!%s\n", ""); + if (sngss7_channel_status_clear(sngss7_info)) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + } } break; @@ -1180,6 +1184,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) state_flag = 0; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); } else { + SS7_DEBUG_CHAN(ftdmchan, "Waiting on Reset Rsp/Grp Reset to move to DOWN (0x%X)\n", sngss7_info->ckt_flags); } } @@ -1539,19 +1544,49 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) suspend_goto_last: if (ftdmchan->last_state == FTDM_CHANNEL_STATE_UP) { /* proceed to UP */ - } else if (!sngss7_channel_status_clear(sngss7_info)) { - SS7_DEBUG_CHAN(ftdmchan,"Channel opted to stay in RESTART due to reset/blocks!%s\n", ""); + } else if (!sngss7_reset_status_clear(sngss7_info) || + sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_PAUSED)) { + + /* At this point the circuit is in reset, if the call is + in use make sure that at least REMOTE REL flag is set + in order to drop the call on the sip side */ + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) { + if (!sngss7_test_ckt_flag (sngss7_info, FLAG_LOCAL_REL) && + !sngss7_test_ckt_flag (sngss7_info, FLAG_REMOTE_REL)) { + sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); + } + } + SS7_DEBUG_CHAN(ftdmchan,"Channel opted to stay in RESTART due to reset!%s\n", ""); SS7_DEBUG_CHAN(ftdmchan,"Current flags: ckt=0x%X, blk=0x%X, circuit->flag=0x%X\n", sngss7_info->ckt_flags, sngss7_info->blk_flags, sngss7_info->circuit->flags ); goto suspend_goto_restart; - } else { - SS7_DEBUG_CHAN(ftdmchan,"Channel signaling is up proceed to DOWN! [Last State=%s]\n", ftdm_channel_state2str(ftdmchan->last_state)); + + } else if (sngss7_channel_status_clear(sngss7_info)) { + + /* In this case all resets and blocks are clear sig state is up, thus go to DOWN */ + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_RESTART || + ftdmchan->last_state == FTDM_CHANNEL_STATE_TERMINATING) { + ftdmchan->last_state = FTDM_CHANNEL_STATE_DOWN; + } + + SS7_DEBUG_CHAN(ftdmchan,"Channel signallig is UP: proceed to State %s!\n", + ftdm_channel_state2str(ftdmchan->last_state)); SS7_DEBUG_CHAN(ftdmchan,"Current flags: ckt=0x%X, blk=0x%X, circuit->flag=0x%X\n", sngss7_info->ckt_flags, sngss7_info->blk_flags, sngss7_info->circuit->flags ); - ftdmchan->last_state = FTDM_CHANNEL_STATE_DOWN; + + } else { + + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_DOWN) { + ftdmchan->last_state = FTDM_CHANNEL_STATE_RESTART; + } + SS7_DEBUG_CHAN(ftdmchan,"Channel signaling is in block state: proceed to State=%s]\n", + ftdm_channel_state2str(ftdmchan->last_state)); + SS7_DEBUG_CHAN(ftdmchan,"Current flags: ckt=0x%X, blk=0x%X, circuit->flag=0x%X\n", + sngss7_info->ckt_flags, sngss7_info->blk_flags, + sngss7_info->circuit->flags); } state_flag = 0; From b3297c7f3b1f5cb0bab720df1ce970aa664ec064 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 2 Dec 2011 11:24:34 -0500 Subject: [PATCH 100/822] freetdm: fix license path to use sngss7 path limits do not use strcpy, use ftdm_set_string which is safer do not use strcpy when snprintf is safer and cleaner --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h | 5 ++--- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 631dadf007..e39c57802f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -51,7 +51,6 @@ /* DEFINES ********************************************************************/ #define MAX_NAME_LEN 25 -#define MAX_PATH 4096 #define MAX_CIC_LENGTH 5 #define MAX_CIC_MAP_LENGTH 1000 @@ -411,8 +410,8 @@ typedef struct sng_relay { typedef struct sng_ss7_cfg { uint32_t spc; uint32_t procId; - char license[MAX_PATH]; - char signature[MAX_PATH]; + char license[MAX_SNGSS7_PATH]; + char signature[MAX_SNGSS7_PATH]; uint32_t transparent_iam_max_size; uint32_t flags; sng_relay_t relay[MAX_RELAY_CHANNELS+1]; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 2fbd2e5631..f1c6625b85 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -472,9 +472,8 @@ static int ftmod_ss7_parse_sng_gen(ftdm_conf_node_t *sng_gen) /**********************************************************************/ } else if (!strcasecmp(parm->var, "license")) { /**********************************************************************/ - strcpy(g_ftdm_sngss7_data.cfg.license, parm->val); - strcpy(g_ftdm_sngss7_data.cfg.signature, parm->val); - strcat(g_ftdm_sngss7_data.cfg.signature, ".sig"); + ftdm_set_string(g_ftdm_sngss7_data.cfg.license, parm->val); + snprintf(g_ftdm_sngss7_data.cfg.signature, sizeof(g_ftdm_sngss7_data.cfg.signature), "%s.sig", parm->val); SS7_DEBUG("Found license file = %s\n", g_ftdm_sngss7_data.cfg.license); SS7_DEBUG("Found signature file = %s\n", g_ftdm_sngss7_data.cfg.signature); /**********************************************************************/ From e582586876ca7b81774355982dbb7976a873755b Mon Sep 17 00:00:00 2001 From: James Zhang Date: Mon, 5 Dec 2011 16:58:26 -0500 Subject: [PATCH 101/822] Freetdm: adding X-FreeTDM-ANI-NADI and X-FreeTDM-DNIS-NADI support --- libs/freetdm/mod_freetdm/mod_freetdm.c | 8 +++++++- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c | 2 +- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c | 10 +++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index c9daadac12..a0d2279ba3 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1355,7 +1355,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi /* Used by ftmod_sangoma_ss7 only */ sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-DNIS-NADI"); if (sipvar) { - ftdm_usrmsg_add_var(&usrmsg, "ss7_clg_nadi", sipvar); + ftdm_usrmsg_add_var(&usrmsg, "ss7_cld_nadi", sipvar); } sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-RDNIS"); @@ -1711,6 +1711,12 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_clg_nadi"); if (!ftdm_strlen_zero(var_value)) { switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-NADI", "%s", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-ANI-NADI", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_cld_nadi"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-DNIS-NADI", "%s", var_value); } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdnis_screen_ind"); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 295d127064..7c9b3061f0 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -201,10 +201,10 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ } copy_redirgNum_from_sngss7(ftdmchan, &siConEvnt->redirgNum); - copy_genNmb_from_sngss7(ftdmchan, &siConEvnt->genNmb); copy_cgPtyCat_from_sngss7(ftdmchan, &siConEvnt->cgPtyCat); + copy_cdPtyNum_from_sngss7(ftdmchan, &siConEvnt->cdPtyNum); /* fill in the TMR/bearer capability */ if (siConEvnt->txMedReq.eh.pres) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 7696974807..3203e52e7d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -193,7 +193,15 @@ ftdm_status_t copy_cgPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *cgPt ftdm_status_t copy_cdPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cdPtyNum) { - /* TODO: Implement me */ + char var[FTDM_DIGITS_LIMIT]; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + if (cdPtyNum->eh.pres == PRSNT_NODEF && + cdPtyNum->natAddrInd.pres == PRSNT_NODEF) { + sprintf(var, "%d", cdPtyNum->natAddrInd.val); + sngss7_add_var(sngss7_info, "ss7_cld_nadi", var); + } + return FTDM_SUCCESS; } From 1cbeb33b2dd88727fb5ecbf7c8937780be05f8d3 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Tue, 6 Dec 2011 15:38:05 -0500 Subject: [PATCH 102/822] freetdm: adding support of x-headers for Redirection Information X-FreeTDM-RDINF-Indicator X-FreeTDM-RDINF-OrigReason X-FreeTDM-RDINF-Count X-FreeTDM-RDINF-Reason --- libs/freetdm/mod_freetdm/mod_freetdm.c | 40 ++++++++- .../ftmod_sangoma_ss7_handle.c | 1 + .../ftmod_sangoma_ss7_main.h | 3 + .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 4 + .../ftmod_sangoma_ss7_support.c | 85 +++++++++++++++++++ 5 files changed, 132 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index a0d2279ba3..ecd9189b39 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1438,6 +1438,24 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi if (sipvar) { ftdm_usrmsg_add_var(&usrmsg, "ss7_iam", sipvar); } + + /* redirection information */ + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-RDINF-Indicator"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_rdinfo_indicator", sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-RDINF-OrigReason"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_rdinfo_orig", sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-RDINF-Count"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_rdinfo_count", sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-RDINF-Reason"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_rdinfo_reason", sipvar); + } } if (switch_test_flag(outbound_profile, SWITCH_CPF_SCREEN)) { @@ -1707,7 +1725,27 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-NADI", "%d", channel_caller_data->rdnis.type); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-Plan", "%d", channel_caller_data->rdnis.plan); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-CPC", "%s", ftdm_calling_party_category2str(channel_caller_data->cpc)); - + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdinfo_indicator"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDINF-Indicator", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdinfo_orig"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDINF-OrigReason", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdinfo_count"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDINF-Count", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdinfo_reason"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDINF-Reason", "%s", var_value); + } + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_clg_nadi"); if (!ftdm_strlen_zero(var_value)) { switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-NADI", "%s", var_value); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 7c9b3061f0..0497955059 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -201,6 +201,7 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ } copy_redirgNum_from_sngss7(ftdmchan, &siConEvnt->redirgNum); + copy_redirgInfo_from_sngss7(ftdmchan, &siConEvnt->redirInfo); copy_genNmb_from_sngss7(ftdmchan, &siConEvnt->genNmb); copy_cgPtyCat_from_sngss7(ftdmchan, &siConEvnt->cgPtyCat); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index e39c57802f..bb02d7e3ed 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -841,6 +841,9 @@ ftdm_status_t copy_cdPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cd ftdm_status_t copy_cdPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cdPtyNum); ftdm_status_t copy_redirgNum_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *redirgNum); ftdm_status_t copy_redirgNum_from_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *redirgNum); +ftdm_status_t copy_redirgInfo_from_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *redirInfo); +ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *redirInfo); + ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum); ftdm_status_t copy_locPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum); ftdm_status_t copy_genNmb_to_sngss7(ftdm_channel_t *ftdmchan, SiGenNum *genNmb); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index 4c7bbf084c..fbfab15d1e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -91,6 +91,10 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* Redirecting Number */ copy_redirgNum_to_sngss7(ftdmchan, &iam.redirgNum); + /* Redirecting Information */ + copy_redirgInfo_to_sngss7(ftdmchan, &iam.redirInfo); + + /* Access Transport */ copy_accTrnspt_to_sngss7(ftdmchan, &iam.accTrnspt); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 3203e52e7d..3230292675 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -198,6 +198,7 @@ ftdm_status_t copy_cdPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cd if (cdPtyNum->eh.pres == PRSNT_NODEF && cdPtyNum->natAddrInd.pres == PRSNT_NODEF) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Called Party Number NADI %d\n", cdPtyNum->natAddrInd.val); sprintf(var, "%d", cdPtyNum->natAddrInd.val); sngss7_add_var(sngss7_info, "ss7_cld_nadi", var); } @@ -538,6 +539,90 @@ ftdm_status_t copy_redirgNum_from_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *r return FTDM_SUCCESS; } +ftdm_status_t copy_redirgInfo_from_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *redirInfo) +{ + char val[20]; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + if (redirInfo->eh.pres != PRSNT_NODEF ) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No Redirecting Information available\n"); + return FTDM_SUCCESS; + } + + + if (redirInfo->redirInd.pres == PRSNT_NODEF) { + snprintf(val, sizeof(val), "%d", redirInfo->redirInd.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirection Information - redirection indicator:%s\n", val); + sngss7_add_var(sngss7_info, "ss7_rdinfo_indicator", val); + } + + if (redirInfo->origRedirReas.pres == PRSNT_NODEF) { + snprintf(val, sizeof(val), "%d", redirInfo->origRedirReas.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirection Information - original redirection reason:%s\n", val); + sngss7_add_var(sngss7_info, "ss7_rdinfo_orig", val); + } + + if (redirInfo->redirCnt.pres == PRSNT_NODEF) { + snprintf(val, sizeof(val), "%d", redirInfo->redirCnt.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirection Information - redirection count:%s\n", val); + sngss7_add_var(sngss7_info, "ss7_rdinfo_count", val); + } + + if (redirInfo->redirReas.pres == PRSNT_NODEF) { + snprintf(val, sizeof(val), "%d", redirInfo->redirReas.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirection Information - redirection reason:%s\n", val); + sngss7_add_var(sngss7_info, "ss7_rdinfo_reason", val); + } + + return FTDM_SUCCESS; +} + +ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *redirInfo) +{ + const char* val = NULL; + int bProceed = 0; + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdinfo_indicator"); + if (!ftdm_strlen_zero(val)) { + redirInfo->redirInd.val = atoi(val); + bProceed = 1; + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Redirection Information on Redirection Indicator\n"); + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdinfo_orig"); + if (!ftdm_strlen_zero(val)) { + redirInfo->origRedirReas.val = atoi(val); + bProceed = 1; + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Redirection Information on Original Reasons\n"); + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdinfo_count"); + if (!ftdm_strlen_zero(val)) { + redirInfo->redirCnt.val = atoi(val); + bProceed = 1; + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Redirection Information on Redirection Count\n"); + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdinfo_reason"); + if (!ftdm_strlen_zero(val)) { + redirInfo->redirReas.val = atoi(val); + bProceed = 1; + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Redirection Information on Redirection Reasons\n"); + } + + if( bProceed == 1 ) { + redirInfo->eh.pres = PRSNT_NODEF; + } else { + redirInfo->eh.pres = NOTPRSNT; + } + + return FTDM_SUCCESS; +} + ftdm_status_t copy_cgPtyCat_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyCat *cgPtyCat) { ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; From 9db322f2e0a035c898509f915134cee0e47ce398 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Wed, 14 Dec 2011 19:56:25 -0500 Subject: [PATCH 103/822] Fixed hw alarm crash. When we get hw alarm in the middle of configuration. It can happen with large number of circuits. On RESTART if we are PAUSED do not try to send RESET and stay in RESTART state --- .../ftmod_sangoma_ss7_main.c | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 280cc1a428..aef7a6edef 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -295,24 +295,35 @@ static void handle_hw_alarm(ftdm_event_t *e) for (x = (g_ftdm_sngss7_data.cfg.procId * MAX_CIC_MAP_LENGTH) + 1; g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0; x++) { if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == SNG_CKT_VOICE) { ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCkt[x].obj; + + /* NC. Its possible for alarms to come in the middle of configuration + especially on large systems */ + if (!ss7_info || !ss7_info->ftdmchan) { + SS7_DEBUG("handle_hw_alarm: span=%i chan=%i ckt=%i x=%i - ss7_info=%p ftdmchan=%p\n", + ftdmchan->physical_span_id,ftdmchan->physical_chan_id, + g_ftdm_sngss7_data.cfg.isupCkt[x].id,x, + ss7_info,ss7_info?ss7_info->ftdmchan:NULL); + continue; + } + ftdmchan = ss7_info->ftdmchan; if (e->channel->physical_span_id == ftdmchan->physical_span_id && e->channel->physical_chan_id == ftdmchan->physical_chan_id) { - SS7_DEBUG("handle_hw_alarm: span=%i chan=%i ckt=%i x=%i\n",ftdmchan->physical_span_id,ftdmchan->physical_chan_id,g_ftdm_sngss7_data.cfg.isupCkt[x].id,x); + SS7_DEBUG_CHAN(ftdmchan,"handle_hw_alarm: span=%i chan=%i ckt=%i x=%i\n",ftdmchan->physical_span_id,ftdmchan->physical_chan_id,g_ftdm_sngss7_data.cfg.isupCkt[x].id,x); if (e->enum_id == FTDM_OOB_ALARM_TRAP) { - SS7_DEBUG("handle_hw_alarm: Set FLAG_GRP_HW_BLOCK_TX\n"); + SS7_DEBUG_CHAN(ftdmchan,"handle_hw_alarm: Set FLAG_GRP_HW_BLOCK_TX\n"); sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX); if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); } } else if (e->enum_id == FTDM_OOB_ALARM_CLEAR) { - SS7_DEBUG("handle_hw_alarm: Clear\n"); + SS7_DEBUG_CHAN(ftdmchan,"handle_hw_alarm: Clear\n"); sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX); sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); if (sngss7_test_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX_DN)) { sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); - SS7_DEBUG("handle_hw_alarm: Setting FLAG_GRP_HW_UNBLK_TX\n"); + SS7_DEBUG_CHAN(ftdmchan,"handle_hw_alarm: Setting FLAG_GRP_HW_UNBLK_TX\n"); if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); } @@ -1077,6 +1088,11 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) SS7_DEBUG_CHAN(ftdmchan,"RESTART: Current flags: ckt=0x%X, blk=0x%X\n", sngss7_info->ckt_flags, sngss7_info->blk_flags); + + if (sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_PAUSED)) { + SS7_DEBUG_CHAN(ftdmchan,"Circuit PAUSED stay in RESTART%s\n", ""); + break; + } if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_UCIC_BLOCK)) { if ((sngss7_test_ckt_flag(sngss7_info, FLAG_RESET_RX)) || @@ -1225,6 +1241,8 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* clear the PAUSE flag */ sngss7_clear_ckt_flag(sngss7_info, FLAG_INFID_PAUSED); + /* We tried to hangup the call while in PAUSED state. + We must send a RESET to clear this circuit */ if (sngss7_test_ckt_flag (sngss7_info, FLAG_LOCAL_REL)) { SS7_DEBUG_CHAN(ftdmchan, "Channel local release on RESUME, restart Reset procedure%s\n", ""); /* By setting RESET_TX flag the check below sngss7_tx_reset_status_pending() will From ce9ce53b2d9496052a741739100a8ec2a71e75d2 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Wed, 14 Dec 2011 20:06:57 -0500 Subject: [PATCH 104/822] Fixed the previous commit --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index aef7a6edef..5edf7d4851 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -310,20 +310,21 @@ static void handle_hw_alarm(ftdm_event_t *e) if (e->channel->physical_span_id == ftdmchan->physical_span_id && e->channel->physical_chan_id == ftdmchan->physical_chan_id) { - SS7_DEBUG_CHAN(ftdmchan,"handle_hw_alarm: span=%i chan=%i ckt=%i x=%i\n",ftdmchan->physical_span_id,ftdmchan->physical_chan_id,g_ftdm_sngss7_data.cfg.isupCkt[x].id,x); + SS7_DEBUG_CHAN(ftdmchan,"handle_hw_alarm: span=%i chan=%i ckt=%i x=%i\n", + ftdmchan->physical_span_id,ftdmchan->physical_chan_id,g_ftdm_sngss7_data.cfg.isupCkt[x].id,x); if (e->enum_id == FTDM_OOB_ALARM_TRAP) { - SS7_DEBUG_CHAN(ftdmchan,"handle_hw_alarm: Set FLAG_GRP_HW_BLOCK_TX\n"); + SS7_DEBUG_CHAN(ftdmchan,"handle_hw_alarm: Set FLAG_GRP_HW_BLOCK_TX %s\n", " "); sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX); if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); } } else if (e->enum_id == FTDM_OOB_ALARM_CLEAR) { - SS7_DEBUG_CHAN(ftdmchan,"handle_hw_alarm: Clear\n"); + SS7_DEBUG_CHAN(ftdmchan,"handle_hw_alarm: Clear %s \n", " "); sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX); sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); if (sngss7_test_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX_DN)) { sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); - SS7_DEBUG_CHAN(ftdmchan,"handle_hw_alarm: Setting FLAG_GRP_HW_UNBLK_TX\n"); + SS7_DEBUG_CHAN(ftdmchan,"handle_hw_alarm: Setting FLAG_GRP_HW_UNBLK_TX %s\n"," "); if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); } From 09dd96455e20996cb4be31c310b13357fb149142 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 15 Dec 2011 12:34:56 -0500 Subject: [PATCH 105/822] switch-core: changed the exit status when modules fail to load to 65 (EX_DATAERR), init scripts must be updated to handle 65 instead of 1 to detect module loading errors --- src/switch.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/switch.c b/src/switch.c index 038dd2c759..d33f8170c2 100644 --- a/src/switch.c +++ b/src/switch.c @@ -898,7 +898,9 @@ int main(int argc, char *argv[]) if (switch_core_init_and_modload(flags, nc ? SWITCH_FALSE : SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Failed to initialize modules: %s\n", err); - return 1; + /* 65 is EX_DATAERR (see sysexits.h), meaning some input from the user failed, some init scripts use + * this to tell when fs fails to start due to configuration error */ + return 65; } if (switch_file_open(&fd, pid_path, SWITCH_FOPEN_READ, SWITCH_FPROT_UREAD | SWITCH_FPROT_UWRITE, pool) == SWITCH_STATUS_SUCCESS) { From b057d873cfd1c168bc598b3740cbb9c09b71e3c4 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Thu, 15 Dec 2011 15:47:41 -0500 Subject: [PATCH 106/822] Added a retry on configuraiton. Its possible to timeout on ISUP ckt config in scenarios of huge load. --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 5edf7d4851..a98f2ee209 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1878,6 +1878,7 @@ static ftdm_status_t ftdm_sangoma_ss7_stop(ftdm_span_t * span) static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config) { sngss7_span_data_t *ss7_span_info; + int sngss7_retry_cnt=5; ftdm_log (FTDM_LOG_INFO, "Configuring ftmod_sangoma_ss7 span = %s(%d)...\n", span->name, @@ -1932,7 +1933,13 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config) } /* configure libsngss7 */ +try_cfg_again: if (ft_to_sngss7_cfg_all()) { + if (sngss7_retry_cnt--) { + ftdm_sleep (500); + ftdm_log (FTDM_LOG_DEBUG, "Failed to configure LibSngSS7 - retrying!\n"); + goto try_cfg_again; + } ftdm_log (FTDM_LOG_CRIT, "Failed to configure LibSngSS7!\n"); ftdm_sleep (1000); return FTDM_FAIL; From 494947bf591d2d284bb52592e2609b6facdbd36f Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Thu, 15 Dec 2011 15:50:58 -0500 Subject: [PATCH 107/822] Reverted the previous commit of doing nothing on RESTART while in PAUSE --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index a98f2ee209..f6c61162b1 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1090,11 +1090,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_info->ckt_flags, sngss7_info->blk_flags); - if (sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_PAUSED)) { - SS7_DEBUG_CHAN(ftdmchan,"Circuit PAUSED stay in RESTART%s\n", ""); - break; - } - if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_UCIC_BLOCK)) { if ((sngss7_test_ckt_flag(sngss7_info, FLAG_RESET_RX)) || (sngss7_test_ckt_flag(sngss7_info, FLAG_GRP_RESET_RX))) { From 732a0ed2de6773409146debaef4a008685bb6717 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Thu, 15 Dec 2011 20:39:38 -0500 Subject: [PATCH 108/822] Fix for 3000ms timeout on hangup. Where FS does not hangup the channel with in 3sec. Without this fix, it was possible that 2 FS sessions use the single span/chan freetdm session. Merged the feature from git master of freetdm --- libs/freetdm/mod_freetdm/mod_freetdm.c | 41 +++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index ecd9189b39..003be91b17 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -496,6 +496,14 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session) private_t *tech_pvt = NULL; ftdm_chan_type_t chantype; uint32_t tokencnt; + char *uuid = NULL; + uint8_t uuid_found = 0; + uint32_t t = 0; + const char *token = NULL; + int span_id = 0; + int chan_id = 0; + const char *name = NULL; + channel = switch_core_session_get_channel(session); assert(channel != NULL); @@ -503,10 +511,42 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session) tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); + /* ignore any further I/O requests, we're hanging up already! */ + switch_clear_flag_locked(tech_pvt, TFLAG_IO); + + if (!tech_pvt->ftdmchan) { goto end; } + name = switch_channel_get_name(channel); + + span_id = tech_pvt->ftdmchan ? ftdm_channel_get_span_id(tech_pvt->ftdmchan) : 0; + chan_id = tech_pvt->ftdmchan ? ftdm_channel_get_id(tech_pvt->ftdmchan) : 0; + + + /* Now verify the device is still attached to this call :-) + * Sometimes the FS core takes too long (more than 3 seconds) in calling + * channel_on_hangup() and the FreeTDM core decides to take the brute + * force approach and hangup and detach themselves from the call. Later + * when FS finally comes around, we might end up hanging up the device + * attached to another call, this verification avoids that. */ + uuid = switch_core_session_get_uuid(session); + tokencnt = ftdm_channel_get_token_count(tech_pvt->ftdmchan); + for (t = 0; t < tokencnt; t++) { + token = ftdm_channel_get_token(tech_pvt->ftdmchan, t); + if (!zstr(token) && !strcasecmp(uuid, token)) { + uuid_found = 1; + break; + } + } + + if (!uuid_found) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Device [%d:%d] is no longer attached to %s. Nothing to do.\n", span_id, chan_id, name); + goto end; + } + + ftdm_channel_clear_token(tech_pvt->ftdmchan, switch_core_session_get_uuid(session)); chantype = ftdm_channel_get_type(tech_pvt->ftdmchan); @@ -2459,7 +2499,6 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal) switch_set_flag_locked(tech_pvt, TFLAG_DEAD); channel = switch_core_session_get_channel(session); switch_channel_hangup(channel, caller_data->hangup_cause); - ftdm_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session)); switch_core_session_rwunlock(session); } } From 485746305a420a0993da0cb539e0a58789bdd993 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Fri, 16 Dec 2011 10:06:57 -0500 Subject: [PATCH 109/822] Set the cpu thresholds to 92 and 82 Set the 3000ms warning to NOTICE not CRIT --- libs/freetdm/src/ftdm_io.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index bb866610a2..731b9f88ef 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -5455,7 +5455,7 @@ static void execute_safety_hangup(void *data) ftdm_channel_lock(fchan); fchan->hangup_timer = 0; if (fchan->state == FTDM_CHANNEL_STATE_TERMINATING) { - ftdm_log_chan(fchan, FTDM_LOG_CRIT, "Forcing hangup since the user did not confirmed our hangup after %dms\n", FORCE_HANGUP_TIMER); + ftdm_log_chan(fchan, FTDM_LOG_NOTICE, "Forcing hangup since the user did not confirmed our hangup after %dms\n", FORCE_HANGUP_TIMER); _ftdm_channel_call_hangup_nl(__FILE__, __FUNCTION__, __LINE__, fchan, NULL); } else { ftdm_log_chan(fchan, FTDM_LOG_CRIT, "Not performing safety hangup, channel state is %s\n", ftdm_channel_state2str(fchan->state)); @@ -5722,8 +5722,8 @@ FT_DECLARE(ftdm_status_t) ftdm_global_configuration(void) globals.cpu_monitor.enabled = 0; globals.cpu_monitor.interval = 1000; globals.cpu_monitor.alarm_action_flags = 0; - globals.cpu_monitor.set_alarm_threshold = 80; - globals.cpu_monitor.clear_alarm_threshold = 70; + globals.cpu_monitor.set_alarm_threshold = 92; + globals.cpu_monitor.clear_alarm_threshold = 82; if (load_config() != FTDM_SUCCESS) { globals.running = 0; From 83b5929e482a30c7ff265904fe25270db9686148 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sat, 17 Dec 2011 19:36:47 -0500 Subject: [PATCH 110/822] freetdm: remove duplicated ss7 code for location number (previous git merge duplicated it) --- .../ftmod_sangoma_ss7_handle.c | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index b8154f96e8..6a061312a8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -249,34 +249,6 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ SS7_DEBUG_CHAN(ftdmchan, "No Location Number information in IAM%s\n", " "); } - /* Retrieve the Location Number if present (see ITU Q.763, 3.30) */ - if (siConEvnt->cgPtyNum1.eh.pres) { - if (siConEvnt->cgPtyNum1.addrSig.pres) { - /* fill in the ss7 location address number */ - copy_tknStr_from_sngss7(siConEvnt->cgPtyNum1.addrSig, var, siConEvnt->cgPtyNum1.oddEven); - sngss7_add_var(sngss7_info, "ss7_loc_digits", var); - } - - if (siConEvnt->cgPtyNum1.scrnInd.pres) { - /* fill in the screening indication value */ - sprintf(var, "%d", siConEvnt->cgPtyNum1.scrnInd.val); - sngss7_add_var(sngss7_info, "ss7_loc_screen_ind", var); - } - - if (siConEvnt->cgPtyNum1.presRest.pres) { - /* fill in the presentation value */ - sprintf(var, "%d", siConEvnt->cgPtyNum1.presRest.val); - sngss7_add_var(sngss7_info, "ss7_loc_pres_ind", var); - } - - if (siConEvnt->cgPtyNum1.natAddrInd.pres) { - sprintf(var, "%d", siConEvnt->cgPtyNum1.natAddrInd.val); - sngss7_add_var(sngss7_info, "ss7_loc_nadi", var); - } - } else { - SS7_DEBUG_CHAN(ftdmchan, "No Location Number information in IAM%s\n", " "); - } - sprintf(var, "%d", sngss7_info->circuit->cic); sngss7_add_var(sngss7_info, "ss7_cic", var); From 7e2ef3a55cdd77148941772f8170b72dc3b6c651 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Sun, 18 Dec 2011 23:02:59 -0500 Subject: [PATCH 111/822] freetdm: The remote hangup logic that waits for 3sec for FS to hanup up before hanging up the freetdm channel by force seems to have a memory leak. I have increased the timeout to 30sec and made the print statement WARNING level. --- libs/freetdm/src/ftdm_io.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 731b9f88ef..8b179ccf05 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -52,7 +52,7 @@ struct tm *localtime_r(const time_t *clock, struct tm *result); #endif -#define FORCE_HANGUP_TIMER 3000 +#define FORCE_HANGUP_TIMER 30000 #define SPAN_PENDING_CHANS_QUEUE_SIZE 1000 #define SPAN_PENDING_SIGNALS_QUEUE_SIZE 1000 #define FTDM_READ_TRACE_INDEX 0 @@ -5455,7 +5455,7 @@ static void execute_safety_hangup(void *data) ftdm_channel_lock(fchan); fchan->hangup_timer = 0; if (fchan->state == FTDM_CHANNEL_STATE_TERMINATING) { - ftdm_log_chan(fchan, FTDM_LOG_NOTICE, "Forcing hangup since the user did not confirmed our hangup after %dms\n", FORCE_HANGUP_TIMER); + ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Forcing hangup since the user did not confirmed our hangup after %dms\n", FORCE_HANGUP_TIMER); _ftdm_channel_call_hangup_nl(__FILE__, __FUNCTION__, __LINE__, fchan, NULL); } else { ftdm_log_chan(fchan, FTDM_LOG_CRIT, "Not performing safety hangup, channel state is %s\n", ftdm_channel_state2str(fchan->state)); From b6ca6c5b1da2d577d6ae95cbf0ce445ed59f2043 Mon Sep 17 00:00:00 2001 From: Nenad Corbic Date: Mon, 19 Dec 2011 02:27:38 -0500 Subject: [PATCH 112/822] freetdm: Added sng_cc_resource_check() On SIG Down we must not fail a call instead try hunting for another. The only time we can fail the call and not bother hunting is if sng_cc_resource_check fails. Took out configuration retry as the config code is now fixed in sng_ss7 library. Transaction id fix. Unit Tested: NSG UP -- start full load kill NSG NSG UP again on full load make sure it comes up fine. --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c | 9 +++---- .../ftmod_sangoma_ss7_main.c | 25 +++++++++++-------- .../ftmod_sangoma_ss7_main.h | 6 +++++ 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c index 25510e8c7a..327ca40f05 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c @@ -77,9 +77,9 @@ int ft_to_sngss7_cfg_all(void) int ret = 0; /* check if we have done gen_config already */ - if (!(g_ftdm_sngss7_data.gen_config)) { + if (g_ftdm_sngss7_data.gen_config == SNG_GEN_CFG_STATUS_INIT) { /* update the global gen_config so we don't do it again */ - g_ftdm_sngss7_data.gen_config = 1; + g_ftdm_sngss7_data.gen_config = SNG_GEN_CFG_STATUS_PENDING; /* start of by checking if the license and sig file are valid */ if (sng_validate_license(g_ftdm_sngss7_data.cfg.license, @@ -209,13 +209,12 @@ int ft_to_sngss7_cfg_all(void) } } /* if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP2)) */ - g_ftdm_sngss7_data.gen_config = 2; + g_ftdm_sngss7_data.gen_config = SNG_GEN_CFG_STATUS_DONE; } /* if (!(g_ftdm_sngss7_data.gen_config)) */ - /* FIXME: Please change number 2 to an ENUM that is more explanatory */ - if (g_ftdm_sngss7_data.gen_config != 2) { + if (g_ftdm_sngss7_data.gen_config != SNG_GEN_CFG_STATUS_DONE) { SS7_CRITICAL("General configuration FAILED!\n"); return 1; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index f6c61162b1..c963ea7cb7 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1653,8 +1653,10 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(ftdm_sangoma_ss7_outgoing_call) /* check if the channel sig state is UP */ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) { - SS7_ERROR_CHAN(ftdmchan, "Requested channel sig state is down, cancelling call!%s\n", " "); - goto outgoing_fail; + SS7_ERROR_CHAN(ftdmchan, "Requested channel sig state is down, skipping channell!%s\n", " "); + /* Sig state will be down due to a block. + Right action is to hunt for another call */ + goto outgoing_break; } /* check if there is a remote block */ @@ -1679,6 +1681,14 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(ftdm_sangoma_ss7_outgoing_call) goto outgoing_break; } + + /* This is a gracefull stack resource check. + Removing this function will cause unpredictable + ungracefule errors. */ + if (sng_cc_resource_check()) { + goto outgoing_fail; + } + /* check the state of the channel */ switch (ftdmchan->state){ /**************************************************************************/ @@ -1873,7 +1883,6 @@ static ftdm_status_t ftdm_sangoma_ss7_stop(ftdm_span_t * span) static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config) { sngss7_span_data_t *ss7_span_info; - int sngss7_retry_cnt=5; ftdm_log (FTDM_LOG_INFO, "Configuring ftmod_sangoma_ss7 span = %s(%d)...\n", span->name, @@ -1923,20 +1932,14 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config) /* parse the configuration and apply to the global config structure */ if (ftmod_ss7_parse_xml(ftdm_parameters, span)) { ftdm_log (FTDM_LOG_CRIT, "Failed to parse configuration!\n"); - ftdm_sleep (1000); + ftdm_sleep (100); return FTDM_FAIL; } /* configure libsngss7 */ -try_cfg_again: if (ft_to_sngss7_cfg_all()) { - if (sngss7_retry_cnt--) { - ftdm_sleep (500); - ftdm_log (FTDM_LOG_DEBUG, "Failed to configure LibSngSS7 - retrying!\n"); - goto try_cfg_again; - } ftdm_log (FTDM_LOG_CRIT, "Failed to configure LibSngSS7!\n"); - ftdm_sleep (1000); + ftdm_sleep (100); return FTDM_FAIL; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index bb02d7e3ed..78210d50fb 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -116,6 +116,12 @@ typedef enum { SNG_CALLING = 2 } sng_addr_type_t; +typedef enum { + SNG_GEN_CFG_STATUS_INIT = 0, + SNG_GEN_CFG_STATUS_PENDING = 1, + SNG_GEN_CFG_STATUS_DONE = 2 +} nsg_gen_cfg_type_t; + typedef struct sng_mtp2_error_type { int init; char sng_type[MAX_NAME_LEN]; From 8eeb37a81b57226053caf9c2d151de721e4f6308 Mon Sep 17 00:00:00 2001 From: William Adam Date: Wed, 21 Dec 2011 14:56:03 -0500 Subject: [PATCH 113/822] Fixed bug#2215 - SPIROU transparent IAM max size error --- .../freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index f1c6625b85..f7d0171f93 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -1923,7 +1923,7 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) SS7_DEBUG("Found transparent_iam %d\n", sng_ccSpan.transparent_iam); #endif } else if (!strcasecmp(parm->var, "transparent_iam_max_size")) { - sng_ccSpan.transparent_iam_max_size = ftdm_true(parm->val); + sng_ccSpan.transparent_iam_max_size = atoi(parm->val); SS7_DEBUG("Found transparent_iam_max_size %d\n", sng_ccSpan.transparent_iam_max_size); } else if (!strcasecmp(parm->var, "cpg_on_progress_media")) { sng_ccSpan.cpg_on_progress_media = ftdm_true(parm->val); From 5ac80d39399a366ee72aa80cbd2e12aa100016c1 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 19 Jan 2012 16:31:52 -0500 Subject: [PATCH 114/822] FreeTDM: fixing redirect information outgoing call bug --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c | 11 +++++++++++ .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 0497955059..0bed14c2e6 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -252,8 +252,19 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sprintf(var, "%d", sngss7_info->circuit->cic); sngss7_add_var(sngss7_info, "ss7_cic", var); + + if (siConEvnt->orgPteCde.eh.pres) { + sprintf(var, "%d",(uint32_t)siConEvnt->orgPteCde.sigPointCode.val); + sngss7_add_var(sngss7_info, "ss7_opc", var); + SS7_DEBUG_CHAN(ftdmchan, " OPC = d%\n", (uint32_t)siConEvnt->orgPteCde.sigPointCode.val); + } else { + SS7_DEBUG_CHAN(ftdmchan, "No OPC information in IAM%s\n", " "); + } + + /* original code, should be removed after review. sprintf(var, "%d", g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].spc ); sngss7_add_var(sngss7_info, "ss7_opc", var); + */ if (siConEvnt->callRef.callId.pres) { /* %x expect an unsigned int so as callId is a U32, casting to uint32_t diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 3230292675..59777b048b 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -585,6 +585,7 @@ ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *r val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdinfo_indicator"); if (!ftdm_strlen_zero(val)) { redirInfo->redirInd.val = atoi(val); + redirInfo->redirInd.pres = 1; bProceed = 1; } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Redirection Information on Redirection Indicator\n"); @@ -593,6 +594,7 @@ ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *r val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdinfo_orig"); if (!ftdm_strlen_zero(val)) { redirInfo->origRedirReas.val = atoi(val); + redirInfo->origRedirReas.pres = 1; bProceed = 1; } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Redirection Information on Original Reasons\n"); @@ -601,6 +603,7 @@ ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *r val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdinfo_count"); if (!ftdm_strlen_zero(val)) { redirInfo->redirCnt.val = atoi(val); + redirInfo->redirCnt.pres= 1; bProceed = 1; } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Redirection Information on Redirection Count\n"); @@ -609,6 +612,7 @@ ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *r val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdinfo_reason"); if (!ftdm_strlen_zero(val)) { redirInfo->redirReas.val = atoi(val); + redirInfo->redirReas.pres = 1; bProceed = 1; } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Redirection Information on Redirection Reasons\n"); From 63ecf4e9091c1a9f2fd18d5ce324375275162739 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 19 Jan 2012 16:55:15 -0500 Subject: [PATCH 115/822] FreeTDM: remove the portion of opc fix --- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 0bed14c2e6..a4d16b7dd2 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -253,18 +253,8 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_add_var(sngss7_info, "ss7_cic", var); - if (siConEvnt->orgPteCde.eh.pres) { - sprintf(var, "%d",(uint32_t)siConEvnt->orgPteCde.sigPointCode.val); - sngss7_add_var(sngss7_info, "ss7_opc", var); - SS7_DEBUG_CHAN(ftdmchan, " OPC = d%\n", (uint32_t)siConEvnt->orgPteCde.sigPointCode.val); - } else { - SS7_DEBUG_CHAN(ftdmchan, "No OPC information in IAM%s\n", " "); - } - - /* original code, should be removed after review. sprintf(var, "%d", g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].spc ); sngss7_add_var(sngss7_info, "ss7_opc", var); - */ if (siConEvnt->callRef.callId.pres) { /* %x expect an unsigned int so as callId is a U32, casting to uint32_t From 8d1d930085d9a594bff424d01ca5f9f8c33fbd72 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 19 Jan 2012 18:04:03 -0500 Subject: [PATCH 116/822] FreeTDM: fixing OPC bug using local SPC - take the DPC of the link and set it as OPC in x-header - this is what the user want's to have --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index a4d16b7dd2..9c3bd65426 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -253,7 +253,7 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_add_var(sngss7_info, "ss7_cic", var); - sprintf(var, "%d", g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].spc ); + sprintf(var, "%d", g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].dpc ); sngss7_add_var(sngss7_info, "ss7_opc", var); if (siConEvnt->callRef.callId.pres) { From 34c8e58ae1a500d0fd1855b88c4ce86f317fc03f Mon Sep 17 00:00:00 2001 From: James Zhang Date: Wed, 25 Jan 2012 16:00:20 -0500 Subject: [PATCH 117/822] FreeTDM: location value in REL message set to 0x04 - only available to SPIROU --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index fbfab15d1e..4b5f82f52d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -259,7 +259,11 @@ void ft_to_sngss7_rel (ftdm_channel_t * ftdmchan) rel.causeDgn.eh.pres = PRSNT_NODEF; rel.causeDgn.location.pres = PRSNT_NODEF; +#ifdef SANGOMA_SPIROU + rel.causeDgn.location.val = 0x04; +#else rel.causeDgn.location.val = 0x01; +#endif rel.causeDgn.cdeStand.pres = PRSNT_NODEF; rel.causeDgn.cdeStand.val = 0x00; rel.causeDgn.recommend.pres = NOTPRSNT; From 28e27248e5d86ef553973dc39827bd099d2db853 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Wed, 25 Jan 2012 18:00:41 -0500 Subject: [PATCH 118/822] FreeTDM: remove the previous commit - hardcode does not work in this matter --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index 4b5f82f52d..fbfab15d1e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -259,11 +259,7 @@ void ft_to_sngss7_rel (ftdm_channel_t * ftdmchan) rel.causeDgn.eh.pres = PRSNT_NODEF; rel.causeDgn.location.pres = PRSNT_NODEF; -#ifdef SANGOMA_SPIROU - rel.causeDgn.location.val = 0x04; -#else rel.causeDgn.location.val = 0x01; -#endif rel.causeDgn.cdeStand.pres = PRSNT_NODEF; rel.causeDgn.cdeStand.val = 0x00; rel.causeDgn.recommend.pres = NOTPRSNT; From 90f538c0a0e08197f9add62131f1a5ee9a3522c0 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 26 Jan 2012 11:19:41 -0500 Subject: [PATCH 119/822] FreeTDM: Fixing issues of SPIROU - redirect number in Transparent IAM - redirect information in Transparent IAM - called party number in Transparent IAM - adding incoming uuid to x-header to check loop calls --- libs/freetdm/mod_freetdm/mod_freetdm.c | 23 ++++++++++++++++++- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 9 ++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 003be91b17..e694a0f8fa 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -115,6 +115,8 @@ struct private_object { ftdm_channel_t *ftdmchan; uint32_t write_error; uint32_t read_error; + char network_peer_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1]; + }; /* private data attached to FTDM channels (only FXS for now) */ @@ -1246,6 +1248,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi int argc = 0; const char *var; const char *dest_num = NULL, *callerid_num = NULL; + const char *network_peer_uuid = NULL; ftdm_hunting_scheme_t hunting; ftdm_usrmsg_t usrmsg; @@ -1336,6 +1339,9 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi if (session && globals.sip_headers) { switch_channel_t *channel = switch_core_session_get_channel(session); const char *sipvar; + + network_peer_uuid = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-TransUUID"); + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-CallerName"); if (sipvar) { ftdm_set_string(caller_data.cid_name, sipvar); @@ -1592,6 +1598,20 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi goto fail; } + if (network_peer_uuid) { + switch_core_session_t *network_peer = switch_core_session_locate(network_peer_uuid); + if (network_peer) { + const char *my_uuid = switch_core_session_get_uuid(*new_session); + private_t *peer_private = switch_core_session_get_private(network_peer); + switch_set_string(tech_pvt->network_peer_uuid, network_peer_uuid); + switch_set_string(peer_private->network_peer_uuid, my_uuid); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Session %s is network-bridged with %s\n", my_uuid, network_peer_uuid); + + switch_core_session_rwunlock(network_peer); + } + } + caller_profile = switch_caller_profile_clone(*new_session, outbound_profile); caller_profile->destination_number = switch_core_strdup(caller_profile->pool, switch_str_nil(dest_num)); caller_profile->caller_id_number = switch_core_strdup(caller_profile->pool, switch_str_nil(callerid_num)); @@ -1617,7 +1637,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi } else { cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; } - goto fail; + goto fail; } return SWITCH_CAUSE_SUCCESS; @@ -1746,6 +1766,7 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session if (globals.sip_headers) { switch_channel_set_variable(channel, "sip_h_X-FreeTDM-SpanName", ftdm_channel_get_span_name(sigmsg->channel)); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-TransUUID", "%s",switch_core_session_get_uuid(session)); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-SpanNumber", "%d", spanid); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-ChanNumber", "%d", chanid); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index fbfab15d1e..0c8cf3832a 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -58,6 +58,15 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) if (sngss7_info->circuit->transparent_iam && sngss7_retrieve_iam(ftdmchan, &iam) == FTDM_SUCCESS) { SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Transparent)\n", sngss7_info->circuit->cic); + + /* Called Number information */ + copy_cdPtyNum_to_sngss7(ftdmchan, &iam.cdPtyNum); + + /* Redirecting Number */ + copy_redirgNum_to_sngss7(ftdmchan, &iam.redirgNum); + + /* Redirecting Information */ + copy_redirgInfo_to_sngss7(ftdmchan, &iam.redirInfo); } else { /* Nature of Connection Indicators */ copy_natConInd_to_sngss7(ftdmchan, &iam.natConInd); From 1b964054de8aa60299c9ffc29647ccbcd457d44f Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 26 Jan 2012 15:21:51 -0500 Subject: [PATCH 120/822] freetdm: Add new queue for ss7 clone messages, all incoming messages are queued now --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 18 ++++++++++++++++++ .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h | 1 + .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 3 +++ 3 files changed, 22 insertions(+) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index c963ea7cb7..ebee2c382d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -511,6 +511,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev { sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + sngss7_event_data_t *event_clone = NULL; /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(sngss7_event->circuit, &sngss7_info, &ftdmchan)) { @@ -521,6 +522,22 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev /* now that we have the right channel ... put a lock on it so no-one else can use it */ ftdm_channel_lock(ftdmchan); + if (sngss7_info->event_queue) { + if (sngss7_event->event_id == SNGSS7_CON_IND_EVENT) { + /* this is the first event in a call, flush the event queue */ + while ((event_clone = ftdm_queue_dequeue(sngss7_info->event_queue))) { + SS7_WARN("Discarding clone event from past call for circuit = %d!\n", sngss7_event->circuit); + ftdm_safe_free(event_clone); + } + } + /* clone the event and save it for later usage */ + event_clone = ftdm_calloc(1, sizeof(*sngss7_event)); + if (event_clone) { + memcpy(clone, sngss7_event, sizeof(*sngss7_event)); + ftdm_queue_enqueue(sngss7_info->event_queue, clone); + } + } + /* while there's a state change present on this channel process it */ ftdm_channel_advance_states(ftdmchan); @@ -576,6 +593,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev break; /**************************************************************************/ case (SNGSS7_SSP_STA_CFM_EVENT): + SS7_ERROR("dazed and confused ... hu?!\n"); break; /**************************************************************************/ default: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 78210d50fb..2a1ca1749e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -485,6 +485,7 @@ typedef struct sngss7_chan_data { sngss7_group_data_t rx_gra; sngss7_group_data_t tx_grs; sngss7_group_data_t ucic; + ftdm_queue_t *event_queue; } sngss7_chan_data_t; #define SNGSS7_RX_GRS_PENDING (1 << 0) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index f7d0171f93..d7732cce6c 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -2925,6 +2925,9 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan) /* prepare the global info sturcture */ ss7_info = ftdm_calloc(1, sizeof(sngss7_chan_data_t)); ss7_info->ftdmchan = NULL; + if (ftdm_queue_create(&ss7_info->event_queue, SNGSS7_EVENT_QUEUE_SIZE) != FTDM_SUCCESS) { + SS7_CRITICAL("Failed to create ss7 cic event queue\n"); + } ss7_info->circuit = &g_ftdm_sngss7_data.cfg.isupCkt[x]; g_ftdm_sngss7_data.cfg.isupCkt[x].obj = ss7_info; From 98d566b29c5ebc43834c27c8859d042b69ef94ba Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 26 Jan 2012 16:39:43 -0500 Subject: [PATCH 121/822] FreeTDM: adding variable ss7_rel_loc for REL location indicator (to support SPIROU) --- libs/freetdm/mod_freetdm/mod_freetdm.c | 11 +++++++++++ .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 11 ++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index e694a0f8fa..1ecf1fe7ef 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -506,6 +506,9 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session) int chan_id = 0; const char *name = NULL; + ftdm_usrmsg_t usrmsg; + memset(&usrmsg, 0, sizeof(ftdm_usrmsg_t)); + channel = switch_core_session_get_channel(session); assert(channel != NULL); @@ -574,11 +577,19 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session) case FTDM_CHAN_TYPE_CAS: case FTDM_CHAN_TYPE_B: { + const char *sipvar; ftdm_call_cause_t hcause = switch_channel_get_cause_q850(channel); if (hcause < 1 || hcause > 127) { hcause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER; } + sipvar = switch_channel_get_variable(channel, "ss7_rel_loc"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_rel_loc", sipvar); + } + /* ftdm_channel_call_hangup_with_cause(tech_pvt->ftdmchan, hcause); + */ + ftdm_channel_call_hangup_with_cause_ex(tech_pvt->ftdmchan, hcause, &usrmsg); } break; default: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index 0c8cf3832a..f73fd871b4 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -259,6 +259,7 @@ void ft_to_sngss7_anm (ftdm_channel_t * ftdmchan) /******************************************************************************/ void ft_to_sngss7_rel (ftdm_channel_t * ftdmchan) { + const char *loc_ind = NULL; SS7_FUNC_TRACE_ENTER (__FUNCTION__); sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; @@ -268,7 +269,15 @@ void ft_to_sngss7_rel (ftdm_channel_t * ftdmchan) rel.causeDgn.eh.pres = PRSNT_NODEF; rel.causeDgn.location.pres = PRSNT_NODEF; - rel.causeDgn.location.val = 0x01; + + loc_ind = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rel_loc"); + if (!ftdm_strlen_zero(loc_ind)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied location indicator in REL, value \"%s\"\n", loc_ind); + rel.causeDgn.location.val = atoi(loc_ind); + } else { + rel.causeDgn.location.val = 0x01; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied location indicator in REL, using 0x01\"%s\"\n", ""); + } rel.causeDgn.cdeStand.pres = PRSNT_NODEF; rel.causeDgn.cdeStand.val = 0x00; rel.causeDgn.recommend.pres = NOTPRSNT; From a1a1af579b9b6cbf7349c5e39b8d51a260eb443f Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 26 Jan 2012 16:50:38 -0500 Subject: [PATCH 122/822] freetdm: Implement SS7 transparent IAM functionality using the event clones queue --- libs/freetdm/mod_freetdm/mod_freetdm.c | 17 ++++++ .../ftmod_sangoma_ss7_main.c | 15 ++++- .../ftmod_sangoma_ss7_main.h | 1 + .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 55 ++++++++++++++++++- 4 files changed, 86 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 003be91b17..204e5a894f 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1603,6 +1603,23 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi hunt_data.tech_pvt = tech_pvt; caller_data.priv = &hunt_data; + if (session + && (var = channel_get_variable(session, var_event, FREETDM_VAR_PREFIX "native_sigbridge")) + && switch_true(var) + && switch_core_session_compare(*new_session, session)) { + char sigbridge_peer[255]; + private_t *peer_pvt = switch_core_session_get_private(session); + switch_channel_t *peer_chan = switch_core_session_get_channel(session); + switch_channel_t *our_chan = switch_core_session_get_channel(*new_session); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, + "Bridging native signaling of channel %s to channel %s\n", + switch_channel_get_name(peer_chan), switch_channel_get_name(our_chan)); + snprintf(sigbridge_peer, sizeof(sigbridge_peer), "%u:%u", + ftdm_channel_get_span_id(peer_pvt->ftdmchan), ftdm_channel_get_id(peer_pvt->ftdmchan)); + ftdm_usrmsg_add_var(&usrmsg, "sigbridge_peer", sigbridge_peer); + } + + if ((status = ftdm_call_place_ex(&caller_data, &hunting, &usrmsg)) != FTDM_SUCCESS) { if (tech_pvt->read_codec.implementation) { switch_core_codec_destroy(&tech_pvt->read_codec); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index ebee2c382d..bcb518ff9d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -526,7 +526,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev if (sngss7_event->event_id == SNGSS7_CON_IND_EVENT) { /* this is the first event in a call, flush the event queue */ while ((event_clone = ftdm_queue_dequeue(sngss7_info->event_queue))) { - SS7_WARN("Discarding clone event from past call for circuit = %d!\n", sngss7_event->circuit); + SS7_WARN("[CIC:%d]Discarding clone event from past call!\n", sngss7_info->circuit->cic); ftdm_safe_free(event_clone); } } @@ -1076,6 +1076,19 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) if (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_OPEN)) { ftdm_channel_t *close_chan = ftdmchan; + + /* detach native bridging if needed (only the outbound leg is responsible for that) + Inbound leg was responsible of flushing its queue of events, but peer attach/detach + is left as an outbound leg responsibility + */ + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + sngss7_chan_data_t *peer_info = sngss7_info->peer_data; + sngss7_info->peer_data = NULL; + if (peer_info) { + peer_info->peer_data = NULL; + } + } + /* close the channel */ SS7_DEBUG_CHAN(ftdmchan,"FTDM Channel Close %s\n", ""); ftdm_channel_close (&close_chan); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 2a1ca1749e..2fc6f740c7 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -486,6 +486,7 @@ typedef struct sngss7_chan_data { sngss7_group_data_t tx_grs; sngss7_group_data_t ucic; ftdm_queue_t *event_queue; + struct sngss7_chan_data *peer_data; } sngss7_chan_data_t; #define SNGSS7_RX_GRS_PENDING (1 << 0) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index fbfab15d1e..eda03715f3 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -44,6 +44,7 @@ /* FUNCTIONS ******************************************************************/ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) { + const char *var = NULL; SiConEvnt iam; sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;; @@ -55,7 +56,59 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) memset (&iam, 0x0, sizeof (iam)); - if (sngss7_info->circuit->transparent_iam && + var = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "sigbridge_peer"); + if (!ftdm_strlen_zero(var)) { + ftdm_status_t status = FTDM_SUCCESS; + int rc = 0; + ftdm_span_t *peer_span = NULL; + ftdm_channel_t *peer_chan = NULL; + sngss7_chan_data_t *peer_info = NULL; + unsigned peer_span_id = 0; + unsigned peer_chan_id = 0; + rc = sscanf(var, "%u:%u", &peer_span_id, &peer_chan_id); + if (rc != 2) { + SS7_ERROR_CHAN(ftdmchan, "Failed to parse sigbridge_peer string '%s'\n", var); + } else { + status = ftdm_span_find(peer_span_id, &peer_span); + if (status != FTDM_SUCCESS || !peer_span) { + SS7_ERROR_CHAN(ftdmchan, "Failed to find peer span for channel id '%u:%u'\n", peer_span_id, peer_chan_id); + } else if (peer_span->signal_type != FTDM_SIGTYPE_SS7) { + SS7_ERROR_CHAN(ftdmchan, "Peer channel %d:%d has different signaling type %d'\n", + peer_span_id, peer_chan_id, peer_span->signal_type); + } else { + if (peer_chan_id > (FTDM_MAX_CHANNELS_SPAN+1) || !(peer_chan = peer_span->channels[peer_chan_id])) { + SS7_ERROR_CHAN(ftdmchan, "Invalid peer channel id '%u:%u'\n", peer_span_id, peer_chan_id); + } else { + sngss7_event_data_t *event_clone = NULL; + peer_info = peer_chan->call_data; + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Starting native bridge with peer CIC %d\n", + sngss7_info->circuit->cic, peer_info->circuit->cic); + /* make each one of us aware of the native bridge */ + peer_info->peer_data = sngss7_info; + sngss7_info->peer_data = peer_info; + /* flush our own queue */ + while ((event_clone = ftdm_queue_dequeue(sngss7_info->event_queue))) { + SS7_WARN("[CIC:%d]Discarding clone event from past call!\n", sngss7_info->circuit->cic); + ftdm_safe_free(event_clone); + } + } + } + } + } + + if (sngss7_info->peer_data) { + sngss7_event_data_t *event_clone = ftdm_queue_dequeue(sngss7_info->peer_data->event_queue); + /* Retrieve IAM from our peer */ + if (!event_clone) { + SS7_ERROR_CHAN(ftdmchan, "No event clone in peer queue!%s\n", ""); + } else if (event_clone->event_id != SNGSS7_CON_IND_EVENT) { + /* first message in the queue should ALWAYS be an IAM */ + SS7_ERROR_CHAN(ftdmchan, "Invalid initial peer message type '%d'\n", event_clone->event_id); + } else { + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged)\n", sngss7_info->circuit->cic); + memcpy(&iam, &event_clone->event.siConEvnt, sizeof(iam)); + } + } else if (sngss7_info->circuit->transparent_iam && sngss7_retrieve_iam(ftdmchan, &iam) == FTDM_SUCCESS) { SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Transparent)\n", sngss7_info->circuit->cic); } else { From b4e8d5b6086ddf861760db21686ad4344f470356 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 26 Jan 2012 17:22:45 -0500 Subject: [PATCH 123/822] freetdm: Fix incorrect variable name leading to segfault --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index bcb518ff9d..96b662bdbb 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -533,8 +533,8 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev /* clone the event and save it for later usage */ event_clone = ftdm_calloc(1, sizeof(*sngss7_event)); if (event_clone) { - memcpy(clone, sngss7_event, sizeof(*sngss7_event)); - ftdm_queue_enqueue(sngss7_info->event_queue, clone); + memcpy(event_clone, sngss7_event, sizeof(*sngss7_event)); + ftdm_queue_enqueue(sngss7_info->event_queue, event_clone); } } From 95baef882153eef83885022024ef5c07251b3a79 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 26 Jan 2012 17:37:35 -0500 Subject: [PATCH 124/822] FreeTDM: patch SPIROU requests - adding freetdm_iam_loc_pres variable to disable LOC in transparent IAM - confirming freetdm_bearer_capability is working properly --- libs/freetdm/mod_freetdm/mod_freetdm.c | 4 ++++ .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 3 +++ .../ftmod_sangoma_ss7_support.c | 22 ++++++++++++++----- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 1ecf1fe7ef..c2712621da 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1523,9 +1523,13 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi caller_data.pres = FTDM_PRES_RESTRICTED; } + if ((var = channel_get_variable(session, var_event, "freetdm_iam_loc_pres"))) { + ftdm_usrmsg_add_var(&usrmsg, "iam_loc_pres", var); + } if ((var = channel_get_variable(session, var_event, "freetdm_bearer_capability"))) { caller_data.bearer_capability = (uint8_t)atoi(var); } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "freetdm_bearer_capability is set to %s \n", var ); if ((var = channel_get_variable(session, var_event, "freetdm_bearer_layer1"))) { caller_data.bearer_layer1 = (uint8_t)atoi(var); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index f73fd871b4..a5311e9afc 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -67,6 +67,9 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* Redirecting Information */ copy_redirgInfo_to_sngss7(ftdmchan, &iam.redirInfo); + + /* Location Number information */ + copy_locPtyNum_to_sngss7(ftdmchan, &iam.cgPtyNum1); } else { /* Nature of Connection Indicators */ copy_natConInd_to_sngss7(ftdmchan, &iam.natConInd); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 59777b048b..957649fa21 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -243,15 +243,25 @@ ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *loc { const char *val = NULL; const char *loc_nadi = NULL; + int pres_val = PRSNT_NODEF; sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; - locPtyNum->eh.pres = PRSNT_NODEF; - locPtyNum->natAddrInd.pres = PRSNT_NODEF; + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "iam_loc_pres"); + if (!ftdm_strlen_zero(val)) { + if (!strcasecmp(val, "false")) { + pres_val = NOTPRSNT; + } + } + + + locPtyNum->eh.pres = pres_val; + locPtyNum->natAddrInd.pres = pres_val; locPtyNum->natAddrInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].loc_nadi; - locPtyNum->scrnInd.pres = PRSNT_NODEF; + locPtyNum->scrnInd.pres = pres_val; val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_loc_screen_ind"); if (!ftdm_strlen_zero(val)) { locPtyNum->scrnInd.val = atoi(val); @@ -260,7 +270,7 @@ ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *loc } ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Location Reference Code Screening Ind %d\n", locPtyNum->scrnInd.val); - locPtyNum->presRest.pres = PRSNT_NODEF; + locPtyNum->presRest.pres = pres_val; val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_pres_ind"); if (!ftdm_strlen_zero(val)) { locPtyNum->presRest.val = atoi(val); @@ -269,10 +279,10 @@ ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *loc } ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Calling Party Number Presentation Ind %d\n", locPtyNum->presRest.val); - locPtyNum->numPlan.pres = PRSNT_NODEF; + locPtyNum->numPlan.pres = pres_val; locPtyNum->numPlan.val = 0x01; - locPtyNum->niInd.pres = PRSNT_NODEF; + locPtyNum->niInd.pres = pres_val; locPtyNum->niInd.val = 0x00; /* check if the user would like a custom NADI value for the Location Reference */ From 3235fa079a26142e8c499441b08660254dfee55c Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 26 Jan 2012 18:00:34 -0500 Subject: [PATCH 125/822] FreeTDM: fix for SPIROU - adding freetdm_iam_fwd_ind_isdn_access_ind (value must be 0 or 1) to modify forward call indicator's ISDN access indicator value in transparent IAM --- libs/freetdm/mod_freetdm/mod_freetdm.c | 5 ++++- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 3 +++ .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c | 10 +++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index c2712621da..cdcb8ca1e0 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1523,13 +1523,16 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi caller_data.pres = FTDM_PRES_RESTRICTED; } + if ((var = channel_get_variable(session, var_event, "freetdm_iam_fwd_ind_isdn_access_ind"))) { + ftdm_usrmsg_add_var(&usrmsg, "iam_fwd_ind_isdn_access_ind", var); + } + if ((var = channel_get_variable(session, var_event, "freetdm_iam_loc_pres"))) { ftdm_usrmsg_add_var(&usrmsg, "iam_loc_pres", var); } if ((var = channel_get_variable(session, var_event, "freetdm_bearer_capability"))) { caller_data.bearer_capability = (uint8_t)atoi(var); } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "freetdm_bearer_capability is set to %s \n", var ); if ((var = channel_get_variable(session, var_event, "freetdm_bearer_layer1"))) { caller_data.bearer_layer1 = (uint8_t)atoi(var); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index a5311e9afc..d25b3342f0 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -70,6 +70,9 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* Location Number information */ copy_locPtyNum_to_sngss7(ftdmchan, &iam.cgPtyNum1); + + /* Forward Call Indicators */ + copy_fwdCallInd_to_sngss7(ftdmchan, &iam.fwdCallInd); } else { /* Nature of Connection Indicators */ copy_natConInd_to_sngss7(ftdmchan, &iam.natConInd); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 957649fa21..c25597cd40 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -763,6 +763,8 @@ ftdm_status_t copy_natConInd_to_sngss7(ftdm_channel_t *ftdmchan, SiNatConInd *na ftdm_status_t copy_fwdCallInd_to_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd *fwdCallInd) { + const char *val = NULL; + int acc_val = ISDNACC_ISDN; sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; fwdCallInd->eh.pres = PRSNT_NODEF; @@ -779,7 +781,13 @@ ftdm_status_t copy_fwdCallInd_to_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd * fwdCallInd->isdnUsrPrtPrfInd.pres = PRSNT_NODEF; fwdCallInd->isdnUsrPrtPrfInd.val = PREF_PREFAW; fwdCallInd->isdnAccInd.pres = PRSNT_NODEF; - fwdCallInd->isdnAccInd.val = ISDNACC_ISDN; + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "iam_fwd_ind_isdn_access_ind"); + if (!ftdm_strlen_zero(val)) { + acc_val = (int)atoi(val); + } + + fwdCallInd->isdnAccInd.val = acc_val; fwdCallInd->sccpMethInd.pres = PRSNT_NODEF; fwdCallInd->sccpMethInd.val = SCCPMTH_NOIND; From 977b546f9a420a7cc4699cabb12223744ffc93b4 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 26 Jan 2012 18:52:27 -0500 Subject: [PATCH 126/822] FreeTDM: reuse sip_h_X-FreeTDM-LOC = NULL to indicate disable LOC --- libs/freetdm/mod_freetdm/mod_freetdm.c | 3 --- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c | 9 ++------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index cdcb8ca1e0..9d15ad8eec 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1527,9 +1527,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi ftdm_usrmsg_add_var(&usrmsg, "iam_fwd_ind_isdn_access_ind", var); } - if ((var = channel_get_variable(session, var_event, "freetdm_iam_loc_pres"))) { - ftdm_usrmsg_add_var(&usrmsg, "iam_loc_pres", var); - } if ((var = channel_get_variable(session, var_event, "freetdm_bearer_capability"))) { caller_data.bearer_capability = (uint8_t)atoi(var); } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index c25597cd40..fde1278b15 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -248,15 +248,10 @@ ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *loc sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; - - val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "iam_loc_pres"); - if (!ftdm_strlen_zero(val)) { - if (!strcasecmp(val, "false")) { - pres_val = NOTPRSNT; - } + if (!strcasecmp(caller_data->loc.digits, "NULL")) { + pres_val = NOTPRSNT; } - locPtyNum->eh.pres = pres_val; locPtyNum->natAddrInd.pres = pres_val; locPtyNum->natAddrInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].loc_nadi; From 71c3cf365aa724eed3429ffc736674bf1c77cd4a Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 26 Jan 2012 19:25:04 -0500 Subject: [PATCH 127/822] FreeTDM: adding sip_h_X-FreeTDM-RDNIS-Presentation in redirecting number to give the ability to change RDNIS Presentation value for Transparent IAM --- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index fde1278b15..2088f240b6 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -444,6 +444,13 @@ ftdm_status_t copy_redirgNum_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *red return FTDM_FAIL; } } else { + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdnis_pres_ind"); + if (!ftdm_strlen_zero(val)) { + redirgNum->presRest.val = atoi(val); + } + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirecting Number Address Presentation Restricted Ind:%d\n", redirgNum->presRest.val); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Redirection Number\n"); return FTDM_SUCCESS; } From 23a328389b6bbfa905501ca907de6e2cf91a700e Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 26 Jan 2012 22:44:19 -0500 Subject: [PATCH 128/822] freetdm: Initial attempt to bridge natively SS7 signaling between 2 channels --- libs/freetdm/src/ftdm_io.c | 71 +++- .../ftmod_sangoma_ss7_main.c | 397 +++++++++++++++++- .../ftmod_sangoma_ss7_main.h | 7 +- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 61 ++- libs/freetdm/src/include/private/ftdm_core.h | 6 + libs/freetdm/src/include/private/ftdm_types.h | 2 + 6 files changed, 491 insertions(+), 53 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 8b179ccf05..6ebe5fc161 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -53,8 +53,6 @@ struct tm *localtime_r(const time_t *clock, struct tm *result); #endif #define FORCE_HANGUP_TIMER 30000 -#define SPAN_PENDING_CHANS_QUEUE_SIZE 1000 -#define SPAN_PENDING_SIGNALS_QUEUE_SIZE 1000 #define FTDM_READ_TRACE_INDEX 0 #define FTDM_WRITE_TRACE_INDEX 1 #define MAX_CALLIDS 6000 @@ -2201,6 +2199,12 @@ static ftdm_status_t _ftdm_channel_call_hangup_nl(const char *file, const char * { ftdm_status_t status = FTDM_SUCCESS; + if (ftdm_test_flag(chan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { + ftdm_log_chan_ex(chan, file, func, line, FTDM_LOG_LEVEL_DEBUG, + "Ignoring hangup in channel in state %s (native bridge enabled)\n", ftdm_channel_state2str(chan->state)); + goto done; + } + if (chan->state != FTDM_CHANNEL_STATE_DOWN) { if (chan->state == FTDM_CHANNEL_STATE_HANGUP) { /* make user's life easier, and just ignore double hangup requests */ @@ -2227,6 +2231,8 @@ static ftdm_status_t _ftdm_channel_call_hangup_nl(const char *file, const char * ftdm_channel_close(&chan); } } + +done: return status; } @@ -2322,6 +2328,15 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch ftdm_channel_lock(ftdmchan); + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { + ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_DEBUG, + "Ignoring indication %s in channel in state %s (native bridge enabled)\n", + ftdm_channel_indication2str(indication), + ftdm_channel_state2str(ftdmchan->state)); + status = FTDM_SUCCESS; + goto done; + } + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IND_ACK_PENDING)) { ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "Cannot indicate %s in channel with indication %s still pending in state %s\n", ftdm_channel_indication2str(indication), @@ -2422,10 +2437,50 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_reset(const char *file, const char *func return FTDM_SUCCESS; } +FT_DECLARE(ftdm_status_t) ftdm_get_channel_from_string(const char *string_id, ftdm_span_t **out_span, ftdm_channel_t **out_channel) +{ + ftdm_status_t status = FTDM_SUCCESS; + int rc = 0; + ftdm_span_t *span = NULL; + ftdm_channel_t *ftdmchan = NULL; + unsigned span_id = 0; + unsigned chan_id = 0; + + *out_span = NULL; + *out_channel = NULL; + + rc = sscanf(string_id, "%u:%u", &span_id, &chan_id); + if (rc != 2) { + ftdm_log(FTDM_LOG_ERROR, "Failed to parse channel id string '%s'\n", string_id); + status = FTDM_EINVAL; + goto done; + } + + status = ftdm_span_find(span_id, &span); + if (status != FTDM_SUCCESS || !span) { + ftdm_log(FTDM_LOG_ERROR, "Failed to find span for channel id string '%s'\n", string_id); + status = FTDM_EINVAL; + goto done; + } + + if (chan_id > (FTDM_MAX_CHANNELS_SPAN+1) || !(ftdmchan = span->channels[chan_id])) { + ftdm_log(FTDM_LOG_ERROR, "Invalid channel id string '%s'\n", string_id); + status = FTDM_EINVAL; + goto done; + } + + status = FTDM_SUCCESS; + *out_span = span; + *out_channel = ftdmchan; +done: + return status; +} + /* this function MUST be called with the channel lock held with lock recursivity of 1 exactly, * and the caller must be aware we might unlock the channel for a brief period of time and then lock it again */ static ftdm_status_t _ftdm_channel_call_place_nl(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_usrmsg_t *usrmsg) { + const char *var = NULL; ftdm_status_t status = FTDM_FAIL; ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "null channel"); @@ -2461,6 +2516,17 @@ static ftdm_status_t _ftdm_channel_call_place_nl(const char *file, const char *f ftdm_set_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED); ftdm_call_set_call_id(ftdmchan, &ftdmchan->caller_data); + var = ftdm_usrmsg_get_var(usrmsg, "sigbridge_peer"); + if (var) { + ftdm_span_t *peer_span = NULL; + ftdm_channel_t *peer_chan = NULL; + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "enabling native signaling bridge!\n"); + ftdm_set_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE); + ftdm_get_channel_from_string(var, &peer_span, &peer_chan); + if (peer_chan) { + ftdm_set_flag(peer_chan, FTDM_CHANNEL_NATIVE_SIGBRIDGE); + } + } /* if the signaling stack left the channel in state down on success, is expecting us to move to DIALING */ if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN) { @@ -2662,6 +2728,7 @@ static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan) ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_ANSWERED); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_USER_HANGUP); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_DIGITAL_MEDIA); + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE); ftdm_mutex_lock(ftdmchan->pre_buffer_mutex); ftdm_buffer_destroy(&ftdmchan->pre_buffer); ftdmchan->pre_buffer_size = 0; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 96b662bdbb..dddb0b2bef 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -55,6 +55,7 @@ ftdm_sngss7_data_t g_ftdm_sngss7_data; /* PROTOTYPES *****************************************************************/ static void *ftdm_sangoma_ss7_run (ftdm_thread_t * me, void *obj); static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_event); +static void ftdm_sangoma_ss7_process_peer_stack_event (ftdm_channel_t *ftdmchan, sngss7_event_data_t *sngss7_event); static ftdm_status_t ftdm_sangoma_ss7_stop (ftdm_span_t * span); static ftdm_status_t ftdm_sangoma_ss7_start (ftdm_span_t * span); @@ -338,9 +339,10 @@ static void handle_hw_alarm(ftdm_event_t *e) /* MONITIOR THREADS ***********************************************************/ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) { - ftdm_interrupt_t *ftdm_sangoma_ss7_int[2]; + ftdm_interrupt_t *ftdm_sangoma_ss7_int[3]; ftdm_span_t *ftdmspan = (ftdm_span_t *) obj; ftdm_channel_t *ftdmchan = NULL; + ftdm_channel_t *peerchan = NULL; ftdm_event_t *event = NULL; sngss7_event_data_t *sngss7_event = NULL; sngss7_span_data_t *sngss7_span = (sngss7_span_data_t *)ftdmspan->signal_data; @@ -365,6 +367,12 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) goto ftdm_sangoma_ss7_run_exit; } + /* get an interrupt queue for this span for peer channel events */ + if (ftdm_queue_get_interrupt (sngss7_span->peer_chans, &ftdm_sangoma_ss7_int[2]) != FTDM_SUCCESS) { + SS7_CRITICAL ("Failed to get a ftdm_interrupt for span = %d for peer channel events queue!\n", ftdmspan->span_id); + goto ftdm_sangoma_ss7_run_exit; + } + while (ftdm_running () && !(ftdm_test_flag (ftdmspan, FTDM_SPAN_STOP_THREAD))) { int x = 0; if (b_alarm_test) { @@ -395,7 +403,7 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) } /* check the channel state queue for an event*/ - switch ((ftdm_interrupt_multiple_wait(ftdm_sangoma_ss7_int, 2, 100))) { + switch ((ftdm_interrupt_multiple_wait(ftdm_sangoma_ss7_int, ftdm_array_len(ftdm_sangoma_ss7_int), 100))) { /**********************************************************************/ case FTDM_SUCCESS: /* process all pending state changes */ @@ -412,6 +420,31 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) ftdm_mutex_unlock (ftdmchan->mutex); } + /* clean out all peer pending channel events */ + while ((peerchan = ftdm_queue_dequeue (sngss7_span->peer_chans))) { + /* note that the channels being dequeued here may not belong to this span + they may belong to just about any other span that one of our channels + happens to be bridged to */ + sngss7_chan_data_t *peer_info = peerchan->call_data; + sngss7_chan_data_t *chan_info = peer_info->peer_data; + ftdmchan = chan_info->ftdmchan; + + /* + if there is any state changes at all, those will be done in the opposite channel + to peerchan (where the original event was received), therefore we must lock ftdmchan, + but do not need to lock peerchan as we only read its event queue, which is already + locked when dequeueing */ + ftdm_channel_lock(ftdmchan); + + /* clean out all pending stack events in the peer channel */ + while ((sngss7_event = ftdm_queue_dequeue(peer_info->event_queue))) { + ftdm_sangoma_ss7_process_peer_stack_event(ftdmchan, sngss7_event); + ftdm_safe_free(sngss7_event); + } + + ftdm_channel_lock(ftdmchan); + } + /* clean out all pending stack events */ while ((sngss7_event = ftdm_queue_dequeue(sngss7_span->event_queue))) { ftdm_sangoma_ss7_process_stack_event(sngss7_event); @@ -522,24 +555,60 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev /* now that we have the right channel ... put a lock on it so no-one else can use it */ ftdm_channel_lock(ftdmchan); - if (sngss7_info->event_queue) { - if (sngss7_event->event_id == SNGSS7_CON_IND_EVENT) { - /* this is the first event in a call, flush the event queue */ - while ((event_clone = ftdm_queue_dequeue(sngss7_info->event_queue))) { - SS7_WARN("[CIC:%d]Discarding clone event from past call!\n", sngss7_info->circuit->cic); - ftdm_safe_free(event_clone); - } - } - /* clone the event and save it for later usage */ - event_clone = ftdm_calloc(1, sizeof(*sngss7_event)); - if (event_clone) { - memcpy(event_clone, sngss7_event, sizeof(*sngss7_event)); - ftdm_queue_enqueue(sngss7_info->event_queue, event_clone); + /* while there's a state change present on this channel process it */ + ftdm_channel_advance_states(ftdmchan); + + if (sngss7_event->event_id == SNGSS7_CON_IND_EVENT) { + /* this is the first event in a call, flush the event queue */ + while ((event_clone = ftdm_queue_dequeue(sngss7_info->event_queue))) { + SS7_WARN("[CIC:%d]Discarding clone event from past call!\n", sngss7_info->circuit->cic); + ftdm_safe_free(event_clone); } } - /* while there's a state change present on this channel process it */ - ftdm_channel_advance_states(ftdmchan); + /* clone the event and save it for later usage */ + event_clone = ftdm_calloc(1, sizeof(*sngss7_event)); + if (event_clone) { + memcpy(event_clone, sngss7_event, sizeof(*sngss7_event)); + ftdm_queue_enqueue(sngss7_info->event_queue, event_clone); + if (sngss7_info->peer_data) { + sngss7_span_data_t *sngss7_peer_span = (sngss7_span_data_t *)sngss7_info->peer_data->ftdmchan->span->signal_data; + /* we already have a peer attached, wake him up */ + ftdm_queue_enqueue(sngss7_peer_span->peer_chans, sngss7_info->ftdmchan); + } + } + + /* we could test for sngss7_info->peer_data too, bit this flag is set earlier, the earlier we know the better */ + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { + /* most messages are simply relayed in sig bridge mode, except for hangup which requires state changing */ + switch (sngss7_event->event_id) { + case SNGSS7_REL_IND_EVENT: + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + break; + case SNGSS7_REL_CFM_EVENT: + { + ftdm_channel_t *peer_chan = sngss7_info->peer_data->ftdmchan; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + if (peer_chan) { + /* we need to unlock our chan or we risk deadlock */ + ftdm_channel_advance_states(ftdmchan); + ftdm_channel_unlock(ftdmchan); + + ftdm_channel_lock(peer_chan); + if (peer_chan->state != FTDM_CHANNEL_STATE_DOWN) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + } + ftdm_channel_unlock(peer_chan); + + ftdm_channel_lock(ftdmchan); + } + } + break; + default: + break; + } + goto done; + } /* figure out the type of event and send it to the right handler */ switch (sngss7_event->event_id) { @@ -602,6 +671,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev /**************************************************************************/ } +done: /* while there's a state change present on this channel process it */ ftdm_channel_advance_states(ftdmchan); @@ -610,8 +680,290 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev } +FTDM_ENUM_NAMES(SNG_EVENT_TYPE_NAMES, SNG_EVENT_TYPE_STRINGS) +FTDM_STR2ENUM(ftdm_str2sngss7_event, ftdm_sngss7_event2str, sng_event_type_t, SNG_EVENT_TYPE_NAMES, SNGSS7_INVALID_EVENT) +static void ftdm_sangoma_ss7_process_peer_stack_event (ftdm_channel_t *ftdmchan, sngss7_event_data_t *sngss7_event) +{ + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + if (ftdmchan->state < FTDM_CHANNEL_STATE_UP) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP); + ftdm_channel_advance_states(ftdmchan); + } + + SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]Relaying message %s from bridged peer\n", + sngss7_info->circuit->cic, ftdm_sngss7_event2str(sngss7_event->event_id)); + + switch (sngss7_event->event_id) { + + case (SNGSS7_CON_IND_EVENT): + SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]Rx IAM (bridged)??\n", sngss7_info->circuit->cic); + break; + + case (SNGSS7_CON_CFM_EVENT): + /* send the ANM request to LibSngSS7 */ + sng_cc_con_response(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &sngss7_event->event.siConEvnt, + 5); + + SS7_INFO_CHAN(ftdmchan, "[CIC:%d]Tx peer ANM\n", sngss7_info->circuit->cic); + break; + + case (SNGSS7_CON_STA_EVENT): + switch (sngss7_event->evntType) { + /**************************************************************************/ + case (ADDRCMPLT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer ACM\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (MODIFY): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer MODIFY\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (MODCMPLT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer MODIFY-COMPLETE\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (MODREJ): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer MODIFY-REJECT\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (PROGRESS): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CPG\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (FRWDTRSFR): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer FOT\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (INFORMATION): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer INF\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (INFORMATREQ): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer INR\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (SUBSADDR): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer SAM\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (EXIT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer EXIT\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (NETRESMGT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer NRM\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (IDENTREQ): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer IDR\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (IDENTRSP): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer IRS\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (MALCLLPRNT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer MALICIOUS CALL\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (CHARGE): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CRG\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (TRFFCHGE): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CRG-TARIFF\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (CHARGEACK): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CRG-ACK\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (CALLOFFMSG): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CALL-OFFER\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (LOOPPRVNT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer LOP\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (TECT_TIMEOUT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer ECT-Timeout\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (RINGSEND): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer RINGING-SEND\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (CALLCLEAR): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CALL-LINE Clear\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (PRERELEASE): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer PRI\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (APPTRANSPORT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer APM\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (OPERATOR): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer OPERATOR\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (METPULSE): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer METERING-PULSE\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (CLGPTCLR): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CALLING_PARTY_CLEAR\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (SUBDIRNUM): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer SUB-DIR\n", sngss7_info->circuit->cic); + break; +#ifdef SANGOMA_SPIROU + case (CHARGE_ACK): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer TXA\n", sngss7_info->circuit->cic); + break; + case (CHARGE_UNIT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer ITX\n", sngss7_info->circuit->cic); + break; +#endif + /**************************************************************************/ + default: + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer Unknown Msg %d\n", sngss7_info->circuit->cic, sngss7_event->evntType); + break; + /**************************************************************************/ + } + sng_cc_con_status (1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &sngss7_event->event.siCnStEvnt, + sngss7_event->evntType); + + break; + /**************************************************************************/ + case (SNGSS7_REL_IND_EVENT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer REL cause=%d\n", sngss7_info->circuit->cic, sngss7_event->event.siRelEvnt.causeDgn.causeVal.val); + + //handle_rel_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siRelEvnt); + sng_cc_rel_request (1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &sngss7_event->event.siRelEvnt); + break; + + /**************************************************************************/ + case (SNGSS7_REL_CFM_EVENT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer RLC\n", sngss7_info->circuit->cic); + sng_cc_rel_response (1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &sngss7_event->event.siRelEvnt); + //handle_rel_cfm(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siRelEvnt); + break; + + /**************************************************************************/ + case (SNGSS7_DAT_IND_EVENT): + //handle_dat_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siInfoEvnt); + break; + /**************************************************************************/ + case (SNGSS7_FAC_IND_EVENT): + //handle_fac_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, sngss7_event->evntType, &sngss7_event->event.siFacEvnt); + break; + /**************************************************************************/ + case (SNGSS7_FAC_CFM_EVENT): + //handle_fac_cfm(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, sngss7_event->evntType, &sngss7_event->event.siFacEvnt); + break; + /**************************************************************************/ + case (SNGSS7_UMSG_IND_EVENT): + //handle_umsg_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit); + break; + /**************************************************************************/ + case (SNGSS7_STA_IND_EVENT): + //handle_sta_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, sngss7_event->globalFlg, sngss7_event->evntType, &sngss7_event->event.siStaEvnt); + break; + /**************************************************************************/ + case (SNGSS7_SUSP_IND_EVENT): + //handle_susp_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siSuspEvnt); + break; + /**************************************************************************/ + case (SNGSS7_RESM_IND_EVENT): + //handle_resm_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siResmEvnt); + break; + /**************************************************************************/ + case (SNGSS7_SSP_STA_CFM_EVENT): + SS7_ERROR("dazed and confused ... hu?!\n"); + break; + /**************************************************************************/ + default: + SS7_ERROR("Unknown Event Id!\n"); + break; + /**************************************************************************/ + } + +} + +static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t *ftdmchan); +static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t *ftdmchan) +{ + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + ftdm_channel_complete_state(ftdmchan); + + switch (ftdmchan->state) { + + case FTDM_CHANNEL_STATE_DOWN: + { + /* both peers come here after the channel processing the RLC moves the pair to DOWN */ + ftdm_channel_t *close_chan = ftdmchan; + + /* detach native bridging if needed (only the outbound leg is responsible for that to avoid races or messy locks) */ + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + sngss7_chan_data_t *peer_info = sngss7_info->peer_data; + sngss7_info->peer_data = NULL; + if (peer_info) { + peer_info->peer_data = NULL; + } + } + + /* close the channel */ + ftdm_channel_close (&close_chan); + } + break; + + case FTDM_CHANNEL_STATE_UP: + { + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + sngss7_send_signal(sngss7_info, FTDM_SIGEVENT_UP); + } + } + break; + + case FTDM_CHANNEL_STATE_TERMINATING: + { + /* when receiving REL we move to TERMINATING and notify the user that the bridge is ending */ + sngss7_send_signal(sngss7_info, FTDM_SIGEVENT_STOP); + } + break; + + default: + break; + } + + return FTDM_SUCCESS; +} + /******************************************************************************/ -ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) +ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) { sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; sng_isup_inf_t *isup_intf = NULL; @@ -623,6 +975,9 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_info->ckt_flags, sngss7_info->blk_flags); + if (sngss7_info->peer_data) { + return ftdm_sangoma_ss7_native_bridge_state_change(ftdmchan); + } /*check what state we are supposed to be in */ switch (ftdmchan->state) { @@ -1940,6 +2295,12 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config) return FTDM_FAIL; } + /* create an peer channel queue for this span */ + if ((ftdm_queue_create(&(ss7_span_info)->peer_chans, SPAN_PENDING_CHANS_QUEUE_SIZE)) != FTDM_SUCCESS) { + SS7_CRITICAL("Unable to create peer chans queue!\n"); + return FTDM_FAIL; + } + /*setup the span structure with the info so far */ g_ftdm_sngss7_data.sig_cb = sig_cb; span->start = ftdm_sangoma_ss7_start; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 2fc6f740c7..7404a8e55d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -81,8 +81,12 @@ typedef enum { SNGSS7_STA_IND_EVENT, SNGSS7_SUSP_IND_EVENT, SNGSS7_RESM_IND_EVENT, - SNGSS7_SSP_STA_CFM_EVENT + SNGSS7_SSP_STA_CFM_EVENT, + SNGSS7_INVALID_EVENT, } sng_event_type_t; +#define SNG_EVENT_TYPE_STRINGS "CON_IND", "CON_CFM", "CON_STA", "REL_IND", "REL_CFM", "DAT_IND", "FAC_IND", \ + "FAC_CFM", "UMSG_IND", "STA_IND", "SUSP_IND", "RESM_IND", "SSP_STA_CFM", "INVALID" +FTDM_STR2ENUM_P(ftdm_str2sngss7_event, ftdm_sngss7_event2str, sng_event_type_t) typedef enum { SNG_BIT_A = (1 << 0), @@ -500,6 +504,7 @@ typedef struct sngss7_span_data { sngss7_group_data_t rx_cgu; sngss7_group_data_t tx_cgu; ftdm_queue_t *event_queue; + ftdm_queue_t *peer_chans; } sngss7_span_data_t; typedef struct sngss7_event_data diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index eda03715f3..96ec5afae9 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -58,45 +58,39 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) var = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "sigbridge_peer"); if (!ftdm_strlen_zero(var)) { - ftdm_status_t status = FTDM_SUCCESS; - int rc = 0; ftdm_span_t *peer_span = NULL; ftdm_channel_t *peer_chan = NULL; sngss7_chan_data_t *peer_info = NULL; - unsigned peer_span_id = 0; - unsigned peer_chan_id = 0; - rc = sscanf(var, "%u:%u", &peer_span_id, &peer_chan_id); - if (rc != 2) { - SS7_ERROR_CHAN(ftdmchan, "Failed to parse sigbridge_peer string '%s'\n", var); + + ftdm_get_channel_from_string(var, &peer_span, &peer_chan); + if (!peer_chan) { + SS7_ERROR_CHAN(ftdmchan, "Failed to find sigbridge peer from string '%s'\n", var); } else { - status = ftdm_span_find(peer_span_id, &peer_span); - if (status != FTDM_SUCCESS || !peer_span) { - SS7_ERROR_CHAN(ftdmchan, "Failed to find peer span for channel id '%u:%u'\n", peer_span_id, peer_chan_id); - } else if (peer_span->signal_type != FTDM_SIGTYPE_SS7) { - SS7_ERROR_CHAN(ftdmchan, "Peer channel %d:%d has different signaling type %d'\n", - peer_span_id, peer_chan_id, peer_span->signal_type); + if (peer_span->signal_type != FTDM_SIGTYPE_SS7) { + SS7_ERROR_CHAN(ftdmchan, "Peer channel '%s' has different signaling type %d'\n", + var, peer_span->signal_type); } else { - if (peer_chan_id > (FTDM_MAX_CHANNELS_SPAN+1) || !(peer_chan = peer_span->channels[peer_chan_id])) { - SS7_ERROR_CHAN(ftdmchan, "Invalid peer channel id '%u:%u'\n", peer_span_id, peer_chan_id); - } else { - sngss7_event_data_t *event_clone = NULL; - peer_info = peer_chan->call_data; - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Starting native bridge with peer CIC %d\n", - sngss7_info->circuit->cic, peer_info->circuit->cic); - /* make each one of us aware of the native bridge */ - peer_info->peer_data = sngss7_info; - sngss7_info->peer_data = peer_info; - /* flush our own queue */ - while ((event_clone = ftdm_queue_dequeue(sngss7_info->event_queue))) { - SS7_WARN("[CIC:%d]Discarding clone event from past call!\n", sngss7_info->circuit->cic); - ftdm_safe_free(event_clone); - } + sngss7_event_data_t *event_clone = NULL; + peer_info = peer_chan->call_data; + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Starting native bridge with peer CIC %d\n", + sngss7_info->circuit->cic, peer_info->circuit->cic); + /* make each one of us aware of the native bridge */ + peer_info->peer_data = sngss7_info; + sngss7_info->peer_data = peer_info; + /* flush our own queue */ + while ((event_clone = ftdm_queue_dequeue(sngss7_info->event_queue))) { + SS7_WARN("[CIC:%d]Discarding clone event from past call!\n", sngss7_info->circuit->cic); + ftdm_safe_free(event_clone); } + /* go up until release comes, note that state processing is done different and much simpler when there is a peer */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP); + ftdm_channel_advance_states(ftdmchan); } } } if (sngss7_info->peer_data) { + sngss7_span_data_t *span_data = ftdmchan->span->signal_data; sngss7_event_data_t *event_clone = ftdm_queue_dequeue(sngss7_info->peer_data->event_queue); /* Retrieve IAM from our peer */ if (!event_clone) { @@ -108,6 +102,9 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged)\n", sngss7_info->circuit->cic); memcpy(&iam, &event_clone->event.siConEvnt, sizeof(iam)); } + /* since this is the first time we dequeue an event from the peer, make sure our main thread process any other events, + this will trigger the interrupt in our span peer_chans queue which will wake up our main thread if it is sleeping */ + ftdm_queue_enqueue(span_data->peer_chans, sngss7_info->peer_data->ftdmchan); } else if (sngss7_info->circuit->transparent_iam && sngss7_retrieve_iam(ftdmchan, &iam) == FTDM_SUCCESS) { SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Transparent)\n", sngss7_info->circuit->cic); @@ -322,10 +319,10 @@ void ft_to_sngss7_rel (ftdm_channel_t * ftdmchan) /* send the REL request to LibSngSS7 */ sng_cc_rel_request (1, - sngss7_info->suInstId, - sngss7_info->spInstId, - sngss7_info->circuit->id, - &rel); + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &rel); SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx REL cause=%d \n", sngss7_info->circuit->cic, diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index f27be789e2..4150480297 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -130,6 +130,9 @@ extern "C" { #endif +#define SPAN_PENDING_CHANS_QUEUE_SIZE 1000 +#define SPAN_PENDING_SIGNALS_QUEUE_SIZE 1000 + #define GOTO_STATUS(label,st) status = st; goto label ; #define ftdm_copy_string(x,y,z) strncpy(x, y, z - 1) @@ -686,6 +689,9 @@ FT_DECLARE(ftdm_status_t) ftdm_sigmsg_remove_var(ftdm_sigmsg_t *sigmsg, const ch */ FT_DECLARE(ftdm_status_t) ftdm_sigmsg_set_raw_data(ftdm_sigmsg_t *sigmsg, void *data, ftdm_size_t datalen); +/*! \brief Retrieve a span and channel data structure from a string in the format 'span_id:chan_id'*/ +FT_DECLARE(ftdm_status_t) ftdm_get_channel_from_string(const char *string_id, ftdm_span_t **out_span, ftdm_channel_t **out_channel); + /*! \brief Assert condition */ diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h index 6df25fe4d2..17e273c425 100755 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -265,6 +265,8 @@ typedef enum { #define FTDM_CHANNEL_BLOCKING (1ULL << 35) /*!< Media is digital */ #define FTDM_CHANNEL_DIGITAL_MEDIA (1ULL << 36) +/*!< Native signaling bridge is enabled */ +#define FTDM_CHANNEL_NATIVE_SIGBRIDGE (1ULL << 37) #include "ftdm_state.h" From f2cdb8c6c75039f431ea51964f0542a73f56fde3 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 26 Jan 2012 23:31:29 -0500 Subject: [PATCH 129/822] freetdm: Fixes for native signaling bridge (now tested, and works for basic call flows) - Fix typo when unlocking channel that resulted in deadlock - Defer clearing of the peer data until it is completely safe (next call) --- libs/freetdm/src/ftdm_state.c | 5 ++++ .../ftmod_sangoma_ss7_main.c | 24 +++++++------------ 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/libs/freetdm/src/ftdm_state.c b/libs/freetdm/src/ftdm_state.c index 6572ab75a4..30ef3ce478 100644 --- a/libs/freetdm/src/ftdm_state.c +++ b/libs/freetdm/src/ftdm_state.c @@ -263,6 +263,9 @@ static ftdm_status_t ftdm_core_set_state(const char *file, const char *func, int } } + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { + goto perform_state_change; + } if (ftdmchan->span->state_map) { ok = ftdm_parse_state_map(ftdmchan, state, ftdmchan->span->state_map); @@ -354,6 +357,8 @@ end: goto done; } +perform_state_change: + ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_DEBUG, "Changed state from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state)); ftdmchan->last_state = ftdmchan->state; ftdmchan->state = state; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index dddb0b2bef..968e557acc 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -441,8 +441,8 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) ftdm_sangoma_ss7_process_peer_stack_event(ftdmchan, sngss7_event); ftdm_safe_free(sngss7_event); } - - ftdm_channel_lock(ftdmchan); + + ftdm_channel_unlock(ftdmchan); } /* clean out all pending stack events */ @@ -564,6 +564,8 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev SS7_WARN("[CIC:%d]Discarding clone event from past call!\n", sngss7_info->circuit->cic); ftdm_safe_free(event_clone); } + /* clear the peer if any */ + sngss7_info->peer_data = NULL; } /* clone the event and save it for later usage */ @@ -596,7 +598,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev ftdm_channel_lock(peer_chan); if (peer_chan->state != FTDM_CHANNEL_STATE_DOWN) { - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + ftdm_set_state(peer_chan, FTDM_CHANNEL_STATE_DOWN); } ftdm_channel_unlock(peer_chan); @@ -923,19 +925,7 @@ static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t case FTDM_CHANNEL_STATE_DOWN: { - /* both peers come here after the channel processing the RLC moves the pair to DOWN */ ftdm_channel_t *close_chan = ftdmchan; - - /* detach native bridging if needed (only the outbound leg is responsible for that to avoid races or messy locks) */ - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { - sngss7_chan_data_t *peer_info = sngss7_info->peer_data; - sngss7_info->peer_data = NULL; - if (peer_info) { - peer_info->peer_data = NULL; - } - } - - /* close the channel */ ftdm_channel_close (&close_chan); } break; @@ -975,6 +965,10 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) sngss7_info->ckt_flags, sngss7_info->blk_flags); + if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) { + sngss7_info->peer_data = NULL; + } + if (sngss7_info->peer_data) { return ftdm_sangoma_ss7_native_bridge_state_change(ftdmchan); } From 1aa4f87b6acd16a3a75f84f611af189725a696eb Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 26 Jan 2012 23:51:21 -0500 Subject: [PATCH 130/822] freetdm: Tweaks to SS7 native bridge feature - Enable native bridge also when receiving the UUID via SIP header - Remove some debug CRIT messages and set a more proper log level --- libs/freetdm/mod_freetdm/mod_freetdm.c | 38 ++++++++++++------- libs/freetdm/src/ftdm_io.c | 1 - .../ftmod_sangoma_ss7_main.c | 2 +- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 1 - 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index a007fef081..2bbcdf97e4 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1260,6 +1260,9 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi const char *var; const char *dest_num = NULL, *callerid_num = NULL; const char *network_peer_uuid = NULL; + char sigbridge_peer[255]; + switch_channel_t *peer_chan = NULL; + switch_channel_t *our_chan = NULL; ftdm_hunting_scheme_t hunting; ftdm_usrmsg_t usrmsg; @@ -1613,17 +1616,22 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi goto fail; } + our_chan = switch_core_session_get_channel(*new_session); + if (network_peer_uuid) { switch_core_session_t *network_peer = switch_core_session_locate(network_peer_uuid); if (network_peer) { - const char *my_uuid = switch_core_session_get_uuid(*new_session); - private_t *peer_private = switch_core_session_get_private(network_peer); - switch_set_string(tech_pvt->network_peer_uuid, network_peer_uuid); - switch_set_string(peer_private->network_peer_uuid, my_uuid); + const char *my_uuid = switch_core_session_get_uuid(*new_session); + private_t *peer_private = switch_core_session_get_private(network_peer); + switch_set_string(tech_pvt->network_peer_uuid, network_peer_uuid); + switch_set_string(peer_private->network_peer_uuid, my_uuid); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Session %s is network-bridged with %s\n", my_uuid, network_peer_uuid); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Session %s is network-bridged with %s\n", + my_uuid, network_peer_uuid); - switch_core_session_rwunlock(network_peer); + snprintf(sigbridge_peer, sizeof(sigbridge_peer), "%u:%u", + ftdm_channel_get_span_id(peer_private->ftdmchan), ftdm_channel_get_id(peer_private->ftdmchan)); + switch_core_session_rwunlock(network_peer); } } @@ -1642,15 +1650,13 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi && (var = channel_get_variable(session, var_event, FREETDM_VAR_PREFIX "native_sigbridge")) && switch_true(var) && switch_core_session_compare(*new_session, session)) { - char sigbridge_peer[255]; private_t *peer_pvt = switch_core_session_get_private(session); - switch_channel_t *peer_chan = switch_core_session_get_channel(session); - switch_channel_t *our_chan = switch_core_session_get_channel(*new_session); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, - "Bridging native signaling of channel %s to channel %s\n", - switch_channel_get_name(peer_chan), switch_channel_get_name(our_chan)); snprintf(sigbridge_peer, sizeof(sigbridge_peer), "%u:%u", ftdm_channel_get_span_id(peer_pvt->ftdmchan), ftdm_channel_get_id(peer_pvt->ftdmchan)); + } + + if (!zstr(sigbridge_peer)) { + peer_chan = switch_core_session_get_channel(session); ftdm_usrmsg_add_var(&usrmsg, "sigbridge_peer", sigbridge_peer); } @@ -1669,7 +1675,13 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi } else { cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; } - goto fail; + goto fail; + } + + if (our_chan && peer_chan) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + "Bridging native signaling of channel %s to channel %s\n", + switch_channel_get_name(peer_chan), switch_channel_get_name(our_chan)); } return SWITCH_CAUSE_SUCCESS; diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 6ebe5fc161..3b11611d49 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -2520,7 +2520,6 @@ static ftdm_status_t _ftdm_channel_call_place_nl(const char *file, const char *f if (var) { ftdm_span_t *peer_span = NULL; ftdm_channel_t *peer_chan = NULL; - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "enabling native signaling bridge!\n"); ftdm_set_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE); ftdm_get_channel_from_string(var, &peer_span, &peer_chan); if (peer_chan) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 968e557acc..24f612545f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -693,7 +693,7 @@ static void ftdm_sangoma_ss7_process_peer_stack_event (ftdm_channel_t *ftdmchan, ftdm_channel_advance_states(ftdmchan); } - SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]Relaying message %s from bridged peer\n", + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Relaying message %s from bridged peer\n", sngss7_info->circuit->cic, ftdm_sngss7_event2str(sngss7_event->event_id)); switch (sngss7_event->event_id) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index 59cb6a4f53..cc66365593 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -79,7 +79,6 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) sngss7_info->peer_data = peer_info; /* flush our own queue */ while ((event_clone = ftdm_queue_dequeue(sngss7_info->event_queue))) { - SS7_WARN("[CIC:%d]Discarding clone event from past call!\n", sngss7_info->circuit->cic); ftdm_safe_free(event_clone); } /* go up until release comes, note that state processing is done different and much simpler when there is a peer */ From a83f04ab6a7e2f8276f6e280c8b1eeb578897a5a Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 27 Jan 2012 00:13:59 -0500 Subject: [PATCH 131/822] freetdm: Relay the rest of SS7 messages supported by libsng_ss7 when in native bridge mode --- .../ftmod_sangoma_ss7_main.c | 55 ++++++++++++++++--- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 24f612545f..06ddd7e8d1 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -561,7 +561,6 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev if (sngss7_event->event_id == SNGSS7_CON_IND_EVENT) { /* this is the first event in a call, flush the event queue */ while ((event_clone = ftdm_queue_dequeue(sngss7_info->event_queue))) { - SS7_WARN("[CIC:%d]Discarding clone event from past call!\n", sngss7_info->circuit->cic); ftdm_safe_free(event_clone); } /* clear the peer if any */ @@ -693,13 +692,13 @@ static void ftdm_sangoma_ss7_process_peer_stack_event (ftdm_channel_t *ftdmchan, ftdm_channel_advance_states(ftdmchan); } - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Relaying message %s from bridged peer\n", + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Receiving message %s from bridged peer\n", sngss7_info->circuit->cic, ftdm_sngss7_event2str(sngss7_event->event_id)); switch (sngss7_event->event_id) { case (SNGSS7_CON_IND_EVENT): - SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]Rx IAM (bridged)??\n", sngss7_info->circuit->cic); + SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]Rx IAM while bridged??\n", sngss7_info->circuit->cic); break; case (SNGSS7_CON_CFM_EVENT): @@ -876,18 +875,48 @@ static void ftdm_sangoma_ss7_process_peer_stack_event (ftdm_channel_t *ftdmchan, /**************************************************************************/ case (SNGSS7_DAT_IND_EVENT): //handle_dat_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siInfoEvnt); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer %s\n", sngss7_info->circuit->cic, ftdm_sngss7_event2str(sngss7_event->event_id)); + sng_cc_dat_request(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &sngss7_event->event.siInfoEvnt); break; /**************************************************************************/ case (SNGSS7_FAC_IND_EVENT): - //handle_fac_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, sngss7_event->evntType, &sngss7_event->event.siFacEvnt); + //handle_fac_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, sngss7_event->evntType, + //&sngss7_event->event.siFacEvnt); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer %s -> %d\n", sngss7_info->circuit->cic, + ftdm_sngss7_event2str(sngss7_event->event_id), sngss7_event->evntType); + sng_cc_fac_request(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + sngss7_event->evntType, + &sngss7_event->event.siFacEvnt); + break; /**************************************************************************/ case (SNGSS7_FAC_CFM_EVENT): - //handle_fac_cfm(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, sngss7_event->evntType, &sngss7_event->event.siFacEvnt); + //handle_fac_cfm(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, + //sngss7_event->evntType, &sngss7_event->event.siFacEvnt); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer %s -> %d\n", sngss7_info->circuit->cic, + ftdm_sngss7_event2str(sngss7_event->event_id), sngss7_event->evntType); + sng_cc_fac_response(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + sngss7_event->evntType, + &sngss7_event->event.siFacEvnt); break; /**************************************************************************/ case (SNGSS7_UMSG_IND_EVENT): //handle_umsg_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer %s\n", sngss7_info->circuit->cic, ftdm_sngss7_event2str(sngss7_event->event_id)); + sng_cc_umsg_request (1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id); break; /**************************************************************************/ case (SNGSS7_STA_IND_EVENT): @@ -896,18 +925,30 @@ static void ftdm_sangoma_ss7_process_peer_stack_event (ftdm_channel_t *ftdmchan, /**************************************************************************/ case (SNGSS7_SUSP_IND_EVENT): //handle_susp_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siSuspEvnt); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer %s\n", sngss7_info->circuit->cic, ftdm_sngss7_event2str(sngss7_event->event_id)); + sng_cc_susp_request (1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &sngss7_event->event.siSuspEvnt); break; /**************************************************************************/ case (SNGSS7_RESM_IND_EVENT): //handle_resm_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siResmEvnt); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer %s\n", sngss7_info->circuit->cic, ftdm_sngss7_event2str(sngss7_event->event_id)); + sng_cc_resm_request(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &sngss7_event->event.siResmEvnt); break; /**************************************************************************/ case (SNGSS7_SSP_STA_CFM_EVENT): - SS7_ERROR("dazed and confused ... hu?!\n"); + SS7_CRITICAL("dazed and confused ... hu?!\n"); break; /**************************************************************************/ default: - SS7_ERROR("Unknown Event Id!\n"); + SS7_ERROR("Failed to relay unknown event id %d!\n", sngss7_event->event_id); break; /**************************************************************************/ } From 2db41c5c793fd18acd25b0cd22499d7b1406b88e Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 27 Jan 2012 06:34:36 -0500 Subject: [PATCH 132/822] freetdm: Fix uninitialized var leading to segfault --- libs/freetdm/mod_freetdm/mod_freetdm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 2bbcdf97e4..a180f03fef 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1267,6 +1267,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi ftdm_usrmsg_t usrmsg; memset(&usrmsg, 0, sizeof(ftdm_usrmsg_t)); + memset(sigbridge_peer, 0, sizeof(sigbridge_peer)); if (!outbound_profile) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing caller profile\n"); @@ -1655,7 +1656,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi ftdm_channel_get_span_id(peer_pvt->ftdmchan), ftdm_channel_get_id(peer_pvt->ftdmchan)); } - if (!zstr(sigbridge_peer)) { + if (session && !zstr(sigbridge_peer)) { peer_chan = switch_core_session_get_channel(session); ftdm_usrmsg_add_var(&usrmsg, "sigbridge_peer", sigbridge_peer); } From 0ff8a087c616177f0162d4acab6bf7be2e60aa4a Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 27 Jan 2012 06:44:11 -0500 Subject: [PATCH 133/822] freetdm: Fix incorrect state transition from DOWN to UP when processing an SS7 clone event --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 06ddd7e8d1..bcc21df7be 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -687,13 +687,13 @@ static void ftdm_sangoma_ss7_process_peer_stack_event (ftdm_channel_t *ftdmchan, { sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; - if (ftdmchan->state < FTDM_CHANNEL_STATE_UP) { + if (ftdmchan->state < FTDM_CHANNEL_STATE_UP && ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP); ftdm_channel_advance_states(ftdmchan); } - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Receiving message %s from bridged peer\n", - sngss7_info->circuit->cic, ftdm_sngss7_event2str(sngss7_event->event_id)); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Receiving message %s from bridged peer (our state = %s)\n", + sngss7_info->circuit->cic, ftdm_sngss7_event2str(sngss7_event->event_id), ftdm_channel_state2str(ftdmchan->state)); switch (sngss7_event->event_id) { From de56f3c465d98bddb916a106092db94a8459d853 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 27 Jan 2012 14:42:33 +0100 Subject: [PATCH 134/822] freetdm: spirou transparent IAM fix for called number --- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index cc66365593..b9914337a5 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -98,8 +98,18 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* first message in the queue should ALWAYS be an IAM */ SS7_ERROR_CHAN(ftdmchan, "Invalid initial peer message type '%d'\n", event_clone->event_id); } else { - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged)\n", sngss7_info->circuit->cic); + ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; + + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged, dialing %s)\n", sngss7_info->circuit->cic, caller_data->dnis.digits); + + /* copy original incoming IAM */ memcpy(&iam, &event_clone->event.siConEvnt, sizeof(iam)); + + /* Change DNIS to whatever was specified, do not change NADI or anything else! */ + copy_tknStr_to_sngss7(caller_data->dnis.digits, &iam.cdPtyNum.addrSig, &iam.cdPtyNum.oddEven); + + /* SPIROU certification hack + If the IAM contains */ } /* since this is the first time we dequeue an event from the peer, make sure our main thread process any other events, this will trigger the interrupt in our span peer_chans queue which will wake up our main thread if it is sleeping */ From 572154693e3e972f50d4385ad3456f73e8235a69 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 27 Jan 2012 16:21:53 +0100 Subject: [PATCH 135/822] freetdm: spirou certification specific changes about RDNIS/RDINF usage --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index b9914337a5..c1eef81d92 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -109,7 +109,31 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) copy_tknStr_to_sngss7(caller_data->dnis.digits, &iam.cdPtyNum.addrSig, &iam.cdPtyNum.oddEven); /* SPIROU certification hack - If the IAM contains */ + If the IAM already contain RDINF, just increment the count and set the RDNIS digits + otherwise, honor RDNIS and RDINF stuff coming from the user */ + if (iam.redirInfo.eh.pres == PRSNT_NODEF) { + const char *val = NULL; + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), redirect info present\n", sngss7_info->circuit->cic); + if (iam.redirInfo.redirCnt.pres) { + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), redirect count present = %d\n", sngss7_info->circuit->cic, iam.redirInfo.redirCnt.val); + iam.redirInfo.redirCnt.val++; + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), redirect count incremented = %d\n", sngss7_info->circuit->cic, iam.redirInfo.redirCnt.val); + } + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdnis_digits"); + if (!ftdm_strlen_zero(val)) { + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), found user supplied RDNIS digits = %s\n", sngss7_info->circuit->cic, val); + copy_tknStr_to_sngss7((char*)val, &iam.redirgNum.addrSig, &iam.redirgNum.oddEven); + } else { + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), not found user supplied RDNIS digits\n", sngss7_info->circuit->cic); + } + } else { + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), redirect info not present, attempting to copy user supplied values\n", sngss7_info->circuit->cic); + /* Redirecting Number */ + copy_redirgNum_to_sngss7(ftdmchan, &iam.redirgNum); + + /* Redirecting Information */ + copy_redirgInfo_to_sngss7(ftdmchan, &iam.redirInfo); + } } /* since this is the first time we dequeue an event from the peer, make sure our main thread process any other events, this will trigger the interrupt in our span peer_chans queue which will wake up our main thread if it is sleeping */ From 3199513c96b0fef5cca09b283361da449ffedcad Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 27 Jan 2012 16:22:45 +0100 Subject: [PATCH 136/822] freetdm: More spirou certification changes - Send RLC immediately even when in native bridge mode - Do not enqueue RLC coming from the network --- .../ftmod_sangoma_ss7_main.c | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index bcc21df7be..993ea68e5a 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -567,18 +567,20 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev sngss7_info->peer_data = NULL; } - /* clone the event and save it for later usage */ - event_clone = ftdm_calloc(1, sizeof(*sngss7_event)); - if (event_clone) { - memcpy(event_clone, sngss7_event, sizeof(*sngss7_event)); - ftdm_queue_enqueue(sngss7_info->event_queue, event_clone); - if (sngss7_info->peer_data) { - sngss7_span_data_t *sngss7_peer_span = (sngss7_span_data_t *)sngss7_info->peer_data->ftdmchan->span->signal_data; - /* we already have a peer attached, wake him up */ - ftdm_queue_enqueue(sngss7_peer_span->peer_chans, sngss7_info->ftdmchan); + /* clone the event and save it for later usage, we do not clone RLC messages */ + if (sngss7_event->event_id != SNGSS7_REL_CFM_EVENT) { + event_clone = ftdm_calloc(1, sizeof(*sngss7_event)); + if (event_clone) { + memcpy(event_clone, sngss7_event, sizeof(*sngss7_event)); + ftdm_queue_enqueue(sngss7_info->event_queue, event_clone); + if (sngss7_info->peer_data) { + sngss7_span_data_t *sngss7_peer_span = (sngss7_span_data_t *)sngss7_info->peer_data->ftdmchan->span->signal_data; + /* we already have a peer attached, wake him up */ + ftdm_queue_enqueue(sngss7_peer_span->peer_chans, sngss7_info->ftdmchan); + } } } - + /* we could test for sngss7_info->peer_data too, bit this flag is set earlier, the earlier we know the better */ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { /* most messages are simply relayed in sig bridge mode, except for hangup which requires state changing */ @@ -981,6 +983,7 @@ static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t case FTDM_CHANNEL_STATE_TERMINATING: { + ft_to_sngss7_rlc(ftdmchan); /* when receiving REL we move to TERMINATING and notify the user that the bridge is ending */ sngss7_send_signal(sngss7_info, FTDM_SIGEVENT_STOP); } From 8476d664656b9ffdb0cbb775d33d4ac4be53c039 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 27 Jan 2012 18:54:06 +0100 Subject: [PATCH 137/822] freetdm: Cancel ISUP T6 timer when using native bridge (Spirou certification fix) --- .../ftmod_sangoma_ss7_main.c | 59 +++++++++++++++++++ .../ftmod_sangoma_ss7_main.h | 2 + 2 files changed, 61 insertions(+) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 993ea68e5a..4c47ee0578 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -40,6 +40,13 @@ /* INCLUDE ********************************************************************/ #include "ftmod_sangoma_ss7_main.h" +#include +#include +#include +#include +#include +#include +#include /******************************************************************************/ /* DEFINES ********************************************************************/ @@ -567,6 +574,33 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev sngss7_info->peer_data = NULL; } + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { + + if (sngss7_event->event_id == SNGSS7_SUSP_IND_EVENT) { + sngss7_set_ckt_flag(sngss7_info, FLAG_SUS_RECVD); + sngss7_clear_ckt_flag(sngss7_info, FLAG_T6_CANCELED); + } + + if (sngss7_test_ckt_flag(sngss7_info, FLAG_SUS_RECVD) && + !sngss7_test_ckt_flag(sngss7_info, FLAG_T6_CANCELED)) { + /* SPIROU cert, disable ISUP T6 when bridged natively */ + int trc = 0; + SiCon *siCon = NULL; + if (siFindSuInstId(sngss7_info->suInstId, &siCon) != RFAILED) { + if (siCon) { + trc = siStopConTmr(siCon, TMR_T6I); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Stopped T6 timer (%d)\n", sngss7_info->circuit->cic, trc); + sngss7_set_ckt_flag(sngss7_info, FLAG_T6_CANCELED); + } else { + SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]siCon is null!\n", sngss7_info->circuit->cic); + } + } else { + SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]could not find siCon\n", sngss7_info->circuit->cic); + } + } + + } + /* clone the event and save it for later usage, we do not clone RLC messages */ if (sngss7_event->event_id != SNGSS7_REL_CFM_EVENT) { event_clone = ftdm_calloc(1, sizeof(*sngss7_event)); @@ -955,6 +989,29 @@ static void ftdm_sangoma_ss7_process_peer_stack_event (ftdm_channel_t *ftdmchan, /**************************************************************************/ } + if ((sngss7_event->event_id == SNGSS7_SUSP_IND_EVENT)) { + sngss7_set_ckt_flag(sngss7_info, FLAG_SUS_RECVD); + } + + if (sngss7_test_ckt_flag(sngss7_info, FLAG_SUS_RECVD) && + !sngss7_test_ckt_flag(sngss7_info, FLAG_T6_CANCELED)) { + /* SPIROU cert, disable ISUP T6 when bridged natively */ + int trc = 0; + SiCon *siCon = NULL; + if (siFindSuInstId(sngss7_info->suInstId, &siCon) != RFAILED) { + if (siCon) { + trc = siStopConTmr(siCon, TMR_T6I); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Stopped T6 timer (%d)\n", sngss7_info->circuit->cic, trc); + sngss7_set_ckt_flag(sngss7_info, FLAG_T6_CANCELED); + } else { + SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]siCon is null!\n", sngss7_info->circuit->cic); + } + } else { + SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]could not find siCon\n", sngss7_info->circuit->cic); + } + } + + } static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t *ftdmchan); @@ -969,6 +1026,8 @@ static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t case FTDM_CHANNEL_STATE_DOWN: { ftdm_channel_t *close_chan = ftdmchan; + sngss7_clear_ckt_flag(sngss7_info, FLAG_SUS_RECVD); + sngss7_clear_ckt_flag(sngss7_info, FLAG_T6_CANCELED); ftdm_channel_close (&close_chan); } break; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 7404a8e55d..b5494bc174 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -550,6 +550,8 @@ typedef enum { FLAG_INFID_PAUSED = (1 << 15), FLAG_SENT_ACM = (1 << 16), FLAG_SENT_CPG = (1 << 17), + FLAG_SUS_RECVD = (1 << 18), + FLAG_T6_CANCELED = (1 << 19), FLAG_RELAY_DOWN = (1 << 30), FLAG_CKT_RECONFIG = (1 << 31) } sng_ckt_flag_t; From 777f946e2f0f02f058171c7c0e13a973d6bed837 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Mon, 30 Jan 2012 10:28:08 -0500 Subject: [PATCH 138/822] freetdm: adding susp/resm/rels but not finished. disable t6 finished. --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 125 +++++++++++++++++- .../ftmod_sangoma_ss7_main.c | 27 ++-- 2 files changed, 142 insertions(+), 10 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 2c8f5172b9..d738edb959 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -71,6 +71,10 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, static ftdm_status_t handle_tx_rsc(ftdm_stream_handle_t *stream, int span, int chan, int verbose); static ftdm_status_t handle_tx_grs(ftdm_stream_handle_t *stream, int span, int chan, int range, int verbose); +static ftdm_status_t handle_tx_susp(ftdm_stream_handle_t *stream, int span, int chan, int verbose); +static ftdm_status_t handle_tx_resm(ftdm_stream_handle_t *stream, int span, int chan, int verbose); +static ftdm_status_t handle_tx_rels(ftdm_stream_handle_t *stream, int span, int chan, int verbose); + static ftdm_status_t handle_tx_blo(ftdm_stream_handle_t *stream, int span, int chan, int verbose); static ftdm_status_t handle_tx_ubl(ftdm_stream_handle_t *stream, int span, int chan, int verbose); @@ -458,9 +462,49 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha goto handle_cli_error; /**********************************************************************/ } + + /**************************************************************************/ + /* sending resume for a ckt's call */ + } else if (!strcasecmp(argv[c], "resm") == FTDM_FAIL) { + if (check_arg_count(argc, 5) == FTDM_FAIL) { + goto handle_cli_error_argc; + } + + if (extract_span_chan(argv, 2, &span, &chan) == FTDM_SUCCESS) { + handle_tx_resm(stream, span, chan, verbose); + } else { + stream->write_function(stream, "Bad command format. \n"); + goto handle_cli_error_argc; + } + /**************************************************************************/ + /* sending resume for a ckt's call */ + } else if (!strcasecmp(argv[c], "rels")) { + if (check_arg_count(argc, 5) == FTDM_FAIL) { + goto handle_cli_error_argc; + } + + if (extract_span_chan(argv, 2, &span, &chan) == FTDM_SUCCESS) { + handle_tx_rels(stream, span, chan, verbose); + } else { + stream->write_function(stream, "Bad command format.\n"); + goto handle_cli_error_argc; + } + + /**************************************************************************/ + /* sending suspend for a ckt's call */ + } else if (!strcasecmp(argv[c], "susp")) { + if (check_arg_count(argc, 5) == FTDM_FAIL) { + goto handle_cli_error_argc; + } + + if (extract_span_chan(argv, 2, &span, &chan) == FTDM_SUCCESS) { + handle_tx_susp(stream, span, chan, verbose); + } else { + stream->write_function(stream, "Bad command format. \n"); + goto handle_cli_error_argc; + } /**************************************************************************/ } else if (!strcasecmp(argv[c], "blo")) { - /**************************************************************************/ if (check_arg_count(argc, 2)) goto handle_cli_error_argc; c++; @@ -1330,6 +1374,85 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, return FTDM_SUCCESS; } +static ftdm_status_t handle_tx_resm(ftdm_stream_handle_t *stream, int span, int chan, int verbose) +{ + SS7_ERROR("JZ error alert. handle_tx_resm \n"); + return FTDM_FAIL; +} +static ftdm_status_t handle_tx_rels(ftdm_stream_handle_t *stream, int span, int chan, int verbose) +{ + SS7_ERROR("JZ error alert. handle_tx_rels \n"); + return FTDM_FAIL; +} + +/******************************************************************************/ +static ftdm_status_t handle_tx_susp(ftdm_stream_handle_t *stream, int span, int chan, int verbose) +{ + int x; + sngss7_chan_data_t *ss7_info; + ftdm_channel_t *ftdmchan; + int lspan; + int lchan; + + SS7_ERROR("JZ error alert. handle_tx_susp \n"); + return FTDM_FAIL; + + x = (g_ftdm_sngss7_data.cfg.procId * 1000) + 1; + while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == SNG_CKT_VOICE) { + ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCkt[x].obj; + ftdmchan = ss7_info->ftdmchan; + + /* if span == 0 then all spans should be printed */ + if (span == 0) { + lspan = ftdmchan->physical_span_id; + } else { + lspan = span; + } + + /* if chan == 0 then all chans should be printed */ + if (chan == 0) { + lchan = ftdmchan->physical_chan_id; + } else { + lchan = chan; + } + + if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) { + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change|give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic); + /* check if we need to die */ + ftdm_assert(0, "State change not completed\n"); + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + /* move to the next channel */ + continue; + } else { + /* throw the ckt block flag */ + sngss7_set_ckt_blk_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX); + + /* set the channel to suspended state */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + } + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + } /* if ( span and chan) */ + + } /* if ( cic != 0) */ + + /* go the next circuit */ + x++; + } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x]id != 0) */ + + handle_show_blocks(stream, span, chan, verbose); + + return FTDM_SUCCESS; +} /******************************************************************************/ static ftdm_status_t handle_tx_blo(ftdm_stream_handle_t *stream, int span, int chan, int verbose) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 4c47ee0578..3f87ccf713 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -40,13 +40,6 @@ /* INCLUDE ********************************************************************/ #include "ftmod_sangoma_ss7_main.h" -#include -#include -#include -#include -#include -#include -#include /******************************************************************************/ /* DEFINES ********************************************************************/ @@ -583,6 +576,14 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev if (sngss7_test_ckt_flag(sngss7_info, FLAG_SUS_RECVD) && !sngss7_test_ckt_flag(sngss7_info, FLAG_T6_CANCELED)) { + if (sng_cancel_isup_tmr(sngss7_info->suInstId, ISUP_T6i) == RFAILED ) { + SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]could not stop timer T6 \n", sngss7_info->circuit->cic); + } else { + sngss7_set_ckt_flag(sngss7_info, FLAG_T6_CANCELED); + SS7_ERROR_CHAN(ftdmchan,"[CIC:%d] isup timer T6 has been cancelled. \n", sngss7_info->circuit->cic); + } + +#if 0 /* SPIROU cert, disable ISUP T6 when bridged natively */ int trc = 0; SiCon *siCon = NULL; @@ -597,6 +598,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev } else { SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]could not find siCon\n", sngss7_info->circuit->cic); } +#endif } } @@ -995,6 +997,14 @@ static void ftdm_sangoma_ss7_process_peer_stack_event (ftdm_channel_t *ftdmchan, if (sngss7_test_ckt_flag(sngss7_info, FLAG_SUS_RECVD) && !sngss7_test_ckt_flag(sngss7_info, FLAG_T6_CANCELED)) { + if (sng_cancel_isup_tmr(sngss7_info->suInstId, ISUP_T6i) == RFAILED ) { + SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]could not stop timer T6 \n", sngss7_info->circuit->cic); + } else { + sngss7_set_ckt_flag(sngss7_info, FLAG_T6_CANCELED); + SS7_ERROR_CHAN(ftdmchan,"[CIC:%d] isup timer T6 has been cancelled. \n", sngss7_info->circuit->cic); + } + +#if 0 /* SPIROU cert, disable ISUP T6 when bridged natively */ int trc = 0; SiCon *siCon = NULL; @@ -1009,9 +1019,8 @@ static void ftdm_sangoma_ss7_process_peer_stack_event (ftdm_channel_t *ftdmchan, } else { SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]could not find siCon\n", sngss7_info->circuit->cic); } +#endif } - - } static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t *ftdmchan); From 14d8b42e58355597cdfb49a30626313afa8e695a Mon Sep 17 00:00:00 2001 From: James Zhang Date: Mon, 30 Jan 2012 13:19:36 -0500 Subject: [PATCH 139/822] freetdm: testing code of sending suspend message --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 85 +++++++++---------- .../ftmod_sangoma_ss7_main.h | 2 +- 2 files changed, 42 insertions(+), 45 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index d738edb959..6e97a3db4e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -1389,67 +1389,64 @@ static ftdm_status_t handle_tx_rels(ftdm_stream_handle_t *stream, int span, int static ftdm_status_t handle_tx_susp(ftdm_stream_handle_t *stream, int span, int chan, int verbose) { int x; + ftdm_channel_t *ftdmchan; + int lspan; + int lchan; + SiSuspEvnt suspEvnt; sngss7_chan_data_t *ss7_info; - ftdm_channel_t *ftdmchan; - int lspan; - int lchan; + /* SS7_ERROR("JZ error alert. handle_tx_susp \n"); return FTDM_FAIL; + */ + /* JZ implementation */ + + if (span <= 0 || chan <= 0 || chan >= 32 ) { + SS7_ERROR ("Wrong span number or chan number.\n"); + return FTDM_FAIL; + } + + x = (g_ftdm_sngss7_data.cfg.procId * 1000) + 1; - while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) { + for ( ; g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0; x++) { if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == SNG_CKT_VOICE) { + ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCkt[x].obj; ftdmchan = ss7_info->ftdmchan; - /* if span == 0 then all spans should be printed */ - if (span == 0) { - lspan = ftdmchan->physical_span_id; - } else { - lspan = span; + lspan = span; + lchan = chan; + + if ((ftdmchan->physical_span_id != lspan) && (ftdmchan->physical_chan_id != lchan)) { + continue; } - /* if chan == 0 then all chans should be printed */ - if (chan == 0) { - lchan = ftdmchan->physical_chan_id; - } else { - lchan = chan; - } + ftdm_mutex_lock(ftdmchan->mutex); - if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) { - /* now that we have the right channel...put a lock on it so no-one else can use it */ - ftdm_mutex_lock(ftdmchan->mutex); - - /* check if there is a pending state change|give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic); - /* check if we need to die */ - ftdm_assert(0, "State change not completed\n"); - /* unlock the channel again before we exit */ - ftdm_mutex_unlock(ftdmchan->mutex); - /* move to the next channel */ - continue; - } else { - /* throw the ckt block flag */ - sngss7_set_ckt_blk_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX); - - /* set the channel to suspended state */ - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); - } - - /* unlock the channel again before we exit */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic); + ftdm_assert(0, "State change not completed\n"); ftdm_mutex_unlock(ftdmchan->mutex); + continue; + } - } /* if ( span and chan) */ - - } /* if ( cic != 0) */ - - /* go the next circuit */ - x++; - } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x]id != 0) */ + /* + sngss7_set_ckt_blk_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + */ + suspEvnt.susResInd.eh.pres = PRSNT_NODEF; + suspEvnt.susResInd.susResInd.pres = PRSNT_NODEF; + suspEvnt.susResInd.susResInd.val = EVTSITSUSPREQ; + + sng_cc_susp_request(lspan, ss7_info->suInstId, ss7_info->spInstId, ss7_info->circuit->id, &suspEvnt); + + ftdm_mutex_unlock(ftdmchan->mutex); + } + } handle_show_blocks(stream, span, chan, verbose); + /* end of JZ implementation */ return FTDM_SUCCESS; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index b5494bc174..f9aed03083 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -607,7 +607,7 @@ typedef enum { FLAG_GRP_HW_UNBLK_TX = (1 << 24), FLAG_GRP_HW_UNBLK_TX_DN = (1 << 25), FLAG_GRP_MN_UNBLK_TX = (1 << 26), - FLAG_GRP_MN_UNBLK_TX_DN = (1 << 27) + FLAG_GRP_MN_UNBLK_TX_DN = (1 << 27), } sng_ckt_block_flag_t; #define BLK_FLAGS_STRING \ From c1ad5677429d3c8be6ebfcc756e3328c0f82e073 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Mon, 30 Jan 2012 17:37:57 -0500 Subject: [PATCH 140/822] freetdm: removing sus|res|rel commands --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 121 ------------------ .../ftmod_sangoma_ss7_main.c | 35 ----- 2 files changed, 156 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 6e97a3db4e..cb5584760f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -71,10 +71,6 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, static ftdm_status_t handle_tx_rsc(ftdm_stream_handle_t *stream, int span, int chan, int verbose); static ftdm_status_t handle_tx_grs(ftdm_stream_handle_t *stream, int span, int chan, int range, int verbose); -static ftdm_status_t handle_tx_susp(ftdm_stream_handle_t *stream, int span, int chan, int verbose); -static ftdm_status_t handle_tx_resm(ftdm_stream_handle_t *stream, int span, int chan, int verbose); -static ftdm_status_t handle_tx_rels(ftdm_stream_handle_t *stream, int span, int chan, int verbose); - static ftdm_status_t handle_tx_blo(ftdm_stream_handle_t *stream, int span, int chan, int verbose); static ftdm_status_t handle_tx_ubl(ftdm_stream_handle_t *stream, int span, int chan, int verbose); @@ -462,47 +458,6 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha goto handle_cli_error; /**********************************************************************/ } - - /**************************************************************************/ - /* sending resume for a ckt's call */ - } else if (!strcasecmp(argv[c], "resm") == FTDM_FAIL) { - if (check_arg_count(argc, 5) == FTDM_FAIL) { - goto handle_cli_error_argc; - } - - if (extract_span_chan(argv, 2, &span, &chan) == FTDM_SUCCESS) { - handle_tx_resm(stream, span, chan, verbose); - } else { - stream->write_function(stream, "Bad command format. \n"); - goto handle_cli_error_argc; - } - /**************************************************************************/ - /* sending resume for a ckt's call */ - } else if (!strcasecmp(argv[c], "rels")) { - if (check_arg_count(argc, 5) == FTDM_FAIL) { - goto handle_cli_error_argc; - } - - if (extract_span_chan(argv, 2, &span, &chan) == FTDM_SUCCESS) { - handle_tx_rels(stream, span, chan, verbose); - } else { - stream->write_function(stream, "Bad command format.\n"); - goto handle_cli_error_argc; - } - - /**************************************************************************/ - /* sending suspend for a ckt's call */ - } else if (!strcasecmp(argv[c], "susp")) { - if (check_arg_count(argc, 5) == FTDM_FAIL) { - goto handle_cli_error_argc; - } - - if (extract_span_chan(argv, 2, &span, &chan) == FTDM_SUCCESS) { - handle_tx_susp(stream, span, chan, verbose); - } else { - stream->write_function(stream, "Bad command format. \n"); - goto handle_cli_error_argc; - } /**************************************************************************/ } else if (!strcasecmp(argv[c], "blo")) { if (check_arg_count(argc, 2)) goto handle_cli_error_argc; @@ -1374,82 +1329,6 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, return FTDM_SUCCESS; } -static ftdm_status_t handle_tx_resm(ftdm_stream_handle_t *stream, int span, int chan, int verbose) -{ - SS7_ERROR("JZ error alert. handle_tx_resm \n"); - return FTDM_FAIL; -} -static ftdm_status_t handle_tx_rels(ftdm_stream_handle_t *stream, int span, int chan, int verbose) -{ - SS7_ERROR("JZ error alert. handle_tx_rels \n"); - return FTDM_FAIL; -} - -/******************************************************************************/ -static ftdm_status_t handle_tx_susp(ftdm_stream_handle_t *stream, int span, int chan, int verbose) -{ - int x; - ftdm_channel_t *ftdmchan; - int lspan; - int lchan; - SiSuspEvnt suspEvnt; - sngss7_chan_data_t *ss7_info; - - /* - SS7_ERROR("JZ error alert. handle_tx_susp \n"); - return FTDM_FAIL; - */ - - /* JZ implementation */ - - if (span <= 0 || chan <= 0 || chan >= 32 ) { - SS7_ERROR ("Wrong span number or chan number.\n"); - return FTDM_FAIL; - } - - - x = (g_ftdm_sngss7_data.cfg.procId * 1000) + 1; - for ( ; g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0; x++) { - if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == SNG_CKT_VOICE) { - - ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCkt[x].obj; - ftdmchan = ss7_info->ftdmchan; - - lspan = span; - lchan = chan; - - if ((ftdmchan->physical_span_id != lspan) && (ftdmchan->physical_chan_id != lchan)) { - continue; - } - - ftdm_mutex_lock(ftdmchan->mutex); - - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic); - ftdm_assert(0, "State change not completed\n"); - ftdm_mutex_unlock(ftdmchan->mutex); - continue; - } - - /* - sngss7_set_ckt_blk_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX); - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); - */ - suspEvnt.susResInd.eh.pres = PRSNT_NODEF; - suspEvnt.susResInd.susResInd.pres = PRSNT_NODEF; - suspEvnt.susResInd.susResInd.val = EVTSITSUSPREQ; - - sng_cc_susp_request(lspan, ss7_info->suInstId, ss7_info->spInstId, ss7_info->circuit->id, &suspEvnt); - - ftdm_mutex_unlock(ftdmchan->mutex); - } - } - - handle_show_blocks(stream, span, chan, verbose); - /* end of JZ implementation */ - - return FTDM_SUCCESS; -} /******************************************************************************/ static ftdm_status_t handle_tx_blo(ftdm_stream_handle_t *stream, int span, int chan, int verbose) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 3f87ccf713..950a28500e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -582,25 +582,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev sngss7_set_ckt_flag(sngss7_info, FLAG_T6_CANCELED); SS7_ERROR_CHAN(ftdmchan,"[CIC:%d] isup timer T6 has been cancelled. \n", sngss7_info->circuit->cic); } - -#if 0 - /* SPIROU cert, disable ISUP T6 when bridged natively */ - int trc = 0; - SiCon *siCon = NULL; - if (siFindSuInstId(sngss7_info->suInstId, &siCon) != RFAILED) { - if (siCon) { - trc = siStopConTmr(siCon, TMR_T6I); - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Stopped T6 timer (%d)\n", sngss7_info->circuit->cic, trc); - sngss7_set_ckt_flag(sngss7_info, FLAG_T6_CANCELED); - } else { - SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]siCon is null!\n", sngss7_info->circuit->cic); - } - } else { - SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]could not find siCon\n", sngss7_info->circuit->cic); - } -#endif } - } /* clone the event and save it for later usage, we do not clone RLC messages */ @@ -1003,23 +985,6 @@ static void ftdm_sangoma_ss7_process_peer_stack_event (ftdm_channel_t *ftdmchan, sngss7_set_ckt_flag(sngss7_info, FLAG_T6_CANCELED); SS7_ERROR_CHAN(ftdmchan,"[CIC:%d] isup timer T6 has been cancelled. \n", sngss7_info->circuit->cic); } - -#if 0 - /* SPIROU cert, disable ISUP T6 when bridged natively */ - int trc = 0; - SiCon *siCon = NULL; - if (siFindSuInstId(sngss7_info->suInstId, &siCon) != RFAILED) { - if (siCon) { - trc = siStopConTmr(siCon, TMR_T6I); - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Stopped T6 timer (%d)\n", sngss7_info->circuit->cic, trc); - sngss7_set_ckt_flag(sngss7_info, FLAG_T6_CANCELED); - } else { - SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]siCon is null!\n", sngss7_info->circuit->cic); - } - } else { - SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]could not find siCon\n", sngss7_info->circuit->cic); - } -#endif } } From d1a772bfe9620f1305eeb7d97681a9c798d0108b Mon Sep 17 00:00:00 2001 From: James Zhang Date: Mon, 30 Jan 2012 18:02:26 -0500 Subject: [PATCH 141/822] freetdm: Only hangup with user message when release location information is set --- libs/freetdm/mod_freetdm/mod_freetdm.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index a180f03fef..b78cc078d4 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -506,10 +506,6 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session) int chan_id = 0; const char *name = NULL; - ftdm_usrmsg_t usrmsg; - memset(&usrmsg, 0, sizeof(ftdm_usrmsg_t)); - - channel = switch_core_session_get_channel(session); assert(channel != NULL); @@ -577,19 +573,20 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session) case FTDM_CHAN_TYPE_CAS: case FTDM_CHAN_TYPE_B: { - const char *sipvar; + const char *var = NULL; ftdm_call_cause_t hcause = switch_channel_get_cause_q850(channel); if (hcause < 1 || hcause > 127) { hcause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER; } - sipvar = switch_channel_get_variable(channel, "ss7_rel_loc"); - if (sipvar) { - ftdm_usrmsg_add_var(&usrmsg, "ss7_rel_loc", sipvar); + var = switch_channel_get_variable(channel, "ss7_rel_loc"); + if (var) { + ftdm_usrmsg_t usrmsg; + memset(&usrmsg, 0, sizeof(ftdm_usrmsg_t)); + ftdm_usrmsg_add_var(&usrmsg, "ss7_rel_loc", var); + ftdm_channel_call_hangup_with_cause_ex(tech_pvt->ftdmchan, hcause, &usrmsg); + } else { + ftdm_channel_call_hangup_with_cause(tech_pvt->ftdmchan, hcause); } - /* - ftdm_channel_call_hangup_with_cause(tech_pvt->ftdmchan, hcause); - */ - ftdm_channel_call_hangup_with_cause_ex(tech_pvt->ftdmchan, hcause, &usrmsg); } break; default: From b6c02364a790e81c2d67b33b1cd432ee9af9750d Mon Sep 17 00:00:00 2001 From: James Zhang Date: Mon, 30 Jan 2012 18:26:08 -0500 Subject: [PATCH 142/822] freetdm: Reduce the size of the span peer channels and ss7 info per channel clone event queues --- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 2 +- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h | 2 ++ .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 10 ++++------ .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 950a28500e..5f2beee65b 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -2367,7 +2367,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config) } /* create an peer channel queue for this span */ - if ((ftdm_queue_create(&(ss7_span_info)->peer_chans, SPAN_PENDING_CHANS_QUEUE_SIZE)) != FTDM_SUCCESS) { + if ((ftdm_queue_create(&(ss7_span_info)->peer_chans, SNGSS7_PEER_CHANS_QUEUE_SIZE)) != FTDM_SUCCESS) { SS7_CRITICAL("Unable to create peer chans queue!\n"); return FTDM_FAIL; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index f9aed03083..c77599d3d9 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -56,6 +56,8 @@ #define MAX_CIC_MAP_LENGTH 1000 #define SNGSS7_EVENT_QUEUE_SIZE 100 +#define SNGSS7_PEER_CHANS_QUEUE_SIZE 100 +#define SNGSS7_CHAN_EVENT_QUEUE_SIZE 5 #define MAX_SIZEOF_SUBADDR_IE 24 /* as per Q931 4.5.9 */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index c1eef81d92..20e661d73e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -113,21 +113,19 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) otherwise, honor RDNIS and RDINF stuff coming from the user */ if (iam.redirInfo.eh.pres == PRSNT_NODEF) { const char *val = NULL; - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), redirect info present\n", sngss7_info->circuit->cic); if (iam.redirInfo.redirCnt.pres) { - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), redirect count present = %d\n", sngss7_info->circuit->cic, iam.redirInfo.redirCnt.val); iam.redirInfo.redirCnt.val++; - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), redirect count incremented = %d\n", sngss7_info->circuit->cic, iam.redirInfo.redirCnt.val); + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), redirect count incremented = %d\n", sngss7_info->circuit->cic, iam.redirInfo.redirCnt.val); } val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdnis_digits"); if (!ftdm_strlen_zero(val)) { - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), found user supplied RDNIS digits = %s\n", sngss7_info->circuit->cic, val); + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), found user supplied RDNIS digits = %s\n", sngss7_info->circuit->cic, val); copy_tknStr_to_sngss7((char*)val, &iam.redirgNum.addrSig, &iam.redirgNum.oddEven); } else { - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), not found user supplied RDNIS digits\n", sngss7_info->circuit->cic); + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), not found user supplied RDNIS digits\n", sngss7_info->circuit->cic); } } else { - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), redirect info not present, attempting to copy user supplied values\n", sngss7_info->circuit->cic); + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), redirect info not present, attempting to copy user supplied values\n", sngss7_info->circuit->cic); /* Redirecting Number */ copy_redirgNum_to_sngss7(ftdmchan, &iam.redirgNum); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index d7732cce6c..e76397580e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -2925,7 +2925,7 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan) /* prepare the global info sturcture */ ss7_info = ftdm_calloc(1, sizeof(sngss7_chan_data_t)); ss7_info->ftdmchan = NULL; - if (ftdm_queue_create(&ss7_info->event_queue, SNGSS7_EVENT_QUEUE_SIZE) != FTDM_SUCCESS) { + if (ftdm_queue_create(&ss7_info->event_queue, SNGSS7_CHAN_EVENT_QUEUE_SIZE) != FTDM_SUCCESS) { SS7_CRITICAL("Failed to create ss7 cic event queue\n"); } ss7_info->circuit = &g_ftdm_sngss7_data.cfg.isupCkt[x]; From c9c68a7759ab2ea60e9115d6046850311aa6b1b8 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Mon, 30 Jan 2012 19:15:02 -0500 Subject: [PATCH 143/822] freetdm: Some more clean up for ss7 event cloning - The queue size has been bumped again, long calls could potentially require more elements (multiple resume/suspend) - The queue is only used when there is a call active --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 16 ++++++++++++---- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h | 12 ++++++++++-- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 8 ++++---- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 5f2beee65b..20b2199f21 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -545,6 +545,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; sngss7_event_data_t *event_clone = NULL; + int clone_event = 0; /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(sngss7_event->circuit, &sngss7_info, &ftdmchan)) { @@ -560,11 +561,16 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev if (sngss7_event->event_id == SNGSS7_CON_IND_EVENT) { /* this is the first event in a call, flush the event queue */ - while ((event_clone = ftdm_queue_dequeue(sngss7_info->event_queue))) { - ftdm_safe_free(event_clone); - } + sngss7_flush_queue(sngss7_info->event_queue); /* clear the peer if any */ sngss7_info->peer_data = NULL; + clone_event++; + } + + /* if the call has already started and the event is not a release confirmation, clone the event */ + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED) && + sngss7_event->event_id != SNGSS7_REL_CFM_EVENT) { + clone_event++; } if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { @@ -586,7 +592,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev } /* clone the event and save it for later usage, we do not clone RLC messages */ - if (sngss7_event->event_id != SNGSS7_REL_CFM_EVENT) { + if (clone_event) { event_clone = ftdm_calloc(1, sizeof(*sngss7_event)); if (event_clone) { memcpy(event_clone, sngss7_event, sizeof(*sngss7_event)); @@ -1002,6 +1008,7 @@ static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t ftdm_channel_t *close_chan = ftdmchan; sngss7_clear_ckt_flag(sngss7_info, FLAG_SUS_RECVD); sngss7_clear_ckt_flag(sngss7_info, FLAG_T6_CANCELED); + sngss7_flush_queue(sngss7_info->event_queue); ftdm_channel_close (&close_chan); } break; @@ -1517,6 +1524,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) /* close the channel */ SS7_DEBUG_CHAN(ftdmchan,"FTDM Channel Close %s\n", ""); + sngss7_flush_queue(sngss7_info->event_queue); ftdm_channel_close (&close_chan); } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index c77599d3d9..fb60183bf8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -57,7 +57,7 @@ #define SNGSS7_EVENT_QUEUE_SIZE 100 #define SNGSS7_PEER_CHANS_QUEUE_SIZE 100 -#define SNGSS7_CHAN_EVENT_QUEUE_SIZE 5 +#define SNGSS7_CHAN_EVENT_QUEUE_SIZE 100 #define MAX_SIZEOF_SUBADDR_IE 24 /* as per Q931 4.5.9 */ @@ -65,6 +65,14 @@ (switchtype == LSI_SW_ANS92) || \ (switchtype == LSI_SW_ANS95) +#define sngss7_flush_queue(queue) \ + do { \ + void *__queue_data = NULL; \ + while ((__queue_data = ftdm_queue_dequeue(queue))) { \ + ftdm_safe_free(__queue_data); \ + } \ + } while (0) + typedef struct ftdm2trillium { uint8_t ftdm_val; uint8_t trillium_val; @@ -552,7 +560,7 @@ typedef enum { FLAG_INFID_PAUSED = (1 << 15), FLAG_SENT_ACM = (1 << 16), FLAG_SENT_CPG = (1 << 17), - FLAG_SUS_RECVD = (1 << 18), + FLAG_SUS_RECVD = (1 << 18), FLAG_T6_CANCELED = (1 << 19), FLAG_RELAY_DOWN = (1 << 30), FLAG_CKT_RECONFIG = (1 << 31) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index 20e661d73e..00d06905dd 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -70,17 +70,17 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) SS7_ERROR_CHAN(ftdmchan, "Peer channel '%s' has different signaling type %d'\n", var, peer_span->signal_type); } else { - sngss7_event_data_t *event_clone = NULL; peer_info = peer_chan->call_data; SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Starting native bridge with peer CIC %d\n", sngss7_info->circuit->cic, peer_info->circuit->cic); + /* make each one of us aware of the native bridge */ peer_info->peer_data = sngss7_info; sngss7_info->peer_data = peer_info; + /* flush our own queue */ - while ((event_clone = ftdm_queue_dequeue(sngss7_info->event_queue))) { - ftdm_safe_free(event_clone); - } + sngss7_flush_queue(sngss7_info->event_queue); + /* go up until release comes, note that state processing is done different and much simpler when there is a peer */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP); ftdm_channel_advance_states(ftdmchan); From cca407d09a1dbddfa876497ac9f3c172e2eac92b Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 31 Jan 2012 15:18:53 -0500 Subject: [PATCH 144/822] freetdm: Fix bug in SS7 state processing introduced during the changes for native bridging that caused infinite SUSPEND state executions due to peer member not being cleared at the end of the call --- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 20b2199f21..fa36c7280a 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1049,14 +1049,14 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) sngss7_info->ckt_flags, sngss7_info->blk_flags); - if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) { + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { + /* DIALING is the only state we process normally when doing an outgoing call that is natively bridged */ + if (ftdmchan->state != FTDM_CHANNEL_STATE_DIALING) { + return ftdm_sangoma_ss7_native_bridge_state_change(ftdmchan); + } sngss7_info->peer_data = NULL; } - if (sngss7_info->peer_data) { - return ftdm_sangoma_ss7_native_bridge_state_change(ftdmchan); - } - /*check what state we are supposed to be in */ switch (ftdmchan->state) { /**************************************************************************/ From e8407ab1e1300e27ce65f63be8b214355cf8d80a Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 31 Jan 2012 17:13:10 -0500 Subject: [PATCH 145/822] mod_logfile: Fix compilation that was broken due to previous merge Note that we no longer use our custom-made log rotation as the FreeSWITCH mainstream project added that feature we just re-use the same feature with a different parameter --- src/mod/loggers/mod_logfile/mod_logfile.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/mod/loggers/mod_logfile/mod_logfile.c b/src/mod/loggers/mod_logfile/mod_logfile.c index 9e16f5d73e..27f0aeba37 100644 --- a/src/mod/loggers/mod_logfile/mod_logfile.c +++ b/src/mod/loggers/mod_logfile/mod_logfile.c @@ -116,8 +116,6 @@ static switch_status_t mod_logfile_openlogfile(logfile_profile_t *profile, switc static switch_status_t mod_logfile_rotate(logfile_profile_t *profile) { unsigned int i = 0; - unsigned int fcount = 0; - const char *fname = NULL; char *filename = NULL; switch_status_t stat = 0; int64_t offset = 0; @@ -125,15 +123,6 @@ static switch_status_t mod_logfile_rotate(logfile_profile_t *profile) switch_time_exp_t tm; char date[80] = ""; switch_size_t retsize; - char *dend = NULL; - char *hay = NULL; - switch_dir_t *dirhandle = NULL; - switch_time_t wtime = 0; - char dirname[128]; - char filebuf[128]; - char fullfile[512]; - char filetodelete[128]; - switch_finfo_t statinfo; switch_status_t status = SWITCH_STATUS_SUCCESS; switch_mutex_lock(globals.mutex); @@ -344,8 +333,8 @@ static switch_status_t load_profile(switch_xml_t xml) new_profile->logfile = strdup(val); } else if (!strcmp(var, "rollover")) { new_profile->roll_size = switch_atoui(val); - } else if (!strcmp(var, "maximum-rotate")) || - (!strcmp(var, "maxfilecount")) { + } else if (!strcmp(var, "maximum-rotate") || + !strcmp(var, "maxfilecount")) { /* maxfilecount is backwards compatible parameter, we had our own log rotation code * and eventually mainstream FreeSWITCH included the parameter maximum-rotate which * did pretty much the same as ours, I deleted the old code and stayed with the official From 34b0f8ad74edde0b049e4edcc87466ef4fd28a84 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 2 Feb 2012 11:38:12 -0500 Subject: [PATCH 146/822] spandsp: fixing t38 with configurable tone type. - tone_type value is taken from dialplan t38_gateway function's 2nd parameter - tone type could be one of cng|ced_preamble|ans|ans_pr|ansam|preamble - in dialplan, if enable t38 in ftdm-to-sip, tone type should be set to "t38_gateway peer cng" - if enable t38 in sip-to-ftdm, tone type should be set to "t38_gateway peer ced_preamble" --- .../applications/mod_spandsp/mod_spandsp.c | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/mod/applications/mod_spandsp/mod_spandsp.c b/src/mod/applications/mod_spandsp/mod_spandsp.c index 68ac50f137..2f9b47419d 100644 --- a/src/mod/applications/mod_spandsp/mod_spandsp.c +++ b/src/mod/applications/mod_spandsp/mod_spandsp.c @@ -125,12 +125,14 @@ static void event_handler(switch_event_t *event) SWITCH_STANDARD_APP(t38_gateway_function) { switch_channel_t *channel = switch_core_session_get_channel(session); - time_t timeout = switch_epoch_time_now(NULL) + 20; + time_t timeout = 20; const char *var; int argc = 0; char *argv[2] = { 0 }; char *dupdata; const char *direction = NULL, *flags = NULL; + + int tone_type = 0; if (!zstr(data) && (dupdata = switch_core_session_strdup(session, data))) { if ((argc = switch_split(dupdata, ' ', argv))) { @@ -156,14 +158,35 @@ SWITCH_STANDARD_APP(t38_gateway_function) if ((var = switch_channel_get_variable(channel, "t38_gateway_detect_timeout"))) { long to = atol(var); if (to > -1) { - timeout = (time_t) (switch_epoch_time_now(NULL) + to); + timeout = to; } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s invalid timeout value.\n", switch_channel_get_name(channel)); } } + if (!strcasecmp(flags, "cng")) { + tone_type = MODEM_CONNECT_TONES_FAX_CNG; + } else if (!strcasecmp(flags, "ans")) { + tone_type = MODEM_CONNECT_TONES_ANS; + } else if (!strcasecmp(flags, "ans_pr")) { + tone_type = MODEM_CONNECT_TONES_ANS_PR; + } else if (!strcasecmp(flags, "ansam")) { + tone_type = MODEM_CONNECT_TONES_ANSAM; + } else if (!strcasecmp(flags, "ansam_pr")) { + tone_type = MODEM_CONNECT_TONES_ANSAM_PR; + } else if (!strcasecmp(flags, "preamble")) { + tone_type = MODEM_CONNECT_TONES_FAX_PREAMBLE; + } else if (!strcasecmp(flags, "ced_preamble")) { + tone_type = MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE; + } else { + tone_type = MODEM_CONNECT_TONES_NONE; + } + + + //switch_ivr_tone_detect_session(session, "t38", "1100.0", "rw", timeout, 1, direction, NULL, t38_gateway_start); - spandsp_fax_detect_session(session, "rw", timeout, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, 1, direction, NULL, t38_gateway_start); + //spandsp_fax_detect_session(session, "rw", timeout, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, 1, direction, NULL, t38_gateway_start); + spandsp_fax_detect_session(session, "rw", timeout, tone_type, 1, direction, NULL, t38_gateway_start); } } From 03fee3de39ef0e21034edb136c6fd4aaf57f9a57 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 2 Feb 2012 13:48:44 -0500 Subject: [PATCH 147/822] fs_cli: fix empty prompt in nbss7 --- libs/esl/fs_cli.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/esl/fs_cli.c b/libs/esl/fs_cli.c index faac75a437..81ab0c696b 100644 --- a/libs/esl/fs_cli.c +++ b/libs/esl/fs_cli.c @@ -1287,11 +1287,13 @@ int main(int argc, char *argv[]) snprintf(prompt_str, sizeof(prompt_str), PROMPT_PREFIX "@%s> ", profile->name); } bare_prompt_str_len = (int)strlen(bare_prompt_str); + #if 0 if (feature_level) { - snprintf(prompt_str, sizeof(prompt_str), "%s%s%s", prompt_color, bare_prompt_str, input_text_color); + snprintf(prompt_str, sizeof(prompt_str), "%s%s%s #", prompt_color, bare_prompt_str, input_text_color); } else { - snprintf(prompt_str, sizeof(prompt_str), "%s", bare_prompt_str); + snprintf(prompt_str, sizeof(prompt_str), "%s >> ", bare_prompt_str); } + #endif connect: connected = 0; while (--loops > 0) { From 460814d8713e6b8f585ace3c857f4db1a394e747 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Fri, 3 Feb 2012 15:32:10 -0500 Subject: [PATCH 148/822] esl: fix command prompt --- libs/esl/fs_cli.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/libs/esl/fs_cli.c b/libs/esl/fs_cli.c index 81ab0c696b..193157e5cd 100644 --- a/libs/esl/fs_cli.c +++ b/libs/esl/fs_cli.c @@ -1153,6 +1153,7 @@ int main(int argc, char *argv[]) #else feature_level = 1; #endif + feature_level = 0; strncpy(internal_profile.host, "127.0.0.1", sizeof(internal_profile.host)); strncpy(internal_profile.pass, "ClueCon", sizeof(internal_profile.pass)); @@ -1287,13 +1288,15 @@ int main(int argc, char *argv[]) snprintf(prompt_str, sizeof(prompt_str), PROMPT_PREFIX "@%s> ", profile->name); } bare_prompt_str_len = (int)strlen(bare_prompt_str); - #if 0 if (feature_level) { - snprintf(prompt_str, sizeof(prompt_str), "%s%s%s #", prompt_color, bare_prompt_str, input_text_color); - } else { - snprintf(prompt_str, sizeof(prompt_str), "%s >> ", bare_prompt_str); - } - #endif + snprintf(prompt_str, sizeof(prompt_str), "%s%s%s", prompt_color, bare_prompt_str, input_text_color); + } + /* + else { + + snprintf(prompt_str, sizeof(prompt_str), "%s", bare_prompt_str); + } + */ connect: connected = 0; while (--loops > 0) { From b0ee65b45a301d191f3636d07253b0270f17af1e Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 9 Feb 2012 11:15:48 -0500 Subject: [PATCH 149/822] freetdm: adding new commands and removing unused ones - ftdm ss7 show - ftdm ss7 show span X - ftdm ss7 show status linkset X - ftdm ss7 inhibit X - ftdm ss7 uninhibit X --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index cb5584760f..ece88caac2 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -784,16 +784,24 @@ static ftdm_status_t handle_print_usage(ftdm_stream_handle_t *stream) stream->write_function(stream, "ftdm ss7 set ftrace X Y\n"); stream->write_function(stream, "ftdm ss7 set mtrace X Y\n"); stream->write_function(stream, "\n"); - stream->write_function(stream, "ftmod_sangoma_ss7 information:\n"); - stream->write_function(stream, "ftdm ss7 show status mtp3 X\n"); + + stream->write_function(stream, "ftmod_sangoma_ss7 signaling information:\n"); + stream->write_function(stream, "ftdm ss7 show \n"); stream->write_function(stream, "ftdm ss7 show status mtp2 X\n"); + stream->write_function(stream, "ftdm ss7 show status mtp3 X\n"); + stream->write_function(stream, "ftdm ss7 show status linkset X\n"); + stream->write_function(stream, "\n"); + + stream->write_function(stream, "ftmod_sangoma_ss7 circuit information:\n"); + stream->write_function(stream, "ftdm ss7 show span all\n"); + stream->write_function(stream, "ftdm ss7 show span X\n"); stream->write_function(stream, "ftdm ss7 show status span X chan Y\n"); stream->write_function(stream, "ftdm ss7 show free span X chan Y\n"); stream->write_function(stream, "ftdm ss7 show blocks span X chan Y\n"); - stream->write_function(stream, "ftdm ss7 show inuse span X chan Y\n"); stream->write_function(stream, "ftdm ss7 show inreset span X chan Y\n"); stream->write_function(stream, "\n"); + stream->write_function(stream, "ftmod_sangoma_ss7 circuit control:\n"); stream->write_function(stream, "ftdm ss7 blo span X chan Y\n"); stream->write_function(stream, "ftdm ss7 ubl span X chan Y\n"); @@ -802,9 +810,12 @@ static ftdm_status_t handle_print_usage(ftdm_stream_handle_t *stream) stream->write_function(stream, "ftdm ss7 cgb span X chan Y range Z\n"); stream->write_function(stream, "ftdm ss7 cgu span X chan Y range Z\n"); stream->write_function(stream, "\n"); + stream->write_function(stream, "ftmod_sangoma_ss7 link control:\n"); + /* stream->write_function(stream, "ftdm ss7 inhibit link X\n"); stream->write_function(stream, "ftdm ss7 uninhibit link X\n"); + */ stream->write_function(stream, "ftdm ss7 activate link X\n"); stream->write_function(stream, "ftdm ss7 deactivate link X\n"); stream->write_function(stream, "ftdm ss7 activate linkset X\n"); From 024a043e2c2fcf5c64ae4326db42cceb360fb60f Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 9 Feb 2012 14:04:45 -0500 Subject: [PATCH 150/822] freetdm: initial fix to rx cgb --- .../ftmod_sangoma_ss7_handle.c | 54 ++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 41223199b0..0999eed4d8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -2338,7 +2338,8 @@ ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ int blockType = 0; int byte = 0; int bit = 0; - int x; + int x; + int loop_range=0; ftdm_running_return(FTDM_FAIL); @@ -2405,6 +2406,56 @@ ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ } /* loop over the cics starting from circuit until range+1 */ + loop_range = circuit + range + 1; + x circuit; + while( x < loop_range ) { + if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != SNG_CKT_VOICE) { + loop_range++; + } + else { + if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x); + break; + } + + ftdm_mutex_lock(ftdmchan->mutex); + if (status[byte] & (1 << bit)) { + switch (blockType) { + /**********************************************************************/ + case 0: /* maintenance oriented */ + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); + break; + /**********************************************************************/ + case 1: /* hardware failure oriented */ + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); + break; + /**********************************************************************/ + case 2: /* reserved for national use */ + break; + /**********************************************************************/ + default: + break; + /**********************************************************************/ + } + } + + /* bring the sig status down */ + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + /* update the bit and byte counter*/ + bit ++; + if (bit == 8) { + byte++; + bit = 0; + } + } + x++; + } + +#if 0 for (x = circuit; x < (circuit + range + 1); x++) { /* confirm this is a voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != SNG_CKT_VOICE) continue; @@ -2460,6 +2511,7 @@ ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ } } /* for (x = circuit; x < (circuit + range + 1); x++) */ +#endif /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { From b78b612b47a48ed9080608abe7bd462079de4c28 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 9 Feb 2012 14:11:21 -0500 Subject: [PATCH 151/822] freetdm: fixing cgu with signaling link in unblock range --- .../ftmod_sangoma_ss7_handle.c | 60 ++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 0999eed4d8..6726627750 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -2407,7 +2407,7 @@ ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* loop over the cics starting from circuit until range+1 */ loop_range = circuit + range + 1; - x circuit; + x = circuit; while( x < loop_range ) { if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != SNG_CKT_VOICE) { loop_range++; @@ -2538,7 +2538,8 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ int blockType = 0; int byte = 0; int bit = 0; - int x; + int x; + int loop_range=0; ftdm_sigmsg_t sigev; ftdm_running_return(FTDM_FAIL); @@ -2608,6 +2609,60 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ } /* loop over the cics starting from circuit until range+1 */ + loop_range = circuit + range + 1; + x = circuit; + while( x < loop_range ) { + if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != SNG_CKT_VOICE) { + loop_range++; + } + else { + /* lock the channel */ + ftdm_mutex_lock(ftdmchan->mutex); + + if (status[byte] & (1 << bit)) { + switch (blockType) { + /**********************************************************************/ + case 0: /* maintenance oriented */ + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); + break; + /**********************************************************************/ + case 1: /* hardware failure oriented */ + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); + break; + /**********************************************************************/ + case 2: /* reserved for national use */ + break; + /**********************************************************************/ + default: + break; + /**********************************************************************/ + } /* switch (blockType) */ + } /* if (status[byte] & (1 << bit)) */ + + sigev.chan_id = ftdmchan->chan_id; + sigev.span_id = ftdmchan->span_id; + sigev.channel = ftdmchan; + + /* bring the sig status down */ + if (sngss7_channel_status_clear(sngss7_info)) { + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + } + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + /* update the bit and byte counter*/ + bit ++; + if (bit == 8) { + byte++; + bit = 0; + } + } + x++; + } +#if 0 for (x = circuit; x < (circuit + range + 1); x++) { if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != SNG_CKT_VOICE) continue; /* grab the circuit in question */ @@ -2661,6 +2716,7 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ } } /* for (x = circuit; x < (circuit + range + 1); x++) */ +#endif /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { From 7b3a3d86b9dfe368371caa741245af0c1a18b417 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 9 Feb 2012 14:32:08 -0500 Subject: [PATCH 152/822] freetdm: fixed cgu/cgb commands wrongly setting cic status when the range covers one or more signaling links --- .../ftmod_sangoma_ss7_handle.c | 144 +++++++++--------- 1 file changed, 73 insertions(+), 71 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 6726627750..84da8b95e9 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -2415,41 +2415,40 @@ ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ else { if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x); - break; - } - - ftdm_mutex_lock(ftdmchan->mutex); - if (status[byte] & (1 << bit)) { - switch (blockType) { - /**********************************************************************/ - case 0: /* maintenance oriented */ - sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); - break; - /**********************************************************************/ - case 1: /* hardware failure oriented */ - sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); - break; - /**********************************************************************/ - case 2: /* reserved for national use */ - break; - /**********************************************************************/ - default: - break; - /**********************************************************************/ + } else { + ftdm_mutex_lock(ftdmchan->mutex); + if (status[byte] & (1 << bit)) { + switch (blockType) { + /**********************************************************************/ + case 0: /* maintenance oriented */ + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); + break; + /**********************************************************************/ + case 1: /* hardware failure oriented */ + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); + break; + /**********************************************************************/ + case 2: /* reserved for national use */ + break; + /**********************************************************************/ + default: + break; + /**********************************************************************/ + } } - } - /* bring the sig status down */ - sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); + /* bring the sig status down */ + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); - /* unlock the channel again before we exit */ - ftdm_mutex_unlock(ftdmchan->mutex); + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); - /* update the bit and byte counter*/ - bit ++; - if (bit == 8) { - byte++; - bit = 0; + /* update the bit and byte counter*/ + bit ++; + if (bit == 8) { + byte++; + bit = 0; + } } } x++; @@ -2616,48 +2615,51 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ loop_range++; } else { - /* lock the channel */ - ftdm_mutex_lock(ftdmchan->mutex); - - if (status[byte] & (1 << bit)) { - switch (blockType) { - /**********************************************************************/ - case 0: /* maintenance oriented */ - sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); - sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); - sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); - break; - /**********************************************************************/ - case 1: /* hardware failure oriented */ - sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); - break; - /**********************************************************************/ - case 2: /* reserved for national use */ - break; - /**********************************************************************/ - default: - break; - /**********************************************************************/ - } /* switch (blockType) */ - } /* if (status[byte] & (1 << bit)) */ - - sigev.chan_id = ftdmchan->chan_id; - sigev.span_id = ftdmchan->span_id; - sigev.channel = ftdmchan; - - /* bring the sig status down */ - if (sngss7_channel_status_clear(sngss7_info)) { - sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x); } - - /* unlock the channel again before we exit */ - ftdm_mutex_unlock(ftdmchan->mutex); + else { + ftdm_mutex_lock(ftdmchan->mutex); - /* update the bit and byte counter*/ - bit ++; - if (bit == 8) { - byte++; - bit = 0; + if (status[byte] & (1 << bit)) { + switch (blockType) { + /**********************************************************************/ + case 0: /* maintenance oriented */ + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); + break; + /**********************************************************************/ + case 1: /* hardware failure oriented */ + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); + break; + /**********************************************************************/ + case 2: /* reserved for national use */ + break; + /**********************************************************************/ + default: + break; + /**********************************************************************/ + } /* switch (blockType) */ + } /* if (status[byte] & (1 << bit)) */ + + sigev.chan_id = ftdmchan->chan_id; + sigev.span_id = ftdmchan->span_id; + sigev.channel = ftdmchan; + + /* bring the sig status down */ + if (sngss7_channel_status_clear(sngss7_info)) { + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + } + + ftdm_mutex_unlock(ftdmchan->mutex); + + /* update the bit and byte counter*/ + bit ++; + if (bit == 8) { + byte++; + bit = 0; + } } } x++; From a46c03ef6588f9a476838d4f17429a456364ed5b Mon Sep 17 00:00:00 2001 From: James Zhang Date: Fri, 10 Feb 2012 17:29:28 -0500 Subject: [PATCH 153/822] freetdm: fixing glare - adding configuration of glare handling rule - fixed cic status remains COLLECTING --- .../ftmod_sangoma_ss7_handle.c | 4 +- .../ftmod_sangoma_ss7_main.c | 48 ++++++++++++++----- .../ftmod_sangoma_ss7_main.h | 22 +++++++++ .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 48 ++++++++++++++----- 4 files changed, 98 insertions(+), 24 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 84da8b95e9..2eed15e391 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -33,6 +33,7 @@ * Contributors: * * Ricardo Barroetaveña + * James Zhang * */ @@ -96,7 +97,7 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; char var[FTDM_DIGITS_LIMIT]; - + memset(var, '\0', sizeof(var)); ftdm_running_return(FTDM_FAIL); @@ -199,7 +200,6 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ } else { SS7_INFO_CHAN(ftdmchan,"No Called party (DNIS) information in IAM!%s\n", " "); } - copy_redirgNum_from_sngss7(ftdmchan, &siConEvnt->redirgNum); copy_redirgInfo_from_sngss7(ftdmchan, &siConEvnt->redirInfo); copy_genNmb_from_sngss7(ftdmchan, &siConEvnt->genNmb); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index fa36c7280a..2463d59115 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -35,6 +35,7 @@ * * Moises Silva * David Yat Sin + * James Zhang * */ @@ -1086,14 +1087,12 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) /*now go to the RING state */ state_flag = 0; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); - } else if (i >= sngss7_info->circuit->min_digits) { SS7_DEBUG_CHAN(ftdmchan, "Received %d digits (min digits = %d)\n", i, sngss7_info->circuit->min_digits); /*now go to the RING state */ state_flag = 0; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); - } else { /* if we are coming from idle state then we have already been here once before */ if (ftdmchan->last_state != FTDM_CHANNEL_STATE_IDLE) { @@ -1101,7 +1100,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) i, sngss7_info->circuit->min_digits, ftdmchan->caller_data.dnis.digits); - + /* start ISUP t35 */ if (ftdm_sched_timer (sngss7_info->t35.sched, "t35", @@ -1530,20 +1529,47 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) /* check if there is a glared call that needs to be processed */ if (sngss7_test_ckt_flag(sngss7_info, FLAG_GLARE)) { - - /* clear the glare flag */ sngss7_clear_ckt_flag (sngss7_info, FLAG_GLARE); - /* check if we have an IAM stored...if we don't have one just exit */ if (sngss7_info->glare.circuit != 0) { - /* send the saved call back in to us */ - handle_con_ind (0, - sngss7_info->glare.spInstId, - sngss7_info->glare.circuit, - &sngss7_info->glare.iam); + int bHandle=0; + switch (g_ftdm_sngss7_data.cfg.glareResolution) { + case SNGSS7_GLARE_DOWN: + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Giving control to the other side, handling copied IAM from glare. \n", sngss7_info->circuit->cic); + bHandle = 1; + break; + case SNGSS7_GLARE_PC: + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Trying to handle IAM copied from glare. \n", sngss7_info->circuit->cic); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]My PC = %d, incoming PC = %d. \n", sngss7_info->circuit->cic, + g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].spc, + g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].dpc ); + + if( g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].spc > g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].dpc ) + { + if ((sngss7_info->circuit->cic % 2) == 1 ) { + bHandle = 1; + } + } else { + if( (sngss7_info->circuit->cic % 2) == 0 ) { + bHandle = 1; + } + } + + break; + default: /* if configured as SNGSS7_GLARE_CONTROL, always abandon incoming glared IAM. */ + bHandle = 0; + break; + } + + if (!bHandle) { + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Handling glare IAM. \n", sngss7_info->circuit->cic); + handle_con_ind (0, sngss7_info->glare.spInstId, sngss7_info->glare.circuit, &sngss7_info->glare.iam); + } + /* clear the glare info */ memset(&sngss7_info->glare, 0x0, sizeof(sngss7_glare_data_t)); + state_flag = 0; } } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index fb60183bf8..f288a78e5f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -29,6 +29,12 @@ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Contributors: + * + * James Zhang + * */ /******************************************************************************/ #ifndef __FTMOD_SNG_SS7_H__ @@ -195,6 +201,21 @@ typedef struct sng_mtp2_link { uint32_t t7; } sng_mtp2_link_t; +/* defining glare handling methods: + SNGSS7_GLARE_PC: + higher PointCode controls even number CIC + lower PointCode controls odd number CIC + SNGSS7_GLARE_DOWN: + always give control to the other side + SNGSS7_GLARE_CONTROL: + always trying to control +*/ +typedef enum { + SNGSS7_GLARE_PC = 0, + SNGSS7_GLARE_DOWN, + SNGSS7_GLARE_CONTROL +} sng_glare_resolution; + typedef struct sng_mtp3_link { char name[MAX_NAME_LEN]; uint32_t flags; @@ -444,6 +465,7 @@ typedef struct sng_ss7_cfg { sng_isup_ckt_t isupCkt[10000]; /* KONRAD - only need 2000 ( and 0-1000 aren't used) since other servers are registerd else where */ sng_nsap_t nsap[MAX_NSAPS+1]; sng_isap_t isap[MAX_ISAPS+1]; + sng_glare_resolution glareResolution; } sng_ss7_cfg_t; typedef struct ftdm_sngss7_data { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 430b9895fe..6ea7400b37 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -29,6 +29,12 @@ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Contributors: + * + * James Zhang + * */ /* INCLUDE ********************************************************************/ @@ -191,6 +197,7 @@ static int ftmod_ss7_fill_in_self_route(int spc, int linkType, int switchType, i static int ftmod_ss7_fill_in_circuits(sng_span_t *sngSpan); static int ftmod_ss7_next_timeslot(char *ch_map, sng_timeslot_t *timeslot); +static void ftmod_ss7_set_glare_resolution (const char *method); /******************************************************************************/ @@ -451,6 +458,26 @@ static int ftmod_ss7_parse_sng_isup(ftdm_conf_node_t *sng_isup) return FTDM_SUCCESS; } +static void ftmod_ss7_set_glare_resolution (const char *method) +{ + sng_glare_resolution iMethod=SNGSS7_GLARE_PC; + if (!method || (strlen (method) <=0) ) { + SS7_ERROR( "Wrong glare resolution parameter, using default. \n" ); + } else { + if (!strcasecmp( method, "PointCode")) { + iMethod = SNGSS7_GLARE_PC; + } else if (!strcasecmp( method, "Down")) { + iMethod = SNGSS7_GLARE_DOWN; + } else if (!strcasecmp( method, "Control")) { + iMethod = SNGSS7_GLARE_CONTROL; + } else { + SS7_ERROR( "Wrong glare resolution parameter, using default. \n" ); + iMethod = SNGSS7_GLARE_PC; + } + } + g_ftdm_sngss7_data.cfg.glareResolution = iMethod; +} + /******************************************************************************/ static int ftmod_ss7_parse_sng_gen(ftdm_conf_node_t *sng_gen) { @@ -463,28 +490,27 @@ static int ftmod_ss7_parse_sng_gen(ftdm_conf_node_t *sng_gen) /* extract all the information from the parameters */ for (i = 0; i < num_parms; i++) { - /**************************************************************************/ - if (!strcasecmp(parm->var, "procId")) { - /**********************************************************************/ g_ftdm_sngss7_data.cfg.procId = atoi(parm->val); SS7_DEBUG("Found a procId = %d\n", g_ftdm_sngss7_data.cfg.procId); - /**********************************************************************/ - } else if (!strcasecmp(parm->var, "license")) { - /**********************************************************************/ + } + else if (!strcasecmp(parm->var, "license")) { ftdm_set_string(g_ftdm_sngss7_data.cfg.license, parm->val); snprintf(g_ftdm_sngss7_data.cfg.signature, sizeof(g_ftdm_sngss7_data.cfg.signature), "%s.sig", parm->val); SS7_DEBUG("Found license file = %s\n", g_ftdm_sngss7_data.cfg.license); SS7_DEBUG("Found signature file = %s\n", g_ftdm_sngss7_data.cfg.signature); - /**********************************************************************/ - } else if (!strcasecmp(parm->var, "transparent_iam_max_size")) { + } + else if (!strcasecmp(parm->var, "transparent_iam_max_size")) { g_ftdm_sngss7_data.cfg.transparent_iam_max_size = atoi(parm->val); SS7_DEBUG("Found a transparent_iam max size = %d\n", g_ftdm_sngss7_data.cfg.transparent_iam_max_size); - } else { - /**********************************************************************/ + } + else if (!strcasecmp(parm->var, "glare-reso")) { + ftmod_ss7_set_glare_resolution (parm->val); + SS7_DEBUG("Found glare resolution configuration = %d %s\n", g_ftdm_sngss7_data.cfg.glareResolution, parm->val ); + } + else { SS7_ERROR("Found an invalid parameter \"%s\"!\n", parm->val); return FTDM_FAIL; - /**********************************************************************/ } /* move to the next parmeter */ From a6e868f588572034dbf41866432138aa54a10aa4 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 16 Feb 2012 14:49:18 -0500 Subject: [PATCH 154/822] freetdm: Fix spirou certification native bridge issue - The outgoing tdm leg should not move to UP until after the IAM is sent at the end of the function - The UP state should be processed immediately otherwise the state processor is not run due to the way the main ss7 processing loop currently works --- libs/freetdm/src/ftdm_state.c | 10 +++++++-- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 21 ++++++++++++++++--- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/libs/freetdm/src/ftdm_state.c b/libs/freetdm/src/ftdm_state.c index 30ef3ce478..03f2cd8e18 100644 --- a/libs/freetdm/src/ftdm_state.c +++ b/libs/freetdm/src/ftdm_state.c @@ -48,9 +48,15 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const c ftdm_time_t diff = 0; ftdm_channel_state_t state = fchan->state; + if (fchan->state_status == FTDM_STATE_STATUS_NEW) { + ftdm_log_chan_ex(fchan, file, func, line, FTDM_LOG_LEVEL_CRIT, + "Asking to complete state change from %s to %s in %llums, but the state is still unprocessed (this might be a bug!)\n", + ftdm_channel_state2str(fchan->last_state), ftdm_channel_state2str(state), diff); + /* We should probably return here with FTDM_FAIL if we don't see this message in production environments for a while (2012-02-16) */ + } + if (fchan->state_status == FTDM_STATE_STATUS_COMPLETED) { - ftdm_assert_return(!ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE), FTDM_FAIL, - "State change flag set but state is not completed\n"); + ftdm_assert_return(!ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE), FTDM_FAIL, "State change flag set but state is already completed\n"); return FTDM_SUCCESS; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index 00d06905dd..7ad510079f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -46,6 +46,7 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) { const char *var = NULL; SiConEvnt iam; + ftdm_bool_t native_going_up = FTDM_FALSE; sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;; SS7_FUNC_TRACE_ENTER (__FUNCTION__); @@ -81,9 +82,11 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* flush our own queue */ sngss7_flush_queue(sngss7_info->event_queue); - /* go up until release comes, note that state processing is done different and much simpler when there is a peer */ - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP); - ftdm_channel_advance_states(ftdmchan); + /* Go to up until release comes, note that state processing is done different and much simpler when there is a peer, + We can't go to UP state right away yet though, so do not set the state to UP here, wait until the end of this function + because moving from one state to another causes the ftdmchan->usrmsg structure to be wiped + and we still need those variables for further IAM processing */ + native_going_up = FTDM_TRUE; } } } @@ -211,6 +214,18 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) &iam, 0); + if (native_going_up) { + /* + Note that this function (ft_to_sngss7_iam) is run within the main SS7 processing loop in + response to the DIALING state handler, we can set the state to UP here and that will + implicitly complete the DIALING state, but we *MUST* also advance the state handler + right away for a native bridge, otherwise, the processing state function (ftdm_sangoma_ss7_process_state_change) + will complete the state without having executed the handler for FTDM_CHANNEL_STATE_UP, and we won't notify + the user sending FTDM_SIGEVENT_UP which can cause the application to misbehave (ie, no audio) */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP); + ftdm_channel_advance_states(ftdmchan); + } + SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } From 8c8d649221b6d700d9738c619ceef0689aa0e134 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 16 Feb 2012 15:14:06 -0500 Subject: [PATCH 155/822] freetdm: Add support to set/receive location and original call number SS7 elements through variables (including SIP X headers) --- libs/freetdm/mod_freetdm/mod_freetdm.c | 55 ++++++++++++- .../ftmod_sangoma_ss7_main.h | 3 + .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 21 ++++- .../ftmod_sangoma_ss7_support.c | 81 ++++++++++++++++--- 4 files changed, 148 insertions(+), 12 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index b78cc078d4..01d7c282c3 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1400,6 +1400,22 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi ftdm_set_string(caller_data.loc.digits, sipvar); } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-LOC-Screen"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_loc_screen_ind", sipvar); + } + + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-LOC-Presentation"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_loc_pres_ind", sipvar); + } + + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-LOC-NADI"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_loc_nadi", sipvar); + } + + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-DNIS-TON"); if (sipvar) { caller_data.dnis.type = (uint8_t)atoi(sipvar); @@ -1514,6 +1530,24 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi if (sipvar) { ftdm_usrmsg_add_var(&usrmsg, "ss7_rdinfo_reason", sipvar); } + + + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-OCN"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_ocn", sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-OCN-NADI"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_ocn_nadi", sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-OCN-Plan"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_ocn_plan", sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-OCN-Presentation"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_ocn_pres", sipvar); + } } if (switch_test_flag(outbound_profile, SWITCH_CPF_SCREEN)) { @@ -1944,10 +1978,29 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_loc_nadi"); - printf ( "ss7_loc_nadi = %s \n " , var_value ); if (!ftdm_strlen_zero(var_value)) { switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-LOC-NADI", "%s", var_value); } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_ocn"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OCN", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_ocn_nadi"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OCN-NADI", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_ocn_plan"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OCN-Plan", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_ocn_pres"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OCN-Presentation", "%s", var_value); + } } /* Add any call variable to the dial plan */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index fb60183bf8..86cdc73bc9 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -868,6 +868,9 @@ ftdm_status_t copy_redirgNum_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *red ftdm_status_t copy_redirgNum_from_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *redirgNum); ftdm_status_t copy_redirgInfo_from_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *redirInfo); ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *redirInfo); +ftdm_status_t copy_ocn_to_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum); +ftdm_status_t copy_ocn_from_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum); + ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum); ftdm_status_t copy_locPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index 7ad510079f..930457c7c8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -135,6 +135,11 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* Redirecting Information */ copy_redirgInfo_to_sngss7(ftdmchan, &iam.redirInfo); } + + if (iam.origCdNum.eh.pres != PRSNT_NODEF) { + /* Original Called Number */ + copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum); + } } /* since this is the first time we dequeue an event from the peer, make sure our main thread process any other events, this will trigger the interrupt in our span peer_chans queue which will wake up our main thread if it is sleeping */ @@ -157,6 +162,9 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* Forward Call Indicators */ copy_fwdCallInd_to_sngss7(ftdmchan, &iam.fwdCallInd); + + /* Original Called Number */ + copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum); } else { /* Nature of Connection Indicators */ copy_natConInd_to_sngss7(ftdmchan, &iam.natConInd); @@ -193,6 +201,8 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* Redirecting Information */ copy_redirgInfo_to_sngss7(ftdmchan, &iam.redirInfo); + /* Original Called Number */ + copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum); /* Access Transport */ copy_accTrnspt_to_sngss7(ftdmchan, &iam.accTrnspt); @@ -236,6 +246,7 @@ void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan) sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; SiCnStEvnt acm; + const char *backwardInd = NULL; memset (&acm, 0x0, sizeof (acm)); @@ -253,8 +264,16 @@ void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan) acm.bckCallInd.intInd.val = INTIND_NOINTW; acm.bckCallInd.end2EndInfoInd.pres = PRSNT_NODEF; acm.bckCallInd.end2EndInfoInd.val = E2EINF_NOINFO; + acm.bckCallInd.isdnUsrPrtInd.pres = PRSNT_NODEF; - acm.bckCallInd.isdnUsrPrtInd.val = ISUP_USED; + acm.bckCallInd.isdnUsrPrtInd.val = ISUP_NOTUSED; + backwardInd = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "acm_bi_iup"); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied backward indicator ISDN user part indicator ACM, value \"%s\"\n", backwardInd); + if (!ftdm_strlen_zero(backwardInd)) { + if (atoi(backwardInd) != 0 ) { + acm.bckCallInd.isdnUsrPrtInd.val = ISUP_USED; + } + } acm.bckCallInd.holdInd.pres = PRSNT_NODEF; acm.bckCallInd.holdInd.val = HOLD_NOTREQD; acm.bckCallInd.isdnAccInd.pres = PRSNT_NODEF; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 2088f240b6..4557c00a10 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -259,20 +259,20 @@ ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *loc locPtyNum->scrnInd.pres = pres_val; val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_loc_screen_ind"); if (!ftdm_strlen_zero(val)) { - locPtyNum->scrnInd.val = atoi(val); + locPtyNum->scrnInd.val = atoi(val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Screening Ind %d\n", locPtyNum->scrnInd.val); } else { - locPtyNum->scrnInd.val = caller_data->screen; + locPtyNum->scrnInd.val = caller_data->screen; } - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Location Reference Code Screening Ind %d\n", locPtyNum->scrnInd.val); locPtyNum->presRest.pres = pres_val; - val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_pres_ind"); + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_loc_pres_ind"); if (!ftdm_strlen_zero(val)) { - locPtyNum->presRest.val = atoi(val); + locPtyNum->presRest.val = atoi(val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Presentation Ind %d\n", locPtyNum->presRest.val); } else { - locPtyNum->presRest.val = caller_data->pres; + locPtyNum->presRest.val = caller_data->pres; } - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Calling Party Number Presentation Ind %d\n", locPtyNum->presRest.val); locPtyNum->numPlan.pres = pres_val; locPtyNum->numPlan.val = 0x01; @@ -286,11 +286,10 @@ ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *loc ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Reference NADI value \"%s\"\n", loc_nadi); locPtyNum->natAddrInd.val = atoi(loc_nadi); } else { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied NADI value found for LOC, using \"%d\"\n", locPtyNum->natAddrInd.val); locPtyNum->natAddrInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].loc_nadi; locPtyNum->natAddrInd.val = 0x03; - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied NADI value found for LOC, using \"%d\"\n", locPtyNum->natAddrInd.val); } - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Location Reference Presentation Ind %d\n", locPtyNum->presRest.val); return copy_tknStr_to_sngss7(caller_data->loc.digits, &locPtyNum->addrSig, &locPtyNum->oddEven); } @@ -439,7 +438,7 @@ ftdm_status_t copy_redirgNum_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *red return FTDM_FAIL; } } else if (!ftdm_strlen_zero(caller_data->rdnis.digits)) { - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Redirection Number\"%s\"\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Redirection Number\"%s\"\n", caller_data->rdnis.digits); if (copy_tknStr_to_sngss7(caller_data->rdnis.digits, &redirgNum->addrSig, &redirgNum->oddEven) != FTDM_SUCCESS) { return FTDM_FAIL; } @@ -639,6 +638,68 @@ ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *r return FTDM_SUCCESS; } +ftdm_status_t copy_ocn_from_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum) +{ + return FTDM_FAIL; +} + +ftdm_status_t copy_ocn_to_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum) +{ + + const char *val = NULL; + int bProceed = 0; + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn"); + if (!ftdm_strlen_zero(val)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number \"%s\"\n", val); + if (copy_tknStr_to_sngss7((char*)val, &origCdNum->addrSig, &origCdNum->oddEven) != FTDM_SUCCESS) { + return FTDM_FAIL; + } + origCdNum->addrSig.pres = 1; + } else { + return FTDM_SUCCESS; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn_nadi"); + if (!ftdm_strlen_zero(val)) { + origCdNum->natAddr.val = atoi(val); + origCdNum->natAddr.pres = 1; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number NADI value \"%s\"\n", val); + bProceed = 1; + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Original Called Number NADI value\n"); + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn_plan"); + if (!ftdm_strlen_zero(val)) { + origCdNum->numPlan.val = atoi(val); + origCdNum->numPlan.pres = 1; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number Plan value \"%s\"\n", val); + bProceed = 1; + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Original Called Number Plan value\n"); + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn_pres"); + if (!ftdm_strlen_zero(val)) { + origCdNum->presRest.val = atoi(val); + origCdNum->presRest.pres = 1; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number Presentation value \"%s\"\n", val); + bProceed = 1; + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Original Called Number Presentation value\n"); + } + + if( bProceed == 1 ) { + origCdNum->eh.pres = PRSNT_NODEF; + } else { + origCdNum->eh.pres = NOTPRSNT; + } + + + return FTDM_SUCCESS; +} + ftdm_status_t copy_cgPtyCat_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyCat *cgPtyCat) { ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; From 4ccc26f08b94404246c951d13d62dbafe2ecc781 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 16 Feb 2012 15:15:22 -0500 Subject: [PATCH 156/822] freetdm: Fix improper logging statement when doing native ss7 bridge (peer_chan was set to the SIP leg) --- libs/freetdm/mod_freetdm/mod_freetdm.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 01d7c282c3..f9381ce133 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1650,11 +1650,13 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi our_chan = switch_core_session_get_channel(*new_session); + /* Figure out if there is a native bridge requested through SIP x headers */ if (network_peer_uuid) { switch_core_session_t *network_peer = switch_core_session_locate(network_peer_uuid); if (network_peer) { const char *my_uuid = switch_core_session_get_uuid(*new_session); private_t *peer_private = switch_core_session_get_private(network_peer); + peer_chan = switch_core_session_get_channel(network_peer); switch_set_string(tech_pvt->network_peer_uuid, network_peer_uuid); switch_set_string(peer_private->network_peer_uuid, my_uuid); @@ -1665,6 +1667,15 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi ftdm_channel_get_span_id(peer_private->ftdmchan), ftdm_channel_get_id(peer_private->ftdmchan)); switch_core_session_rwunlock(network_peer); } + /* Figure out if there is a native bridge requested through dial plan variable and the originating channel is also freetdm (not going through SIP) */ + } else if (session + && (var = channel_get_variable(session, var_event, FREETDM_VAR_PREFIX "native_sigbridge")) + && switch_true(var) + && switch_core_session_compare(*new_session, session)) { + private_t *peer_pvt = switch_core_session_get_private(session); + peer_chan = switch_core_session_get_channel(session); + snprintf(sigbridge_peer, sizeof(sigbridge_peer), "%u:%u", + ftdm_channel_get_span_id(peer_pvt->ftdmchan), ftdm_channel_get_id(peer_pvt->ftdmchan)); } caller_profile = switch_caller_profile_clone(*new_session, outbound_profile); @@ -1678,21 +1689,11 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi hunt_data.tech_pvt = tech_pvt; caller_data.priv = &hunt_data; - if (session - && (var = channel_get_variable(session, var_event, FREETDM_VAR_PREFIX "native_sigbridge")) - && switch_true(var) - && switch_core_session_compare(*new_session, session)) { - private_t *peer_pvt = switch_core_session_get_private(session); - snprintf(sigbridge_peer, sizeof(sigbridge_peer), "%u:%u", - ftdm_channel_get_span_id(peer_pvt->ftdmchan), ftdm_channel_get_id(peer_pvt->ftdmchan)); - } - if (session && !zstr(sigbridge_peer)) { peer_chan = switch_core_session_get_channel(session); ftdm_usrmsg_add_var(&usrmsg, "sigbridge_peer", sigbridge_peer); } - if ((status = ftdm_call_place_ex(&caller_data, &hunting, &usrmsg)) != FTDM_SUCCESS) { if (tech_pvt->read_codec.implementation) { switch_core_codec_destroy(&tech_pvt->read_codec); From 1f34c9301e6a737890f9d756f87554afc8a96f4e Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 16 Feb 2012 16:08:21 -0500 Subject: [PATCH 157/822] freetdm: Remove optimistic sanity check, prints spurious error messages --- libs/freetdm/src/ftdm_state.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftdm_state.c b/libs/freetdm/src/ftdm_state.c index 03f2cd8e18..c6d45c3c3c 100644 --- a/libs/freetdm/src/ftdm_state.c +++ b/libs/freetdm/src/ftdm_state.c @@ -48,12 +48,22 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const c ftdm_time_t diff = 0; ftdm_channel_state_t state = fchan->state; +#if 0 + /* I could not perform this sanity check without more disruptive changes. Ideally we should check here if the signaling module completing the state + executed a state processor (called ftdm_channel_advance_states() which call fchan->span->state_processor(fchan)) for the state. That is just a + sanity check, as in the past we had at least one bug where the signaling module set the state and then accidentally changed the state to a new one + without calling ftdm_channel_advance_states(), meaning the state processor for the first state was not executed and that lead to unexpected behavior. + + If we want to be able to perform this kind of sanity check it would be nice to add a new state status (FTDM_STATE_STATUS_PROCESSING), the function + ftdm_channel_advance_states() would set the state_status to PROCESSING and then the check below for STATUS_NEW would be valid. Currently is not + valid because the signaling module may be completing the state at the end of the state_processor callback and therefore the state will still be + in STATUS_NEW, and is perfectly valid ... */ if (fchan->state_status == FTDM_STATE_STATUS_NEW) { ftdm_log_chan_ex(fchan, file, func, line, FTDM_LOG_LEVEL_CRIT, "Asking to complete state change from %s to %s in %llums, but the state is still unprocessed (this might be a bug!)\n", ftdm_channel_state2str(fchan->last_state), ftdm_channel_state2str(state), diff); - /* We should probably return here with FTDM_FAIL if we don't see this message in production environments for a while (2012-02-16) */ } +#endif if (fchan->state_status == FTDM_STATE_STATUS_COMPLETED) { ftdm_assert_return(!ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE), FTDM_FAIL, "State change flag set but state is already completed\n"); From 3f43b053a07cd26d40bc4bb069b7a8cff8315ce7 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 16 Feb 2012 16:49:51 -0500 Subject: [PATCH 158/822] freetdm: adding x-ocn-* headers for incoming sip calls --- libs/freetdm/mod_freetdm/mod_freetdm.c | 1 + .../ftmod_sangoma_ss7_handle.c | 1 + .../ftmod_sangoma_ss7_support.c | 36 ++++++++++++++++++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index f9381ce133..c3e5c486db 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -26,6 +26,7 @@ * Anthony Minessale II * Moises Silva * David Yat Sin + * James Zhang * * * mod_freetdm.c -- FreeTDM Endpoint Module diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 9c3bd65426..f080352d4a 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -200,6 +200,7 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ SS7_INFO_CHAN(ftdmchan,"No Called party (DNIS) information in IAM!%s\n", " "); } + copy_ocn_from_sngss7(ftdmchan, &siConEvnt->origCdNum); copy_redirgNum_from_sngss7(ftdmchan, &siConEvnt->redirgNum); copy_redirgInfo_from_sngss7(ftdmchan, &siConEvnt->redirInfo); copy_genNmb_from_sngss7(ftdmchan, &siConEvnt->genNmb); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 4557c00a10..e7af4bb6e0 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -640,7 +640,41 @@ ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *r ftdm_status_t copy_ocn_from_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum) { - return FTDM_FAIL; + + char val[20]; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + if (origCdNum->eh.pres != PRSNT_NODEF ) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No Original Called Number available\n"); + return FTDM_SUCCESS; + } + + + if (origCdNum->addrSig.pres == PRSNT_NODEF) { + copy_tknStr_from_sngss7(origCdNum->addrSig, val, origCdNum->oddEven); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number digits:%s\n", val); + sngss7_add_var(sngss7_info, "ss7_ocn", val); + } + + if (origCdNum->natAddr.pres == PRSNT_NODEF) { + snprintf(val, sizeof(val), "%d", origCdNum->natAddr.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - NADI:%s\n", val); + sngss7_add_var(sngss7_info, "ss7_ocn_nadi", val); + } + + if (origCdNum->numPlan.pres == PRSNT_NODEF) { + snprintf(val, sizeof(val), "%d", origCdNum->numPlan.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number -plan:%s\n", val); + sngss7_add_var(sngss7_info, "ss7_ocn_plan", val); + } + + if (origCdNum->presRest.pres == PRSNT_NODEF) { + snprintf(val, sizeof(val), "%d", origCdNum->presRest.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - presentation:%s\n", val); + sngss7_add_var(sngss7_info, "ss7_ocn_pres", val); + } + + return FTDM_SUCCESS; } ftdm_status_t copy_ocn_to_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum) From 713b55cd585aab9c6ea7969e6f03b30d10a5a7e6 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 16 Feb 2012 18:33:00 -0500 Subject: [PATCH 159/822] freetdm: fixing improper log position in tx acm function --- .../freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index 930457c7c8..84b9a9b7f2 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -268,8 +268,8 @@ void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan) acm.bckCallInd.isdnUsrPrtInd.pres = PRSNT_NODEF; acm.bckCallInd.isdnUsrPrtInd.val = ISUP_NOTUSED; backwardInd = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "acm_bi_iup"); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied backward indicator ISDN user part indicator ACM, value \"%s\"\n", backwardInd); if (!ftdm_strlen_zero(backwardInd)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied backward indicator ISDN user part indicator ACM, value \"%s\"\n", backwardInd); if (atoi(backwardInd) != 0 ) { acm.bckCallInd.isdnUsrPrtInd.val = ISUP_USED; } From 6ed6fd2c1a467a9ab9ec5138cbd6102c76e44973 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Fri, 24 Feb 2012 15:43:23 -0500 Subject: [PATCH 160/822] freetdm: latest SPIROU fixes in releases.3.4 branch merged in releases.3.5 --- libs/freetdm/mod_freetdm/mod_freetdm.c | 75 ++++++++++-- libs/freetdm/src/ftdm_state.c | 21 +++- .../ftmod_sangoma_ss7_handle.c | 1 + .../ftmod_sangoma_ss7_main.h | 2 + .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 44 ++++++- .../ftmod_sangoma_ss7_support.c | 111 ++++++++++++++++-- 6 files changed, 227 insertions(+), 27 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 11f30019e8..699ce194e1 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -26,6 +26,7 @@ * Anthony Minessale II * Moises Silva * David Yat Sin + * James Zhang * * * mod_freetdm.c -- FreeTDM Endpoint Module @@ -1459,6 +1460,21 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi ftdm_set_string(caller_data.loc.digits, sipvar); } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-LOC-Screen"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_loc_screen_ind", sipvar); + } + + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-LOC-Presentation"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_loc_pres_ind", sipvar); + } + + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-LOC-NADI"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_loc_nadi", sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-DNIS-TON"); if (sipvar) { caller_data.dnis.type = (uint8_t)atoi(sipvar); @@ -1573,6 +1589,23 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi if (sipvar) { ftdm_usrmsg_add_var(&usrmsg, "ss7_rdinfo_reason", sipvar); } + + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-OCN"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_ocn", sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-OCN-NADI"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_ocn_nadi", sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-OCN-Plan"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_ocn_plan", sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-OCN-Presentation"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_ocn_pres", sipvar); + } } if (switch_test_flag(outbound_profile, SWITCH_CPF_SCREEN)) { @@ -1675,11 +1708,13 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi our_chan = switch_core_session_get_channel(*new_session); + /* Figure out if there is a native bridge requested through SIP x headers */ if (network_peer_uuid) { switch_core_session_t *network_peer = switch_core_session_locate(network_peer_uuid); if (network_peer) { const char *my_uuid = switch_core_session_get_uuid(*new_session); private_t *peer_private = switch_core_session_get_private(network_peer); + peer_chan = switch_core_session_get_channel(network_peer); switch_set_string(tech_pvt->network_peer_uuid, network_peer_uuid); switch_set_string(peer_private->network_peer_uuid, my_uuid); @@ -1690,6 +1725,16 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi ftdm_channel_get_span_id(peer_private->ftdmchan), ftdm_channel_get_id(peer_private->ftdmchan)); switch_core_session_rwunlock(network_peer); } + + /* Figure out if there is a native bridge requested through dial plan variable and the originating channel is also freetdm (not going through SIP) */ + } else if (session + && (var = channel_get_variable(session, var_event, FREETDM_VAR_PREFIX "native_sigbridge")) + && switch_true(var) + && switch_core_session_compare(*new_session, session)) { + private_t *peer_pvt = switch_core_session_get_private(session); + peer_chan = switch_core_session_get_channel(session); + snprintf(sigbridge_peer, sizeof(sigbridge_peer), "%u:%u", + ftdm_channel_get_span_id(peer_pvt->ftdmchan), ftdm_channel_get_id(peer_pvt->ftdmchan)); } caller_profile = switch_caller_profile_clone(*new_session, outbound_profile); @@ -1703,21 +1748,11 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi hunt_data.tech_pvt = tech_pvt; caller_data.priv = &hunt_data; - if (session - && (var = channel_get_variable(session, var_event, FREETDM_VAR_PREFIX "native_sigbridge")) - && switch_true(var) - && switch_core_session_compare(*new_session, session)) { - private_t *peer_pvt = switch_core_session_get_private(session); - snprintf(sigbridge_peer, sizeof(sigbridge_peer), "%u:%u", - ftdm_channel_get_span_id(peer_pvt->ftdmchan), ftdm_channel_get_id(peer_pvt->ftdmchan)); - } - if (session && !zstr(sigbridge_peer)) { peer_chan = switch_core_session_get_channel(session); ftdm_usrmsg_add_var(&usrmsg, "sigbridge_peer", sigbridge_peer); } - if ((status = ftdm_call_place_ex(&caller_data, &hunting, &usrmsg)) != FTDM_SUCCESS) { if (tech_pvt->read_codec.implementation) { switch_core_codec_destroy(&tech_pvt->read_codec); @@ -1999,10 +2034,28 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_loc_nadi"); - printf ( "ss7_loc_nadi = %s \n " , var_value ); if (!ftdm_strlen_zero(var_value)) { switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-LOC-NADI", "%s", var_value); } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_ocn"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OCN", "%s", var_value); + } + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_ocn_nadi"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OCN-NADI", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_ocn_plan"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OCN-Plan", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_ocn_pres"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OCN-Presentation", "%s", var_value); + } } /* Add any call variable to the dial plan */ diff --git a/libs/freetdm/src/ftdm_state.c b/libs/freetdm/src/ftdm_state.c index 30ef3ce478..bd670d0062 100644 --- a/libs/freetdm/src/ftdm_state.c +++ b/libs/freetdm/src/ftdm_state.c @@ -48,9 +48,26 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const c ftdm_time_t diff = 0; ftdm_channel_state_t state = fchan->state; + +#if 0 + /* I could not perform this sanity check without more disruptive changes. Ideally we should check here if the signaling module completing the state + executed a state processor (called ftdm_channel_advance_states() which call fchan->span->state_processor(fchan)) for the state. That is just a + sanity check, as in the past we had at least one bug where the signaling module set the state and then accidentally changed the state to a new one + without calling ftdm_channel_advance_states(), meaning the state processor for the first state was not executed and that lead to unexpected behavior. + + If we want to be able to perform this kind of sanity check it would be nice to add a new state status (FTDM_STATE_STATUS_PROCESSING), the function + ftdm_channel_advance_states() would set the state_status to PROCESSING and then the check below for STATUS_NEW would be valid. Currently is not + valid because the signaling module may be completing the state at the end of the state_processor callback and therefore the state will still be + in STATUS_NEW, and is perfectly valid ... */ + if (fchan->state_status == FTDM_STATE_STATUS_NEW) { + ftdm_log_chan_ex(fchan, file, func, line, FTDM_LOG_LEVEL_CRIT, + "Asking to complete state change from %s to %s in %llums, but the state is still unprocessed (this might be a bug!)\n", + ftdm_channel_state2str(fchan->last_state), ftdm_channel_state2str(state), diff); + } +#endif + if (fchan->state_status == FTDM_STATE_STATUS_COMPLETED) { - ftdm_assert_return(!ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE), FTDM_FAIL, - "State change flag set but state is not completed\n"); + ftdm_assert_return(!ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE), FTDM_FAIL, "State change flag set but state is already completed\n"); return FTDM_SUCCESS; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 2eed15e391..667dc09ba0 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -200,6 +200,7 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ } else { SS7_INFO_CHAN(ftdmchan,"No Called party (DNIS) information in IAM!%s\n", " "); } + copy_ocn_from_sngss7(ftdmchan, &siConEvnt->origCdNum); copy_redirgNum_from_sngss7(ftdmchan, &siConEvnt->redirgNum); copy_redirgInfo_from_sngss7(ftdmchan, &siConEvnt->redirInfo); copy_genNmb_from_sngss7(ftdmchan, &siConEvnt->genNmb); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index f288a78e5f..63d4ded203 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -890,6 +890,8 @@ ftdm_status_t copy_redirgNum_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *red ftdm_status_t copy_redirgNum_from_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *redirgNum); ftdm_status_t copy_redirgInfo_from_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *redirInfo); ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *redirInfo); +ftdm_status_t copy_ocn_to_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum); +ftdm_status_t copy_ocn_from_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum); ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum); ftdm_status_t copy_locPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index 00d06905dd..fb91b834ec 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -46,6 +46,7 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) { const char *var = NULL; SiConEvnt iam; + ftdm_bool_t native_going_up = FTDM_FALSE; sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;; SS7_FUNC_TRACE_ENTER (__FUNCTION__); @@ -81,9 +82,11 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* flush our own queue */ sngss7_flush_queue(sngss7_info->event_queue); - /* go up until release comes, note that state processing is done different and much simpler when there is a peer */ - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP); - ftdm_channel_advance_states(ftdmchan); + /* Go to up until release comes, note that state processing is done different and much simpler when there is a peer, + We can't go to UP state right away yet though, so do not set the state to UP here, wait until the end of this function + because moving from one state to another causes the ftdmchan->usrmsg structure to be wiped + and we still need those variables for further IAM processing */ + native_going_up = FTDM_TRUE; } } } @@ -132,6 +135,11 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* Redirecting Information */ copy_redirgInfo_to_sngss7(ftdmchan, &iam.redirInfo); } + + if (iam.origCdNum.eh.pres != PRSNT_NODEF) { + /* Original Called Number */ + copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum); + } } /* since this is the first time we dequeue an event from the peer, make sure our main thread process any other events, this will trigger the interrupt in our span peer_chans queue which will wake up our main thread if it is sleeping */ @@ -154,6 +162,9 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* Forward Call Indicators */ copy_fwdCallInd_to_sngss7(ftdmchan, &iam.fwdCallInd); + + /* Original Called Number */ + copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum); } else { /* Nature of Connection Indicators */ copy_natConInd_to_sngss7(ftdmchan, &iam.natConInd); @@ -190,6 +201,8 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* Redirecting Information */ copy_redirgInfo_to_sngss7(ftdmchan, &iam.redirInfo); + /* Original Called Number */ + copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum); /* Access Transport */ copy_accTrnspt_to_sngss7(ftdmchan, &iam.accTrnspt); @@ -211,6 +224,19 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) &iam, 0); + + if (native_going_up) { + /* + Note that this function (ft_to_sngss7_iam) is run within the main SS7 processing loop in + response to the DIALING state handler, we can set the state to UP here and that will + implicitly complete the DIALING state, but we *MUST* also advance the state handler + right away for a native bridge, otherwise, the processing state function (ftdm_sangoma_ss7_process_state_change) + will complete the state without having executed the handler for FTDM_CHANNEL_STATE_UP, and we won't notify + the user sending FTDM_SIGEVENT_UP which can cause the application to misbehave (ie, no audio) */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP); + ftdm_channel_advance_states(ftdmchan); + } + SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -221,6 +247,7 @@ void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan) sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; SiCnStEvnt acm; + const char *backwardInd = NULL; memset (&acm, 0x0, sizeof (acm)); @@ -238,8 +265,17 @@ void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan) acm.bckCallInd.intInd.val = INTIND_NOINTW; acm.bckCallInd.end2EndInfoInd.pres = PRSNT_NODEF; acm.bckCallInd.end2EndInfoInd.val = E2EINF_NOINFO; + acm.bckCallInd.isdnUsrPrtInd.pres = PRSNT_NODEF; - acm.bckCallInd.isdnUsrPrtInd.val = ISUP_USED; + acm.bckCallInd.isdnUsrPrtInd.val = ISUP_NOTUSED; + backwardInd = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "acm_bi_iup"); + if (!ftdm_strlen_zero(backwardInd)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied backward indicator ISDN user part indicator ACM, value \"%s\"\n", backwardInd); + if (atoi(backwardInd) != 0 ) { + acm.bckCallInd.isdnUsrPrtInd.val = ISUP_USED; + } + } + acm.bckCallInd.holdInd.pres = PRSNT_NODEF; acm.bckCallInd.holdInd.val = HOLD_NOTREQD; acm.bckCallInd.isdnAccInd.pres = PRSNT_NODEF; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 2088f240b6..5bd9799c8f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -259,20 +259,20 @@ ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *loc locPtyNum->scrnInd.pres = pres_val; val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_loc_screen_ind"); if (!ftdm_strlen_zero(val)) { - locPtyNum->scrnInd.val = atoi(val); + locPtyNum->scrnInd.val = atoi(val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Screening Ind %d\n", locPtyNum->scrnInd.val); } else { - locPtyNum->scrnInd.val = caller_data->screen; + locPtyNum->scrnInd.val = caller_data->screen; } - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Location Reference Code Screening Ind %d\n", locPtyNum->scrnInd.val); locPtyNum->presRest.pres = pres_val; - val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_pres_ind"); + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_loc_pres_ind"); if (!ftdm_strlen_zero(val)) { - locPtyNum->presRest.val = atoi(val); + locPtyNum->presRest.val = atoi(val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Presentation Ind %d\n", locPtyNum->presRest.val); } else { - locPtyNum->presRest.val = caller_data->pres; + locPtyNum->presRest.val = caller_data->pres; } - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Calling Party Number Presentation Ind %d\n", locPtyNum->presRest.val); locPtyNum->numPlan.pres = pres_val; locPtyNum->numPlan.val = 0x01; @@ -286,11 +286,10 @@ ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *loc ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Reference NADI value \"%s\"\n", loc_nadi); locPtyNum->natAddrInd.val = atoi(loc_nadi); } else { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied NADI value found for LOC, using \"%d\"\n", locPtyNum->natAddrInd.val); locPtyNum->natAddrInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].loc_nadi; locPtyNum->natAddrInd.val = 0x03; - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied NADI value found for LOC, using \"%d\"\n", locPtyNum->natAddrInd.val); } - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Location Reference Presentation Ind %d\n", locPtyNum->presRest.val); return copy_tknStr_to_sngss7(caller_data->loc.digits, &locPtyNum->addrSig, &locPtyNum->oddEven); } @@ -439,7 +438,7 @@ ftdm_status_t copy_redirgNum_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *red return FTDM_FAIL; } } else if (!ftdm_strlen_zero(caller_data->rdnis.digits)) { - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Redirection Number\"%s\"\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Redirection Number\"%s\"\n", caller_data->rdnis.digits); if (copy_tknStr_to_sngss7(caller_data->rdnis.digits, &redirgNum->addrSig, &redirgNum->oddEven) != FTDM_SUCCESS) { return FTDM_FAIL; } @@ -639,6 +638,98 @@ ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *r return FTDM_SUCCESS; } +ftdm_status_t copy_ocn_from_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum) +{ + char val[20]; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + if (origCdNum->eh.pres != PRSNT_NODEF ) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No Original Called Number available\n"); + return FTDM_SUCCESS; + } + + if (origCdNum->addrSig.pres == PRSNT_NODEF) { + copy_tknStr_from_sngss7(origCdNum->addrSig, val, origCdNum->oddEven); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number digits:%s\n", val); + sngss7_add_var(sngss7_info, "ss7_ocn", val); + } + + if (origCdNum->natAddr.pres == PRSNT_NODEF) { + snprintf(val, sizeof(val), "%d", origCdNum->natAddr.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - NADI:%s\n", val); + sngss7_add_var(sngss7_info, "ss7_ocn_nadi", val); + } + + if (origCdNum->numPlan.pres == PRSNT_NODEF) { + snprintf(val, sizeof(val), "%d", origCdNum->numPlan.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number -plan:%s\n", val); + sngss7_add_var(sngss7_info, "ss7_ocn_plan", val); + } + + if (origCdNum->presRest.pres == PRSNT_NODEF) { + snprintf(val, sizeof(val), "%d", origCdNum->presRest.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - presentation:%s\n", val); + sngss7_add_var(sngss7_info, "ss7_ocn_pres", val); + } + + return FTDM_SUCCESS; +} + +ftdm_status_t copy_ocn_to_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum) +{ + const char *val = NULL; + int bProceed = 0; + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn"); + if (!ftdm_strlen_zero(val)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number \"%s\"\n", val); + if (copy_tknStr_to_sngss7((char*)val, &origCdNum->addrSig, &origCdNum->oddEven) != FTDM_SUCCESS) { + return FTDM_FAIL; + } + origCdNum->addrSig.pres = 1; + } else { + return FTDM_SUCCESS; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn_nadi"); + if (!ftdm_strlen_zero(val)) { + origCdNum->natAddr.val = atoi(val); + origCdNum->natAddr.pres = 1; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number NADI value \"%s\"\n", val); + bProceed = 1; + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Original Called Number NADI value\n"); + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn_plan"); + if (!ftdm_strlen_zero(val)) { + origCdNum->numPlan.val = atoi(val); + origCdNum->numPlan.pres = 1; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number Plan value \"%s\"\n", val); + bProceed = 1; + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Original Called Number Plan value\n"); + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn_pres"); + if (!ftdm_strlen_zero(val)) { + origCdNum->presRest.val = atoi(val); + origCdNum->presRest.pres = 1; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number Presentation value \"%s\"\n", val); + bProceed = 1; + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Original Called Number Presentation value\n"); + } + + if( bProceed == 1 ) { + origCdNum->eh.pres = PRSNT_NODEF; + } else { + origCdNum->eh.pres = NOTPRSNT; + } + + return FTDM_SUCCESS; +} + ftdm_status_t copy_cgPtyCat_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyCat *cgPtyCat) { ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; From 938fafb09e72492acec51dd9d5109f64a6d54d39 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Fri, 24 Feb 2012 16:09:58 -0500 Subject: [PATCH 161/822] freetdm: fixing problem during review - review board number 98 --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c | 13 ++++++------- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 3 +-- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 5bd9799c8f..91e1f90043 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -286,10 +286,9 @@ ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *loc ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Reference NADI value \"%s\"\n", loc_nadi); locPtyNum->natAddrInd.val = atoi(loc_nadi); } else { - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied NADI value found for LOC, using \"%d\"\n", locPtyNum->natAddrInd.val); locPtyNum->natAddrInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].loc_nadi; - locPtyNum->natAddrInd.val = 0x03; - } + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied NADI value found for LOC, using \"%d\"\n", locPtyNum->natAddrInd.val); + } return copy_tknStr_to_sngss7(caller_data->loc.digits, &locPtyNum->addrSig, &locPtyNum->oddEven); } @@ -650,25 +649,25 @@ ftdm_status_t copy_ocn_from_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCd if (origCdNum->addrSig.pres == PRSNT_NODEF) { copy_tknStr_from_sngss7(origCdNum->addrSig, val, origCdNum->oddEven); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number digits:%s\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - Digits: %s\n", val); sngss7_add_var(sngss7_info, "ss7_ocn", val); } if (origCdNum->natAddr.pres == PRSNT_NODEF) { snprintf(val, sizeof(val), "%d", origCdNum->natAddr.val); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - NADI:%s\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - NADI: %s\n", val); sngss7_add_var(sngss7_info, "ss7_ocn_nadi", val); } if (origCdNum->numPlan.pres == PRSNT_NODEF) { snprintf(val, sizeof(val), "%d", origCdNum->numPlan.val); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number -plan:%s\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number -Plan: %s\n", val); sngss7_add_var(sngss7_info, "ss7_ocn_plan", val); } if (origCdNum->presRest.pres == PRSNT_NODEF) { snprintf(val, sizeof(val), "%d", origCdNum->presRest.val); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - presentation:%s\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - Presentation: %s\n", val); sngss7_add_var(sngss7_info, "ss7_ocn_pres", val); } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 6ea7400b37..ee39e0dcb4 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -2004,8 +2004,7 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) flag_loc_nadi = 1; sng_ccSpan.loc_nadi = atoi(parm->val); SS7_DEBUG("Found default LOC_NADI parm->value = %d\n", sng_ccSpan.loc_nadi); - printf( " --- jz: we got loc nadi from XML, val = %d \n" , sng_ccSpan.loc_nadi); - + /**********************************************************************/ } else if (!strcasecmp(parm->var, "lpa_on_cot")) { /**********************************************************************/ From b5f69db10f551f9582515fe1b4ac04aeae4f7223 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Fri, 24 Feb 2012 16:21:21 -0500 Subject: [PATCH 162/822] freetdm: fixing printing in ftmod_sangoma_ss7_support.c functions --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 91e1f90043..7426b033b8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -661,7 +661,7 @@ ftdm_status_t copy_ocn_from_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCd if (origCdNum->numPlan.pres == PRSNT_NODEF) { snprintf(val, sizeof(val), "%d", origCdNum->numPlan.val); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number -Plan: %s\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - Plan: %s\n", val); sngss7_add_var(sngss7_info, "ss7_ocn_plan", val); } @@ -681,7 +681,7 @@ ftdm_status_t copy_ocn_to_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNu val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn"); if (!ftdm_strlen_zero(val)) { - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number \"%s\"\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number - Digits: %s\n", val); if (copy_tknStr_to_sngss7((char*)val, &origCdNum->addrSig, &origCdNum->oddEven) != FTDM_SUCCESS) { return FTDM_FAIL; } @@ -694,7 +694,7 @@ ftdm_status_t copy_ocn_to_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNu if (!ftdm_strlen_zero(val)) { origCdNum->natAddr.val = atoi(val); origCdNum->natAddr.pres = 1; - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number NADI value \"%s\"\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number - NADI: %s\n", val); bProceed = 1; } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Original Called Number NADI value\n"); @@ -704,7 +704,7 @@ ftdm_status_t copy_ocn_to_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNu if (!ftdm_strlen_zero(val)) { origCdNum->numPlan.val = atoi(val); origCdNum->numPlan.pres = 1; - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number Plan value \"%s\"\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number - Plan: %s\n", val); bProceed = 1; } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Original Called Number Plan value\n"); @@ -714,7 +714,7 @@ ftdm_status_t copy_ocn_to_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNu if (!ftdm_strlen_zero(val)) { origCdNum->presRest.val = atoi(val); origCdNum->presRest.pres = 1; - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number Presentation value \"%s\"\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number - Presentation: %s\n", val); bProceed = 1; } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Original Called Number Presentation value\n"); From eeec65265aa2bcce552df6effd0c18ecda473d8a Mon Sep 17 00:00:00 2001 From: James Zhang Date: Fri, 24 Feb 2012 16:32:44 -0500 Subject: [PATCH 163/822] freetdm: fixing format and loc_nadi value according to review board No. 98 --- .../ftmod_sangoma_ss7_support.c | 55 +++++++++---------- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 1 - 2 files changed, 25 insertions(+), 31 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index e7af4bb6e0..4bfa5d2065 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -257,21 +257,21 @@ ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *loc locPtyNum->natAddrInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].loc_nadi; locPtyNum->scrnInd.pres = pres_val; - val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_loc_screen_ind"); + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_loc_screen_ind"); if (!ftdm_strlen_zero(val)) { locPtyNum->scrnInd.val = atoi(val); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Screening Ind %d\n", locPtyNum->scrnInd.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Screening Ind %d\n", locPtyNum->scrnInd.val); } else { locPtyNum->scrnInd.val = caller_data->screen; } locPtyNum->presRest.pres = pres_val; - val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_loc_pres_ind"); + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_loc_pres_ind"); if (!ftdm_strlen_zero(val)) { locPtyNum->presRest.val = atoi(val); ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Presentation Ind %d\n", locPtyNum->presRest.val); } else { - locPtyNum->presRest.val = caller_data->pres; + locPtyNum->presRest.val = caller_data->pres; } locPtyNum->numPlan.pres = pres_val; @@ -286,10 +286,9 @@ ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *loc ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Reference NADI value \"%s\"\n", loc_nadi); locPtyNum->natAddrInd.val = atoi(loc_nadi); } else { - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied NADI value found for LOC, using \"%d\"\n", locPtyNum->natAddrInd.val); locPtyNum->natAddrInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].loc_nadi; - locPtyNum->natAddrInd.val = 0x03; - } + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied NADI value found for LOC, using \"%d\"\n", locPtyNum->natAddrInd.val); + } return copy_tknStr_to_sngss7(caller_data->loc.digits, &locPtyNum->addrSig, &locPtyNum->oddEven); } @@ -640,7 +639,6 @@ ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *r ftdm_status_t copy_ocn_from_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum) { - char val[20]; sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; @@ -649,43 +647,41 @@ ftdm_status_t copy_ocn_from_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCd return FTDM_SUCCESS; } - if (origCdNum->addrSig.pres == PRSNT_NODEF) { copy_tknStr_from_sngss7(origCdNum->addrSig, val, origCdNum->oddEven); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number digits:%s\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - Digits: %s\n", val); sngss7_add_var(sngss7_info, "ss7_ocn", val); } - + if (origCdNum->natAddr.pres == PRSNT_NODEF) { snprintf(val, sizeof(val), "%d", origCdNum->natAddr.val); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - NADI:%s\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - NADI: %s\n", val); sngss7_add_var(sngss7_info, "ss7_ocn_nadi", val); } - + if (origCdNum->numPlan.pres == PRSNT_NODEF) { snprintf(val, sizeof(val), "%d", origCdNum->numPlan.val); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number -plan:%s\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - Plan: %s\n", val); sngss7_add_var(sngss7_info, "ss7_ocn_plan", val); } if (origCdNum->presRest.pres == PRSNT_NODEF) { snprintf(val, sizeof(val), "%d", origCdNum->presRest.val); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - presentation:%s\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - Presentation: %s\n", val); sngss7_add_var(sngss7_info, "ss7_ocn_pres", val); } - + return FTDM_SUCCESS; } ftdm_status_t copy_ocn_to_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum) { - const char *val = NULL; int bProceed = 0; - + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn"); if (!ftdm_strlen_zero(val)) { - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number \"%s\"\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number - Digits: %s\n", val); if (copy_tknStr_to_sngss7((char*)val, &origCdNum->addrSig, &origCdNum->oddEven) != FTDM_SUCCESS) { return FTDM_FAIL; } @@ -698,39 +694,38 @@ ftdm_status_t copy_ocn_to_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNu if (!ftdm_strlen_zero(val)) { origCdNum->natAddr.val = atoi(val); origCdNum->natAddr.pres = 1; - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number NADI value \"%s\"\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number - NADI: %s\n", val); bProceed = 1; - } else { + } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Original Called Number NADI value\n"); } - + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn_plan"); if (!ftdm_strlen_zero(val)) { origCdNum->numPlan.val = atoi(val); origCdNum->numPlan.pres = 1; - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number Plan value \"%s\"\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number - Plan: %s\n", val); bProceed = 1; - } else { + } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Original Called Number Plan value\n"); } - + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn_pres"); if (!ftdm_strlen_zero(val)) { origCdNum->presRest.val = atoi(val); origCdNum->presRest.pres = 1; - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number Presentation value \"%s\"\n", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number - Presentation: %s\n", val); bProceed = 1; - } else { + } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Original Called Number Presentation value\n"); } - + if( bProceed == 1 ) { origCdNum->eh.pres = PRSNT_NODEF; } else { origCdNum->eh.pres = NOTPRSNT; } - - + return FTDM_SUCCESS; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index e76397580e..24293ef0ee 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -1978,7 +1978,6 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) flag_loc_nadi = 1; sng_ccSpan.loc_nadi = atoi(parm->val); SS7_DEBUG("Found default LOC_NADI parm->value = %d\n", sng_ccSpan.loc_nadi); - printf( " --- jz: we got loc nadi from XML, val = %d \n" , sng_ccSpan.loc_nadi); /**********************************************************************/ } else if (!strcasecmp(parm->var, "lpa_on_cot")) { From 3c4fdca9e0bb43f9656fa70f00e4ddf738a2169b Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Wed, 7 Mar 2012 19:04:31 -0500 Subject: [PATCH 164/822] freetdm: Fix redmine issue #2931 - Crash on SIP to SS7 call after sigbridge call The code was improperly using peer_data as an indicator that the sigbridge ss7 mode was enabled. The channel flag FTDM_CHANNEL_NATIVE_SIGBRDIGE should be used instead --- libs/freetdm/src/ftdm_io.c | 6 ++++++ .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 3b11611d49..513fc0c595 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -2449,6 +2449,12 @@ FT_DECLARE(ftdm_status_t) ftdm_get_channel_from_string(const char *string_id, ft *out_span = NULL; *out_channel = NULL; + if (!string_id) { + ftdm_log(FTDM_LOG_ERROR, "Cannot parse NULL channel id string\n"); + status = FTDM_EINVAL; + goto done; + } + rc = sscanf(string_id, "%u:%u", &span_id, &chan_id); if (rc != 2) { ftdm_log(FTDM_LOG_ERROR, "Failed to parse channel id string '%s'\n", string_id); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index 84b9a9b7f2..5f0a0f0960 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -57,12 +57,12 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) memset (&iam, 0x0, sizeof (iam)); - var = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "sigbridge_peer"); - if (!ftdm_strlen_zero(var)) { + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { ftdm_span_t *peer_span = NULL; ftdm_channel_t *peer_chan = NULL; sngss7_chan_data_t *peer_info = NULL; + var = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "sigbridge_peer"); ftdm_get_channel_from_string(var, &peer_span, &peer_chan); if (!peer_chan) { SS7_ERROR_CHAN(ftdmchan, "Failed to find sigbridge peer from string '%s'\n", var); @@ -91,7 +91,7 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) } } - if (sngss7_info->peer_data) { + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE) && sngss7_info->peer_data) { sngss7_span_data_t *span_data = ftdmchan->span->signal_data; sngss7_event_data_t *event_clone = ftdm_queue_dequeue(sngss7_info->peer_data->event_queue); /* Retrieve IAM from our peer */ From 19f01bf50a1b478b7206f2b9f083b08ac357ff12 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 15 Mar 2012 18:05:47 -0400 Subject: [PATCH 165/822] freetdm: fixing a potential crash on a rarely happened situation --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 4 +++ .../ftmod_sangoma_ss7_main.c | 26 ++++++++++--------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index cb5584760f..60b44cec1e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -1314,6 +1314,10 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, }else { stream->write_function(stream, "relay=N"); } + +#ifdef SMG_RELAY_DBG + stream->write_function(stream, "| flag=0x%llx", ftdmchan->flags); +#endif } #ifdef SMG_RELAY_DBG diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index fa36c7280a..ecd83a14d4 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -614,20 +614,22 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev break; case SNGSS7_REL_CFM_EVENT: { - ftdm_channel_t *peer_chan = sngss7_info->peer_data->ftdmchan; - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); - if (peer_chan) { - /* we need to unlock our chan or we risk deadlock */ - ftdm_channel_advance_states(ftdmchan); - ftdm_channel_unlock(ftdmchan); + if (sngss7_info->peer_data) { + ftdm_channel_t *peer_chan = sngss7_info->peer_data->ftdmchan; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + if (peer_chan) { + /* we need to unlock our chan or we risk deadlock */ + ftdm_channel_advance_states(ftdmchan); + ftdm_channel_unlock(ftdmchan); - ftdm_channel_lock(peer_chan); - if (peer_chan->state != FTDM_CHANNEL_STATE_DOWN) { - ftdm_set_state(peer_chan, FTDM_CHANNEL_STATE_DOWN); + ftdm_channel_lock(peer_chan); + if (peer_chan->state != FTDM_CHANNEL_STATE_DOWN) { + ftdm_set_state(peer_chan, FTDM_CHANNEL_STATE_DOWN); + } + ftdm_channel_unlock(peer_chan); + + ftdm_channel_lock(ftdmchan); } - ftdm_channel_unlock(peer_chan); - - ftdm_channel_lock(ftdmchan); } } break; From 46ddfc0ebbf92a8bc0d67794c5ada396a15064ec Mon Sep 17 00:00:00 2001 From: James Zhang Date: Fri, 16 Mar 2012 11:19:01 -0400 Subject: [PATCH 166/822] freetdm: fixing glare with different options --- .../ftmod_sangoma_ss7_handle.c | 166 +++++------------- .../ftmod_sangoma_ss7_main.c | 6 +- 2 files changed, 46 insertions(+), 126 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 667dc09ba0..f48d25ce3c 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -315,13 +315,13 @@ handle_glare: /* setup the hangup cause */ ftdmchan->caller_data.hangup_cause = 34; /* Circuit Congrestion */ - - /* this is a remote hangup request */ - sngss7_set_ckt_flag(sngss7_info, FLAG_REMOTE_REL); - - /* move the state of the channel to Terminating to end the call */ + + /* move the state of the channel to Terminating to end the call + in TERMINATING state, the release cause is set to REMOTE_REL + in any means. So we don't have to set the release reason here. + */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); - } /* if (!(sngss7_test_ckt_flag(sngss7_info, FLAG_GLARE))) */ + } break; /**************************************************************************/ default: /* should not have gotten an IAM while in this state */ @@ -1282,6 +1282,7 @@ ftdm_status_t handle_reattempt(uint32_t suInstId, uint32_t spInstId, uint32_t ci /* the glare flag is already up so it was caught ... do nothing */ SS7_DEBUG_CHAN(ftdmchan, "Glare flag is already up...nothing to do!%s\n", " "); } else { + int bHangup = 0; SS7_DEBUG_CHAN(ftdmchan, "Glare flag is not up yet...indicating glare from reattempt!%s\n", " "); /* glare, throw the flag */ sngss7_set_ckt_flag(sngss7_info, FLAG_GLARE); @@ -1289,14 +1290,45 @@ ftdm_status_t handle_reattempt(uint32_t suInstId, uint32_t spInstId, uint32_t ci /* clear any existing glare data from the channel */ memset(&sngss7_info->glare, 0x0, sizeof(sngss7_glare_data_t)); + if (g_ftdm_sngss7_data.cfg.glareResolution == SNGSS7_GLARE_DOWN) { + /* If I'm in DOWN mode, I will always hangup my call. */ + bHangup = 1; + } + else if (g_ftdm_sngss7_data.cfg.glareResolution == SNGSS7_GLARE_PC) { + /* I'm in PointCode mode. + Case 1: My point code is higher than the other side. + If the CIC number is even, I'm trying to control. + If the CIC number is odd, I'll hangup my call and back off. + Case 2: My point code is lower than the other side. + If the CIC number is odd, I'm trying to control. + If the CIC number is even, I'll hangup my call and back off. + */ + if( g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].spc > g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].dpc ) + { + if ((sngss7_info->circuit->cic % 2) == 1 ) { + bHangup = 1; + } + } else { + if( (sngss7_info->circuit->cic % 2) == 0 ) { + bHangup = 1; + } + } + } + else { + /* If I'm in CONTROL mode, I will not hangup my call. */ + bHangup = 0; + } + + if (bHangup) { /* setup the hangup cause */ ftdmchan->caller_data.hangup_cause = 34; /* Circuit Congrestion */ - /* this is a remote hangup request */ - sngss7_set_ckt_flag(sngss7_info, FLAG_REMOTE_REL); - - /* move the state of the channel to Terminating to end the call */ - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + /* move the state of the channel to Terminating to end the call + in TERMINATING state, the release cause is set to REMOTE_REL + in any means. So we don't have to set the release reason here. + */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + } } /* unlock the channel again before we exit */ @@ -2455,63 +2487,6 @@ ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ x++; } -#if 0 - for (x = circuit; x < (circuit + range + 1); x++) { - /* confirm this is a voice channel */ - if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != SNG_CKT_VOICE) continue; - - /* grab the circuit in question */ - if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { - SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x); - break; - } - - /* lock the channel */ - ftdm_mutex_lock(ftdmchan->mutex); - -#if 0 - SS7_ERROR("KONRAD -> circuit=%d, byte=%d, bit=%d, status[byte]=%d, math=%d\n", - x, - byte, - bit, - status[byte], - (status[byte] & (1 << bit))); -#endif - if (status[byte] & (1 << bit)) { - switch (blockType) { - /**********************************************************************/ - case 0: /* maintenance oriented */ - sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); - break; - /**********************************************************************/ - case 1: /* hardware failure oriented */ - sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); - break; - /**********************************************************************/ - case 2: /* reserved for national use */ - break; - /**********************************************************************/ - default: - break; - /**********************************************************************/ - } /* switch (blockType) */ - } - - /* bring the sig status down */ - sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); - - /* unlock the channel again before we exit */ - ftdm_mutex_unlock(ftdmchan->mutex); - - /* update the bit and byte counter*/ - bit ++; - if (bit == 8) { - byte++; - bit = 0; - } - - } /* for (x = circuit; x < (circuit + range + 1); x++) */ -#endif /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -2665,61 +2640,6 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ } x++; } -#if 0 - for (x = circuit; x < (circuit + range + 1); x++) { - if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != SNG_CKT_VOICE) continue; - /* grab the circuit in question */ - if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { - SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x); - break; - } - - /* lock the channel */ - ftdm_mutex_lock(ftdmchan->mutex); - - if (status[byte] & (1 << bit)) { - switch (blockType) { - /**********************************************************************/ - case 0: /* maintenance oriented */ - sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); - sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); - sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); - break; - /**********************************************************************/ - case 1: /* hardware failure oriented */ - sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); - break; - /**********************************************************************/ - case 2: /* reserved for national use */ - break; - /**********************************************************************/ - default: - break; - /**********************************************************************/ - } /* switch (blockType) */ - } /* if (status[byte] & (1 << bit)) */ - - sigev.chan_id = ftdmchan->chan_id; - sigev.span_id = ftdmchan->span_id; - sigev.channel = ftdmchan; - - /* bring the sig status down */ - if (sngss7_channel_status_clear(sngss7_info)) { - sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); - } - - /* unlock the channel again before we exit */ - ftdm_mutex_unlock(ftdmchan->mutex); - - /* update the bit and byte counter*/ - bit ++; - if (bit == 8) { - byte++; - bit = 0; - } - - } /* for (x = circuit; x < (circuit + range + 1); x++) */ -#endif /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 2463d59115..9b6c561742 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1471,14 +1471,14 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) SS7_DEBUG_CHAN(ftdmchan,"All reset flags cleared %s\n", ""); /* all flags are down so we can bring up the sig status */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); - } /* if (!ftdm_test_flag (ftdmchan, FTDM_CHANNEL_SIG_UP)) */ + } } else { state_flag = 0; SS7_DEBUG_CHAN(ftdmchan,"Down detected blocked flags go to SUSPEND %s\n", " "); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); break; - } /* if !blocked */ + } } else { SS7_DEBUG_CHAN(ftdmchan,"Reset flags present (0x%X)\n", sngss7_info->ckt_flags); @@ -1486,7 +1486,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) state_flag = 0; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); } - } /* if ((ftdmchan->last_state == FTDM_CHANNEL_STATE_RESTART) */ + } /* check if t35 is active */ if (sngss7_info->t35.hb_timer_id) { From 10277be8d6b2df8a97f1ee9564cb6468691bb2cc Mon Sep 17 00:00:00 2001 From: James Zhang Date: Fri, 16 Mar 2012 11:40:21 -0400 Subject: [PATCH 167/822] freetdm: synchronizing fixes in releases.3.5 version - glare - cgb/cgu range bug - inhibit/uninhibit --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 17 +- .../ftmod_sangoma_ss7_handle.c | 256 ++++++++++-------- .../ftmod_sangoma_ss7_main.c | 50 +++- .../ftmod_sangoma_ss7_main.h | 23 +- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 52 +++- 5 files changed, 257 insertions(+), 141 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 60b44cec1e..3f1a03f4d8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -784,16 +784,24 @@ static ftdm_status_t handle_print_usage(ftdm_stream_handle_t *stream) stream->write_function(stream, "ftdm ss7 set ftrace X Y\n"); stream->write_function(stream, "ftdm ss7 set mtrace X Y\n"); stream->write_function(stream, "\n"); - stream->write_function(stream, "ftmod_sangoma_ss7 information:\n"); - stream->write_function(stream, "ftdm ss7 show status mtp3 X\n"); + + stream->write_function(stream, "ftmod_sangoma_ss7 signaling information:\n"); + stream->write_function(stream, "ftdm ss7 show \n"); stream->write_function(stream, "ftdm ss7 show status mtp2 X\n"); + stream->write_function(stream, "ftdm ss7 show status mtp3 X\n"); + stream->write_function(stream, "ftdm ss7 show status linkset X\n"); + stream->write_function(stream, "\n"); + + stream->write_function(stream, "ftmod_sangoma_ss7 circuit information:\n"); + stream->write_function(stream, "ftdm ss7 show span all\n"); + stream->write_function(stream, "ftdm ss7 show span X\n"); stream->write_function(stream, "ftdm ss7 show status span X chan Y\n"); stream->write_function(stream, "ftdm ss7 show free span X chan Y\n"); stream->write_function(stream, "ftdm ss7 show blocks span X chan Y\n"); - stream->write_function(stream, "ftdm ss7 show inuse span X chan Y\n"); stream->write_function(stream, "ftdm ss7 show inreset span X chan Y\n"); stream->write_function(stream, "\n"); + stream->write_function(stream, "ftmod_sangoma_ss7 circuit control:\n"); stream->write_function(stream, "ftdm ss7 blo span X chan Y\n"); stream->write_function(stream, "ftdm ss7 ubl span X chan Y\n"); @@ -802,9 +810,12 @@ static ftdm_status_t handle_print_usage(ftdm_stream_handle_t *stream) stream->write_function(stream, "ftdm ss7 cgb span X chan Y range Z\n"); stream->write_function(stream, "ftdm ss7 cgu span X chan Y range Z\n"); stream->write_function(stream, "\n"); + stream->write_function(stream, "ftmod_sangoma_ss7 link control:\n"); + /* stream->write_function(stream, "ftdm ss7 inhibit link X\n"); stream->write_function(stream, "ftdm ss7 uninhibit link X\n"); + */ stream->write_function(stream, "ftdm ss7 activate link X\n"); stream->write_function(stream, "ftdm ss7 deactivate link X\n"); stream->write_function(stream, "ftdm ss7 activate linkset X\n"); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index f080352d4a..d9816dfa0e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -33,6 +33,7 @@ * Contributors: * * Ricardo Barroetaveña + * James Zhang * */ @@ -199,7 +200,6 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ } else { SS7_INFO_CHAN(ftdmchan,"No Called party (DNIS) information in IAM!%s\n", " "); } - copy_ocn_from_sngss7(ftdmchan, &siConEvnt->origCdNum); copy_redirgNum_from_sngss7(ftdmchan, &siConEvnt->redirgNum); copy_redirgInfo_from_sngss7(ftdmchan, &siConEvnt->redirInfo); @@ -316,13 +316,13 @@ handle_glare: /* setup the hangup cause */ ftdmchan->caller_data.hangup_cause = 34; /* Circuit Congrestion */ - - /* this is a remote hangup request */ - sngss7_set_ckt_flag(sngss7_info, FLAG_REMOTE_REL); - - /* move the state of the channel to Terminating to end the call */ + + /* move the state of the channel to Terminating to end the call + in TERMINATING state, the release cause is set to REMOTE_REL + in any means. So we don't have to set the release reason here. + */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); - } /* if (!(sngss7_test_ckt_flag(sngss7_info, FLAG_GLARE))) */ + } break; /**************************************************************************/ default: /* should not have gotten an IAM while in this state */ @@ -1283,6 +1283,7 @@ ftdm_status_t handle_reattempt(uint32_t suInstId, uint32_t spInstId, uint32_t ci /* the glare flag is already up so it was caught ... do nothing */ SS7_DEBUG_CHAN(ftdmchan, "Glare flag is already up...nothing to do!%s\n", " "); } else { + int bHangup = 0; SS7_DEBUG_CHAN(ftdmchan, "Glare flag is not up yet...indicating glare from reattempt!%s\n", " "); /* glare, throw the flag */ sngss7_set_ckt_flag(sngss7_info, FLAG_GLARE); @@ -1290,14 +1291,45 @@ ftdm_status_t handle_reattempt(uint32_t suInstId, uint32_t spInstId, uint32_t ci /* clear any existing glare data from the channel */ memset(&sngss7_info->glare, 0x0, sizeof(sngss7_glare_data_t)); + if (g_ftdm_sngss7_data.cfg.glareResolution == SNGSS7_GLARE_DOWN) { + /* If I'm in DOWN mode, I will always hangup my call. */ + bHangup = 1; + } + else if (g_ftdm_sngss7_data.cfg.glareResolution == SNGSS7_GLARE_PC) { + /* I'm in PointCode mode. + Case 1: My point code is higher than the other side. + If the CIC number is even, I'm trying to control. + If the CIC number is odd, I'll hangup my call and back off. + Case 2: My point code is lower than the other side. + If the CIC number is odd, I'm trying to control. + If the CIC number is even, I'll hangup my call and back off. + */ + if( g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].spc > g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].dpc ) + { + if ((sngss7_info->circuit->cic % 2) == 1 ) { + bHangup = 1; + } + } else { + if( (sngss7_info->circuit->cic % 2) == 0 ) { + bHangup = 1; + } + } + } + else { + /* If I'm in CONTROL mode, I will not hangup my call. */ + bHangup = 0; + } + + if (bHangup) { /* setup the hangup cause */ ftdmchan->caller_data.hangup_cause = 34; /* Circuit Congrestion */ - /* this is a remote hangup request */ - sngss7_set_ckt_flag(sngss7_info, FLAG_REMOTE_REL); - - /* move the state of the channel to Terminating to end the call */ - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + /* move the state of the channel to Terminating to end the call + in TERMINATING state, the release cause is set to REMOTE_REL + in any means. So we don't have to set the release reason here. + */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + } } /* unlock the channel again before we exit */ @@ -2340,7 +2372,8 @@ ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ int blockType = 0; int byte = 0; int bit = 0; - int x; + int x; + int loop_range=0; ftdm_running_return(FTDM_FAIL); @@ -2407,61 +2440,54 @@ ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ } /* loop over the cics starting from circuit until range+1 */ - for (x = circuit; x < (circuit + range + 1); x++) { - /* confirm this is a voice channel */ - if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != SNG_CKT_VOICE) continue; - - /* grab the circuit in question */ - if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { - SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x); - break; + loop_range = circuit + range + 1; + x = circuit; + while( x < loop_range ) { + if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != SNG_CKT_VOICE) { + loop_range++; } - - /* lock the channel */ - ftdm_mutex_lock(ftdmchan->mutex); + else { + if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x); + } else { + ftdm_mutex_lock(ftdmchan->mutex); + if (status[byte] & (1 << bit)) { + switch (blockType) { + /**********************************************************************/ + case 0: /* maintenance oriented */ + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); + break; + /**********************************************************************/ + case 1: /* hardware failure oriented */ + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); + break; + /**********************************************************************/ + case 2: /* reserved for national use */ + break; + /**********************************************************************/ + default: + break; + /**********************************************************************/ + } + } -#if 0 - SS7_ERROR("KONRAD -> circuit=%d, byte=%d, bit=%d, status[byte]=%d, math=%d\n", - x, - byte, - bit, - status[byte], - (status[byte] & (1 << bit))); -#endif - if (status[byte] & (1 << bit)) { - switch (blockType) { - /**********************************************************************/ - case 0: /* maintenance oriented */ - sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); - break; - /**********************************************************************/ - case 1: /* hardware failure oriented */ - sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); - break; - /**********************************************************************/ - case 2: /* reserved for national use */ - break; - /**********************************************************************/ - default: - break; - /**********************************************************************/ - } /* switch (blockType) */ + /* bring the sig status down */ + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + /* update the bit and byte counter*/ + bit ++; + if (bit == 8) { + byte++; + bit = 0; + } + } } + x++; + } - /* bring the sig status down */ - sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); - - /* unlock the channel again before we exit */ - ftdm_mutex_unlock(ftdmchan->mutex); - - /* update the bit and byte counter*/ - bit ++; - if (bit == 8) { - byte++; - bit = 0; - } - - } /* for (x = circuit; x < (circuit + range + 1); x++) */ /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -2488,7 +2514,8 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ int blockType = 0; int byte = 0; int bit = 0; - int x; + int x; + int loop_range=0; ftdm_sigmsg_t sigev; ftdm_running_return(FTDM_FAIL); @@ -2558,59 +2585,62 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ } /* loop over the cics starting from circuit until range+1 */ - for (x = circuit; x < (circuit + range + 1); x++) { - if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != SNG_CKT_VOICE) continue; - /* grab the circuit in question */ - if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { - SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x); - break; + loop_range = circuit + range + 1; + x = circuit; + while( x < loop_range ) { + if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != SNG_CKT_VOICE) { + loop_range++; } - - /* lock the channel */ - ftdm_mutex_lock(ftdmchan->mutex); + else { + if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x); + } + else { + ftdm_mutex_lock(ftdmchan->mutex); - if (status[byte] & (1 << bit)) { - switch (blockType) { - /**********************************************************************/ - case 0: /* maintenance oriented */ - sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); - sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); - sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); - break; - /**********************************************************************/ - case 1: /* hardware failure oriented */ - sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); - break; - /**********************************************************************/ - case 2: /* reserved for national use */ - break; - /**********************************************************************/ - default: - break; - /**********************************************************************/ - } /* switch (blockType) */ - } /* if (status[byte] & (1 << bit)) */ + if (status[byte] & (1 << bit)) { + switch (blockType) { + /**********************************************************************/ + case 0: /* maintenance oriented */ + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); + break; + /**********************************************************************/ + case 1: /* hardware failure oriented */ + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); + break; + /**********************************************************************/ + case 2: /* reserved for national use */ + break; + /**********************************************************************/ + default: + break; + /**********************************************************************/ + } /* switch (blockType) */ + } /* if (status[byte] & (1 << bit)) */ - sigev.chan_id = ftdmchan->chan_id; - sigev.span_id = ftdmchan->span_id; - sigev.channel = ftdmchan; + sigev.chan_id = ftdmchan->chan_id; + sigev.span_id = ftdmchan->span_id; + sigev.channel = ftdmchan; - /* bring the sig status down */ - if (sngss7_channel_status_clear(sngss7_info)) { - sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + /* bring the sig status down */ + if (sngss7_channel_status_clear(sngss7_info)) { + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + } + + ftdm_mutex_unlock(ftdmchan->mutex); + + /* update the bit and byte counter*/ + bit ++; + if (bit == 8) { + byte++; + bit = 0; + } + } } - - /* unlock the channel again before we exit */ - ftdm_mutex_unlock(ftdmchan->mutex); - - /* update the bit and byte counter*/ - bit ++; - if (bit == 8) { - byte++; - bit = 0; - } - - } /* for (x = circuit; x < (circuit + range + 1); x++) */ + x++; + } /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index ecd83a14d4..fe129c0f73 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -35,6 +35,7 @@ * * Moises Silva * David Yat Sin + * James Zhang * */ @@ -1474,14 +1475,14 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) SS7_DEBUG_CHAN(ftdmchan,"All reset flags cleared %s\n", ""); /* all flags are down so we can bring up the sig status */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); - } /* if (!ftdm_test_flag (ftdmchan, FTDM_CHANNEL_SIG_UP)) */ + } } else { state_flag = 0; SS7_DEBUG_CHAN(ftdmchan,"Down detected blocked flags go to SUSPEND %s\n", " "); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); break; - } /* if !blocked */ + } } else { SS7_DEBUG_CHAN(ftdmchan,"Reset flags present (0x%X)\n", sngss7_info->ckt_flags); @@ -1489,7 +1490,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) state_flag = 0; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); } - } /* if ((ftdmchan->last_state == FTDM_CHANNEL_STATE_RESTART) */ + } /* check if t35 is active */ if (sngss7_info->t35.hb_timer_id) { @@ -1532,20 +1533,47 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) /* check if there is a glared call that needs to be processed */ if (sngss7_test_ckt_flag(sngss7_info, FLAG_GLARE)) { - - /* clear the glare flag */ sngss7_clear_ckt_flag (sngss7_info, FLAG_GLARE); - /* check if we have an IAM stored...if we don't have one just exit */ if (sngss7_info->glare.circuit != 0) { - /* send the saved call back in to us */ - handle_con_ind (0, - sngss7_info->glare.spInstId, - sngss7_info->glare.circuit, - &sngss7_info->glare.iam); + int bHandle=0; + switch (g_ftdm_sngss7_data.cfg.glareResolution) { + case SNGSS7_GLARE_DOWN: + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Giving control to the other side, handling copied IAM from glare. \n", sngss7_info->circuit->cic); + bHandle = 1; + break; + case SNGSS7_GLARE_PC: + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Trying to handle IAM copied from glare. \n", sngss7_info->circuit->cic); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]My PC = %d, incoming PC = %d. \n", sngss7_info->circuit->cic, + g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].spc, + g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].dpc ); + + if( g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].spc > g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].dpc ) + { + if ((sngss7_info->circuit->cic % 2) == 1 ) { + bHandle = 1; + } + } else { + if( (sngss7_info->circuit->cic % 2) == 0 ) { + bHandle = 1; + } + } + + break; + default: /* if configured as SNGSS7_GLARE_CONTROL, always abandon incoming glared IAM. */ + bHandle = 0; + break; + } + + if (!bHandle) { + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Handling glare IAM. \n", sngss7_info->circuit->cic); + handle_con_ind (0, sngss7_info->glare.spInstId, sngss7_info->glare.circuit, &sngss7_info->glare.iam); + } + /* clear the glare info */ memset(&sngss7_info->glare, 0x0, sizeof(sngss7_glare_data_t)); + state_flag = 0; } } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 86cdc73bc9..63d4ded203 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -29,6 +29,12 @@ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Contributors: + * + * James Zhang + * */ /******************************************************************************/ #ifndef __FTMOD_SNG_SS7_H__ @@ -195,6 +201,21 @@ typedef struct sng_mtp2_link { uint32_t t7; } sng_mtp2_link_t; +/* defining glare handling methods: + SNGSS7_GLARE_PC: + higher PointCode controls even number CIC + lower PointCode controls odd number CIC + SNGSS7_GLARE_DOWN: + always give control to the other side + SNGSS7_GLARE_CONTROL: + always trying to control +*/ +typedef enum { + SNGSS7_GLARE_PC = 0, + SNGSS7_GLARE_DOWN, + SNGSS7_GLARE_CONTROL +} sng_glare_resolution; + typedef struct sng_mtp3_link { char name[MAX_NAME_LEN]; uint32_t flags; @@ -444,6 +465,7 @@ typedef struct sng_ss7_cfg { sng_isup_ckt_t isupCkt[10000]; /* KONRAD - only need 2000 ( and 0-1000 aren't used) since other servers are registerd else where */ sng_nsap_t nsap[MAX_NSAPS+1]; sng_isap_t isap[MAX_ISAPS+1]; + sng_glare_resolution glareResolution; } sng_ss7_cfg_t; typedef struct ftdm_sngss7_data { @@ -871,7 +893,6 @@ ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *r ftdm_status_t copy_ocn_to_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum); ftdm_status_t copy_ocn_from_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum); - ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum); ftdm_status_t copy_locPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum); ftdm_status_t copy_genNmb_to_sngss7(ftdm_channel_t *ftdmchan, SiGenNum *genNmb); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 24293ef0ee..ad47f0cbb4 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -29,6 +29,12 @@ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Contributors: + * + * James Zhang + * */ /* INCLUDE ********************************************************************/ @@ -191,6 +197,7 @@ static int ftmod_ss7_fill_in_self_route(int spc, int linkType, int switchType, i static int ftmod_ss7_fill_in_circuits(sng_span_t *sngSpan); static int ftmod_ss7_next_timeslot(char *ch_map, sng_timeslot_t *timeslot); +static void ftmod_ss7_set_glare_resolution (const char *method); /******************************************************************************/ @@ -239,11 +246,11 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa if (!strcasecmp(var, "dialplan")) { /**********************************************************************/ - /* do i give a shit about this??? */ + /* don't care for now */ /**********************************************************************/ } else if (!strcasecmp(var, "context")) { /**********************************************************************/ - /* do i give a shit about this??? */ + /* don't care for now */ /**********************************************************************/ } else if (!strcasecmp(var, "ccSpanId")) { /**********************************************************************/ @@ -451,6 +458,26 @@ static int ftmod_ss7_parse_sng_isup(ftdm_conf_node_t *sng_isup) return FTDM_SUCCESS; } +static void ftmod_ss7_set_glare_resolution (const char *method) +{ + sng_glare_resolution iMethod=SNGSS7_GLARE_PC; + if (!method || (strlen (method) <=0) ) { + SS7_ERROR( "Wrong glare resolution parameter, using default. \n" ); + } else { + if (!strcasecmp( method, "PointCode")) { + iMethod = SNGSS7_GLARE_PC; + } else if (!strcasecmp( method, "Down")) { + iMethod = SNGSS7_GLARE_DOWN; + } else if (!strcasecmp( method, "Control")) { + iMethod = SNGSS7_GLARE_CONTROL; + } else { + SS7_ERROR( "Wrong glare resolution parameter, using default. \n" ); + iMethod = SNGSS7_GLARE_DOWN; + } + } + g_ftdm_sngss7_data.cfg.glareResolution = iMethod; +} + /******************************************************************************/ static int ftmod_ss7_parse_sng_gen(ftdm_conf_node_t *sng_gen) { @@ -463,28 +490,27 @@ static int ftmod_ss7_parse_sng_gen(ftdm_conf_node_t *sng_gen) /* extract all the information from the parameters */ for (i = 0; i < num_parms; i++) { - /**************************************************************************/ - if (!strcasecmp(parm->var, "procId")) { - /**********************************************************************/ g_ftdm_sngss7_data.cfg.procId = atoi(parm->val); SS7_DEBUG("Found a procId = %d\n", g_ftdm_sngss7_data.cfg.procId); - /**********************************************************************/ - } else if (!strcasecmp(parm->var, "license")) { - /**********************************************************************/ + } + else if (!strcasecmp(parm->var, "license")) { ftdm_set_string(g_ftdm_sngss7_data.cfg.license, parm->val); snprintf(g_ftdm_sngss7_data.cfg.signature, sizeof(g_ftdm_sngss7_data.cfg.signature), "%s.sig", parm->val); SS7_DEBUG("Found license file = %s\n", g_ftdm_sngss7_data.cfg.license); SS7_DEBUG("Found signature file = %s\n", g_ftdm_sngss7_data.cfg.signature); - /**********************************************************************/ - } else if (!strcasecmp(parm->var, "transparent_iam_max_size")) { + } + else if (!strcasecmp(parm->var, "transparent_iam_max_size")) { g_ftdm_sngss7_data.cfg.transparent_iam_max_size = atoi(parm->val); SS7_DEBUG("Found a transparent_iam max size = %d\n", g_ftdm_sngss7_data.cfg.transparent_iam_max_size); - } else { - /**********************************************************************/ + } + else if (!strcasecmp(parm->var, "glare-reso")) { + ftmod_ss7_set_glare_resolution (parm->val); + SS7_DEBUG("Found glare resolution configuration = %d %s\n", g_ftdm_sngss7_data.cfg.glareResolution, parm->val ); + } + else { SS7_ERROR("Found an invalid parameter \"%s\"!\n", parm->val); return FTDM_FAIL; - /**********************************************************************/ } /* move to the next parmeter */ From 63a2c847ebe320f4c4d16e1d34cfc4e84365e357 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Fri, 16 Mar 2012 12:24:10 -0400 Subject: [PATCH 168/822] freetdm: merge native bridge fix from releases.3.4 which solves the crash on outgoing calls after native bridge --- libs/freetdm/src/ftdm_io.c | 6 ++++ .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 4 +++ .../ftmod_sangoma_ss7_main.c | 30 +++++++++++-------- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 26 ++++++++-------- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 63029e74e0..a2d80a40eb 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -2453,6 +2453,12 @@ FT_DECLARE(ftdm_status_t) ftdm_get_channel_from_string(const char *string_id, ft *out_span = NULL; *out_channel = NULL; + if (!string_id) { + ftdm_log(FTDM_LOG_ERROR, "Cannot parse NULL channel id string\n"); + status = FTDM_EINVAL; + goto done; + } + rc = sscanf(string_id, "%u:%u", &span_id, &chan_id); if (rc != 2) { ftdm_log(FTDM_LOG_ERROR, "Failed to parse channel id string '%s'\n", string_id); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index ece88caac2..3f1a03f4d8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -1325,6 +1325,10 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, }else { stream->write_function(stream, "relay=N"); } + +#ifdef SMG_RELAY_DBG + stream->write_function(stream, "| flag=0x%llx", ftdmchan->flags); +#endif } #ifdef SMG_RELAY_DBG diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 9b6c561742..fe129c0f73 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -615,20 +615,22 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev break; case SNGSS7_REL_CFM_EVENT: { - ftdm_channel_t *peer_chan = sngss7_info->peer_data->ftdmchan; - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); - if (peer_chan) { - /* we need to unlock our chan or we risk deadlock */ - ftdm_channel_advance_states(ftdmchan); - ftdm_channel_unlock(ftdmchan); + if (sngss7_info->peer_data) { + ftdm_channel_t *peer_chan = sngss7_info->peer_data->ftdmchan; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + if (peer_chan) { + /* we need to unlock our chan or we risk deadlock */ + ftdm_channel_advance_states(ftdmchan); + ftdm_channel_unlock(ftdmchan); - ftdm_channel_lock(peer_chan); - if (peer_chan->state != FTDM_CHANNEL_STATE_DOWN) { - ftdm_set_state(peer_chan, FTDM_CHANNEL_STATE_DOWN); + ftdm_channel_lock(peer_chan); + if (peer_chan->state != FTDM_CHANNEL_STATE_DOWN) { + ftdm_set_state(peer_chan, FTDM_CHANNEL_STATE_DOWN); + } + ftdm_channel_unlock(peer_chan); + + ftdm_channel_lock(ftdmchan); } - ftdm_channel_unlock(peer_chan); - - ftdm_channel_lock(ftdmchan); } } break; @@ -1087,12 +1089,14 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) /*now go to the RING state */ state_flag = 0; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); + } else if (i >= sngss7_info->circuit->min_digits) { SS7_DEBUG_CHAN(ftdmchan, "Received %d digits (min digits = %d)\n", i, sngss7_info->circuit->min_digits); /*now go to the RING state */ state_flag = 0; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); + } else { /* if we are coming from idle state then we have already been here once before */ if (ftdmchan->last_state != FTDM_CHANNEL_STATE_IDLE) { @@ -1100,7 +1104,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) i, sngss7_info->circuit->min_digits, ftdmchan->caller_data.dnis.digits); - + /* start ISUP t35 */ if (ftdm_sched_timer (sngss7_info->t35.sched, "t35", diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index fb91b834ec..5f0a0f0960 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -57,12 +57,12 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) memset (&iam, 0x0, sizeof (iam)); - var = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "sigbridge_peer"); - if (!ftdm_strlen_zero(var)) { + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { ftdm_span_t *peer_span = NULL; ftdm_channel_t *peer_chan = NULL; sngss7_chan_data_t *peer_info = NULL; + var = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "sigbridge_peer"); ftdm_get_channel_from_string(var, &peer_span, &peer_chan); if (!peer_chan) { SS7_ERROR_CHAN(ftdmchan, "Failed to find sigbridge peer from string '%s'\n", var); @@ -82,16 +82,16 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* flush our own queue */ sngss7_flush_queue(sngss7_info->event_queue); - /* Go to up until release comes, note that state processing is done different and much simpler when there is a peer, - We can't go to UP state right away yet though, so do not set the state to UP here, wait until the end of this function - because moving from one state to another causes the ftdmchan->usrmsg structure to be wiped - and we still need those variables for further IAM processing */ + /* Go to up until release comes, note that state processing is done different and much simpler when there is a peer, + We can't go to UP state right away yet though, so do not set the state to UP here, wait until the end of this function + because moving from one state to another causes the ftdmchan->usrmsg structure to be wiped + and we still need those variables for further IAM processing */ native_going_up = FTDM_TRUE; } } } - if (sngss7_info->peer_data) { + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE) && sngss7_info->peer_data) { sngss7_span_data_t *span_data = ftdmchan->span->signal_data; sngss7_event_data_t *event_clone = ftdm_queue_dequeue(sngss7_info->peer_data->event_queue); /* Retrieve IAM from our peer */ @@ -224,18 +224,17 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) &iam, 0); - if (native_going_up) { /* - Note that this function (ft_to_sngss7_iam) is run within the main SS7 processing loop in - response to the DIALING state handler, we can set the state to UP here and that will + Note that this function (ft_to_sngss7_iam) is run within the main SS7 processing loop in + response to the DIALING state handler, we can set the state to UP here and that will implicitly complete the DIALING state, but we *MUST* also advance the state handler right away for a native bridge, otherwise, the processing state function (ftdm_sangoma_ss7_process_state_change) will complete the state without having executed the handler for FTDM_CHANNEL_STATE_UP, and we won't notify the user sending FTDM_SIGEVENT_UP which can cause the application to misbehave (ie, no audio) */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP); ftdm_channel_advance_states(ftdmchan); - } + } SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; @@ -267,15 +266,14 @@ void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan) acm.bckCallInd.end2EndInfoInd.val = E2EINF_NOINFO; acm.bckCallInd.isdnUsrPrtInd.pres = PRSNT_NODEF; - acm.bckCallInd.isdnUsrPrtInd.val = ISUP_NOTUSED; + acm.bckCallInd.isdnUsrPrtInd.val = ISUP_NOTUSED; backwardInd = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "acm_bi_iup"); if (!ftdm_strlen_zero(backwardInd)) { ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied backward indicator ISDN user part indicator ACM, value \"%s\"\n", backwardInd); if (atoi(backwardInd) != 0 ) { - acm.bckCallInd.isdnUsrPrtInd.val = ISUP_USED; + acm.bckCallInd.isdnUsrPrtInd.val = ISUP_USED; } } - acm.bckCallInd.holdInd.pres = PRSNT_NODEF; acm.bckCallInd.holdInd.val = HOLD_NOTREQD; acm.bckCallInd.isdnAccInd.pres = PRSNT_NODEF; From f1d80cd25d13d78deab88ea7f559e63aa899f319 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Fri, 16 Mar 2012 16:09:54 -0400 Subject: [PATCH 169/822] freetdm: fixing default values for ISUP --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index ad47f0cbb4..230476d8e1 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -2788,7 +2788,7 @@ static int ftmod_ss7_fill_in_isap(sng_isap_t *sng_isap) if (sng_isap->t1 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t1 = sng_isap->t1; } else { - g_ftdm_sngss7_data.cfg.isap[i].t1 = 200; + g_ftdm_sngss7_data.cfg.isap[i].t1 = 150; } if (sng_isap->t2 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t2 = sng_isap->t2; @@ -2803,17 +2803,17 @@ static int ftmod_ss7_fill_in_isap(sng_isap_t *sng_isap) if (sng_isap->t6 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t6 = sng_isap->t6; } else { - g_ftdm_sngss7_data.cfg.isap[i].t6 = 200; + g_ftdm_sngss7_data.cfg.isap[i].t6 = 600; } if (sng_isap->t7 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t7 = sng_isap->t7; } else { - g_ftdm_sngss7_data.cfg.isap[i].t7 = 250; + g_ftdm_sngss7_data.cfg.isap[i].t7 = 200; } if (sng_isap->t8 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t8 = sng_isap->t8; } else { - g_ftdm_sngss7_data.cfg.isap[i].t8 = 120; + g_ftdm_sngss7_data.cfg.isap[i].t8 = 100; } if (sng_isap->t9 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t9 = sng_isap->t9; From fbc5322e65eca3e9258053c6035f2f6ff675255e Mon Sep 17 00:00:00 2001 From: James Zhang Date: Tue, 20 Mar 2012 10:51:53 -0400 Subject: [PATCH 170/822] freetdm: fixing wrong default timer values --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index ee39e0dcb4..724fee25b9 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -2788,7 +2788,7 @@ static int ftmod_ss7_fill_in_isap(sng_isap_t *sng_isap) if (sng_isap->t1 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t1 = sng_isap->t1; } else { - g_ftdm_sngss7_data.cfg.isap[i].t1 = 200; + g_ftdm_sngss7_data.cfg.isap[i].t1 = 150; } if (sng_isap->t2 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t2 = sng_isap->t2; @@ -2803,17 +2803,17 @@ static int ftmod_ss7_fill_in_isap(sng_isap_t *sng_isap) if (sng_isap->t6 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t6 = sng_isap->t6; } else { - g_ftdm_sngss7_data.cfg.isap[i].t6 = 200; + g_ftdm_sngss7_data.cfg.isap[i].t6 = 600; } if (sng_isap->t7 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t7 = sng_isap->t7; } else { - g_ftdm_sngss7_data.cfg.isap[i].t7 = 250; + g_ftdm_sngss7_data.cfg.isap[i].t7 = 200; } if (sng_isap->t8 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t8 = sng_isap->t8; } else { - g_ftdm_sngss7_data.cfg.isap[i].t8 = 120; + g_ftdm_sngss7_data.cfg.isap[i].t8 = 100; } if (sng_isap->t9 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t9 = sng_isap->t9; From e560ddccdec0232a040851f088db1adec2cbc7f4 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Tue, 20 Mar 2012 11:56:29 -0400 Subject: [PATCH 171/822] freeswitch: taking out -Ox cflags and have them replaced with -O0 we dont want to optimize out symbols for debugging --- build/config/ax_cc_maxopt.m4 | 16 ++++++------ libs/apr/build/NWGNUenvironment.inc | 2 +- libs/apr/build/apr_hints.m4 | 2 +- libs/apr/configure.in | 8 +++--- libs/broadvoice/configure.ac | 8 +++--- libs/broadvoice/debian/rules | 2 +- libs/curl/lib/Makefile.b32 | 2 +- libs/curl/lib/Makefile.m32 | 2 +- libs/curl/src/Makefile.b32 | 2 +- libs/curl/src/makefile.amiga | 2 +- libs/js/nsprpub/configure.in | 20 +++++++------- libs/libg722_1/configure.ac | 8 +++--- libs/libsndfile/INSTALL | 2 +- libs/pcre/configure.ac | 10 +++---- libs/portaudio/Makefile.darwin | 2 +- libs/portaudio/SConstruct | 2 +- .../bindings/cpp/build/gnu/configure | 14 +++++----- .../bindings/cpp/build/gnu/configure.ac | 2 +- libs/portaudio/bindings/cpp/configure.ac | 2 +- libs/portaudio/build/dev-cpp/Makefile-static | 6 ++--- libs/portaudio/configure.in | 2 +- libs/sqlite/Makefile.linux-gcc | 6 ++--- libs/sqlite/mkso.sh | 2 +- libs/sqlite/publish.sh | 2 +- libs/srtp/INSTALL | 2 +- libs/srtp/build/config/ax_cc_maxopt.m4 | 16 ++++++------ libs/srtp/configure.in | 10 +++---- libs/yaml/aclocal.m4 | 2 +- libs/yaml/configure | 18 ++++++------- src/mod/applications/mod_avmd/Makefile | 4 +-- .../endpoints/mod_gsmopen/asterisk/Makefile | 2 +- .../gsmlib-1.10-patched-12ubuntu1/configure | 26 +++++++++---------- src/mod/languages/mod_lua/lua/Makefile | 4 +-- 33 files changed, 105 insertions(+), 105 deletions(-) diff --git a/build/config/ax_cc_maxopt.m4 b/build/config/ax_cc_maxopt.m4 index 6205ee84c8..40bb95c8b7 100644 --- a/build/config/ax_cc_maxopt.m4 +++ b/build/config/ax_cc_maxopt.m4 @@ -10,7 +10,7 @@ AC_ARG_ENABLE(portable-binary, [AC_HELP_STRING([--enable-portable-binary], [disa if test "$ac_test_CFLAGS" != "set"; then CFLAGS="" case $ax_cv_c_compiler_vendor in - dec) CFLAGS="-newc -w0 -O5 -ansi_alias -ansi_args -fp_reorder -tune host" + dec) CFLAGS="-newc -w0 -O0 -ansi_alias -ansi_args -fp_reorder -tune host" if test "x$acx_maxopt_portable" = xno; then CFLAGS="$CFLAGS -arch host" fi;; @@ -31,13 +31,13 @@ if test "$ac_test_CFLAGS" != "set"; then xlc_opt="-qtune=auto" fi AX_CHECK_COMPILER_FLAGS($xlc_opt, - CFLAGS="-O3 -qansialias -w $xlc_opt", - [CFLAGS="-O3 -qansialias -w" + CFLAGS="-O0 -qansialias -w $xlc_opt", + [CFLAGS="-O0 -qansialias -w" echo "******************************************************" echo "* You seem to have the IBM C compiler. It is *" echo "* recommended for best performance that you use: *" echo "* *" - echo "* CFLAGS=-O3 -qarch=xxx -qtune=xxx -qansialias -w *" + echo "* CFLAGS=-O0 -qarch=xxx -qtune=xxx -qansialias -w *" echo "* ^^^ ^^^ *" echo "* where xxx is pwr2, pwr3, 604, or whatever kind of *" echo "* CPU you have. (Set the CFLAGS environment var. *" @@ -45,7 +45,7 @@ if test "$ac_test_CFLAGS" != "set"; then echo "******************************************************"]) ;; - intel) CFLAGS="-O3 -ansi_alias" + intel) CFLAGS="-O0 -ansi_alias" if test "x$acx_maxopt_portable" = xno; then icc_archflag=unknown icc_flags="" @@ -78,7 +78,7 @@ if test "$ac_test_CFLAGS" != "set"; then gnu) # default optimization flags for gcc on all systems - CFLAGS="-O3 -fomit-frame-pointer" + CFLAGS="-O0 -fomit-frame-pointer" # -malign-double for x86 systems AX_CHECK_COMPILER_FLAGS(-malign-double, CFLAGS="$CFLAGS -malign-double") @@ -99,10 +99,10 @@ if test "$ac_test_CFLAGS" != "set"; then echo "********************************************************" echo "* WARNING: Don't know the best CFLAGS for this system *" echo "* Use ./configure CFLAGS=... to specify your own flags *" - echo "* (otherwise, a default of CFLAGS=-O3 will be used) *" + echo "* (otherwise, a default of CFLAGS=-O0 will be used) *" echo "********************************************************" echo "" - CFLAGS="-O3" + CFLAGS="-O0" fi AX_CHECK_COMPILER_FLAGS($CFLAGS, [], [ diff --git a/libs/apr/build/NWGNUenvironment.inc b/libs/apr/build/NWGNUenvironment.inc index fd54b487c9..884330fbb7 100644 --- a/libs/apr/build/NWGNUenvironment.inc +++ b/libs/apr/build/NWGNUenvironment.inc @@ -161,7 +161,7 @@ endif # -O4,p level 4 optimizations, optimize for speed ifeq "$(RELEASE)" "optimized" -CFLAGS += -O4,p +CFLAGS += -O0,p endif # -prefix apr_arch_pre_nw.h #include pre_nw.h for all files diff --git a/libs/apr/build/apr_hints.m4 b/libs/apr/build/apr_hints.m4 index 1347653659..a7011db555 100644 --- a/libs/apr/build/apr_hints.m4 +++ b/libs/apr/build/apr_hints.m4 @@ -326,7 +326,7 @@ dnl # Not a problem in 10.20. Otherwise, who knows? ;; *convex-v11*) APR_ADDTO(CPPFLAGS, [-DCONVEXOS11]) - APR_SETIFNULL(CFLAGS, [-O1]) + APR_SETIFNULL(CFLAGS, [-O0]) APR_ADDTO(CFLAGS, [-ext]) ;; i860-intel-osf1) diff --git a/libs/apr/configure.in b/libs/apr/configure.in index 68c030e124..a1d375d768 100644 --- a/libs/apr/configure.in +++ b/libs/apr/configure.in @@ -239,7 +239,7 @@ nl=' ' echo "${nl}Check for compiler flags..." -dnl AC_PROG_CC sets -g in CFLAGS (and -O2 for gcc) by default. +dnl AC_PROG_CC sets -g in CFLAGS (and -O0 for gcc) by default. dnl On OS/390 this causes the compiler to insert extra debugger dnl hook instructions. That's fine for debug/maintainer builds, not fine dnl otherwise. @@ -287,8 +287,8 @@ AC_ARG_ENABLE(profile,[ --enable-profile Turn on profiling for the build APR_ADDTO(CFLAGS, -pg) APR_REMOVEFROM(CFLAGS, -g) if test "$host" = "i586-pc-beos"; then - APR_REMOVEFROM(CFLAGS, -O2) - APR_ADDTO(CFLAGS, -O1) + APR_REMOVEFROM(CFLAGS, -O0) + APR_ADDTO(CFLAGS, -O0) APR_ADDTO(LDFLAGS, -p) fi fi @@ -340,7 +340,7 @@ AC_ARG_ENABLE(pool-debug, if test "$host" = "i586-pc-beos"; then AC_ARG_ENABLE(malloc-debug,[ --enable-malloc-debug Switch on malloc_debug for BeOS], - APR_REMOVEFROM(CFLAGS, -O2) + APR_REMOVEFROM(CFLAGS, -O0) APR_ADDTO(CPPFLAGS, -fcheck-memory-usage -D_KERNEL_MODE) ) dnl fi diff --git a/libs/broadvoice/configure.ac b/libs/broadvoice/configure.ac index ceb92a57cb..10d279ed8a 100644 --- a/libs/broadvoice/configure.ac +++ b/libs/broadvoice/configure.ac @@ -71,9 +71,9 @@ then CC_FOR_BUILD=${CC_FOR_BUILD-gcc} CPPFLAGS_FOR_BUILD="\$(CPPFLAGS)" CC=${CC-${host_alias}-gcc} - CFLAGS=${CFLAGS-"-g -O2"} + CFLAGS=${CFLAGS-"-g -O0"} CXX=${CXX-${host_alias}-c++} - CXXFLAGS=${CXXFLAGS-"-g -O2"} + CXXFLAGS=${CXXFLAGS-"-g -O0"} else # Set reasonable default values for some tools even if not Canadian. # Of course, these are different reasonable default values, originally @@ -108,8 +108,8 @@ else fi CXX=${CXX-"c++"} - CFLAGS=${CFLAGS-"-g -O2"} - CXXFLAGS=${CXXFLAGS-"-g -O2"} + CFLAGS=${CFLAGS-"-g -O0"} + CXXFLAGS=${CXXFLAGS-"-g -O0"} fi AC_DEFUN([REMOVE_FROM_VAR],[ diff --git a/libs/broadvoice/debian/rules b/libs/broadvoice/debian/rules index 636e1b42ae..b4f11d6876 100644 --- a/libs/broadvoice/debian/rules +++ b/libs/broadvoice/debian/rules @@ -21,7 +21,7 @@ CFLAGS = -Wall -g ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) CFLAGS += -O0 else - CFLAGS += -O2 + CFLAGS += -O0 endif include /usr/share/dpatch/dpatch.make diff --git a/libs/curl/lib/Makefile.b32 b/libs/curl/lib/Makefile.b32 index 4544d7e7be..97c27ddf12 100644 --- a/libs/curl/lib/Makefile.b32 +++ b/libs/curl/lib/Makefile.b32 @@ -35,7 +35,7 @@ RM = del LIB = tlib IMPLIB = implib -CXXFLAGS = -q -5 -O2 -w-aus -w-ccc -w-csu -w-par -w-pia -w-rch -w-inl -w-ngu -w-pro -tWM +CXXFLAGS = -q -5 -O0 -w-aus -w-ccc -w-csu -w-par -w-pia -w-rch -w-inl -w-ngu -w-pro -tWM LIBFLAGS = /C /P32 LDFLAGS = -q -lq -laa -tWD diff --git a/libs/curl/lib/Makefile.m32 b/libs/curl/lib/Makefile.m32 index 77085c6b08..1e7977f24c 100644 --- a/libs/curl/lib/Makefile.m32 +++ b/libs/curl/lib/Makefile.m32 @@ -26,7 +26,7 @@ STRIP = strip -g ## Nothing more to do below this line! INCLUDES = -I. -I../include -CFLAGS = -g -O2 -DMINGW32 -DBUILDING_LIBCURL -DHAVE_LONGLONG +CFLAGS = -g -O0 -DMINGW32 -DBUILDING_LIBCURL -DHAVE_LONGLONG ifdef SSL INCLUDES += -I"$(OPENSSL_PATH)/outinc" -I"$(OPENSSL_PATH)/outinc/openssl" CFLAGS += -DUSE_SSLEAY -DUSE_OPENSSL -DHAVE_OPENSSL_ENGINE_H -DHAVE_OPENSSL_PKCS12_H \ diff --git a/libs/curl/src/Makefile.b32 b/libs/curl/src/Makefile.b32 index d4c1a073c9..b7ad61733a 100644 --- a/libs/curl/src/Makefile.b32 +++ b/libs/curl/src/Makefile.b32 @@ -32,7 +32,7 @@ CP = copy RM = del LIB = tlib -CXXFLAGS = -q -5 -O2 -w-aus -w-ccc -w-csu -w-par -w-pia -w-rch -w-inl -w-ngu -w-pro -tWM +CXXFLAGS = -q -5 -O0 -w-aus -w-ccc -w-csu -w-par -w-pia -w-rch -w-inl -w-ngu -w-pro -tWM LDFLAGS = -q -lq -lap INCDIRS = -I.;../include;../lib diff --git a/libs/curl/src/makefile.amiga b/libs/curl/src/makefile.amiga index 9e03e070f0..15234d422c 100755 --- a/libs/curl/src/makefile.amiga +++ b/libs/curl/src/makefile.amiga @@ -8,7 +8,7 @@ ATCPSDKI= /GG/netinclude CC = m68k-amigaos-gcc -CFLAGS = -I$(ATCPSDKI) -m68020-60 -O2 -msoft-float -noixemul -g -I. -I../include -W -Wall +CFLAGS = -I$(ATCPSDKI) -m68020-60 -O0 -msoft-float -noixemul -g -I. -I../include -W -Wall LIBS = ../lib/libcurl.a -lssl -lcrypto -lz MANPAGE = ../docs/curl.1 README = ../docs/MANUAL diff --git a/libs/js/nsprpub/configure.in b/libs/js/nsprpub/configure.in index 93d3bd9f85..b3fcffe60c 100644 --- a/libs/js/nsprpub/configure.in +++ b/libs/js/nsprpub/configure.in @@ -62,7 +62,7 @@ USE_CPLUS= USE_IPV6= USE_MDUPDATE= _MACOSX_DEPLOYMENT_TARGET= -_OPTIMIZE_FLAGS=-O +_OPTIMIZE_FLAGS=-O0 _DEBUG_FLAGS=-g MOZ_DEBUG=1 MOZ_OPTIMIZE= @@ -176,7 +176,7 @@ AC_ARG_WITH(mozilla, fi]) AC_ARG_ENABLE(optimize, - [ --enable-optimize(=val) Enable code optimizations (val, ie. -O2) ], + [ --enable-optimize(=val) Enable code optimizations (val, ie. -O0) ], [ if test "$enableval" != "no"; then MOZ_OPTIMIZE=1 if test -n "$enableval" && test "$enableval" != "yes"; then @@ -887,7 +887,7 @@ case "$target" in RESOLVE_LINK_SYMBOLS=1 case "${target_cpu}" in i*86) - _OPTIMIZE_FLAGS=-O2 + _OPTIMIZE_FLAGS=-O0 _DEBUG_FLAGS='-gdwarf-2 -O0' MKSHLIB='$(CCC) $(DSO_LDOPTS) -o $@' AC_CHECK_LIB(bind, gethostbyaddr, [OS_LIBS="$OS_LIBS -lbind -lsocket"]) @@ -897,7 +897,7 @@ case "$target" in CCC=mwcc LD=mwld DSO_LDOPTS='-xms -export pragma -init _init_routine_ -term _term_routine_ -lroot -lnet /boot/develop/lib/ppc/glue-noinit.a /boot/develop/lib/ppc/init_term_dyn.o /boot/develop/lib/ppc/start_dyn.o' - _OPTIMIZE_FLAGS=-O2 + _OPTIMIZE_FLAGS=-O0 _DEBUG_FLAGS='-g -O0' ;; esac @@ -1115,7 +1115,7 @@ tools are selected during the Xcode/Developer Tools installation.]) AC_DEFINE(_DGUX_SOURCE) AC_DEFINE(_POSIX4A_DRAFT6_SOURCE) DSO_LDOPTS=-G - _OPTIMIZE_FLAGS=-O2 + _OPTIMIZE_FLAGS=-O0 _DEBUG_FLAGS= MDCPUCFG_H=_dgux.cfg PR_MD_CSRCS=dgux.c @@ -1334,7 +1334,7 @@ tools are selected during the Xcode/Developer Tools installation.]) dnl AS='$(CC) -Wp,-P -x assembler-with-cpp -D_ASM -mips2 $(INCLUDES)' CFLAGS="$CFLAGS -Wall -Wno-format" - _OPTIMIZE_FLAGS="-O6" + _OPTIMIZE_FLAGS="-O0" else if test -n "$USE_N32"; then AS='as -D_ASM $(INCLUDES) -n32' @@ -1408,7 +1408,7 @@ tools are selected during the Xcode/Developer Tools installation.]) MKSHLIB='$(CC) $(DSO_LDOPTS) $(OS_LDFLAGS) -o $@' DSO_CFLAGS=-fPIC DSO_LDOPTS='-shared -Wl,-soname -Wl,$(notdir $@)' - _OPTIMIZE_FLAGS=-O2 + _OPTIMIZE_FLAGS=-O0 _DEBUG_FLAGS="-g" # most people on linux use gcc/gdb, and that # combo is not yet good at debugging inlined # functions (even when using DWARF2 as the @@ -1485,7 +1485,7 @@ tools are selected during the Xcode/Developer Tools installation.]) CFLAGS="$CFLAGS -W3 -nologo -GF -Gy" DLLFLAGS='-OUT:"$@"' _DEBUG_FLAGS=-Z7 - _OPTIMIZE_FLAGS=-O2 + _OPTIMIZE_FLAGS=-O0 if test -z "$MOZ_OPTIMIZE"; then CFLAGS="$CFLAGS -Od" fi @@ -1724,7 +1724,7 @@ mips-sony-newsos*) DSO_CFLAGS=-fPIC DSO_LDOPTS=-shared OS_LIBS="$OS_LIBS -lsocket" - _OPTIMIZE_FLAGS="-O1" + _OPTIMIZE_FLAGS="-O0" _DEBUG_FLAGS="-gstabs" ;; @@ -2082,7 +2082,7 @@ mips-sony-newsos*) DSO_CFLAGS= DSO_LDOPTS='-Zomf -Zdll -Zmap' LDFLAGS='-Zmap' - _OPTIMIZE_FLAGS="-O2 -s" + _OPTIMIZE_FLAGS="-O0 -s" _DEBUG_FLAGS="-g -fno-inline" if test -n "$MOZ_OPTIMIZE"; then DSO_LDOPTS="$DSO_LDOPTS -Zlinker /EXEPACK:2 -Zlinker /PACKCODE -Zlinker /PACKDATA" diff --git a/libs/libg722_1/configure.ac b/libs/libg722_1/configure.ac index 62095ce374..e5385d4091 100644 --- a/libs/libg722_1/configure.ac +++ b/libs/libg722_1/configure.ac @@ -64,9 +64,9 @@ then CC_FOR_BUILD=${CC_FOR_BUILD-gcc} CPPFLAGS_FOR_BUILD="\$(CPPFLAGS)" CC=${CC-${host_alias}-gcc} - CFLAGS=${CFLAGS-"-g -O2"} + CFLAGS=${CFLAGS-"-g -O0"} CXX=${CXX-${host_alias}-c++} - CXXFLAGS=${CXXFLAGS-"-g -O2"} + CXXFLAGS=${CXXFLAGS-"-g -O0"} else # Set reasonable default values for some tools even if not Canadian. # Of course, these are different reasonable default values, originally @@ -101,8 +101,8 @@ else fi CXX=${CXX-"c++"} - CFLAGS=${CFLAGS-"-g -O2"} - CXXFLAGS=${CXXFLAGS-"-g -O2"} + CFLAGS=${CFLAGS-"-g -O0"} + CXXFLAGS=${CXXFLAGS-"-g -O0"} fi AC_DEFUN([REMOVE_FROM_VAR],[ diff --git a/libs/libsndfile/INSTALL b/libs/libsndfile/INSTALL index b42a17ac46..d520a54b6b 100644 --- a/libs/libsndfile/INSTALL +++ b/libs/libsndfile/INSTALL @@ -59,7 +59,7 @@ the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: - CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + CC=c89 CFLAGS=-O0 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure diff --git a/libs/pcre/configure.ac b/libs/pcre/configure.ac index b6f79f98cf..7bf7c95b35 100644 --- a/libs/pcre/configure.ac +++ b/libs/pcre/configure.ac @@ -26,7 +26,7 @@ CFLAGS="$CFLAGS $CONFIGURE_CFLAGS" CXXFLAGS="$CXXFLAGS $CONFIGURE_CXXFLAGS" LDFLAGS="$LDFLAGS $CONFIGURE_LDFLAGS" -# The default CFLAGS and CXXFLAGS in Autoconf are "-g -O2" for gcc and just +# The default CFLAGS and CXXFLAGS in Autoconf are "-g -O0" for gcc and just # "-g" for any other compiler. There doesn't seem to be a standard way of # getting rid of the -g (which I don't think is needed for a production # library). This fudge seems to achieve the necessary. First, we remember the @@ -44,9 +44,9 @@ AC_PROG_CXX if test "x$remember_set_CFLAGS" = "x" then - if test "$CFLAGS" = "-g -O2" + if test "$CFLAGS" = "-g -O0" then - CFLAGS="-O2" + CFLAGS="-O0" elif test "$CFLAGS" = "-g" then CFLAGS="" @@ -55,9 +55,9 @@ fi if test "x$remember_set_CXXFLAGS" = "x" then - if test "$CXXFLAGS" = "-g -O2" + if test "$CXXFLAGS" = "-g -O0" then - CXXFLAGS="-O2" + CXXFLAGS="-O0" elif test "$CXXFLAGS" = "-g" then CXXFLAGS="" diff --git a/libs/portaudio/Makefile.darwin b/libs/portaudio/Makefile.darwin index 9aec51de24..0d37963f04 100644 --- a/libs/portaudio/Makefile.darwin +++ b/libs/portaudio/Makefile.darwin @@ -11,7 +11,7 @@ top_srcdir = . srcdir = . top_builddir = . -OPT_LEVEL := -O2 +OPT_LEVEL := -O0 PREFIX = /usr/local prefix = $(PREFIX) exec_prefix = ${prefix} diff --git a/libs/portaudio/SConstruct b/libs/portaudio/SConstruct index 15d36bad57..3c4bca0df7 100644 --- a/libs/portaudio/SConstruct +++ b/libs/portaudio/SConstruct @@ -39,7 +39,7 @@ if Platform in Posix: baseLinkFlags = threadCFlags = "-pthread" baseCxxFlags = baseCFlags = "-Wall -pedantic -pipe " + threadCFlags debugCxxFlags = debugCFlags = "-g" - optCxxFlags = optCFlags = "-O2" + optCxxFlags = optCFlags = "-O0" env["CCFLAGS"] = baseCFlags.split() env["CXXFLAGS"] = baseCxxFlags.split() env["LINKFLAGS"] = baseLinkFlags.split() diff --git a/libs/portaudio/bindings/cpp/build/gnu/configure b/libs/portaudio/bindings/cpp/build/gnu/configure index 69070c66d4..e91013c07c 100644 --- a/libs/portaudio/bindings/cpp/build/gnu/configure +++ b/libs/portaudio/bindings/cpp/build/gnu/configure @@ -1263,7 +1263,7 @@ PORTAUDIO="$PACPP_ROOT/../portaudio" PACPP_INC="$PACPP_ROOT/include" INCLUDES="-I$PACPP_INC -I$PORTAUDIO -I$PORTAUDIO/pa_common" -CFLAGS="-g -O2 -Wall -ansi -pedantic $INCLUDES" +CFLAGS="-g -O0 -Wall -ansi -pedantic $INCLUDES" CXXFLAGS="$CFLAGS" PALIBDIR="$PORTAUDIO/lib" @@ -1908,13 +1908,13 @@ if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then - CFLAGS="-g -O2" + CFLAGS="-g -O0" else - CFLAGS="-g" + CFLAGS="-g -O0" fi else if test "$GCC" = yes; then - CFLAGS="-O2" + CFLAGS="-O0" else CFLAGS= fi @@ -2350,13 +2350,13 @@ if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then - CXXFLAGS="-g -O2" + CXXFLAGS="-g -O0" else - CXXFLAGS="-g" + CXXFLAGS="-g -O0" fi else if test "$GXX" = yes; then - CXXFLAGS="-O2" + CXXFLAGS="-O0" else CXXFLAGS= fi diff --git a/libs/portaudio/bindings/cpp/build/gnu/configure.ac b/libs/portaudio/bindings/cpp/build/gnu/configure.ac index 5457c53420..071a7e94ef 100644 --- a/libs/portaudio/bindings/cpp/build/gnu/configure.ac +++ b/libs/portaudio/bindings/cpp/build/gnu/configure.ac @@ -24,7 +24,7 @@ PORTAUDIO="$PACPP_ROOT/../portaudio" PACPP_INC="$PACPP_ROOT/include" INCLUDES="-I$PACPP_INC -I$PORTAUDIO -I$PORTAUDIO/pa_common" -CFLAGS="-g -O2 -Wall -ansi -pedantic $INCLUDES" +CFLAGS="-g -O0 -Wall -ansi -pedantic $INCLUDES" CXXFLAGS="$CFLAGS" PALIBDIR="$PORTAUDIO/lib" diff --git a/libs/portaudio/bindings/cpp/configure.ac b/libs/portaudio/bindings/cpp/configure.ac index 100656ac41..94baff8fc3 100644 --- a/libs/portaudio/bindings/cpp/configure.ac +++ b/libs/portaudio/bindings/cpp/configure.ac @@ -25,7 +25,7 @@ PORTAUDIO_ROOT="../.." # Various other variables and flags DEFAULT_INCLUDES="-I$PACPP_ROOT/include -I$PACPP_ROOT/$PORTAUDIO_ROOT/include" -CFLAGS=${CFLAGS-"-g -O2 -Wall -ansi -pedantic"} +CFLAGS=${CFLAGS-"-g -O0 -Wall -ansi -pedantic"} CXXFLAGS=${CXXFLAGS-"${CFLAGS}"} LT_VERSION_INFO="lt_current:lt_revision:lt_age" diff --git a/libs/portaudio/build/dev-cpp/Makefile-static b/libs/portaudio/build/dev-cpp/Makefile-static index 2a1647ddc5..65fcb5dacf 100644 --- a/libs/portaudio/build/dev-cpp/Makefile-static +++ b/libs/portaudio/build/dev-cpp/Makefile-static @@ -7,12 +7,12 @@ WINDRES = windres.exe RES = OBJ = ./pa_skeleton.o ./pa_stream.o ./pa_trace.o ./pa_allocation.o ./pa_converters.o ./pa_cpuload.o ./pa_dither.o ./pa_front.o ./pa_process.o ./pa_asio.o ./pa_win_util.o ./pa_win_hostapis.o ./pa_win_ds.o ./dsound_wrapper.o ./pa_win_wmme.o ./iasiothiscallresolver.o $(RES) LINKOBJ = ./pa_skeleton.o ./pa_stream.o ./pa_trace.o ./pa_allocation.o ./pa_converters.o ./pa_cpuload.o ./pa_dither.o ./pa_front.o ./pa_process.o ./pa_asio.o ./pa_win_util.o ./pa_win_hostapis.o ./pa_win_ds.o ./dsound_wrapper.o ./pa_win_wmme.o ./iasiothiscallresolver.o $(RES) -LIBS = -L"C:/Dev-CPP/lib" -fmessage-length=0 -O3 -s +LIBS = -L"C:/Dev-CPP/lib" -fmessage-length=0 -O0 -s INCS = -I"C:/Dev-CPP/include" -I"../../../asiosdk2" -I"../../../asiosdk2/common" -I"../../../asiosdk2/host" -I"../../../asiosdk2/host/pc" -I"../../pa_common" CXXINCS = -I"C:/Dev-CPP/include/c++" -I"C:/Dev-CPP/include/c++/mingw32" -I"C:/Dev-CPP/include/c++/backward" -I"C:/Dev-CPP/include" -I"../../../asiosdk2" -I"../../../asiosdk2/common" -I"../../../asiosdk2/host" -I"../../../asiosdk2/host/pc" -I"../../pa_common" BIN = portaudio-static.a -CXXFLAGS = $(CXXINCS)-O3 -fmessage-length=0 -Wall -CFLAGS = $(INCS)-O3 -fmessage-length=0 -Wall +CXXFLAGS = $(CXXINCS)-O0 -fmessage-length=0 -Wall +CFLAGS = $(INCS)-O0 -fmessage-length=0 -Wall .PHONY: all all-before all-after clean clean-custom diff --git a/libs/portaudio/configure.in b/libs/portaudio/configure.in index f4ef9abbee..24deaf701c 100644 --- a/libs/portaudio/configure.in +++ b/libs/portaudio/configure.in @@ -130,7 +130,7 @@ AC_SUBST(CXXFLAGS) AC_SUBST(NASM) AC_SUBST(NASMOPT) -CFLAGS=${CFLAGS:-"-g -O2 -Wall -pedantic -pipe -fPIC"} +CFLAGS=${CFLAGS:-"-g -O0 -Wall -pedantic -pipe -fPIC"} if [[ $ac_cv_c_bigendian = "yes" ]] ; then CFLAGS="$CFLAGS -DPA_BIG_ENDIAN" diff --git a/libs/sqlite/Makefile.linux-gcc b/libs/sqlite/Makefile.linux-gcc index c865024b44..e3a3d385dd 100644 --- a/libs/sqlite/Makefile.linux-gcc +++ b/libs/sqlite/Makefile.linux-gcc @@ -19,7 +19,7 @@ TOP = ../sqlite #### C Compiler and options for use in building executables that # will run on the platform that is doing the build. # -BCC = gcc -g -O2 +BCC = gcc -g -O0 #BCC = /opt/ancic/bin/c89 -0 #### If the target operating system supports the "usleep()" system @@ -70,10 +70,10 @@ EXE = # will run on the target platform. This is usually the same # as BCC, unless you are cross-compiling. # -TCC = gcc -O6 +TCC = gcc -O0 #TCC = gcc -g -O0 -Wall #TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage -#TCC = /opt/mingw/bin/i386-mingw32-gcc -O6 +#TCC = /opt/mingw/bin/i386-mingw32-gcc -O0 #TCC = /opt/ansic/bin/c89 -O +z -Wl,-a,archive #### Tools used to build a static library. diff --git a/libs/sqlite/mkso.sh b/libs/sqlite/mkso.sh index 9050d74255..d6afb0198d 100755 --- a/libs/sqlite/mkso.sh +++ b/libs/sqlite/mkso.sh @@ -14,7 +14,7 @@ TCLSTUBLIB=$TCLDIR/libtclstub8.4g.a OPTS='-DUSE_TCL_STUBS=1 -DNDEBUG=1 -DHAVE_DLOPEN=1' for i in *.c; do if test $i != 'keywordhash.c'; then - CMD="cc -fPIC $OPTS -O2 -I. -I$TCLDIR -c $i" + CMD="cc -fPIC $OPTS -O0 -I. -I$TCLDIR -c $i" echo $CMD $CMD fi diff --git a/libs/sqlite/publish.sh b/libs/sqlite/publish.sh index 043c89a039..68d7c7f6e8 100755 --- a/libs/sqlite/publish.sh +++ b/libs/sqlite/publish.sh @@ -66,7 +66,7 @@ make target_source cd tsrc rm tclsqlite.c OPTS='-DSTATIC_BUILD=1 -DNDEBUG=1' -i386-mingw32msvc-gcc -O2 $OPTS -I. -I$TCLDIR *.c -o sqlite3.exe +i386-mingw32msvc-gcc -O0 $OPTS -I. -I$TCLDIR *.c -o sqlite3.exe zip ../doc/sqlite-$VERSW.zip sqlite3.exe cd .. diff --git a/libs/srtp/INSTALL b/libs/srtp/INSTALL index 23e5f25d0e..7d2c51bb9d 100644 --- a/libs/srtp/INSTALL +++ b/libs/srtp/INSTALL @@ -78,7 +78,7 @@ details on some of the pertinent environment variables. by setting variables in the command line or in the environment. Here is an example: - ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + ./configure CC=c89 CFLAGS=-O0 LIBS=-lposix *Note Defining Variables::, for more details. diff --git a/libs/srtp/build/config/ax_cc_maxopt.m4 b/libs/srtp/build/config/ax_cc_maxopt.m4 index 6205ee84c8..40bb95c8b7 100644 --- a/libs/srtp/build/config/ax_cc_maxopt.m4 +++ b/libs/srtp/build/config/ax_cc_maxopt.m4 @@ -10,7 +10,7 @@ AC_ARG_ENABLE(portable-binary, [AC_HELP_STRING([--enable-portable-binary], [disa if test "$ac_test_CFLAGS" != "set"; then CFLAGS="" case $ax_cv_c_compiler_vendor in - dec) CFLAGS="-newc -w0 -O5 -ansi_alias -ansi_args -fp_reorder -tune host" + dec) CFLAGS="-newc -w0 -O0 -ansi_alias -ansi_args -fp_reorder -tune host" if test "x$acx_maxopt_portable" = xno; then CFLAGS="$CFLAGS -arch host" fi;; @@ -31,13 +31,13 @@ if test "$ac_test_CFLAGS" != "set"; then xlc_opt="-qtune=auto" fi AX_CHECK_COMPILER_FLAGS($xlc_opt, - CFLAGS="-O3 -qansialias -w $xlc_opt", - [CFLAGS="-O3 -qansialias -w" + CFLAGS="-O0 -qansialias -w $xlc_opt", + [CFLAGS="-O0 -qansialias -w" echo "******************************************************" echo "* You seem to have the IBM C compiler. It is *" echo "* recommended for best performance that you use: *" echo "* *" - echo "* CFLAGS=-O3 -qarch=xxx -qtune=xxx -qansialias -w *" + echo "* CFLAGS=-O0 -qarch=xxx -qtune=xxx -qansialias -w *" echo "* ^^^ ^^^ *" echo "* where xxx is pwr2, pwr3, 604, or whatever kind of *" echo "* CPU you have. (Set the CFLAGS environment var. *" @@ -45,7 +45,7 @@ if test "$ac_test_CFLAGS" != "set"; then echo "******************************************************"]) ;; - intel) CFLAGS="-O3 -ansi_alias" + intel) CFLAGS="-O0 -ansi_alias" if test "x$acx_maxopt_portable" = xno; then icc_archflag=unknown icc_flags="" @@ -78,7 +78,7 @@ if test "$ac_test_CFLAGS" != "set"; then gnu) # default optimization flags for gcc on all systems - CFLAGS="-O3 -fomit-frame-pointer" + CFLAGS="-O0 -fomit-frame-pointer" # -malign-double for x86 systems AX_CHECK_COMPILER_FLAGS(-malign-double, CFLAGS="$CFLAGS -malign-double") @@ -99,10 +99,10 @@ if test "$ac_test_CFLAGS" != "set"; then echo "********************************************************" echo "* WARNING: Don't know the best CFLAGS for this system *" echo "* Use ./configure CFLAGS=... to specify your own flags *" - echo "* (otherwise, a default of CFLAGS=-O3 will be used) *" + echo "* (otherwise, a default of CFLAGS=-O0 will be used) *" echo "********************************************************" echo "" - CFLAGS="-O3" + CFLAGS="-O0" fi AX_CHECK_COMPILER_FLAGS($CFLAGS, [], [ diff --git a/libs/srtp/configure.in b/libs/srtp/configure.in index 2495a55f95..8584be880e 100644 --- a/libs/srtp/configure.in +++ b/libs/srtp/configure.in @@ -49,7 +49,7 @@ case "$host" in IN_LINE="" elif test "x${ax_cv_c_compiler_vendor}" = "xgnu" ; then SOLINK="-Bdynamic -dy -G" - new_AM_CFLAGS="-fPIC -Wall -O4 -fexpensive-optimizations -funroll-loops" + new_AM_CFLAGS="-fPIC -Wall -O0 -fexpensive-optimizations -funroll-loops" new_AM_LDFLAGS="" IN_LINE=inline fi @@ -71,7 +71,7 @@ case "$host" in FUNC_DEF=__func__ elif test "x${ax_cv_c_compiler_vendor}"="xgnu" ; then SOLINK="-shared -Xlinker -x" - new_AM_CFLAGS="-fPIC -Wall -O4 -fexpensive-optimizations -funroll-loops" + new_AM_CFLAGS="-fPIC -Wall -O0 -fexpensive-optimizations -funroll-loops" new_AM_LDFLAGS="" fi DYNAMIC_LIB_EXTEN="so" @@ -84,20 +84,20 @@ case "$host" in FUNC_DEF=__func__ elif test "x${ax_cv_c_compiler_vendor}"="xgnu" ; then SOLINK="-shared -Xlinker -x" - new_AM_CFLAGS="-fpic -Wall -O4 -fexpensive-optimizations -funroll-loops" + new_AM_CFLAGS="-fpic -Wall -O0 -fexpensive-optimizations -funroll-loops" new_AM_LDFLAGS="" fi DYNAMIC_LIB_EXTEN="so" ;; i*6*-*-freebsd*) SOLINK="-shared -Xlinker -x" - new_AM_CFLAGS="-fPIC -Wall -O4 -fexpensive-optimizations -funroll-loops" + new_AM_CFLAGS="-fPIC -Wall -O0 -fexpensive-optimizations -funroll-loops" new_AM_LDFLAGS="" DYNAMIC_LIB_EXTEN="so" ;; x86_64-*-freebsd*|amd64-*-freebsd*) SOLINK="-shared -Xlinker -x" - new_AM_CFLAGS="-fPIC -Wall -O4 -fexpensive-optimizations -funroll-loops" + new_AM_CFLAGS="-fPIC -Wall -O0 -fexpensive-optimizations -funroll-loops" new_AM_LDFLAGS="" DYNAMIC_LIB_EXTEN="so" ;; diff --git a/libs/yaml/aclocal.m4 b/libs/yaml/aclocal.m4 index b7984f0f01..ba1ed63878 100644 --- a/libs/yaml/aclocal.m4 +++ b/libs/yaml/aclocal.m4 @@ -6311,7 +6311,7 @@ ifelse([AC_DISABLE_FAST_INSTALL]) AC_DEFUN([LT_AC_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj, no) - test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O0" AC_SUBST(GCJFLAGS) ]) diff --git a/libs/yaml/configure b/libs/yaml/configure index 66e708215a..f66fa4972c 100755 --- a/libs/yaml/configure +++ b/libs/yaml/configure @@ -3222,13 +3222,13 @@ if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then - CFLAGS="-g -O2" + CFLAGS="-g -O0" else - CFLAGS="-g" + CFLAGS="-g -O0" fi else if test "$GCC" = yes; then - CFLAGS="-O2" + CFLAGS="-O0" else CFLAGS= fi @@ -5579,13 +5579,13 @@ if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then - CXXFLAGS="-g -O2" + CXXFLAGS="-g -O0" else - CXXFLAGS="-g" + CXXFLAGS="-g -O0" fi else if test "$GXX" = yes; then - CXXFLAGS="-O2" + CXXFLAGS="-O0" else CXXFLAGS= fi @@ -6180,13 +6180,13 @@ if test "$ac_test_FFLAGS" = set; then FFLAGS=$ac_save_FFLAGS elif test $ac_cv_prog_f77_g = yes; then if test "x$ac_cv_f77_compiler_gnu" = xyes; then - FFLAGS="-g -O2" + FFLAGS="-g -O0" else - FFLAGS="-g" + FFLAGS="-g -O0" fi else if test "x$ac_cv_f77_compiler_gnu" = xyes; then - FFLAGS="-O2" + FFLAGS="-O0" else FFLAGS= fi diff --git a/src/mod/applications/mod_avmd/Makefile b/src/mod/applications/mod_avmd/Makefile index c4a62d4120..fbf7ccb023 100644 --- a/src/mod/applications/mod_avmd/Makefile +++ b/src/mod/applications/mod_avmd/Makefile @@ -1,6 +1,6 @@ BASE=../../../.. -MOD_CFLAGS= -O2 -#MOD_CFLAGS= -march=core2 -g -O2 -malign-double -mtune=core2 -mmmx -msse -msse2 -msse3 -mssse3 -mfpmath=sse -ffast-math -funroll-loops -fprefetch-loop-arrays -funit-at-a-time -ftracer --save-temps +MOD_CFLAGS= -O0 +#MOD_CFLAGS= -march=core2 -g -O0 -malign-double -mtune=core2 -mmmx -msse -msse2 -msse3 -mssse3 -mfpmath=sse -ffast-math -funroll-loops -fprefetch-loop-arrays -funit-at-a-time -ftracer --save-temps #MOD_LDFLAGS= --save-temps LOCAL_SOURCES=amplitude.c buffer.c desa2.c goertzel.c fast_acosf.c LOCAL_OBJS=amplitude.o buffer.o desa2.o goertzel.o fast_acosf.o diff --git a/src/mod/endpoints/mod_gsmopen/asterisk/Makefile b/src/mod/endpoints/mod_gsmopen/asterisk/Makefile index 6aed86266e..f1b2d54450 100644 --- a/src/mod/endpoints/mod_gsmopen/asterisk/Makefile +++ b/src/mod/endpoints/mod_gsmopen/asterisk/Makefile @@ -33,7 +33,7 @@ CFLAGS+=-g3 CFLAGS+=-I$(AST_INCLUDE_DIR) -I. CFLAGS+=-D_REENTRANT -D_GNU_SOURCE -#CFLAGS+=-O6 +#CFLAGS+=-O0 #CFLAGS+=-march=i586 CFLAGS+=-fomit-frame-pointer ifeq ($(shell uname -m),x86_64) diff --git a/src/mod/endpoints/mod_gsmopen/gsmlib/gsmlib-1.10-patched-12ubuntu1/configure b/src/mod/endpoints/mod_gsmopen/gsmlib/gsmlib-1.10-patched-12ubuntu1/configure index 5918af81fb..23bae83868 100755 --- a/src/mod/endpoints/mod_gsmopen/gsmlib/gsmlib-1.10-patched-12ubuntu1/configure +++ b/src/mod/endpoints/mod_gsmopen/gsmlib/gsmlib-1.10-patched-12ubuntu1/configure @@ -2261,13 +2261,13 @@ if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then - CFLAGS="-g -O2" + CFLAGS="-g -O0" else - CFLAGS="-g" + CFLAGS="-g -O0" fi else if test "$GCC" = yes; then - CFLAGS="-O2" + CFLAGS="-O0" else CFLAGS= fi @@ -3144,7 +3144,7 @@ fi; if test "$CXXFLAGS" = ""; then - CXXFLAGS="-O2" + CXXFLAGS="-O0" fi @@ -4748,13 +4748,13 @@ if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then - CXXFLAGS="-g -O2" + CXXFLAGS="-g -O0" else - CXXFLAGS="-g" + CXXFLAGS="-g -O0" fi else if test "$GXX" = yes; then - CXXFLAGS="-O2" + CXXFLAGS="-O0" else CXXFLAGS= fi @@ -5431,13 +5431,13 @@ if test "$ac_test_FFLAGS" = set; then FFLAGS=$ac_save_FFLAGS elif test $ac_cv_prog_f77_g = yes; then if test "x$ac_cv_f77_compiler_gnu" = xyes; then - FFLAGS="-g -O2" + FFLAGS="-g -O0" else - FFLAGS="-g" + FFLAGS="-g -O0" fi else if test "x$ac_cv_f77_compiler_gnu" = xyes; then - FFLAGS="-O2" + FFLAGS="-O0" else FFLAGS= fi @@ -20153,13 +20153,13 @@ if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then - CXXFLAGS="-g -O2" + CXXFLAGS="-g -O0" else - CXXFLAGS="-g" + CXXFLAGS="-g -O0" fi else if test "$GXX" = yes; then - CXXFLAGS="-O2" + CXXFLAGS="-O0" else CXXFLAGS= fi diff --git a/src/mod/languages/mod_lua/lua/Makefile b/src/mod/languages/mod_lua/lua/Makefile index e4a3cd6108..4e0b5480d6 100644 --- a/src/mod/languages/mod_lua/lua/Makefile +++ b/src/mod/languages/mod_lua/lua/Makefile @@ -8,7 +8,7 @@ PLAT= none CC= gcc -CFLAGS= -O2 -Wall $(MYCFLAGS) +CFLAGS= -O0 -Wall $(MYCFLAGS) AR= ar rcu RANLIB= ranlib RM= rm -f @@ -81,7 +81,7 @@ none: @echo " $(PLATS)" aix: - $(MAKE) all CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" MYLDFLAGS="-brtl -bexpall" + $(MAKE) all CC="xlc" CFLAGS="-O0 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" MYLDFLAGS="-brtl -bexpall" ansi: $(MAKE) all MYCFLAGS=-DLUA_ANSI From 012bc154b07aec248fe4b91581ba1a5ea1d3f0d9 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Wed, 21 Mar 2012 10:00:27 -0400 Subject: [PATCH 172/822] Revert "freetdm: fixing default values for ISUP" This reverts commit f1d80cd25d13d78deab88ea7f559e63aa899f319. --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 230476d8e1..ad47f0cbb4 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -2788,7 +2788,7 @@ static int ftmod_ss7_fill_in_isap(sng_isap_t *sng_isap) if (sng_isap->t1 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t1 = sng_isap->t1; } else { - g_ftdm_sngss7_data.cfg.isap[i].t1 = 150; + g_ftdm_sngss7_data.cfg.isap[i].t1 = 200; } if (sng_isap->t2 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t2 = sng_isap->t2; @@ -2803,17 +2803,17 @@ static int ftmod_ss7_fill_in_isap(sng_isap_t *sng_isap) if (sng_isap->t6 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t6 = sng_isap->t6; } else { - g_ftdm_sngss7_data.cfg.isap[i].t6 = 600; + g_ftdm_sngss7_data.cfg.isap[i].t6 = 200; } if (sng_isap->t7 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t7 = sng_isap->t7; } else { - g_ftdm_sngss7_data.cfg.isap[i].t7 = 200; + g_ftdm_sngss7_data.cfg.isap[i].t7 = 250; } if (sng_isap->t8 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t8 = sng_isap->t8; } else { - g_ftdm_sngss7_data.cfg.isap[i].t8 = 100; + g_ftdm_sngss7_data.cfg.isap[i].t8 = 120; } if (sng_isap->t9 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t9 = sng_isap->t9; From a8e21663ce6684eb665dfddfd1757e76ad13a152 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Wed, 21 Mar 2012 10:05:51 -0400 Subject: [PATCH 173/822] Revert "freeswitch: taking out -Ox cflags and have them replaced with -O0" This reverts commit e560ddccdec0232a040851f088db1adec2cbc7f4. --- build/config/ax_cc_maxopt.m4 | 16 ++++++------ libs/apr/build/NWGNUenvironment.inc | 2 +- libs/apr/build/apr_hints.m4 | 2 +- libs/apr/configure.in | 8 +++--- libs/broadvoice/configure.ac | 8 +++--- libs/broadvoice/debian/rules | 2 +- libs/curl/lib/Makefile.b32 | 2 +- libs/curl/lib/Makefile.m32 | 2 +- libs/curl/src/Makefile.b32 | 2 +- libs/curl/src/makefile.amiga | 2 +- libs/js/nsprpub/configure.in | 20 +++++++------- libs/libg722_1/configure.ac | 8 +++--- libs/libsndfile/INSTALL | 2 +- libs/pcre/configure.ac | 10 +++---- libs/portaudio/Makefile.darwin | 2 +- libs/portaudio/SConstruct | 2 +- .../bindings/cpp/build/gnu/configure | 14 +++++----- .../bindings/cpp/build/gnu/configure.ac | 2 +- libs/portaudio/bindings/cpp/configure.ac | 2 +- libs/portaudio/build/dev-cpp/Makefile-static | 6 ++--- libs/portaudio/configure.in | 2 +- libs/sqlite/Makefile.linux-gcc | 6 ++--- libs/sqlite/mkso.sh | 2 +- libs/sqlite/publish.sh | 2 +- libs/srtp/INSTALL | 2 +- libs/srtp/build/config/ax_cc_maxopt.m4 | 16 ++++++------ libs/srtp/configure.in | 10 +++---- libs/yaml/aclocal.m4 | 2 +- libs/yaml/configure | 18 ++++++------- src/mod/applications/mod_avmd/Makefile | 4 +-- .../endpoints/mod_gsmopen/asterisk/Makefile | 2 +- .../gsmlib-1.10-patched-12ubuntu1/configure | 26 +++++++++---------- src/mod/languages/mod_lua/lua/Makefile | 4 +-- 33 files changed, 105 insertions(+), 105 deletions(-) diff --git a/build/config/ax_cc_maxopt.m4 b/build/config/ax_cc_maxopt.m4 index 40bb95c8b7..6205ee84c8 100644 --- a/build/config/ax_cc_maxopt.m4 +++ b/build/config/ax_cc_maxopt.m4 @@ -10,7 +10,7 @@ AC_ARG_ENABLE(portable-binary, [AC_HELP_STRING([--enable-portable-binary], [disa if test "$ac_test_CFLAGS" != "set"; then CFLAGS="" case $ax_cv_c_compiler_vendor in - dec) CFLAGS="-newc -w0 -O0 -ansi_alias -ansi_args -fp_reorder -tune host" + dec) CFLAGS="-newc -w0 -O5 -ansi_alias -ansi_args -fp_reorder -tune host" if test "x$acx_maxopt_portable" = xno; then CFLAGS="$CFLAGS -arch host" fi;; @@ -31,13 +31,13 @@ if test "$ac_test_CFLAGS" != "set"; then xlc_opt="-qtune=auto" fi AX_CHECK_COMPILER_FLAGS($xlc_opt, - CFLAGS="-O0 -qansialias -w $xlc_opt", - [CFLAGS="-O0 -qansialias -w" + CFLAGS="-O3 -qansialias -w $xlc_opt", + [CFLAGS="-O3 -qansialias -w" echo "******************************************************" echo "* You seem to have the IBM C compiler. It is *" echo "* recommended for best performance that you use: *" echo "* *" - echo "* CFLAGS=-O0 -qarch=xxx -qtune=xxx -qansialias -w *" + echo "* CFLAGS=-O3 -qarch=xxx -qtune=xxx -qansialias -w *" echo "* ^^^ ^^^ *" echo "* where xxx is pwr2, pwr3, 604, or whatever kind of *" echo "* CPU you have. (Set the CFLAGS environment var. *" @@ -45,7 +45,7 @@ if test "$ac_test_CFLAGS" != "set"; then echo "******************************************************"]) ;; - intel) CFLAGS="-O0 -ansi_alias" + intel) CFLAGS="-O3 -ansi_alias" if test "x$acx_maxopt_portable" = xno; then icc_archflag=unknown icc_flags="" @@ -78,7 +78,7 @@ if test "$ac_test_CFLAGS" != "set"; then gnu) # default optimization flags for gcc on all systems - CFLAGS="-O0 -fomit-frame-pointer" + CFLAGS="-O3 -fomit-frame-pointer" # -malign-double for x86 systems AX_CHECK_COMPILER_FLAGS(-malign-double, CFLAGS="$CFLAGS -malign-double") @@ -99,10 +99,10 @@ if test "$ac_test_CFLAGS" != "set"; then echo "********************************************************" echo "* WARNING: Don't know the best CFLAGS for this system *" echo "* Use ./configure CFLAGS=... to specify your own flags *" - echo "* (otherwise, a default of CFLAGS=-O0 will be used) *" + echo "* (otherwise, a default of CFLAGS=-O3 will be used) *" echo "********************************************************" echo "" - CFLAGS="-O0" + CFLAGS="-O3" fi AX_CHECK_COMPILER_FLAGS($CFLAGS, [], [ diff --git a/libs/apr/build/NWGNUenvironment.inc b/libs/apr/build/NWGNUenvironment.inc index 884330fbb7..fd54b487c9 100644 --- a/libs/apr/build/NWGNUenvironment.inc +++ b/libs/apr/build/NWGNUenvironment.inc @@ -161,7 +161,7 @@ endif # -O4,p level 4 optimizations, optimize for speed ifeq "$(RELEASE)" "optimized" -CFLAGS += -O0,p +CFLAGS += -O4,p endif # -prefix apr_arch_pre_nw.h #include pre_nw.h for all files diff --git a/libs/apr/build/apr_hints.m4 b/libs/apr/build/apr_hints.m4 index a7011db555..1347653659 100644 --- a/libs/apr/build/apr_hints.m4 +++ b/libs/apr/build/apr_hints.m4 @@ -326,7 +326,7 @@ dnl # Not a problem in 10.20. Otherwise, who knows? ;; *convex-v11*) APR_ADDTO(CPPFLAGS, [-DCONVEXOS11]) - APR_SETIFNULL(CFLAGS, [-O0]) + APR_SETIFNULL(CFLAGS, [-O1]) APR_ADDTO(CFLAGS, [-ext]) ;; i860-intel-osf1) diff --git a/libs/apr/configure.in b/libs/apr/configure.in index a1d375d768..68c030e124 100644 --- a/libs/apr/configure.in +++ b/libs/apr/configure.in @@ -239,7 +239,7 @@ nl=' ' echo "${nl}Check for compiler flags..." -dnl AC_PROG_CC sets -g in CFLAGS (and -O0 for gcc) by default. +dnl AC_PROG_CC sets -g in CFLAGS (and -O2 for gcc) by default. dnl On OS/390 this causes the compiler to insert extra debugger dnl hook instructions. That's fine for debug/maintainer builds, not fine dnl otherwise. @@ -287,8 +287,8 @@ AC_ARG_ENABLE(profile,[ --enable-profile Turn on profiling for the build APR_ADDTO(CFLAGS, -pg) APR_REMOVEFROM(CFLAGS, -g) if test "$host" = "i586-pc-beos"; then - APR_REMOVEFROM(CFLAGS, -O0) - APR_ADDTO(CFLAGS, -O0) + APR_REMOVEFROM(CFLAGS, -O2) + APR_ADDTO(CFLAGS, -O1) APR_ADDTO(LDFLAGS, -p) fi fi @@ -340,7 +340,7 @@ AC_ARG_ENABLE(pool-debug, if test "$host" = "i586-pc-beos"; then AC_ARG_ENABLE(malloc-debug,[ --enable-malloc-debug Switch on malloc_debug for BeOS], - APR_REMOVEFROM(CFLAGS, -O0) + APR_REMOVEFROM(CFLAGS, -O2) APR_ADDTO(CPPFLAGS, -fcheck-memory-usage -D_KERNEL_MODE) ) dnl fi diff --git a/libs/broadvoice/configure.ac b/libs/broadvoice/configure.ac index 10d279ed8a..ceb92a57cb 100644 --- a/libs/broadvoice/configure.ac +++ b/libs/broadvoice/configure.ac @@ -71,9 +71,9 @@ then CC_FOR_BUILD=${CC_FOR_BUILD-gcc} CPPFLAGS_FOR_BUILD="\$(CPPFLAGS)" CC=${CC-${host_alias}-gcc} - CFLAGS=${CFLAGS-"-g -O0"} + CFLAGS=${CFLAGS-"-g -O2"} CXX=${CXX-${host_alias}-c++} - CXXFLAGS=${CXXFLAGS-"-g -O0"} + CXXFLAGS=${CXXFLAGS-"-g -O2"} else # Set reasonable default values for some tools even if not Canadian. # Of course, these are different reasonable default values, originally @@ -108,8 +108,8 @@ else fi CXX=${CXX-"c++"} - CFLAGS=${CFLAGS-"-g -O0"} - CXXFLAGS=${CXXFLAGS-"-g -O0"} + CFLAGS=${CFLAGS-"-g -O2"} + CXXFLAGS=${CXXFLAGS-"-g -O2"} fi AC_DEFUN([REMOVE_FROM_VAR],[ diff --git a/libs/broadvoice/debian/rules b/libs/broadvoice/debian/rules index b4f11d6876..636e1b42ae 100644 --- a/libs/broadvoice/debian/rules +++ b/libs/broadvoice/debian/rules @@ -21,7 +21,7 @@ CFLAGS = -Wall -g ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) CFLAGS += -O0 else - CFLAGS += -O0 + CFLAGS += -O2 endif include /usr/share/dpatch/dpatch.make diff --git a/libs/curl/lib/Makefile.b32 b/libs/curl/lib/Makefile.b32 index 97c27ddf12..4544d7e7be 100644 --- a/libs/curl/lib/Makefile.b32 +++ b/libs/curl/lib/Makefile.b32 @@ -35,7 +35,7 @@ RM = del LIB = tlib IMPLIB = implib -CXXFLAGS = -q -5 -O0 -w-aus -w-ccc -w-csu -w-par -w-pia -w-rch -w-inl -w-ngu -w-pro -tWM +CXXFLAGS = -q -5 -O2 -w-aus -w-ccc -w-csu -w-par -w-pia -w-rch -w-inl -w-ngu -w-pro -tWM LIBFLAGS = /C /P32 LDFLAGS = -q -lq -laa -tWD diff --git a/libs/curl/lib/Makefile.m32 b/libs/curl/lib/Makefile.m32 index 1e7977f24c..77085c6b08 100644 --- a/libs/curl/lib/Makefile.m32 +++ b/libs/curl/lib/Makefile.m32 @@ -26,7 +26,7 @@ STRIP = strip -g ## Nothing more to do below this line! INCLUDES = -I. -I../include -CFLAGS = -g -O0 -DMINGW32 -DBUILDING_LIBCURL -DHAVE_LONGLONG +CFLAGS = -g -O2 -DMINGW32 -DBUILDING_LIBCURL -DHAVE_LONGLONG ifdef SSL INCLUDES += -I"$(OPENSSL_PATH)/outinc" -I"$(OPENSSL_PATH)/outinc/openssl" CFLAGS += -DUSE_SSLEAY -DUSE_OPENSSL -DHAVE_OPENSSL_ENGINE_H -DHAVE_OPENSSL_PKCS12_H \ diff --git a/libs/curl/src/Makefile.b32 b/libs/curl/src/Makefile.b32 index b7ad61733a..d4c1a073c9 100644 --- a/libs/curl/src/Makefile.b32 +++ b/libs/curl/src/Makefile.b32 @@ -32,7 +32,7 @@ CP = copy RM = del LIB = tlib -CXXFLAGS = -q -5 -O0 -w-aus -w-ccc -w-csu -w-par -w-pia -w-rch -w-inl -w-ngu -w-pro -tWM +CXXFLAGS = -q -5 -O2 -w-aus -w-ccc -w-csu -w-par -w-pia -w-rch -w-inl -w-ngu -w-pro -tWM LDFLAGS = -q -lq -lap INCDIRS = -I.;../include;../lib diff --git a/libs/curl/src/makefile.amiga b/libs/curl/src/makefile.amiga index 15234d422c..9e03e070f0 100755 --- a/libs/curl/src/makefile.amiga +++ b/libs/curl/src/makefile.amiga @@ -8,7 +8,7 @@ ATCPSDKI= /GG/netinclude CC = m68k-amigaos-gcc -CFLAGS = -I$(ATCPSDKI) -m68020-60 -O0 -msoft-float -noixemul -g -I. -I../include -W -Wall +CFLAGS = -I$(ATCPSDKI) -m68020-60 -O2 -msoft-float -noixemul -g -I. -I../include -W -Wall LIBS = ../lib/libcurl.a -lssl -lcrypto -lz MANPAGE = ../docs/curl.1 README = ../docs/MANUAL diff --git a/libs/js/nsprpub/configure.in b/libs/js/nsprpub/configure.in index b3fcffe60c..93d3bd9f85 100644 --- a/libs/js/nsprpub/configure.in +++ b/libs/js/nsprpub/configure.in @@ -62,7 +62,7 @@ USE_CPLUS= USE_IPV6= USE_MDUPDATE= _MACOSX_DEPLOYMENT_TARGET= -_OPTIMIZE_FLAGS=-O0 +_OPTIMIZE_FLAGS=-O _DEBUG_FLAGS=-g MOZ_DEBUG=1 MOZ_OPTIMIZE= @@ -176,7 +176,7 @@ AC_ARG_WITH(mozilla, fi]) AC_ARG_ENABLE(optimize, - [ --enable-optimize(=val) Enable code optimizations (val, ie. -O0) ], + [ --enable-optimize(=val) Enable code optimizations (val, ie. -O2) ], [ if test "$enableval" != "no"; then MOZ_OPTIMIZE=1 if test -n "$enableval" && test "$enableval" != "yes"; then @@ -887,7 +887,7 @@ case "$target" in RESOLVE_LINK_SYMBOLS=1 case "${target_cpu}" in i*86) - _OPTIMIZE_FLAGS=-O0 + _OPTIMIZE_FLAGS=-O2 _DEBUG_FLAGS='-gdwarf-2 -O0' MKSHLIB='$(CCC) $(DSO_LDOPTS) -o $@' AC_CHECK_LIB(bind, gethostbyaddr, [OS_LIBS="$OS_LIBS -lbind -lsocket"]) @@ -897,7 +897,7 @@ case "$target" in CCC=mwcc LD=mwld DSO_LDOPTS='-xms -export pragma -init _init_routine_ -term _term_routine_ -lroot -lnet /boot/develop/lib/ppc/glue-noinit.a /boot/develop/lib/ppc/init_term_dyn.o /boot/develop/lib/ppc/start_dyn.o' - _OPTIMIZE_FLAGS=-O0 + _OPTIMIZE_FLAGS=-O2 _DEBUG_FLAGS='-g -O0' ;; esac @@ -1115,7 +1115,7 @@ tools are selected during the Xcode/Developer Tools installation.]) AC_DEFINE(_DGUX_SOURCE) AC_DEFINE(_POSIX4A_DRAFT6_SOURCE) DSO_LDOPTS=-G - _OPTIMIZE_FLAGS=-O0 + _OPTIMIZE_FLAGS=-O2 _DEBUG_FLAGS= MDCPUCFG_H=_dgux.cfg PR_MD_CSRCS=dgux.c @@ -1334,7 +1334,7 @@ tools are selected during the Xcode/Developer Tools installation.]) dnl AS='$(CC) -Wp,-P -x assembler-with-cpp -D_ASM -mips2 $(INCLUDES)' CFLAGS="$CFLAGS -Wall -Wno-format" - _OPTIMIZE_FLAGS="-O0" + _OPTIMIZE_FLAGS="-O6" else if test -n "$USE_N32"; then AS='as -D_ASM $(INCLUDES) -n32' @@ -1408,7 +1408,7 @@ tools are selected during the Xcode/Developer Tools installation.]) MKSHLIB='$(CC) $(DSO_LDOPTS) $(OS_LDFLAGS) -o $@' DSO_CFLAGS=-fPIC DSO_LDOPTS='-shared -Wl,-soname -Wl,$(notdir $@)' - _OPTIMIZE_FLAGS=-O0 + _OPTIMIZE_FLAGS=-O2 _DEBUG_FLAGS="-g" # most people on linux use gcc/gdb, and that # combo is not yet good at debugging inlined # functions (even when using DWARF2 as the @@ -1485,7 +1485,7 @@ tools are selected during the Xcode/Developer Tools installation.]) CFLAGS="$CFLAGS -W3 -nologo -GF -Gy" DLLFLAGS='-OUT:"$@"' _DEBUG_FLAGS=-Z7 - _OPTIMIZE_FLAGS=-O0 + _OPTIMIZE_FLAGS=-O2 if test -z "$MOZ_OPTIMIZE"; then CFLAGS="$CFLAGS -Od" fi @@ -1724,7 +1724,7 @@ mips-sony-newsos*) DSO_CFLAGS=-fPIC DSO_LDOPTS=-shared OS_LIBS="$OS_LIBS -lsocket" - _OPTIMIZE_FLAGS="-O0" + _OPTIMIZE_FLAGS="-O1" _DEBUG_FLAGS="-gstabs" ;; @@ -2082,7 +2082,7 @@ mips-sony-newsos*) DSO_CFLAGS= DSO_LDOPTS='-Zomf -Zdll -Zmap' LDFLAGS='-Zmap' - _OPTIMIZE_FLAGS="-O0 -s" + _OPTIMIZE_FLAGS="-O2 -s" _DEBUG_FLAGS="-g -fno-inline" if test -n "$MOZ_OPTIMIZE"; then DSO_LDOPTS="$DSO_LDOPTS -Zlinker /EXEPACK:2 -Zlinker /PACKCODE -Zlinker /PACKDATA" diff --git a/libs/libg722_1/configure.ac b/libs/libg722_1/configure.ac index e5385d4091..62095ce374 100644 --- a/libs/libg722_1/configure.ac +++ b/libs/libg722_1/configure.ac @@ -64,9 +64,9 @@ then CC_FOR_BUILD=${CC_FOR_BUILD-gcc} CPPFLAGS_FOR_BUILD="\$(CPPFLAGS)" CC=${CC-${host_alias}-gcc} - CFLAGS=${CFLAGS-"-g -O0"} + CFLAGS=${CFLAGS-"-g -O2"} CXX=${CXX-${host_alias}-c++} - CXXFLAGS=${CXXFLAGS-"-g -O0"} + CXXFLAGS=${CXXFLAGS-"-g -O2"} else # Set reasonable default values for some tools even if not Canadian. # Of course, these are different reasonable default values, originally @@ -101,8 +101,8 @@ else fi CXX=${CXX-"c++"} - CFLAGS=${CFLAGS-"-g -O0"} - CXXFLAGS=${CXXFLAGS-"-g -O0"} + CFLAGS=${CFLAGS-"-g -O2"} + CXXFLAGS=${CXXFLAGS-"-g -O2"} fi AC_DEFUN([REMOVE_FROM_VAR],[ diff --git a/libs/libsndfile/INSTALL b/libs/libsndfile/INSTALL index d520a54b6b..b42a17ac46 100644 --- a/libs/libsndfile/INSTALL +++ b/libs/libsndfile/INSTALL @@ -59,7 +59,7 @@ the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: - CC=c89 CFLAGS=-O0 LIBS=-lposix ./configure + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure diff --git a/libs/pcre/configure.ac b/libs/pcre/configure.ac index 7bf7c95b35..b6f79f98cf 100644 --- a/libs/pcre/configure.ac +++ b/libs/pcre/configure.ac @@ -26,7 +26,7 @@ CFLAGS="$CFLAGS $CONFIGURE_CFLAGS" CXXFLAGS="$CXXFLAGS $CONFIGURE_CXXFLAGS" LDFLAGS="$LDFLAGS $CONFIGURE_LDFLAGS" -# The default CFLAGS and CXXFLAGS in Autoconf are "-g -O0" for gcc and just +# The default CFLAGS and CXXFLAGS in Autoconf are "-g -O2" for gcc and just # "-g" for any other compiler. There doesn't seem to be a standard way of # getting rid of the -g (which I don't think is needed for a production # library). This fudge seems to achieve the necessary. First, we remember the @@ -44,9 +44,9 @@ AC_PROG_CXX if test "x$remember_set_CFLAGS" = "x" then - if test "$CFLAGS" = "-g -O0" + if test "$CFLAGS" = "-g -O2" then - CFLAGS="-O0" + CFLAGS="-O2" elif test "$CFLAGS" = "-g" then CFLAGS="" @@ -55,9 +55,9 @@ fi if test "x$remember_set_CXXFLAGS" = "x" then - if test "$CXXFLAGS" = "-g -O0" + if test "$CXXFLAGS" = "-g -O2" then - CXXFLAGS="-O0" + CXXFLAGS="-O2" elif test "$CXXFLAGS" = "-g" then CXXFLAGS="" diff --git a/libs/portaudio/Makefile.darwin b/libs/portaudio/Makefile.darwin index 0d37963f04..9aec51de24 100644 --- a/libs/portaudio/Makefile.darwin +++ b/libs/portaudio/Makefile.darwin @@ -11,7 +11,7 @@ top_srcdir = . srcdir = . top_builddir = . -OPT_LEVEL := -O0 +OPT_LEVEL := -O2 PREFIX = /usr/local prefix = $(PREFIX) exec_prefix = ${prefix} diff --git a/libs/portaudio/SConstruct b/libs/portaudio/SConstruct index 3c4bca0df7..15d36bad57 100644 --- a/libs/portaudio/SConstruct +++ b/libs/portaudio/SConstruct @@ -39,7 +39,7 @@ if Platform in Posix: baseLinkFlags = threadCFlags = "-pthread" baseCxxFlags = baseCFlags = "-Wall -pedantic -pipe " + threadCFlags debugCxxFlags = debugCFlags = "-g" - optCxxFlags = optCFlags = "-O0" + optCxxFlags = optCFlags = "-O2" env["CCFLAGS"] = baseCFlags.split() env["CXXFLAGS"] = baseCxxFlags.split() env["LINKFLAGS"] = baseLinkFlags.split() diff --git a/libs/portaudio/bindings/cpp/build/gnu/configure b/libs/portaudio/bindings/cpp/build/gnu/configure index e91013c07c..69070c66d4 100644 --- a/libs/portaudio/bindings/cpp/build/gnu/configure +++ b/libs/portaudio/bindings/cpp/build/gnu/configure @@ -1263,7 +1263,7 @@ PORTAUDIO="$PACPP_ROOT/../portaudio" PACPP_INC="$PACPP_ROOT/include" INCLUDES="-I$PACPP_INC -I$PORTAUDIO -I$PORTAUDIO/pa_common" -CFLAGS="-g -O0 -Wall -ansi -pedantic $INCLUDES" +CFLAGS="-g -O2 -Wall -ansi -pedantic $INCLUDES" CXXFLAGS="$CFLAGS" PALIBDIR="$PORTAUDIO/lib" @@ -1908,13 +1908,13 @@ if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then - CFLAGS="-g -O0" + CFLAGS="-g -O2" else - CFLAGS="-g -O0" + CFLAGS="-g" fi else if test "$GCC" = yes; then - CFLAGS="-O0" + CFLAGS="-O2" else CFLAGS= fi @@ -2350,13 +2350,13 @@ if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then - CXXFLAGS="-g -O0" + CXXFLAGS="-g -O2" else - CXXFLAGS="-g -O0" + CXXFLAGS="-g" fi else if test "$GXX" = yes; then - CXXFLAGS="-O0" + CXXFLAGS="-O2" else CXXFLAGS= fi diff --git a/libs/portaudio/bindings/cpp/build/gnu/configure.ac b/libs/portaudio/bindings/cpp/build/gnu/configure.ac index 071a7e94ef..5457c53420 100644 --- a/libs/portaudio/bindings/cpp/build/gnu/configure.ac +++ b/libs/portaudio/bindings/cpp/build/gnu/configure.ac @@ -24,7 +24,7 @@ PORTAUDIO="$PACPP_ROOT/../portaudio" PACPP_INC="$PACPP_ROOT/include" INCLUDES="-I$PACPP_INC -I$PORTAUDIO -I$PORTAUDIO/pa_common" -CFLAGS="-g -O0 -Wall -ansi -pedantic $INCLUDES" +CFLAGS="-g -O2 -Wall -ansi -pedantic $INCLUDES" CXXFLAGS="$CFLAGS" PALIBDIR="$PORTAUDIO/lib" diff --git a/libs/portaudio/bindings/cpp/configure.ac b/libs/portaudio/bindings/cpp/configure.ac index 94baff8fc3..100656ac41 100644 --- a/libs/portaudio/bindings/cpp/configure.ac +++ b/libs/portaudio/bindings/cpp/configure.ac @@ -25,7 +25,7 @@ PORTAUDIO_ROOT="../.." # Various other variables and flags DEFAULT_INCLUDES="-I$PACPP_ROOT/include -I$PACPP_ROOT/$PORTAUDIO_ROOT/include" -CFLAGS=${CFLAGS-"-g -O0 -Wall -ansi -pedantic"} +CFLAGS=${CFLAGS-"-g -O2 -Wall -ansi -pedantic"} CXXFLAGS=${CXXFLAGS-"${CFLAGS}"} LT_VERSION_INFO="lt_current:lt_revision:lt_age" diff --git a/libs/portaudio/build/dev-cpp/Makefile-static b/libs/portaudio/build/dev-cpp/Makefile-static index 65fcb5dacf..2a1647ddc5 100644 --- a/libs/portaudio/build/dev-cpp/Makefile-static +++ b/libs/portaudio/build/dev-cpp/Makefile-static @@ -7,12 +7,12 @@ WINDRES = windres.exe RES = OBJ = ./pa_skeleton.o ./pa_stream.o ./pa_trace.o ./pa_allocation.o ./pa_converters.o ./pa_cpuload.o ./pa_dither.o ./pa_front.o ./pa_process.o ./pa_asio.o ./pa_win_util.o ./pa_win_hostapis.o ./pa_win_ds.o ./dsound_wrapper.o ./pa_win_wmme.o ./iasiothiscallresolver.o $(RES) LINKOBJ = ./pa_skeleton.o ./pa_stream.o ./pa_trace.o ./pa_allocation.o ./pa_converters.o ./pa_cpuload.o ./pa_dither.o ./pa_front.o ./pa_process.o ./pa_asio.o ./pa_win_util.o ./pa_win_hostapis.o ./pa_win_ds.o ./dsound_wrapper.o ./pa_win_wmme.o ./iasiothiscallresolver.o $(RES) -LIBS = -L"C:/Dev-CPP/lib" -fmessage-length=0 -O0 -s +LIBS = -L"C:/Dev-CPP/lib" -fmessage-length=0 -O3 -s INCS = -I"C:/Dev-CPP/include" -I"../../../asiosdk2" -I"../../../asiosdk2/common" -I"../../../asiosdk2/host" -I"../../../asiosdk2/host/pc" -I"../../pa_common" CXXINCS = -I"C:/Dev-CPP/include/c++" -I"C:/Dev-CPP/include/c++/mingw32" -I"C:/Dev-CPP/include/c++/backward" -I"C:/Dev-CPP/include" -I"../../../asiosdk2" -I"../../../asiosdk2/common" -I"../../../asiosdk2/host" -I"../../../asiosdk2/host/pc" -I"../../pa_common" BIN = portaudio-static.a -CXXFLAGS = $(CXXINCS)-O0 -fmessage-length=0 -Wall -CFLAGS = $(INCS)-O0 -fmessage-length=0 -Wall +CXXFLAGS = $(CXXINCS)-O3 -fmessage-length=0 -Wall +CFLAGS = $(INCS)-O3 -fmessage-length=0 -Wall .PHONY: all all-before all-after clean clean-custom diff --git a/libs/portaudio/configure.in b/libs/portaudio/configure.in index 24deaf701c..f4ef9abbee 100644 --- a/libs/portaudio/configure.in +++ b/libs/portaudio/configure.in @@ -130,7 +130,7 @@ AC_SUBST(CXXFLAGS) AC_SUBST(NASM) AC_SUBST(NASMOPT) -CFLAGS=${CFLAGS:-"-g -O0 -Wall -pedantic -pipe -fPIC"} +CFLAGS=${CFLAGS:-"-g -O2 -Wall -pedantic -pipe -fPIC"} if [[ $ac_cv_c_bigendian = "yes" ]] ; then CFLAGS="$CFLAGS -DPA_BIG_ENDIAN" diff --git a/libs/sqlite/Makefile.linux-gcc b/libs/sqlite/Makefile.linux-gcc index e3a3d385dd..c865024b44 100644 --- a/libs/sqlite/Makefile.linux-gcc +++ b/libs/sqlite/Makefile.linux-gcc @@ -19,7 +19,7 @@ TOP = ../sqlite #### C Compiler and options for use in building executables that # will run on the platform that is doing the build. # -BCC = gcc -g -O0 +BCC = gcc -g -O2 #BCC = /opt/ancic/bin/c89 -0 #### If the target operating system supports the "usleep()" system @@ -70,10 +70,10 @@ EXE = # will run on the target platform. This is usually the same # as BCC, unless you are cross-compiling. # -TCC = gcc -O0 +TCC = gcc -O6 #TCC = gcc -g -O0 -Wall #TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage -#TCC = /opt/mingw/bin/i386-mingw32-gcc -O0 +#TCC = /opt/mingw/bin/i386-mingw32-gcc -O6 #TCC = /opt/ansic/bin/c89 -O +z -Wl,-a,archive #### Tools used to build a static library. diff --git a/libs/sqlite/mkso.sh b/libs/sqlite/mkso.sh index d6afb0198d..9050d74255 100755 --- a/libs/sqlite/mkso.sh +++ b/libs/sqlite/mkso.sh @@ -14,7 +14,7 @@ TCLSTUBLIB=$TCLDIR/libtclstub8.4g.a OPTS='-DUSE_TCL_STUBS=1 -DNDEBUG=1 -DHAVE_DLOPEN=1' for i in *.c; do if test $i != 'keywordhash.c'; then - CMD="cc -fPIC $OPTS -O0 -I. -I$TCLDIR -c $i" + CMD="cc -fPIC $OPTS -O2 -I. -I$TCLDIR -c $i" echo $CMD $CMD fi diff --git a/libs/sqlite/publish.sh b/libs/sqlite/publish.sh index 68d7c7f6e8..043c89a039 100755 --- a/libs/sqlite/publish.sh +++ b/libs/sqlite/publish.sh @@ -66,7 +66,7 @@ make target_source cd tsrc rm tclsqlite.c OPTS='-DSTATIC_BUILD=1 -DNDEBUG=1' -i386-mingw32msvc-gcc -O0 $OPTS -I. -I$TCLDIR *.c -o sqlite3.exe +i386-mingw32msvc-gcc -O2 $OPTS -I. -I$TCLDIR *.c -o sqlite3.exe zip ../doc/sqlite-$VERSW.zip sqlite3.exe cd .. diff --git a/libs/srtp/INSTALL b/libs/srtp/INSTALL index 7d2c51bb9d..23e5f25d0e 100644 --- a/libs/srtp/INSTALL +++ b/libs/srtp/INSTALL @@ -78,7 +78,7 @@ details on some of the pertinent environment variables. by setting variables in the command line or in the environment. Here is an example: - ./configure CC=c89 CFLAGS=-O0 LIBS=-lposix + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. diff --git a/libs/srtp/build/config/ax_cc_maxopt.m4 b/libs/srtp/build/config/ax_cc_maxopt.m4 index 40bb95c8b7..6205ee84c8 100644 --- a/libs/srtp/build/config/ax_cc_maxopt.m4 +++ b/libs/srtp/build/config/ax_cc_maxopt.m4 @@ -10,7 +10,7 @@ AC_ARG_ENABLE(portable-binary, [AC_HELP_STRING([--enable-portable-binary], [disa if test "$ac_test_CFLAGS" != "set"; then CFLAGS="" case $ax_cv_c_compiler_vendor in - dec) CFLAGS="-newc -w0 -O0 -ansi_alias -ansi_args -fp_reorder -tune host" + dec) CFLAGS="-newc -w0 -O5 -ansi_alias -ansi_args -fp_reorder -tune host" if test "x$acx_maxopt_portable" = xno; then CFLAGS="$CFLAGS -arch host" fi;; @@ -31,13 +31,13 @@ if test "$ac_test_CFLAGS" != "set"; then xlc_opt="-qtune=auto" fi AX_CHECK_COMPILER_FLAGS($xlc_opt, - CFLAGS="-O0 -qansialias -w $xlc_opt", - [CFLAGS="-O0 -qansialias -w" + CFLAGS="-O3 -qansialias -w $xlc_opt", + [CFLAGS="-O3 -qansialias -w" echo "******************************************************" echo "* You seem to have the IBM C compiler. It is *" echo "* recommended for best performance that you use: *" echo "* *" - echo "* CFLAGS=-O0 -qarch=xxx -qtune=xxx -qansialias -w *" + echo "* CFLAGS=-O3 -qarch=xxx -qtune=xxx -qansialias -w *" echo "* ^^^ ^^^ *" echo "* where xxx is pwr2, pwr3, 604, or whatever kind of *" echo "* CPU you have. (Set the CFLAGS environment var. *" @@ -45,7 +45,7 @@ if test "$ac_test_CFLAGS" != "set"; then echo "******************************************************"]) ;; - intel) CFLAGS="-O0 -ansi_alias" + intel) CFLAGS="-O3 -ansi_alias" if test "x$acx_maxopt_portable" = xno; then icc_archflag=unknown icc_flags="" @@ -78,7 +78,7 @@ if test "$ac_test_CFLAGS" != "set"; then gnu) # default optimization flags for gcc on all systems - CFLAGS="-O0 -fomit-frame-pointer" + CFLAGS="-O3 -fomit-frame-pointer" # -malign-double for x86 systems AX_CHECK_COMPILER_FLAGS(-malign-double, CFLAGS="$CFLAGS -malign-double") @@ -99,10 +99,10 @@ if test "$ac_test_CFLAGS" != "set"; then echo "********************************************************" echo "* WARNING: Don't know the best CFLAGS for this system *" echo "* Use ./configure CFLAGS=... to specify your own flags *" - echo "* (otherwise, a default of CFLAGS=-O0 will be used) *" + echo "* (otherwise, a default of CFLAGS=-O3 will be used) *" echo "********************************************************" echo "" - CFLAGS="-O0" + CFLAGS="-O3" fi AX_CHECK_COMPILER_FLAGS($CFLAGS, [], [ diff --git a/libs/srtp/configure.in b/libs/srtp/configure.in index 8584be880e..2495a55f95 100644 --- a/libs/srtp/configure.in +++ b/libs/srtp/configure.in @@ -49,7 +49,7 @@ case "$host" in IN_LINE="" elif test "x${ax_cv_c_compiler_vendor}" = "xgnu" ; then SOLINK="-Bdynamic -dy -G" - new_AM_CFLAGS="-fPIC -Wall -O0 -fexpensive-optimizations -funroll-loops" + new_AM_CFLAGS="-fPIC -Wall -O4 -fexpensive-optimizations -funroll-loops" new_AM_LDFLAGS="" IN_LINE=inline fi @@ -71,7 +71,7 @@ case "$host" in FUNC_DEF=__func__ elif test "x${ax_cv_c_compiler_vendor}"="xgnu" ; then SOLINK="-shared -Xlinker -x" - new_AM_CFLAGS="-fPIC -Wall -O0 -fexpensive-optimizations -funroll-loops" + new_AM_CFLAGS="-fPIC -Wall -O4 -fexpensive-optimizations -funroll-loops" new_AM_LDFLAGS="" fi DYNAMIC_LIB_EXTEN="so" @@ -84,20 +84,20 @@ case "$host" in FUNC_DEF=__func__ elif test "x${ax_cv_c_compiler_vendor}"="xgnu" ; then SOLINK="-shared -Xlinker -x" - new_AM_CFLAGS="-fpic -Wall -O0 -fexpensive-optimizations -funroll-loops" + new_AM_CFLAGS="-fpic -Wall -O4 -fexpensive-optimizations -funroll-loops" new_AM_LDFLAGS="" fi DYNAMIC_LIB_EXTEN="so" ;; i*6*-*-freebsd*) SOLINK="-shared -Xlinker -x" - new_AM_CFLAGS="-fPIC -Wall -O0 -fexpensive-optimizations -funroll-loops" + new_AM_CFLAGS="-fPIC -Wall -O4 -fexpensive-optimizations -funroll-loops" new_AM_LDFLAGS="" DYNAMIC_LIB_EXTEN="so" ;; x86_64-*-freebsd*|amd64-*-freebsd*) SOLINK="-shared -Xlinker -x" - new_AM_CFLAGS="-fPIC -Wall -O0 -fexpensive-optimizations -funroll-loops" + new_AM_CFLAGS="-fPIC -Wall -O4 -fexpensive-optimizations -funroll-loops" new_AM_LDFLAGS="" DYNAMIC_LIB_EXTEN="so" ;; diff --git a/libs/yaml/aclocal.m4 b/libs/yaml/aclocal.m4 index ba1ed63878..b7984f0f01 100644 --- a/libs/yaml/aclocal.m4 +++ b/libs/yaml/aclocal.m4 @@ -6311,7 +6311,7 @@ ifelse([AC_DISABLE_FAST_INSTALL]) AC_DEFUN([LT_AC_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj, no) - test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O0" + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS) ]) diff --git a/libs/yaml/configure b/libs/yaml/configure index f66fa4972c..66e708215a 100755 --- a/libs/yaml/configure +++ b/libs/yaml/configure @@ -3222,13 +3222,13 @@ if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then - CFLAGS="-g -O0" + CFLAGS="-g -O2" else - CFLAGS="-g -O0" + CFLAGS="-g" fi else if test "$GCC" = yes; then - CFLAGS="-O0" + CFLAGS="-O2" else CFLAGS= fi @@ -5579,13 +5579,13 @@ if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then - CXXFLAGS="-g -O0" + CXXFLAGS="-g -O2" else - CXXFLAGS="-g -O0" + CXXFLAGS="-g" fi else if test "$GXX" = yes; then - CXXFLAGS="-O0" + CXXFLAGS="-O2" else CXXFLAGS= fi @@ -6180,13 +6180,13 @@ if test "$ac_test_FFLAGS" = set; then FFLAGS=$ac_save_FFLAGS elif test $ac_cv_prog_f77_g = yes; then if test "x$ac_cv_f77_compiler_gnu" = xyes; then - FFLAGS="-g -O0" + FFLAGS="-g -O2" else - FFLAGS="-g -O0" + FFLAGS="-g" fi else if test "x$ac_cv_f77_compiler_gnu" = xyes; then - FFLAGS="-O0" + FFLAGS="-O2" else FFLAGS= fi diff --git a/src/mod/applications/mod_avmd/Makefile b/src/mod/applications/mod_avmd/Makefile index fbf7ccb023..c4a62d4120 100644 --- a/src/mod/applications/mod_avmd/Makefile +++ b/src/mod/applications/mod_avmd/Makefile @@ -1,6 +1,6 @@ BASE=../../../.. -MOD_CFLAGS= -O0 -#MOD_CFLAGS= -march=core2 -g -O0 -malign-double -mtune=core2 -mmmx -msse -msse2 -msse3 -mssse3 -mfpmath=sse -ffast-math -funroll-loops -fprefetch-loop-arrays -funit-at-a-time -ftracer --save-temps +MOD_CFLAGS= -O2 +#MOD_CFLAGS= -march=core2 -g -O2 -malign-double -mtune=core2 -mmmx -msse -msse2 -msse3 -mssse3 -mfpmath=sse -ffast-math -funroll-loops -fprefetch-loop-arrays -funit-at-a-time -ftracer --save-temps #MOD_LDFLAGS= --save-temps LOCAL_SOURCES=amplitude.c buffer.c desa2.c goertzel.c fast_acosf.c LOCAL_OBJS=amplitude.o buffer.o desa2.o goertzel.o fast_acosf.o diff --git a/src/mod/endpoints/mod_gsmopen/asterisk/Makefile b/src/mod/endpoints/mod_gsmopen/asterisk/Makefile index f1b2d54450..6aed86266e 100644 --- a/src/mod/endpoints/mod_gsmopen/asterisk/Makefile +++ b/src/mod/endpoints/mod_gsmopen/asterisk/Makefile @@ -33,7 +33,7 @@ CFLAGS+=-g3 CFLAGS+=-I$(AST_INCLUDE_DIR) -I. CFLAGS+=-D_REENTRANT -D_GNU_SOURCE -#CFLAGS+=-O0 +#CFLAGS+=-O6 #CFLAGS+=-march=i586 CFLAGS+=-fomit-frame-pointer ifeq ($(shell uname -m),x86_64) diff --git a/src/mod/endpoints/mod_gsmopen/gsmlib/gsmlib-1.10-patched-12ubuntu1/configure b/src/mod/endpoints/mod_gsmopen/gsmlib/gsmlib-1.10-patched-12ubuntu1/configure index 23bae83868..5918af81fb 100755 --- a/src/mod/endpoints/mod_gsmopen/gsmlib/gsmlib-1.10-patched-12ubuntu1/configure +++ b/src/mod/endpoints/mod_gsmopen/gsmlib/gsmlib-1.10-patched-12ubuntu1/configure @@ -2261,13 +2261,13 @@ if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then - CFLAGS="-g -O0" + CFLAGS="-g -O2" else - CFLAGS="-g -O0" + CFLAGS="-g" fi else if test "$GCC" = yes; then - CFLAGS="-O0" + CFLAGS="-O2" else CFLAGS= fi @@ -3144,7 +3144,7 @@ fi; if test "$CXXFLAGS" = ""; then - CXXFLAGS="-O0" + CXXFLAGS="-O2" fi @@ -4748,13 +4748,13 @@ if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then - CXXFLAGS="-g -O0" + CXXFLAGS="-g -O2" else - CXXFLAGS="-g -O0" + CXXFLAGS="-g" fi else if test "$GXX" = yes; then - CXXFLAGS="-O0" + CXXFLAGS="-O2" else CXXFLAGS= fi @@ -5431,13 +5431,13 @@ if test "$ac_test_FFLAGS" = set; then FFLAGS=$ac_save_FFLAGS elif test $ac_cv_prog_f77_g = yes; then if test "x$ac_cv_f77_compiler_gnu" = xyes; then - FFLAGS="-g -O0" + FFLAGS="-g -O2" else - FFLAGS="-g -O0" + FFLAGS="-g" fi else if test "x$ac_cv_f77_compiler_gnu" = xyes; then - FFLAGS="-O0" + FFLAGS="-O2" else FFLAGS= fi @@ -20153,13 +20153,13 @@ if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then - CXXFLAGS="-g -O0" + CXXFLAGS="-g -O2" else - CXXFLAGS="-g -O0" + CXXFLAGS="-g" fi else if test "$GXX" = yes; then - CXXFLAGS="-O0" + CXXFLAGS="-O2" else CXXFLAGS= fi diff --git a/src/mod/languages/mod_lua/lua/Makefile b/src/mod/languages/mod_lua/lua/Makefile index 4e0b5480d6..e4a3cd6108 100644 --- a/src/mod/languages/mod_lua/lua/Makefile +++ b/src/mod/languages/mod_lua/lua/Makefile @@ -8,7 +8,7 @@ PLAT= none CC= gcc -CFLAGS= -O0 -Wall $(MYCFLAGS) +CFLAGS= -O2 -Wall $(MYCFLAGS) AR= ar rcu RANLIB= ranlib RM= rm -f @@ -81,7 +81,7 @@ none: @echo " $(PLATS)" aix: - $(MAKE) all CC="xlc" CFLAGS="-O0 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" MYLDFLAGS="-brtl -bexpall" + $(MAKE) all CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" MYLDFLAGS="-brtl -bexpall" ansi: $(MAKE) all MYCFLAGS=-DLUA_ANSI From bfefbb55220f48e3c397c8f48c39cfe740cb9325 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Wed, 21 Mar 2012 10:12:59 -0400 Subject: [PATCH 174/822] freetdm: fix isup timers default values --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index ad47f0cbb4..230476d8e1 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -2788,7 +2788,7 @@ static int ftmod_ss7_fill_in_isap(sng_isap_t *sng_isap) if (sng_isap->t1 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t1 = sng_isap->t1; } else { - g_ftdm_sngss7_data.cfg.isap[i].t1 = 200; + g_ftdm_sngss7_data.cfg.isap[i].t1 = 150; } if (sng_isap->t2 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t2 = sng_isap->t2; @@ -2803,17 +2803,17 @@ static int ftmod_ss7_fill_in_isap(sng_isap_t *sng_isap) if (sng_isap->t6 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t6 = sng_isap->t6; } else { - g_ftdm_sngss7_data.cfg.isap[i].t6 = 200; + g_ftdm_sngss7_data.cfg.isap[i].t6 = 600; } if (sng_isap->t7 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t7 = sng_isap->t7; } else { - g_ftdm_sngss7_data.cfg.isap[i].t7 = 250; + g_ftdm_sngss7_data.cfg.isap[i].t7 = 200; } if (sng_isap->t8 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t8 = sng_isap->t8; } else { - g_ftdm_sngss7_data.cfg.isap[i].t8 = 120; + g_ftdm_sngss7_data.cfg.isap[i].t8 = 100; } if (sng_isap->t9 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t9 = sng_isap->t9; From a2db3c24b38eb260bda331f8ec5ae512661b5b5f Mon Sep 17 00:00:00 2001 From: James Zhang Date: Tue, 27 Mar 2012 18:00:24 -0400 Subject: [PATCH 175/822] freetdm: fixing more potential null pointers in native bridge mode. --- .../ftmod_sangoma_ss7_main.c | 45 ++++++++++++------- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 26 ++++++----- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index fe129c0f73..3d30a534cd 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -426,24 +426,33 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) /* note that the channels being dequeued here may not belong to this span they may belong to just about any other span that one of our channels happens to be bridged to */ - sngss7_chan_data_t *peer_info = peerchan->call_data; - sngss7_chan_data_t *chan_info = peer_info->peer_data; - ftdmchan = chan_info->ftdmchan; + sngss7_chan_data_t *peer_info; + sngss7_chan_data_t *chan_info; - /* - if there is any state changes at all, those will be done in the opposite channel - to peerchan (where the original event was received), therefore we must lock ftdmchan, - but do not need to lock peerchan as we only read its event queue, which is already - locked when dequeueing */ - ftdm_channel_lock(ftdmchan); + peer_info = peerchan->call_data; + if (peer_info) { + chan_info = peer_info->peer_data; + if (chan_info) { + ftdmchan = chan_info->ftdmchan; + if (ftdmchan) { - /* clean out all pending stack events in the peer channel */ - while ((sngss7_event = ftdm_queue_dequeue(peer_info->event_queue))) { - ftdm_sangoma_ss7_process_peer_stack_event(ftdmchan, sngss7_event); - ftdm_safe_free(sngss7_event); + /* + if there is any state changes at all, those will be done in the opposite channel + to peerchan (where the original event was received), therefore we must lock ftdmchan, + but do not need to lock peerchan as we only read its event queue, which is already + locked when dequeueing */ + ftdm_channel_lock(ftdmchan); + + /* clean out all pending stack events in the peer channel */ + while ((sngss7_event = ftdm_queue_dequeue(peer_info->event_queue))) { + ftdm_sangoma_ss7_process_peer_stack_event(ftdmchan, sngss7_event); + ftdm_safe_free(sngss7_event); + } + + ftdm_channel_unlock(ftdmchan); + } + } } - - ftdm_channel_unlock(ftdmchan); } /* clean out all pending stack events */ @@ -1519,9 +1528,11 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) */ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { sngss7_chan_data_t *peer_info = sngss7_info->peer_data; - sngss7_info->peer_data = NULL; if (peer_info) { - peer_info->peer_data = NULL; + sngss7_info->peer_data = NULL; + if (peer_info) { + peer_info->peer_data = NULL; + } } } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index 5f0a0f0960..c44c7bd7b2 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -72,21 +72,23 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) var, peer_span->signal_type); } else { peer_info = peer_chan->call_data; - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Starting native bridge with peer CIC %d\n", - sngss7_info->circuit->cic, peer_info->circuit->cic); + if (peer_info) { + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Starting native bridge with peer CIC %d\n", + sngss7_info->circuit->cic, peer_info->circuit->cic); - /* make each one of us aware of the native bridge */ - peer_info->peer_data = sngss7_info; - sngss7_info->peer_data = peer_info; + /* make each one of us aware of the native bridge */ + peer_info->peer_data = sngss7_info; + sngss7_info->peer_data = peer_info; - /* flush our own queue */ - sngss7_flush_queue(sngss7_info->event_queue); + /* flush our own queue */ + sngss7_flush_queue(sngss7_info->event_queue); - /* Go to up until release comes, note that state processing is done different and much simpler when there is a peer, - We can't go to UP state right away yet though, so do not set the state to UP here, wait until the end of this function - because moving from one state to another causes the ftdmchan->usrmsg structure to be wiped - and we still need those variables for further IAM processing */ - native_going_up = FTDM_TRUE; + /* Go to up until release comes, note that state processing is done different and much simpler when there is a peer, + We can't go to UP state right away yet though, so do not set the state to UP here, wait until the end of this function + because moving from one state to another causes the ftdmchan->usrmsg structure to be wiped + and we still need those variables for further IAM processing */ + native_going_up = FTDM_TRUE; + } } } } From 8a589435de7b8656bd18a1a10ff66529380b7f09 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Fri, 30 Mar 2012 16:50:00 -0400 Subject: [PATCH 176/822] freetdm: Adding condition to parse sip headers only for non-freetdm channels. This fixes an issue where ss7 native bridge was accidentally enabled any time two freetdm channels were bridged regardless of the freetdm_native_sigbridge variable value. --- libs/freetdm/mod_freetdm/mod_freetdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index c3e5c486db..6a32098b44 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1349,7 +1349,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi chan_id = 0; } - if (session && globals.sip_headers) { + if (session && globals.sip_headers && !switch_core_session_check_interface (session,freetdm_endpoint_interface) ) { switch_channel_t *channel = switch_core_session_get_channel(session); const char *sipvar; From b324f8679782957bc9db3bdfd6687aa42cba77dd Mon Sep 17 00:00:00 2001 From: James Zhang Date: Tue, 3 Apr 2012 11:23:49 -0400 Subject: [PATCH 177/822] freetdm: Clean up SS7 native bridge code to separate the call control, queuing and resource-cleanup responsibilities clearly between the 2 channels involved in the bridge - Each channel is responsible for clearning its own peer_data and event queue at the end of the call (when moving to DOWN state) - Each channel dequeues messages only from its own queue and enqueues messages in the peer's queue, with the only exception being messages received before the bridge is stablished (IAM for sure and possible SAM messages) because if the bridge is not yet stablished the messages must be queued by the channel in its own queue temporarily until the bridge is ready - When the bridge is ready it is the responsibility of the incoming channel to move the messages that stored temporarily in its own queue to the bridged peer queue - During hangup, each channel is responsible for moving itself to DOWN. The procedure however differs slightly depending on the hangup conditions If the user requests hangup (ie, FreeSWITCH) the request will be noted by setting the FTDM_CHANNEL_USER_HANGUP flag but will not be processed yet because call control is driven only by the link messages (so no hangup from ESL or command line allowed) When REL message comes, the channel receiving it must move to TERMINATING state and: - If the user has not hangup yet (FTDM_CHANNEL_USER_HANGUP flag not set) then notify the user via SIGEVENT_STOP and wait for the user to move to HANGUP state by calling ftdm_channel_call_hangup() before sending RLC - If the user did hangup already (FTDM_CHANNEL_USER_HANGUP flag is set) then skip user notification and move to HANGUP state directly where the RLC message will be sent - On HANGUP state the RLC is sent and the channel is moved to DOWN, final state The peer channel will forward the REL message and wait for RLC from the network, when RLC is received the channel can move straight to DOWN itself because the peer channel is completing its own shutdown procedure when it received the REL message --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c | 1 + .../ftmod_sangoma_ss7_main.c | 163 +++++++----------- .../ftmod_sangoma_ss7_main.h | 6 +- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 41 ++--- 4 files changed, 88 insertions(+), 123 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c index b13c98b1e6..92931c4b8d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c @@ -81,6 +81,7 @@ void sngss7_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiCo /* initalize the sngss7_event */ sngss7_event = ftdm_malloc(sizeof(*sngss7_event)); + if (sngss7_event == NULL) { SS7_ERROR("Failed to allocate memory for sngss7_event!\n"); SS7_FUNC_TRACE_EXIT(__FUNCTION__); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 3d30a534cd..76266f0d53 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -340,10 +340,9 @@ static void handle_hw_alarm(ftdm_event_t *e) /* MONITIOR THREADS ***********************************************************/ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) { - ftdm_interrupt_t *ftdm_sangoma_ss7_int[3]; + ftdm_interrupt_t *ftdm_sangoma_ss7_int[2]; ftdm_span_t *ftdmspan = (ftdm_span_t *) obj; ftdm_channel_t *ftdmchan = NULL; - ftdm_channel_t *peerchan = NULL; ftdm_event_t *event = NULL; sngss7_event_data_t *sngss7_event = NULL; sngss7_span_data_t *sngss7_span = (sngss7_span_data_t *)ftdmspan->signal_data; @@ -368,12 +367,6 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) goto ftdm_sangoma_ss7_run_exit; } - /* get an interrupt queue for this span for peer channel events */ - if (ftdm_queue_get_interrupt (sngss7_span->peer_chans, &ftdm_sangoma_ss7_int[2]) != FTDM_SUCCESS) { - SS7_CRITICAL ("Failed to get a ftdm_interrupt for span = %d for peer channel events queue!\n", ftdmspan->span_id); - goto ftdm_sangoma_ss7_run_exit; - } - while (ftdm_running () && !(ftdm_test_flag (ftdmspan, FTDM_SPAN_STOP_THREAD))) { int x = 0; if (b_alarm_test) { @@ -410,51 +403,26 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) /* clean out all pending channel state changes */ while ((ftdmchan = ftdm_queue_dequeue (ftdmspan->pendingchans))) { + sngss7_chan_data_t *chan_info = ftdmchan->call_data; /*first lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); /* process state changes for this channel until they are all done */ ftdm_channel_advance_states(ftdmchan); + + if (chan_info->peer_data) { + /* clean out all pending stack events in the peer channel */ + while ((sngss7_event = ftdm_queue_dequeue(chan_info->event_queue))) { + ftdm_sangoma_ss7_process_peer_stack_event(ftdmchan, sngss7_event); + ftdm_safe_free(sngss7_event); + } + } /* unlock the channel */ ftdm_mutex_unlock (ftdmchan->mutex); } - /* clean out all peer pending channel events */ - while ((peerchan = ftdm_queue_dequeue (sngss7_span->peer_chans))) { - /* note that the channels being dequeued here may not belong to this span - they may belong to just about any other span that one of our channels - happens to be bridged to */ - sngss7_chan_data_t *peer_info; - sngss7_chan_data_t *chan_info; - - peer_info = peerchan->call_data; - if (peer_info) { - chan_info = peer_info->peer_data; - if (chan_info) { - ftdmchan = chan_info->ftdmchan; - if (ftdmchan) { - - /* - if there is any state changes at all, those will be done in the opposite channel - to peerchan (where the original event was received), therefore we must lock ftdmchan, - but do not need to lock peerchan as we only read its event queue, which is already - locked when dequeueing */ - ftdm_channel_lock(ftdmchan); - - /* clean out all pending stack events in the peer channel */ - while ((sngss7_event = ftdm_queue_dequeue(peer_info->event_queue))) { - ftdm_sangoma_ss7_process_peer_stack_event(ftdmchan, sngss7_event); - ftdm_safe_free(sngss7_event); - } - - ftdm_channel_unlock(ftdmchan); - } - } - } - } - /* clean out all pending stack events */ while ((sngss7_event = ftdm_queue_dequeue(sngss7_span->event_queue))) { ftdm_sangoma_ss7_process_stack_event(sngss7_event); @@ -570,16 +538,16 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev ftdm_channel_advance_states(ftdmchan); if (sngss7_event->event_id == SNGSS7_CON_IND_EVENT) { - /* this is the first event in a call, flush the event queue */ - sngss7_flush_queue(sngss7_info->event_queue); - /* clear the peer if any */ - sngss7_info->peer_data = NULL; clone_event++; } - /* if the call has already started and the event is not a release confirmation, clone the event */ - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED) && - sngss7_event->event_id != SNGSS7_REL_CFM_EVENT) { + /* If the call has already started (we only bridge events related to calls) + * and the event is not a release confirmation, then clone the event. + * We do not clone release cfm events because that is the only event (final event) that is not + * bridged to the other leg, the first Spirou customer we had explicitly requested to send + * release confirm as soon as the release is received and therefore not wait for the other leg + * to send release confirm (hence, not need to clone and enqueue in the other leg) */ + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED) && sngss7_event->event_id != SNGSS7_REL_CFM_EVENT) { clone_event++; } @@ -606,11 +574,38 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev event_clone = ftdm_calloc(1, sizeof(*sngss7_event)); if (event_clone) { memcpy(event_clone, sngss7_event, sizeof(*sngss7_event)); - ftdm_queue_enqueue(sngss7_info->event_queue, event_clone); + /* if we have already a peer channel then enqueue the event in their queue */ if (sngss7_info->peer_data) { - sngss7_span_data_t *sngss7_peer_span = (sngss7_span_data_t *)sngss7_info->peer_data->ftdmchan->span->signal_data; + ftdm_span_t *peer_span = sngss7_info->peer_data->ftdmchan->span; + if (sngss7_info->peer_event_transfer_cnt) { + sngss7_event_data_t *peer_event = NULL; + int qi = 0; + /* looks like for the first time we found our peer, transfer any messages we enqueued */ + for (qi = 0; qi < sngss7_info->peer_event_transfer_cnt; qi++) { + peer_event = ftdm_queue_dequeue(sngss7_info->event_queue); + if (peer_event) { + ftdm_queue_enqueue(sngss7_info->peer_data->event_queue, peer_event); + } else { + /* This should never happen! */ + SS7_CRIT_CHAN(ftdmchan,"[CIC:%d]What!? someone stole my messages!\n", sngss7_info->circuit->cic); + } + } + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Transferred %d messages into my peer's queue\n", + sngss7_info->circuit->cic, sngss7_info->peer_event_transfer_cnt); + sngss7_info->peer_event_transfer_cnt = 0; + } /* we already have a peer attached, wake him up */ - ftdm_queue_enqueue(sngss7_peer_span->peer_chans, sngss7_info->ftdmchan); + ftdm_queue_enqueue(sngss7_info->peer_data->event_queue, event_clone); + ftdm_queue_enqueue(peer_span->pendingchans, sngss7_info->peer_data->ftdmchan); + } else { + /* we don't have a peer yet, save the event on our own queue for later + * only the first event in this queue is directly consumed by our peer (IAM), subsequent events + * must be transferred by us to their queue as soon as we find our peer */ + ftdm_queue_enqueue(sngss7_info->event_queue, event_clone); + if (sngss7_event->event_id != SNGSS7_CON_IND_EVENT) { + /* This could be an SAM, save it for transfer once we know who our peer is (if we ever find that) */ + sngss7_info->peer_event_transfer_cnt++; + } } } } @@ -623,25 +618,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); break; case SNGSS7_REL_CFM_EVENT: - { - if (sngss7_info->peer_data) { - ftdm_channel_t *peer_chan = sngss7_info->peer_data->ftdmchan; - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); - if (peer_chan) { - /* we need to unlock our chan or we risk deadlock */ - ftdm_channel_advance_states(ftdmchan); - ftdm_channel_unlock(ftdmchan); - - ftdm_channel_lock(peer_chan); - if (peer_chan->state != FTDM_CHANNEL_STATE_DOWN) { - ftdm_set_state(peer_chan, FTDM_CHANNEL_STATE_DOWN); - } - ftdm_channel_unlock(peer_chan); - - ftdm_channel_lock(ftdmchan); - } - } - } + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); break; default: break; @@ -1021,6 +998,7 @@ static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t sngss7_clear_ckt_flag(sngss7_info, FLAG_SUS_RECVD); sngss7_clear_ckt_flag(sngss7_info, FLAG_T6_CANCELED); sngss7_flush_queue(sngss7_info->event_queue); + sngss7_info->peer_data = NULL; ftdm_channel_close (&close_chan); } break; @@ -1035,9 +1013,22 @@ static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t case FTDM_CHANNEL_STATE_TERMINATING: { - ft_to_sngss7_rlc(ftdmchan); + /* Release confirm is sent immediately, since Spirou customer asked us not to wait for the second call leg + * to come back with a release confirm ... */ /* when receiving REL we move to TERMINATING and notify the user that the bridge is ending */ - sngss7_send_signal(sngss7_info, FTDM_SIGEVENT_STOP); + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_USER_HANGUP)) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); + } else { + /* Notify the user and wait for their ack before sending RLC */ + sngss7_send_signal(sngss7_info, FTDM_SIGEVENT_STOP); + } + } + break; + + case FTDM_CHANNEL_STATE_HANGUP: + { + ft_to_sngss7_rlc(ftdmchan); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); } break; @@ -1062,11 +1053,11 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) sngss7_info->blk_flags); if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { - /* DIALING is the only state we process normally when doing an outgoing call that is natively bridged */ + /* DIALING is the only state we process normally when doing an outgoing call that is natively bridged, + * all other states are run by a different state machine (and the freetdm core does not do any checking) */ if (ftdmchan->state != FTDM_CHANNEL_STATE_DIALING) { return ftdm_sangoma_ss7_native_bridge_state_change(ftdmchan); } - sngss7_info->peer_data = NULL; } /*check what state we are supposed to be in */ @@ -1521,24 +1512,8 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) if (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_OPEN)) { ftdm_channel_t *close_chan = ftdmchan; - - /* detach native bridging if needed (only the outbound leg is responsible for that) - Inbound leg was responsible of flushing its queue of events, but peer attach/detach - is left as an outbound leg responsibility - */ - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { - sngss7_chan_data_t *peer_info = sngss7_info->peer_data; - if (peer_info) { - sngss7_info->peer_data = NULL; - if (peer_info) { - peer_info->peer_data = NULL; - } - } - } - /* close the channel */ SS7_DEBUG_CHAN(ftdmchan,"FTDM Channel Close %s\n", ""); - sngss7_flush_queue(sngss7_info->event_queue); ftdm_channel_close (&close_chan); } @@ -2415,12 +2390,6 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config) return FTDM_FAIL; } - /* create an peer channel queue for this span */ - if ((ftdm_queue_create(&(ss7_span_info)->peer_chans, SNGSS7_PEER_CHANS_QUEUE_SIZE)) != FTDM_SUCCESS) { - SS7_CRITICAL("Unable to create peer chans queue!\n"); - return FTDM_FAIL; - } - /*setup the span structure with the info so far */ g_ftdm_sngss7_data.sig_cb = sig_cb; span->start = ftdm_sangoma_ss7_start; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 63d4ded203..fcf7b8ef28 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -522,7 +522,8 @@ typedef struct sngss7_chan_data { sngss7_group_data_t tx_grs; sngss7_group_data_t ucic; ftdm_queue_t *event_queue; - struct sngss7_chan_data *peer_data; + struct sngss7_chan_data *peer_data; + uint8_t peer_event_transfer_cnt; } sngss7_chan_data_t; #define SNGSS7_RX_GRS_PENDING (1 << 0) @@ -536,7 +537,6 @@ typedef struct sngss7_span_data { sngss7_group_data_t rx_cgu; sngss7_group_data_t tx_cgu; ftdm_queue_t *event_queue; - ftdm_queue_t *peer_chans; } sngss7_span_data_t; typedef struct sngss7_event_data @@ -970,7 +970,7 @@ if (ftdmchan->state == new_state) { \ #define SS7_INFO_CHAN(fchan, msg, args...) ftdm_log_chan(fchan, FTDM_LOG_INFO, msg , ##args) #define SS7_WARN_CHAN(fchan, msg, args...) ftdm_log_chan(fchan, FTDM_LOG_WARNING, msg , ##args) #define SS7_ERROR_CHAN(fchan, msg, args...) ftdm_log_chan(fchan, FTDM_LOG_ERROR, msg , ##args) -#define SS7_CTRIT_CHAN(fchan, msg, args...) ftdm_log_chan(fchan, FTDM_LOG_CRIT, msg , ##args) +#define SS7_CRIT_CHAN(fchan, msg, args...) ftdm_log_chan(fchan, FTDM_LOG_CRIT, msg , ##args) #ifdef SS7_CODE_DEVEL #define SS7_DEVEL_DEBUG(a,...) ftdm_log(FTDM_LOG_DEBUG,a,##__VA_ARGS__ ); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index c44c7bd7b2..a228cb1ea1 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -48,6 +48,7 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) SiConEvnt iam; ftdm_bool_t native_going_up = FTDM_FALSE; sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;; + sngss7_event_data_t *event_clone = NULL; SS7_FUNC_TRACE_ENTER (__FUNCTION__); @@ -72,33 +73,28 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) var, peer_span->signal_type); } else { peer_info = peer_chan->call_data; - if (peer_info) { - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Starting native bridge with peer CIC %d\n", - sngss7_info->circuit->cic, peer_info->circuit->cic); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Starting native bridge with peer CIC %d\n", + sngss7_info->circuit->cic, peer_info->circuit->cic); - /* make each one of us aware of the native bridge */ - peer_info->peer_data = sngss7_info; - sngss7_info->peer_data = peer_info; + /* retrieve only first message from the others guys queue (must be IAM) */ + event_clone = ftdm_queue_dequeue(peer_info->event_queue); - /* flush our own queue */ - sngss7_flush_queue(sngss7_info->event_queue); + /* make each one of us aware of the native bridge */ + peer_info->peer_data = sngss7_info; + sngss7_info->peer_data = peer_info; - /* Go to up until release comes, note that state processing is done different and much simpler when there is a peer, - We can't go to UP state right away yet though, so do not set the state to UP here, wait until the end of this function - because moving from one state to another causes the ftdmchan->usrmsg structure to be wiped - and we still need those variables for further IAM processing */ - native_going_up = FTDM_TRUE; - } + /* Go to up until release comes, note that state processing is done different and much simpler when there is a peer, + We can't go to UP state right away yet though, so do not set the state to UP here, wait until the end of this function + because moving from one state to another causes the ftdmchan->usrmsg structure to be wiped + and we still need those variables for further IAM processing */ + native_going_up = FTDM_TRUE; } } } - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE) && sngss7_info->peer_data) { - sngss7_span_data_t *span_data = ftdmchan->span->signal_data; - sngss7_event_data_t *event_clone = ftdm_queue_dequeue(sngss7_info->peer_data->event_queue); - /* Retrieve IAM from our peer */ + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { if (!event_clone) { - SS7_ERROR_CHAN(ftdmchan, "No event clone in peer queue!%s\n", ""); + SS7_ERROR_CHAN(ftdmchan, "No IAM event clone in peer queue!%s\n", ""); } else if (event_clone->event_id != SNGSS7_CON_IND_EVENT) { /* first message in the queue should ALWAYS be an IAM */ SS7_ERROR_CHAN(ftdmchan, "Invalid initial peer message type '%d'\n", event_clone->event_id); @@ -143,9 +139,6 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum); } } - /* since this is the first time we dequeue an event from the peer, make sure our main thread process any other events, - this will trigger the interrupt in our span peer_chans queue which will wake up our main thread if it is sleeping */ - ftdm_queue_enqueue(span_data->peer_chans, sngss7_info->peer_data->ftdmchan); } else if (sngss7_info->circuit->transparent_iam && sngss7_retrieve_iam(ftdmchan, &iam) == FTDM_SUCCESS) { SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Transparent)\n", sngss7_info->circuit->cic); @@ -236,7 +229,9 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) the user sending FTDM_SIGEVENT_UP which can cause the application to misbehave (ie, no audio) */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP); ftdm_channel_advance_states(ftdmchan); - } + } + + ftdm_safe_free(event_clone); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; From 339c45b2cbfc8a07df3f06fdf483cce3aeb10022 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Tue, 3 Apr 2012 11:27:25 -0400 Subject: [PATCH 178/822] freetdm: Add documentation for SS7 native bridge --- libs/freetdm/docs/ss7-native-bridge.txt | 43 +++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 libs/freetdm/docs/ss7-native-bridge.txt diff --git a/libs/freetdm/docs/ss7-native-bridge.txt b/libs/freetdm/docs/ss7-native-bridge.txt new file mode 100644 index 0000000000..d44b067b0a --- /dev/null +++ b/libs/freetdm/docs/ss7-native-bridge.txt @@ -0,0 +1,43 @@ +SS7 Native Bridge + +Native bridge is enabled on 2 conditions: + +* The SIP header FreeTDM-TransUUID is set in the originating leg and matches a freetdm channel +* The variable freetdm_native_sigbridge is true and the originating leg is also a freetdm channel + +Some coding rules apply to this feature: + +- Each channel is responsible for clearning its own peer_data and event queue + at the end of the call (when moving to DOWN state) + +- Each channel dequeues messages only from its own queue and enqueues messages + in the peer's queue, with the only exception being messages received before + the bridge is stablished (IAM for sure and possible SAM messages) because + if the bridge is not yet stablished the messages must be queued by the channel + in its own queue temporarily until the bridge is ready + +- When the bridge is ready it is the responsibility of the incoming channel to + move the messages that stored temporarily in its own queue to the bridged peer queue + +- During hangup, each channel is responsible for moving itself to DOWN. The procedure + however differs slightly depending on the hangup conditions + + If the user requests hangup (ie, FreeSWITCH) the request will be noted by setting the + FTDM_CHANNEL_USER_HANGUP flag but will not be processed yet because call control is + driven only by the link messages (so no hangup from ESL or command line allowed) + + When REL message comes, the channel receiving it must move to TERMINATING state and: + + - If the user has not hangup yet (FTDM_CHANNEL_USER_HANGUP flag not set) then + notify the user via SIGEVENT_STOP and wait for the user to move to HANGUP + state by calling ftdm_channel_call_hangup() before sending RLC + + - If the user did hangup already (FTDM_CHANNEL_USER_HANGUP flag is set) then + skip user notification and move to HANGUP state directly where the RLC message + will be sent + +- On HANGUP state the RLC is sent and the channel is moved to DOWN, final state + The peer channel will forward the REL message and wait for RLC from the network, when + RLC is received the channel can move straight to DOWN itself because the peer channel + is completing its own shutdown procedure when it received the REL message + From 7155001c864686dd005e25ef80bfa8b4aef05fc4 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Mon, 16 Jan 2012 12:45:25 -0600 Subject: [PATCH 179/822] FS-3810 --resolve --- src/mod/endpoints/mod_sofia/mod_sofia.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 0fc8c3acfb..ca489f6db7 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -443,7 +443,7 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) } if (!((use_my_cause = switch_channel_get_variable(channel, "sip_ignore_remote_cause")) && switch_true(use_my_cause))) { - ps_cause = switch_channel_get_variable(channel, SWITCH_PROTO_SPECIFIC_HANGUP_CAUSE_VARIABLE); + ps_cause = switch_channel_get_variable(channel, "last_bridge_" SWITCH_PROTO_SPECIFIC_HANGUP_CAUSE_VARIABLE); } if (!zstr(ps_cause) && (!strncasecmp(ps_cause, "sip:", 4) || !strncasecmp(ps_cause, "sips:", 5))) { From 16d4f1f06313a26d45d0b61a188af6d01e79e59b Mon Sep 17 00:00:00 2001 From: James Zhang Date: Wed, 11 Apr 2012 11:20:32 -0400 Subject: [PATCH 180/822] freetdm: INR/INF implementation - When NSG receives INR from network, send back INF with calling party category information IE and calling number information IE. - Introduced a new global setting of "force-inr" for testing purpose. Stinga generated INR/INF packets are not acceptable by trillium stack since it misses call related information in the packets. If configure force-inr to true in freetdm.conf.xml, when NSG receives an incoming IAM, it'll send out INR packet regardless of incoming IAM's IEs, and keep waiting for INF response from the calling side. - T.39 timer is introduced in order to handle INR timeout. The default value of T.39 is 12 seconds and is configurable according to spec. - Only supports calling number IE and calling party category IE in current fix. The customer only needs the calling number IE right now. In ISUP spec, there are 6 optional IEs. NSG only supports calling party number and calling category information IE since the other IEs are not configurable in freetdm.conf.xml or included in IAM message. - In collect state, INR/INF implementation needs to work with existed SAM messages. If NSG sent out INR and wait for SAM, collect state check both INF received and enough dialed numbers received. If one of these conditions are not met, it'll stay in collect state and wait until either conditions met or timeout. After received INF and enough dailed number, state moves to dailing and proceed as regular calls. --- .../ftmod_sangoma_ss7_handle.c | 37 +++++++ .../ftmod_sangoma_ss7_main.c | 104 ++++++++++++++++-- .../ftmod_sangoma_ss7_main.h | 24 ++++ .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 79 +++++++++++++ .../ftmod_sangoma_ss7_support.c | 2 +- .../ftmod_sangoma_ss7_timers.c | 45 +++++++- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 28 +++++ 7 files changed, 304 insertions(+), 15 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index d9816dfa0e..ac309ddc3e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -131,6 +131,16 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* KONRAD FIX ME : check in case there is a ckt and grp block */ } + + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_TX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_SENT); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_RX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_RX_DN); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_TX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_SENT); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_RX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_RX_DN); + sngss7_clear_ckt_flag(sngss7_info, FLAG_FULL_NUMBER); /* check whether the ftdm channel is in a state to accept a call */ switch (ftdmchan->state) { @@ -175,6 +185,12 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* fill in ANI */ ftdm_set_string(ftdmchan->caller_data.ani.digits, ftdmchan->caller_data.cid_num.digits); } + else { + if (g_ftdm_sngss7_data.cfg.force_inr) { + sngss7_set_ckt_flag(sngss7_info, FLAG_INR_TX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_SENT); + } + } if (siConEvnt->cgPtyNum.scrnInd.pres) { /* fill in the screening indication value */ @@ -186,6 +202,11 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ ftdmchan->caller_data.pres = siConEvnt->cgPtyNum.presRest.val; } } else { + if (g_ftdm_sngss7_data.cfg.force_inr) { + sngss7_set_ckt_flag(sngss7_info, FLAG_INR_TX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_SENT); + } + SS7_INFO_CHAN(ftdmchan,"No Calling party (ANI) information in IAM!%s\n", " "); } @@ -437,10 +458,26 @@ ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circ /**************************************************************************/ case (INFORMATION): SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx INF\n", sngss7_info->circuit->cic); + + SS7_DEBUG_CHAN (ftdmchan, "Cancelling T.39 timer %s\n", " "); + /* check if t39 is active */ + if (sngss7_info->t39.hb_timer_id) { + ftdm_sched_cancel_timer (sngss7_info->t39.sched, sngss7_info->t39.hb_timer_id); + SS7_DEBUG_CHAN (ftdmchan, "T.39 timer has been cancelled upon receiving INF message %s\n", " "); + } + + sngss7_set_ckt_flag(sngss7_info, FLAG_INF_RX_DN); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_IDLE); + break; /**************************************************************************/ case (INFORMATREQ): SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx INR\n", sngss7_info->circuit->cic); + + ft_to_sngss7_inf(ftdmchan); + + sngss7_set_ckt_flag(sngss7_info, FLAG_INR_RX); + break; /**************************************************************************/ case (SUBSADDR): diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 76266f0d53..d37a6111ab 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1080,23 +1080,91 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) } /* check if the end of pulsing (ST) character has arrived or the right number of digits */ - if (ftdmchan->caller_data.dnis.digits[i-1] == 'F') { + if (ftdmchan->caller_data.dnis.digits[i-1] == 'F' + || sngss7_test_ckt_flag(sngss7_info, FLAG_FULL_NUMBER) ) + { SS7_DEBUG_CHAN(ftdmchan, "Received the end of pulsing character %s\n", ""); - /* remove the ST */ - ftdmchan->caller_data.dnis.digits[i-1] = '\0'; - - /*now go to the RING state */ - state_flag = 0; - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); + if (!sngss7_test_ckt_flag(sngss7_info, FLAG_FULL_NUMBER)) { + /* remove the ST */ + ftdmchan->caller_data.dnis.digits[i-1] = '\0'; + sngss7_set_ckt_flag(sngss7_info, FLAG_FULL_NUMBER); + } + if (sngss7_test_ckt_flag(sngss7_info, FLAG_INR_TX)) { + if (!sngss7_test_ckt_flag(sngss7_info, FLAG_INR_SENT) ) { + ft_to_sngss7_inr(ftdmchan); + sngss7_set_ckt_flag(sngss7_info, FLAG_INR_SENT); + + SS7_DEBUG_CHAN (ftdmchan, "Scheduling T.39 timer %s \n", " "); + + /* start ISUP t39 */ + if (ftdm_sched_timer (sngss7_info->t39.sched, + "t39", + sngss7_info->t39.beat, + sngss7_info->t39.callback, + &sngss7_info->t39, + &sngss7_info->t39.hb_timer_id)) + { + + SS7_ERROR ("Unable to schedule timer T39, hanging up call!\n"); + + ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_TEMPORARY_FAILURE; + sngss7_set_ckt_flag (sngss7_info, FLAG_LOCAL_REL); + + /* end the call */ + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); + } + }else { + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); + } + } else { + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); + } } else if (i >= sngss7_info->circuit->min_digits) { SS7_DEBUG_CHAN(ftdmchan, "Received %d digits (min digits = %d)\n", i, sngss7_info->circuit->min_digits); - /*now go to the RING state */ - state_flag = 0; - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); - + if (sngss7_test_ckt_flag(sngss7_info, FLAG_INR_TX)) { + if (!sngss7_test_ckt_flag(sngss7_info, FLAG_INR_SENT) ) { + ft_to_sngss7_inr(ftdmchan); + sngss7_set_ckt_flag(sngss7_info, FLAG_INR_SENT); + + SS7_DEBUG_CHAN (ftdmchan, "Scheduling T.39 timer %s\n", " " ); + + /* start ISUP t39 */ + if (ftdm_sched_timer (sngss7_info->t39.sched, + "t39", + sngss7_info->t39.beat, + sngss7_info->t39.callback, + &sngss7_info->t39, + &sngss7_info->t39.hb_timer_id)) + { + + SS7_ERROR ("Unable to schedule timer T39, hanging up call!\n"); + + ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_TEMPORARY_FAILURE; + sngss7_set_ckt_flag (sngss7_info, FLAG_LOCAL_REL); + + /* end the call */ + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); + } + + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_IDLE); + }else { + if (sngss7_test_ckt_flag(sngss7_info, FLAG_INF_RX_DN) ) { + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); + } + } + } else { + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); + } } else { /* if we are coming from idle state then we have already been here once before */ if (ftdmchan->last_state != FTDM_CHANNEL_STATE_IDLE) { @@ -1152,6 +1220,15 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) /**************************************************************************/ case FTDM_CHANNEL_STATE_RING: /*incoming call request */ + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_TX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_SENT); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_RX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_RX_DN); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_TX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_SENT); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_RX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_RX_DN); + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n"); break; @@ -1162,6 +1239,11 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) ftdm_sched_cancel_timer (sngss7_info->t35.sched, sngss7_info->t35.hb_timer_id); } + /* cancel t39 timer */ + if (sngss7_info->t39.hb_timer_id) { + ftdm_sched_cancel_timer (sngss7_info->t39.sched, sngss7_info->t39.hb_timer_id); + } + SS7_DEBUG_CHAN(ftdmchan, "Sending incoming call from %s to %s to FTDM core\n", ftdmchan->caller_data.ani.digits, ftdmchan->caller_data.dnis.digits); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index fcf7b8ef28..66732bf10e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -395,6 +395,7 @@ typedef struct sng_isup_ckt { uint16_t t16; uint16_t t17; uint32_t t35; + uint32_t t39; uint16_t tval; } sng_isup_ckt_t; @@ -466,6 +467,7 @@ typedef struct sng_ss7_cfg { sng_nsap_t nsap[MAX_NSAPS+1]; sng_isap_t isap[MAX_ISAPS+1]; sng_glare_resolution glareResolution; + uint32_t force_inr; } sng_ss7_cfg_t; typedef struct ftdm_sngss7_data { @@ -517,6 +519,7 @@ typedef struct sngss7_chan_data { sngss7_glare_data_t glare; sngss7_timer_data_t t35; sngss7_timer_data_t t10; + sngss7_timer_data_t t39; sngss7_group_data_t rx_grs; sngss7_group_data_t rx_gra; sngss7_group_data_t tx_grs; @@ -584,6 +587,15 @@ typedef enum { FLAG_SENT_CPG = (1 << 17), FLAG_SUS_RECVD = (1 << 18), FLAG_T6_CANCELED = (1 << 19), + FLAG_INR_TX = (1 << 20), + FLAG_INR_SENT = (1 << 21), + FLAG_INR_RX = (1 << 22), + FLAG_INR_RX_DN = (1 << 23), + FLAG_INF_TX = (1 << 24), + FLAG_INF_SENT = (1 << 25), + FLAG_INF_RX = (1 << 26), + FLAG_INF_RX_DN = (1 << 27), + FLAG_FULL_NUMBER = (1 << 28), FLAG_RELAY_DOWN = (1 << 30), FLAG_CKT_RECONFIG = (1 << 31) } sng_ckt_flag_t; @@ -606,6 +618,14 @@ typedef enum { "INF_RESUME", \ "INF_PAUSED", \ "TX_ACM_SENT" \ + "TX_INR" \ + "INR_SENT" \ + "RX_INR" \ + "RX_INR_DN" \ + "TX_INF" \ + "INF SENT" \ + "RX_INF" \ + "RX_INF_DN" \ "RELAY_DOWN", \ "CKT_RECONFIG" FTDM_STR2ENUM_P(ftmod_ss7_ckt_state2flag, ftmod_ss7_ckt_flag2str, sng_ckt_flag_t) @@ -820,6 +840,9 @@ void ft_to_sngss7_cgb(ftdm_channel_t * ftdmchan); void ft_to_sngss7_cgu(ftdm_channel_t * ftdmchan); void ft_to_sngss7_itx (ftdm_channel_t * ftdmchan); void ft_to_sngss7_txa (ftdm_channel_t * ftdmchan); +void ft_to_sngss7_inr(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_inf(ftdm_channel_t *ftdmchan); + /* in ftmod_sangoma_ss7_in.c */ @@ -949,6 +972,7 @@ ftdm_status_t sngss7_add_raw_data(sngss7_chan_data_t *sngss7_info, uint8_t* data /* in ftmod_sangoma_ss7_timers.c */ void handle_isup_t35(void *userdata); void handle_isup_t10(void *userdata); +void handle_isup_t39(void *userdata); /******************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index a228cb1ea1..b5431d8fe8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -237,6 +237,85 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) return; } +void ft_to_sngss7_inf(ftdm_channel_t *ftdmchan) +{ + SiCnStEvnt evnt; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + /* + const char *CallerId = NULL; + const char *CallerCat = NULL; + const char *sipvar; + */ + + memset (&evnt, 0x0, sizeof (evnt)); + + evnt.infoInd.eh.pres = PRSNT_NODEF; + + evnt.infoInd.cgPtyAddrRespInd.pres = PRSNT_NODEF; + evnt.infoInd.cgPtyAddrRespInd.val=CGPRTYADDRESP_INCL; + copy_cgPtyNum_to_sngss7 (ftdmchan, &evnt.cgPtyNum); + + + evnt.infoInd.cgPtyCatRespInd.pres = PRSNT_NODEF; + evnt.infoInd.cgPtyCatRespInd.val = CGPRTYCATRESP_INCL; + copy_cgPtyCat_to_sngss7 (ftdmchan, &evnt.cgPtyCat); + + evnt.infoInd.chrgInfoRespInd.pres = PRSNT_NODEF; + evnt.infoInd.chrgInfoRespInd.val = 0; + + evnt.infoInd.solInfoInd.pres = PRSNT_NODEF; + evnt.infoInd.solInfoInd.val = 0; + + evnt.infoInd.holdProvInd.pres = PRSNT_NODEF; + evnt.infoInd.holdProvInd.val = 0; + + evnt.infoInd.spare.pres = PRSNT_NODEF; + evnt.infoInd.spare.val = 0; + + sng_cc_inf(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &evnt, + INFORMATION); + + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx INF\n", sngss7_info->circuit->cic); + +} + +void ft_to_sngss7_inr(ftdm_channel_t *ftdmchan) +{ + SiCnStEvnt evnt; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + memset (&evnt, 0x0, sizeof (evnt)); + + evnt.infoReqInd.eh.pres = PRSNT_NODEF; + evnt.infoReqInd.cgPtyAdReqInd.pres = PRSNT_NODEF; + evnt.infoReqInd.cgPtyAdReqInd.val=CGPRTYADDREQ_REQ; + + evnt.infoReqInd.holdingInd.pres = PRSNT_NODEF; + evnt.infoReqInd.holdingInd.val = HOLD_NOTREQ; + + evnt.infoReqInd.cgPtyCatReqInd.pres = PRSNT_NODEF; + evnt.infoReqInd.cgPtyCatReqInd.val = CGPRTYCATREQ_REQ; + + evnt.infoReqInd.chrgInfoReqInd.pres = PRSNT_NODEF; + evnt.infoReqInd.chrgInfoReqInd.val = CHRGINFO_NOTREQ; + + evnt.infoReqInd.malCaIdReqInd.pres = PRSNT_NODEF; + evnt.infoReqInd.malCaIdReqInd.val = MLBG_INFONOTREQ; + + sng_cc_inr(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &evnt, + INFORMATREQ); + + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx INR\n", sngss7_info->circuit->cic); +} + void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan) { SS7_FUNC_TRACE_ENTER (__FUNCTION__); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 4bfa5d2065..96359ba595 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -186,7 +186,7 @@ ftdm_status_t copy_cgPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *cgPt ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Calling NADI value \"%s\"\n", clg_nadi); cgPtyNum->natAddrInd.val = atoi(clg_nadi); } - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Calling Party Number Presentation Ind %d\n", cgPtyNum->presRest.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Calling Party Number NADI value %d\n", cgPtyNum->natAddrInd.val); return copy_tknStr_to_sngss7(caller_data->cid_num.digits, &cgPtyNum->addrSig, &cgPtyNum->oddEven); } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c index 6138ea34b0..8cac996213 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c @@ -49,7 +49,7 @@ /******************************************************************************/ /* PROTOTYPES *****************************************************************/ -void handle_isup_t35(void *userdata); + /******************************************************************************/ /* FUNCTIONS ******************************************************************/ @@ -76,10 +76,13 @@ void handle_isup_t35(void *userdata) /* end the call */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); - /* kill t10 if active */ + /* kill t10 t39 if active */ if (sngss7_info->t10.hb_timer_id) { ftdm_sched_cancel_timer (sngss7_info->t10.sched, sngss7_info->t10.hb_timer_id); } + if (sngss7_info->t39.hb_timer_id) { + ftdm_sched_cancel_timer (sngss7_info->t39.sched, sngss7_info->t39.hb_timer_id); + } /*unlock*/ ftdm_channel_unlock(ftdmchan); @@ -108,7 +111,43 @@ void handle_isup_t10(void *userdata) SS7_FUNC_TRACE_EXIT(__FUNCTION__); } - + +void handle_isup_t39(void *userdata) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_timer_data_t *timer = userdata; + sngss7_chan_data_t *sngss7_info = timer->sngss7_info; + ftdm_channel_t *ftdmchan = sngss7_info->ftdmchan; + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_channel_lock(ftdmchan); + + /* Q.764 2.2.5 Address incomplete (T35 expiry action is hangup with cause 28 according to Table A.1/Q.764) */ + SS7_ERROR("[Call-Control] Timer 39 expired on CIC = %d\n", sngss7_info->circuit->cic); + + /* set the flag to indicate this hangup is started from the local side */ + sngss7_set_ckt_flag(sngss7_info, FLAG_LOCAL_REL); + + /* hang up on timer expiry */ + ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_INVALID_NUMBER_FORMAT; + + /* end the call */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); + + /* kill t10 t35 if active */ + if (sngss7_info->t10.hb_timer_id) { + ftdm_sched_cancel_timer (sngss7_info->t10.sched, sngss7_info->t10.hb_timer_id); + } + if (sngss7_info->t35.hb_timer_id) { + ftdm_sched_cancel_timer (sngss7_info->t35.sched, sngss7_info->t35.hb_timer_id); + } + + /*unlock*/ + ftdm_channel_unlock(ftdmchan); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); +} /******************************************************************************/ /* For Emacs: * Local Variables: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 230476d8e1..ee726911af 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -146,6 +146,7 @@ typedef struct sng_ccSpan uint32_t t16; uint32_t t17; uint32_t t35; + uint32_t t39; uint32_t tval; } sng_ccSpan_t; @@ -487,6 +488,7 @@ static int ftmod_ss7_parse_sng_gen(ftdm_conf_node_t *sng_gen) /* Set the transparent_iam_max_size to default value */ g_ftdm_sngss7_data.cfg.transparent_iam_max_size=800; + g_ftdm_sngss7_data.cfg.force_inr = 0; /* extract all the information from the parameters */ for (i = 0; i < num_parms; i++) { @@ -508,6 +510,14 @@ static int ftmod_ss7_parse_sng_gen(ftdm_conf_node_t *sng_gen) ftmod_ss7_set_glare_resolution (parm->val); SS7_DEBUG("Found glare resolution configuration = %d %s\n", g_ftdm_sngss7_data.cfg.glareResolution, parm->val ); } + else if (!strcasecmp(parm->var, "force-inr")) { + if (!strcasecmp(parm->val, "true")) { + g_ftdm_sngss7_data.cfg.force_inr = 1; + } else { + g_ftdm_sngss7_data.cfg.force_inr = 0; + } + SS7_DEBUG("Found INR force configuration = %s\n", parm->val ); + } else { SS7_ERROR("Found an invalid parameter \"%s\"!\n", parm->val); return FTDM_FAIL; @@ -2062,6 +2072,11 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) sng_ccSpan.t35 = atoi(parm->val); SS7_DEBUG("Found isup t35 = %d\n",sng_ccSpan.t35); /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t39")) { + /**********************************************************************/ + sng_ccSpan.t39 = atoi(parm->val); + SS7_DEBUG("Found isup t39 = %d\n",sng_ccSpan.t39); + /**********************************************************************/ } else if (!strcasecmp(parm->var, "isup.tval")) { /**********************************************************************/ sng_ccSpan.tval = atoi(parm->val); @@ -3044,6 +3059,12 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan) } else { g_ftdm_sngss7_data.cfg.isupCkt[x].t35 = ccSpan->t35; } + if (ccSpan->t39 == 0) { + g_ftdm_sngss7_data.cfg.isupCkt[x].t39 = 120; + } else { + g_ftdm_sngss7_data.cfg.isupCkt[x].t39 = ccSpan->t39; + } + if (ccSpan->tval == 0) { g_ftdm_sngss7_data.cfg.isupCkt[x].tval = 10; } else { @@ -3148,6 +3169,13 @@ static int ftmod_ss7_fill_in_circuits(sng_span_t *sngSpan) ss7_info->t10.callback = handle_isup_t10; ss7_info->t10.sngss7_info = ss7_info; + /* prepare the timer structures */ + ss7_info->t39.sched = ((sngss7_span_data_t *)(ftdmspan->signal_data))->sched; + ss7_info->t39.counter = 1; + ss7_info->t39.beat = (isupCkt->t39) * 100; /* beat is in ms, t39 is in 100ms */ + ss7_info->t39.callback = handle_isup_t39; + ss7_info->t39.sngss7_info = ss7_info; + /**************************************************************************/ } /* for (i == 1; i < ftdmspan->chan_count; i++) */ From 8d1c382632e86df9bcbdf290b1b702580e6e513f Mon Sep 17 00:00:00 2001 From: James Zhang Date: Wed, 11 Apr 2012 15:14:29 -0400 Subject: [PATCH 181/822] freetdm: INR/INF implementation - fill in IEs in INF according to INR request - print debug information if IE requested but not supported --- .../ftmod_sangoma_ss7_handle.c | 2 +- .../ftmod_sangoma_ss7_main.h | 2 +- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 58 ++++++++++++------- 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index ac309ddc3e..04dff6ee5e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -474,7 +474,7 @@ ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circ case (INFORMATREQ): SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx INR\n", sngss7_info->circuit->cic); - ft_to_sngss7_inf(ftdmchan); + ft_to_sngss7_inf(ftdmchan, siCnStEvnt); sngss7_set_ckt_flag(sngss7_info, FLAG_INR_RX); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 66732bf10e..4ccf4efe0e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -841,7 +841,7 @@ void ft_to_sngss7_cgu(ftdm_channel_t * ftdmchan); void ft_to_sngss7_itx (ftdm_channel_t * ftdmchan); void ft_to_sngss7_txa (ftdm_channel_t * ftdmchan); void ft_to_sngss7_inr(ftdm_channel_t * ftdmchan); -void ft_to_sngss7_inf(ftdm_channel_t *ftdmchan); +void ft_to_sngss7_inf(ftdm_channel_t *ftdmchan, SiCnStEvnt *inr); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index b5431d8fe8..9ba11ada58 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -237,41 +237,55 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) return; } -void ft_to_sngss7_inf(ftdm_channel_t *ftdmchan) +void ft_to_sngss7_inf(ftdm_channel_t *ftdmchan, SiCnStEvnt *inr) { SiCnStEvnt evnt; sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; - /* - const char *CallerId = NULL; - const char *CallerCat = NULL; - const char *sipvar; - */ - + memset (&evnt, 0x0, sizeof (evnt)); evnt.infoInd.eh.pres = PRSNT_NODEF; - evnt.infoInd.cgPtyAddrRespInd.pres = PRSNT_NODEF; - evnt.infoInd.cgPtyAddrRespInd.val=CGPRTYADDRESP_INCL; - copy_cgPtyNum_to_sngss7 (ftdmchan, &evnt.cgPtyNum); - - evnt.infoInd.cgPtyCatRespInd.pres = PRSNT_NODEF; - evnt.infoInd.cgPtyCatRespInd.val = CGPRTYCATRESP_INCL; - copy_cgPtyCat_to_sngss7 (ftdmchan, &evnt.cgPtyCat); evnt.infoInd.chrgInfoRespInd.pres = PRSNT_NODEF; evnt.infoInd.chrgInfoRespInd.val = 0; - evnt.infoInd.solInfoInd.pres = PRSNT_NODEF; evnt.infoInd.solInfoInd.val = 0; - evnt.infoInd.holdProvInd.pres = PRSNT_NODEF; - evnt.infoInd.holdProvInd.val = 0; - + evnt.infoInd.holdProvInd.val = 0; evnt.infoInd.spare.pres = PRSNT_NODEF; evnt.infoInd.spare.val = 0; - + + if (inr->infoReqInd.eh.pres == PRSNT_NODEF) { + if ((inr->infoReqInd.holdingInd.pres == PRSNT_NODEF) && (inr->infoReqInd.holdingInd.val == HOLD_REQ)) { + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Received INR requesting holding information. Holding is not supported in INF.\n", sngss7_info->circuit->cic); + } + if ((inr->infoReqInd.chrgInfoReqInd.pres == PRSNT_NODEF) && (inr->infoReqInd.chrgInfoReqInd.val == CHRGINFO_REQ)) { + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Received INR requesting charging information. Charging is not supported in INF.\n", sngss7_info->circuit->cic); + } + if ((inr->infoReqInd.malCaIdReqInd.pres == PRSNT_NODEF) && (inr->infoReqInd.malCaIdReqInd.val == CHRGINFO_REQ)) { + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Received INR requesting malicious call id. Malicious call id is not supported in INF.\n", sngss7_info->circuit->cic); + } + + if ((inr->infoReqInd.cgPtyAdReqInd.pres == PRSNT_NODEF) && (inr->infoReqInd.cgPtyAdReqInd.val == CGPRTYADDREQ_REQ)) { + evnt.infoInd.cgPtyAddrRespInd.val=CGPRTYADDRESP_INCL; + copy_cgPtyNum_to_sngss7 (ftdmchan, &evnt.cgPtyNum); + } else { + evnt.infoInd.cgPtyAddrRespInd.val=CGPRTYADDRESP_NOTINCL; + } + + if ((inr->infoReqInd.cgPtyCatReqInd.pres == PRSNT_NODEF) && (inr->infoReqInd.cgPtyCatReqInd.val == CGPRTYCATREQ_REQ)) { + evnt.infoInd.cgPtyCatRespInd.val = CGPRTYCATRESP_INCL; + copy_cgPtyCat_to_sngss7 (ftdmchan, &evnt.cgPtyCat); + } else { + evnt.infoInd.cgPtyCatRespInd.val = CGPRTYCATRESP_NOTINCL; + } + } + else { + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Received INR with no information request. Sending back default INF.\n", sngss7_info->circuit->cic); + } + sng_cc_inf(1, sngss7_info->suInstId, sngss7_info->spInstId, @@ -295,16 +309,16 @@ void ft_to_sngss7_inr(ftdm_channel_t *ftdmchan) evnt.infoReqInd.cgPtyAdReqInd.val=CGPRTYADDREQ_REQ; evnt.infoReqInd.holdingInd.pres = PRSNT_NODEF; - evnt.infoReqInd.holdingInd.val = HOLD_NOTREQ; + evnt.infoReqInd.holdingInd.val = HOLD_REQ; evnt.infoReqInd.cgPtyCatReqInd.pres = PRSNT_NODEF; evnt.infoReqInd.cgPtyCatReqInd.val = CGPRTYCATREQ_REQ; evnt.infoReqInd.chrgInfoReqInd.pres = PRSNT_NODEF; - evnt.infoReqInd.chrgInfoReqInd.val = CHRGINFO_NOTREQ; + evnt.infoReqInd.chrgInfoReqInd.val = CHRGINFO_REQ; evnt.infoReqInd.malCaIdReqInd.pres = PRSNT_NODEF; - evnt.infoReqInd.malCaIdReqInd.val = MLBG_INFONOTREQ; + evnt.infoReqInd.malCaIdReqInd.val = MLBG_INFOREQ; sng_cc_inr(1, sngss7_info->suInstId, From a796c6849c4607c73d71e0080def3bda6b3e63b9 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Fri, 13 Apr 2012 11:18:53 -0400 Subject: [PATCH 182/822] freetdm: fixed no ACM/CPG sending in some situations after native bridge - clear up ACM_SENT & CPG_SENT flag in DOWN state in native bridge state machine --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index d37a6111ab..928db54d51 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -997,6 +997,9 @@ static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t ftdm_channel_t *close_chan = ftdmchan; sngss7_clear_ckt_flag(sngss7_info, FLAG_SUS_RECVD); sngss7_clear_ckt_flag(sngss7_info, FLAG_T6_CANCELED); + sngss7_clear_ckt_flag (sngss7_info, FLAG_SENT_ACM); + sngss7_clear_ckt_flag (sngss7_info, FLAG_SENT_CPG); + sngss7_flush_queue(sngss7_info->event_queue); sngss7_info->peer_data = NULL; ftdm_channel_close (&close_chan); From cd2d67ace17b036fcdc06e2a81a0dd0021c11c92 Mon Sep 17 00:00:00 2001 From: James Date: Fri, 13 Apr 2012 17:26:48 -0400 Subject: [PATCH 183/822] freetdm: fixed group block/unblock state dead lock when signal link is down and recovered later To re-produce this bug: 1. do CGB on one side 2. unplug signaling link cable 3. plug signaling link cable back 4. do CGU on the blocking side 5. cic state stay in RESTART for ever Fix this problem by sending cic to SUSPENDED state after receiving/sending CGU message --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 36 +++++-------------- .../ftmod_sangoma_ss7_handle.c | 7 ++-- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 3f1a03f4d8..df872b260c 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -35,7 +35,7 @@ * */ -#if 0 +#if 0 #define SMG_RELAY_DBG #endif @@ -1332,7 +1332,7 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, } #ifdef SMG_RELAY_DBG - stream->write_function(stream," blk_flag=%x | ckt_flag=%x | chan_flag=%x", ss7_info->blk_flags, ss7_info->ckt_flags, ftdmchan->flags); + stream->write_function(stream," | blk_flag=%x | ckt_flag=%x", ss7_info->blk_flags, ss7_info->ckt_flags); #endif stream->write_function(stream, "\n"); } /* if ( hole, sig, voice) */ @@ -1374,36 +1374,26 @@ static ftdm_status_t handle_tx_blo(ftdm_stream_handle_t *stream, int span, int c } if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) { - /* now that we have the right channel...put a lock on it so no-one else can use it */ ftdm_mutex_lock(ftdmchan->mutex); /* check if there is a pending state change|give it a bit to clear */ if (check_for_state_change(ftdmchan)) { SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic); - /* check if we need to die */ ftdm_assert(0, "State change not completed\n"); - /* unlock the channel again before we exit */ ftdm_mutex_unlock(ftdmchan->mutex); - /* move to the next channel */ continue; } else { - /* throw the ckt block flag */ sngss7_set_ckt_blk_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX); - - /* set the channel to suspended state */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); } - - /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + } - } /* if ( span and chan) */ + } - } /* if ( cic != 0) */ - - /* go the next circuit */ x++; - } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x]id != 0) */ + } handle_show_blocks(stream, span, chan, verbose); @@ -1440,33 +1430,22 @@ static ftdm_status_t handle_tx_ubl(ftdm_stream_handle_t *stream, int span, int c } if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) { - /* now that we have the right channel...put a lock on it so no-one else can use it */ ftdm_mutex_lock(ftdmchan->mutex); /* check if there is a pending state change|give it a bit to clear */ if (check_for_state_change(ftdmchan)) { SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic); - /* check if we need to die */ ftdm_assert(0, "State change not completed\n"); - /* unlock the channel again before we exit */ ftdm_mutex_unlock(ftdmchan->mutex); - /* move to the next channel */ continue; } else { - /* throw the ckt block flag */ sngss7_set_ckt_blk_flag(ss7_info, FLAG_CKT_MN_UNBLK_TX); - - /* clear the block flag */ sngss7_clear_ckt_blk_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX); - - /* check group blocking */ sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_MN_BLOCK_TX); - /* set the channel to suspended state */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); } - /* unlock the channel again before we exit */ ftdm_mutex_unlock(ftdmchan->mutex); } @@ -1812,6 +1791,8 @@ static ftdm_status_t handle_tx_cgb(ftdm_stream_handle_t *stream, int span, int c /* throw the grp maint. block flag */ sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_TX); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + /* bring the sig status down */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); @@ -1945,6 +1926,7 @@ static ftdm_status_t handle_tx_cgu(ftdm_stream_handle_t *stream, int span, int c /* bring the sig status up */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); /* if this is the first channel in the range */ if (!main_chan) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 04dff6ee5e..d0d6c32867 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -1181,11 +1181,12 @@ ftdm_status_t handle_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ break; /**************************************************************************/ case SIT_STA_CGBRSP: /* mntc. oriented CGB response */ - /*handle_cgb_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);*/ + SS7_INFO(" Rx CGBA \n"); break; /**************************************************************************/ case SIT_STA_CGURSP: /* mntc. oriented CGU response */ /*SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));*/ + SS7_INFO(" Rx CGUA \n"); break; /**************************************************************************/ case SIT_STA_GRSREQ: /* circuit group reset request */ @@ -2510,6 +2511,7 @@ ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* bring the sig status down */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); /* unlock the channel again before we exit */ ftdm_mutex_unlock(ftdmchan->mutex); @@ -2665,7 +2667,8 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ if (sngss7_channel_status_clear(sngss7_info)) { sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); } - + + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); ftdm_mutex_unlock(ftdmchan->mutex); /* update the bit and byte counter*/ From e2f1b4ab27ae10990d0db0537f3ee3300c8e9bd5 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Mon, 16 Apr 2012 13:48:35 -0400 Subject: [PATCH 184/822] freetdm: fix REL receiving leg always stay in TERMINATING stae in native bridge mode - This is supposed to be included in commit of b324f8679782957bc9db3bdfd6687aa42cba77dd. Somehow it's not included in that commit. Without this change, the REL receiving leg always stay in TERMINATING state when received an incoming REL message. --- libs/freetdm/src/ftdm_io.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 513fc0c595..1c05797102 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -2199,9 +2199,12 @@ static ftdm_status_t _ftdm_channel_call_hangup_nl(const char *file, const char * { ftdm_status_t status = FTDM_SUCCESS; - if (ftdm_test_flag(chan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { + /* In native sigbridge mode we ignore hangup requests from the user and hangup only when the signaling module decides it */ + if (ftdm_test_flag(chan, FTDM_CHANNEL_NATIVE_SIGBRIDGE) && chan->state != FTDM_CHANNEL_STATE_TERMINATING) { + ftdm_log_chan_ex(chan, file, func, line, FTDM_LOG_LEVEL_DEBUG, "Ignoring hangup in channel in state %s (native bridge enabled)\n", ftdm_channel_state2str(chan->state)); + ftdm_set_flag(chan, FTDM_CHANNEL_USER_HANGUP); goto done; } From 4f5a6557fce63fb739f734b87c50e09764f9cbef Mon Sep 17 00:00:00 2001 From: James Zhang Date: Wed, 18 Apr 2012 10:52:01 -0400 Subject: [PATCH 185/822] freetdm: fix queue full problem - restore flushing queue when channel state goes to down --- .../freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 928db54d51..1098126890 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -1599,6 +1599,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) ftdm_channel_t *close_chan = ftdmchan; /* close the channel */ SS7_DEBUG_CHAN(ftdmchan,"FTDM Channel Close %s\n", ""); + sngss7_flush_queue(sngss7_info->event_queue); ftdm_channel_close (&close_chan); } From ea43cacec763e9e6f347e88f32fa91ba58225a2f Mon Sep 17 00:00:00 2001 From: dyatsin Date: Sun, 22 Apr 2012 07:57:37 -0700 Subject: [PATCH 186/822] initial commit --- README.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000000..828df27ffb --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +freeswitch +========== + +Personal Copy of Freeswitch \ No newline at end of file From d56aebcc13606e053f4c19bb64cf064ce2f59343 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Mon, 30 Apr 2012 14:22:42 -0400 Subject: [PATCH 187/822] Changed error message from CRIT to ERROR, because message is not CRITICAL --- src/switch_core_session.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/switch_core_session.c b/src/switch_core_session.c index 427eb64eb0..0c9252ebc5 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -1419,9 +1419,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_thread_launch(switch_core_se switch_mutex_lock(session->mutex); if (switch_test_flag(session, SSF_THREAD_RUNNING)) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Cannot double-launch thread!\n"); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot double-launch thread!\n"); } else if (switch_test_flag(session, SSF_THREAD_STARTED)) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Cannot launch thread again after it has already been run!\n"); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot launch thread again after it has already been run!\n"); } else { switch_set_flag(session, SSF_THREAD_RUNNING); switch_set_flag(session, SSF_THREAD_STARTED); From 67c43a075917e0de6273c6af883e29292d055c63 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 4 May 2012 18:42:59 -0400 Subject: [PATCH 188/822] Initial commit --- libs/freetdm/src/include/freetdm.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 48758f406f..e9040231b5 100755 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -40,7 +40,6 @@ #ifndef FREETDM_H #define FREETDM_H - #include "ftdm_declare.h" #include "ftdm_call_utils.h" From 6a32e98c492f66fb5914e5f585c62f88bad09714 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Tue, 15 May 2012 19:37:41 -0400 Subject: [PATCH 189/822] Add mod_megaco skeleton with basic profile support and a lot of todos for Kapil --- libs/ldns/install-sh | 29 +++-- src/include/switch_apr.h | 3 +- src/mod/endpoints/mod_megaco/Makefile | 3 + src/mod/endpoints/mod_megaco/megaco.c | 132 ++++++++++++++++++++ src/mod/endpoints/mod_megaco/mod_megaco.c | 141 ++++++++++++++++++++++ src/mod/endpoints/mod_megaco/mod_megaco.h | 56 +++++++++ 6 files changed, 352 insertions(+), 12 deletions(-) create mode 100644 src/mod/endpoints/mod_megaco/Makefile create mode 100644 src/mod/endpoints/mod_megaco/megaco.c create mode 100644 src/mod/endpoints/mod_megaco/mod_megaco.c create mode 100644 src/mod/endpoints/mod_megaco/mod_megaco.h diff --git a/libs/ldns/install-sh b/libs/ldns/install-sh index 6781b987bd..a9244eb078 100755 --- a/libs/ldns/install-sh +++ b/libs/ldns/install-sh @@ -1,7 +1,7 @@ #!/bin/sh # install - install a program, script, or datafile -scriptversion=2009-04-28.21; # UTC +scriptversion=2011-01-19.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the @@ -156,6 +156,10 @@ while test $# -ne 0; do -s) stripcmd=$stripprog;; -t) dst_arg=$2 + # Protect names problematic for `test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac shift;; -T) no_target_directory=true;; @@ -186,6 +190,10 @@ if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then fi shift # arg dst_arg=$arg + # Protect names problematic for `test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac done fi @@ -200,7 +208,11 @@ if test $# -eq 0; then fi if test -z "$dir_arg"; then - trap '(exit $?); exit' 1 2 13 15 + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. @@ -228,9 +240,9 @@ fi for src do - # Protect names starting with `-'. + # Protect names problematic for `test' and other utilities. case $src in - -*) src=./$src;; + -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then @@ -252,12 +264,7 @@ do echo "$0: no destination specified." >&2 exit 1 fi - dst=$dst_arg - # Protect names starting with `-'. - case $dst in - -*) dst=./$dst;; - esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. @@ -385,7 +392,7 @@ do case $dstdir in /*) prefix='/';; - -*) prefix='./';; + [-=\(\)!]*) prefix='./';; *) prefix='';; esac @@ -403,7 +410,7 @@ do for d do - test -z "$d" && continue + test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then diff --git a/src/include/switch_apr.h b/src/include/switch_apr.h index 0c8673570f..e125eb9390 100644 --- a/src/include/switch_apr.h +++ b/src/include/switch_apr.h @@ -773,7 +773,8 @@ typedef gid_t switch_gid_t; typedef ino_t switch_ino_t; typedef dev_t switch_dev_t; #endif - typedef off64_t switch_off_t; + +typedef off_t switch_off_t; /** * Structure for referencing file information diff --git a/src/mod/endpoints/mod_megaco/Makefile b/src/mod/endpoints/mod_megaco/Makefile new file mode 100644 index 0000000000..e65d0f78eb --- /dev/null +++ b/src/mod/endpoints/mod_megaco/Makefile @@ -0,0 +1,3 @@ +BASE=../../../.. +LOCAL_OBJS=megaco.o +include $(BASE)/build/modmake.rules diff --git a/src/mod/endpoints/mod_megaco/megaco.c b/src/mod/endpoints/mod_megaco/megaco.c new file mode 100644 index 0000000000..72d03424f1 --- /dev/null +++ b/src/mod/endpoints/mod_megaco/megaco.c @@ -0,0 +1,132 @@ +/* +* Copyright (c) 2012, Sangoma Technologies +* Mathieu Rene +* All rights reserved. +* +* +*/ + +#include "mod_megaco.h" + +megaco_profile_t *megaco_profile_locate(const char *name) +{ + megaco_profile_t *profile = switch_core_hash_find_rdlock(megaco_globals.profile_hash, name, megaco_globals.profile_rwlock); + + if (profile) { + if (switch_thread_rwlock_tryrdlock(profile->rwlock) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile %s is locked\n", name); + profile = NULL; + } + } + + return profile; +} + +void megaco_profile_release(megaco_profile_t *profile) +{ + switch_thread_rwlock_unlock(profile->rwlock); +} + +static switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) +{ + switch_xml_t cfg, xml, x_profiles, x_profile, x_settings; + switch_status_t status = SWITCH_STATUS_FALSE; + switch_event_t *event = NULL; + int count; + const char *file = "megaco.conf"; + + if (!(xml = switch_xml_open_cfg(file, &cfg, NULL))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not open %s\n", file); + goto done; + } + + if (!(x_profiles = switch_xml_child(cfg, "profiles"))) { + goto done; + } + + for (x_profile = switch_xml_child(x_profiles, "profile"); x_profile; x_profile = x_profile->next) { + const char *name = switch_xml_attr_soft(x_profile, "name"); + if (strcmp(name, profile->name)) { + continue; + } + + if (!(x_settings = switch_xml_child(x_profile, "settings"))) { + goto done; + } + count = switch_event_import_xml(switch_xml_child(x_settings, "param"), "name", "value", &event); + // status = switch_xml_config_parse_event(event, count, reload, instructions); + + /* TODO: Initialize stack configuration */ + } + +done: + if (xml) { + switch_xml_free(xml); + } + + if (event) { + switch_event_destroy(&event); + } + return status; +} + +switch_status_t megaco_profile_start(const char *profilename) +{ + switch_memory_pool_t *pool; + megaco_profile_t *profile; + + switch_assert(profilename); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Starting profile: %s\n", profilename); + + switch_core_new_memory_pool(&pool); + profile = switch_core_alloc(pool, sizeof(*profile)); + profile->pool = pool; + profile->name = switch_core_strdup(pool, profilename); + + switch_thread_rwlock_create(&profile->rwlock, pool); + + /* TODO: Kapil: Insert stack per-interface startup code here */ + + switch_core_hash_insert_wrlock(megaco_globals.profile_hash, profile->name, profile, megaco_globals.profile_rwlock); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Started profile: %s\n", profile->name); + + return SWITCH_STATUS_SUCCESS; +fail: + switch_core_destroy_memory_pool(&pool); + return SWITCH_STATUS_FALSE; +} + + +switch_status_t megaco_profile_destroy(megaco_profile_t **profile) +{ + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Stopping profile: %s\n", (*profile)->name); + switch_thread_rwlock_wrlock((*profile)->rwlock); + + + /* TODO: Kapil: Insert stack per-interface shutdown code here */ + + + switch_thread_rwlock_unlock((*profile)->rwlock); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Stopped profile: %s\n", (*profile)->name); + switch_core_hash_delete_wrlock(megaco_globals.profile_hash, (*profile)->name, megaco_globals.profile_rwlock); + + switch_core_destroy_memory_pool(&(*profile)->pool); + + return SWITCH_STATUS_SUCCESS; +} + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.c b/src/mod/endpoints/mod_megaco/mod_megaco.c new file mode 100644 index 0000000000..bf23077e00 --- /dev/null +++ b/src/mod/endpoints/mod_megaco/mod_megaco.c @@ -0,0 +1,141 @@ +/* +* Copyright (c) 2012, Sangoma Technologies +* Mathieu Rene +* All rights reserved. +* +* +*/ + +#include "mod_megaco.h" + +struct megaco_globals megaco_globals; + +SWITCH_MODULE_LOAD_FUNCTION(mod_megaco_load); +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_megaco_shutdown); +SWITCH_MODULE_DEFINITION(mod_megaco, mod_megaco_load, mod_megaco_shutdown, NULL); + + +#define MEGACO_FUNCTION_SYNTAX "profile [name] [start | stop]" +SWITCH_STANDARD_API(megaco_function) +{ + int argc; + char *argv[10]; + char *dup = NULL; + + if (zstr(cmd)) { + goto usage; + } + + dup = strdup(cmd); + argc = switch_split(dup, ' ', argv); + + if (argc < 1 || zstr(argv[0])) { + goto usage; + } + + if (!strcmp(argv[0], "profile")) { + if (zstr(argv[1]) || zstr(argv[2])) { + goto usage; + } + if (!strcmp(argv[2], "start")) { + megaco_profile_t *profile = megaco_profile_locate(argv[1]); + if (profile) { + megaco_profile_release(profile); + stream->write_function(stream, "-ERR Profile %s is already started\n", argv[2]); + } else { + megaco_profile_start(argv[1]); + stream->write_function(stream, "+OK\n"); + } + } else if (!strcmp(argv[2], "stop")) { + megaco_profile_t *profile = megaco_profile_locate(argv[1]); + if (profile) { + megaco_profile_release(profile); + megaco_profile_destroy(&profile); + stream->write_function(stream, "+OK\n"); + } else { + stream->write_function(stream, "-ERR No such profile\n"); + } + } + } + + goto done; + + usage: + stream->write_function(stream, "-ERR Usage: "MEGACO_FUNCTION_SYNTAX"\n"); + + done: + switch_safe_free(dup); + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t console_complete_hashtable(switch_hash_t *hash, const char *line, const char *cursor, switch_console_callback_match_t **matches) +{ + switch_hash_index_t *hi; + void *val; + const void *vvar; + switch_console_callback_match_t *my_matches = NULL; + switch_status_t status = SWITCH_STATUS_FALSE; + + for (hi = switch_hash_first(NULL, hash); hi; hi = switch_hash_next(hi)) { + switch_hash_this(hi, &vvar, NULL, &val); + switch_console_push_match(&my_matches, (const char *) vvar); + } + + if (my_matches) { + *matches = my_matches; + status = SWITCH_STATUS_SUCCESS; + } + + return status; +} + +static switch_status_t list_profiles(const char *line, const char *cursor, switch_console_callback_match_t **matches) +{ + switch_status_t status; + switch_thread_rwlock_rdlock(megaco_globals.profile_rwlock); + status = console_complete_hashtable(megaco_globals.profile_hash, line, cursor, matches); + switch_thread_rwlock_unlock(megaco_globals.profile_rwlock); + return status; +} + +SWITCH_MODULE_LOAD_FUNCTION(mod_megaco_load) +{ + switch_api_interface_t *api_interface; + + memset(&megaco_globals, 0, sizeof(megaco_globals)); + megaco_globals.pool = pool; + + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + + switch_core_hash_init(&megaco_globals.profile_hash, pool); + switch_thread_rwlock_create(&megaco_globals.profile_rwlock, pool); + + SWITCH_ADD_API(api_interface, "megaco", "megaco", megaco_function, MEGACO_FUNCTION_SYNTAX); + + switch_console_set_complete("add megaco profile ::megaco::list_profiles start"); + switch_console_set_complete("add megaco profile ::megaco::list_profiles stop"); + switch_console_add_complete_func("::megaco::list_profiles", list_profiles); + + /* TODO: Kapil: Insert stack global startup code here */ + + + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_megaco_shutdown) +{ + /* TODO: Kapil: Insert stack global shutdown code here */ + return SWITCH_STATUS_SUCCESS; +} + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.h b/src/mod/endpoints/mod_megaco/mod_megaco.h new file mode 100644 index 0000000000..b12982de8c --- /dev/null +++ b/src/mod/endpoints/mod_megaco/mod_megaco.h @@ -0,0 +1,56 @@ +/* +* Copyright (c) 2012, Sangoma Technologies +* Mathieu Rene +* All rights reserved. +* +* +*/ + + +#ifndef MOD_MEGACO_H +#define MOD_MEGACO_H + +#include + +struct megaco_globals { + switch_memory_pool_t *pool; + switch_hash_t *profile_hash; + switch_thread_rwlock_t *profile_rwlock; + /* TODO: Kapil: add global variables here */ +}; +extern struct megaco_globals megaco_globals; /* < defined in mod_megaco.c */ + +typedef enum { + PF_RUNNING = (1 << 0) +} megaco_profile_flags_t; + +typedef struct megaco_profile_s { + char *name; + switch_memory_pool_t *pool; + switch_thread_rwlock_t *rwlock; /* < Reference counting rwlock */ + megaco_profile_flags_t flags; + + /* TODO: Kapil: Insert interface-specific stack elements here */ +} megaco_profile_t; + + +megaco_profile_t *megaco_profile_locate(const char *name); +void megaco_profile_release(megaco_profile_t *profile); + +switch_status_t megaco_profile_start(const char *profilename); +switch_status_t megaco_profile_destroy(megaco_profile_t **profile); + + +#endif /* MOD_MEGACO_H */ + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ From bb875ce6ff692c129647206ce8956a01fcb8f9d0 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Tue, 15 May 2012 19:45:36 -0400 Subject: [PATCH 190/822] mod_megaco: add sample config file and refuse to start a profile without a configuration --- src/mod/endpoints/mod_megaco/conf/megaco.conf.xml | 9 +++++++++ src/mod/endpoints/mod_megaco/megaco.c | 8 +++++++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/mod/endpoints/mod_megaco/conf/megaco.conf.xml diff --git a/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml b/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml new file mode 100644 index 0000000000..c219023dd8 --- /dev/null +++ b/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/mod/endpoints/mod_megaco/megaco.c b/src/mod/endpoints/mod_megaco/megaco.c index 72d03424f1..9ac7af4355 100644 --- a/src/mod/endpoints/mod_megaco/megaco.c +++ b/src/mod/endpoints/mod_megaco/megaco.c @@ -56,7 +56,8 @@ static switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t r count = switch_event_import_xml(switch_xml_child(x_settings, "param"), "name", "value", &event); // status = switch_xml_config_parse_event(event, count, reload, instructions); - /* TODO: Initialize stack configuration */ + /* TODO: Kapil: Initialize stack configuration */ + status = SWITCH_STATUS_SUCCESS; } done: @@ -87,12 +88,17 @@ switch_status_t megaco_profile_start(const char *profilename) switch_thread_rwlock_create(&profile->rwlock, pool); /* TODO: Kapil: Insert stack per-interface startup code here */ + if (config_profile(profile, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error configuring profile %s\n", profile->name); + goto fail; + } switch_core_hash_insert_wrlock(megaco_globals.profile_hash, profile->name, profile, megaco_globals.profile_rwlock); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Started profile: %s\n", profile->name); return SWITCH_STATUS_SUCCESS; + fail: switch_core_destroy_memory_pool(&pool); return SWITCH_STATUS_FALSE; From dbd90db7196d98ca17eca90f216af5b0907295a3 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Tue, 15 May 2012 19:51:58 -0400 Subject: [PATCH 191/822] Add mod_megaco to modules.conf.in --- build/modules.conf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/build/modules.conf.in b/build/modules.conf.in index 1d27aaad1b..cc99d528f0 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -7,6 +7,7 @@ applications/mod_hash applications/mod_spandsp dialplans/mod_dialplan_xml endpoints/mod_sofia +endpoints/mod_megaco ../../libs/freetdm/mod_freetdm xml_int/mod_xml_cdr event_handlers/mod_event_socket From f3fe2232f38534fdaa53fa91bca6256f2c474e12 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Tue, 15 May 2012 19:52:57 -0400 Subject: [PATCH 192/822] Remove stuff that should've been gitignored --- libs/ldns/install-sh | 29 +++++++++++------------------ src/include/switch_apr.h | 3 +-- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/libs/ldns/install-sh b/libs/ldns/install-sh index a9244eb078..6781b987bd 100755 --- a/libs/ldns/install-sh +++ b/libs/ldns/install-sh @@ -1,7 +1,7 @@ #!/bin/sh # install - install a program, script, or datafile -scriptversion=2011-01-19.21; # UTC +scriptversion=2009-04-28.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the @@ -156,10 +156,6 @@ while test $# -ne 0; do -s) stripcmd=$stripprog;; -t) dst_arg=$2 - # Protect names problematic for `test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac shift;; -T) no_target_directory=true;; @@ -190,10 +186,6 @@ if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then fi shift # arg dst_arg=$arg - # Protect names problematic for `test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac done fi @@ -208,11 +200,7 @@ if test $# -eq 0; then fi if test -z "$dir_arg"; then - do_exit='(exit $ret); exit $ret' - trap "ret=129; $do_exit" 1 - trap "ret=130; $do_exit" 2 - trap "ret=141; $do_exit" 13 - trap "ret=143; $do_exit" 15 + trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. @@ -240,9 +228,9 @@ fi for src do - # Protect names problematic for `test' and other utilities. + # Protect names starting with `-'. case $src in - -* | [=\(\)!]) src=./$src;; + -*) src=./$src;; esac if test -n "$dir_arg"; then @@ -264,7 +252,12 @@ do echo "$0: no destination specified." >&2 exit 1 fi + dst=$dst_arg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst;; + esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. @@ -392,7 +385,7 @@ do case $dstdir in /*) prefix='/';; - [-=\(\)!]*) prefix='./';; + -*) prefix='./';; *) prefix='';; esac @@ -410,7 +403,7 @@ do for d do - test X"$d" = X && continue + test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then diff --git a/src/include/switch_apr.h b/src/include/switch_apr.h index e125eb9390..0c8673570f 100644 --- a/src/include/switch_apr.h +++ b/src/include/switch_apr.h @@ -773,8 +773,7 @@ typedef gid_t switch_gid_t; typedef ino_t switch_ino_t; typedef dev_t switch_dev_t; #endif - -typedef off_t switch_off_t; + typedef off64_t switch_off_t; /** * Structure for referencing file information From 32c5100e625f99c68f7979bddc24100aeea8e293 Mon Sep 17 00:00:00 2001 From: kapil Date: Wed, 16 May 2012 18:36:26 +0530 Subject: [PATCH 193/822] Adding megaco stack configuration code and "megaco.conf.xml" --- src/mod/endpoints/mod_megaco/Makefile | 3 +- .../endpoints/mod_megaco/conf/megaco.conf.xml | 51 +++- src/mod/endpoints/mod_megaco/megaco.c | 61 ++++- src/mod/endpoints/mod_megaco/megaco_cfg.h | 98 ++++++++ src/mod/endpoints/mod_megaco/megaco_xml.c | 219 ++++++++++++++++++ src/mod/endpoints/mod_megaco/mod_megaco.c | 102 +++++++- src/mod/endpoints/mod_megaco/mod_megaco.h | 19 +- 7 files changed, 520 insertions(+), 33 deletions(-) create mode 100644 src/mod/endpoints/mod_megaco/megaco_cfg.h create mode 100644 src/mod/endpoints/mod_megaco/megaco_xml.c diff --git a/src/mod/endpoints/mod_megaco/Makefile b/src/mod/endpoints/mod_megaco/Makefile index e65d0f78eb..29349edca1 100644 --- a/src/mod/endpoints/mod_megaco/Makefile +++ b/src/mod/endpoints/mod_megaco/Makefile @@ -1,3 +1,4 @@ BASE=../../../.. -LOCAL_OBJS=megaco.o +LOCAL_OBJS=megaco.o megaco_cfg.o +LOCAL_LDFLAGS=-lsng_megaco include $(BASE)/build/modmake.rules diff --git a/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml b/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml index c219023dd8..ed849030bf 100644 --- a/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml +++ b/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml @@ -1,9 +1,46 @@ - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mod/endpoints/mod_megaco/megaco.c b/src/mod/endpoints/mod_megaco/megaco.c index 9ac7af4355..20024ace87 100644 --- a/src/mod/endpoints/mod_megaco/megaco.c +++ b/src/mod/endpoints/mod_megaco/megaco.c @@ -29,34 +29,73 @@ void megaco_profile_release(megaco_profile_t *profile) static switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) { - switch_xml_t cfg, xml, x_profiles, x_profile, x_settings; + switch_xml_t cfg, xml, mg_interfaces, mg_interface, tpt_interfaces, tpt_interface, peer_interfaces, peer_interface; switch_status_t status = SWITCH_STATUS_FALSE; switch_event_t *event = NULL; - int count; const char *file = "megaco.conf"; + const char* mg_profile_tpt_id = NULL; + const char* mg_profile_peer_id = NULL; if (!(xml = switch_xml_open_cfg(file, &cfg, NULL))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not open %s\n", file); goto done; } - if (!(x_profiles = switch_xml_child(cfg, "profiles"))) { + if (!(mg_interfaces = switch_xml_child(cfg, "sng_mg_interfaces"))) { goto done; } - for (x_profile = switch_xml_child(x_profiles, "profile"); x_profile; x_profile = x_profile->next) { - const char *name = switch_xml_attr_soft(x_profile, "name"); + /* iterate through MG Interface list to build all MG profiles */ + for (mg_interface = switch_xml_child(mg_interfaces, "sng_mg_interface"); mg_interface; mg_interface = mg_interface->next) { + + const char *name = switch_xml_attr_soft(mg_interface, "name"); if (strcmp(name, profile->name)) { continue; } - if (!(x_settings = switch_xml_child(x_profile, "settings"))) { + /* parse MG profile */ + if(SWITCH_STATUS_FALSE == sng_parse_mg_profile(mg_interface)) { goto done; } - count = switch_event_import_xml(switch_xml_child(x_settings, "param"), "name", "value", &event); - // status = switch_xml_config_parse_event(event, count, reload, instructions); - - /* TODO: Kapil: Initialize stack configuration */ + + mg_profile_tpt_id = switch_xml_attr_soft(mg_interface, "id"); + + /* Now get required transport profile against mg_profile_tpt_id*/ + if (!(tpt_interfaces = switch_xml_child(cfg, "sng_transport_interfaces"))) { + goto done; + } + + for (tpt_interface = switch_xml_child(tpt_interfaces, "sng_transport_interface"); tpt_interface; tpt_interface = tpt_interface->next) { + const char *id = switch_xml_attr_soft(tpt_interface, "id"); + if (strcmp(id, mg_profile_tpt_id)) { + continue; + } + + /* parse MG transport profile */ + if(SWITCH_STATUS_FALSE == sng_parse_mg_tpt_profile(tpt_interface)) { + goto done; + } + } + + /* as of now supporting only one peer */ + mg_profile_peer_id = switch_xml_attr_soft(mg_interface, "peerId"); + /* Now get required peer profile against mg_profile_peer_id*/ + if (!(peer_interfaces = switch_xml_child(cfg, "sng_mg_peer_interfaces"))) { + goto done; + } + + for (peer_interface = switch_xml_child(peer_interfaces, "sng_mg_peer_interface"); peer_interface; peer_interface = peer_interface->next) { + const char *id = switch_xml_attr_soft(peer_interface, "id"); + if (strcmp(id, mg_profile_peer_id)) { + continue; + } + + /* parse MG Peer profile */ + if(SWITCH_STATUS_FALSE == sng_parse_mg_peer_profile(peer_interface)) { + goto done; + } + } + status = SWITCH_STATUS_SUCCESS; } @@ -87,7 +126,6 @@ switch_status_t megaco_profile_start(const char *profilename) switch_thread_rwlock_create(&profile->rwlock, pool); - /* TODO: Kapil: Insert stack per-interface startup code here */ if (config_profile(profile, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error configuring profile %s\n", profile->name); goto fail; @@ -125,7 +163,6 @@ switch_status_t megaco_profile_destroy(megaco_profile_t **profile) return SWITCH_STATUS_SUCCESS; } - /* For Emacs: * Local Variables: * mode:c diff --git a/src/mod/endpoints/mod_megaco/megaco_cfg.h b/src/mod/endpoints/mod_megaco/megaco_cfg.h new file mode 100644 index 0000000000..54bf310b29 --- /dev/null +++ b/src/mod/endpoints/mod_megaco/megaco_cfg.h @@ -0,0 +1,98 @@ +/* +* Copyright (c) 2012, Sangoma Technologies +* Kapil Gupta +* All rights reserved. +* +* +*/ + +#include "sng_megaco/sng_ss7.h" + +#ifndef _MEGACO_CFG_H_ +#define _MEGACO_CFG_H_ + +#define MAX_MID_LEN 30 +#define MAX_DOMAIN_LEN 30 +#define MAX_NAME_LEN 25 +#define MAX_MG_PROFILES 5 + +typedef struct sng_mg_peer{ + char name[MAX_NAME_LEN]; /* Peer Name as defined in config file */ + uint16_t id; /* Peer ID as defined in config file */ + uint8_t ipaddr[MAX_DOMAIN_LEN]; /* Peer IP */ + uint16_t port; /*Peer Port */ + uint8_t mid[MAX_MID_LEN]; /* Peer H.248 MID */ + uint16_t encoding_type; /* Encoding TEXT/Binary */ +}sng_mg_peer_t; + +typedef struct sng_mg_peers{ + uint16_t total_peer; /* Total number of MGC Peer */ + sng_mg_peer_t peers[MG_MAX_PEERS+1]; +}sng_mg_peers_t; + +typedef struct sng_mg_transport_profile{ + char name[MAX_NAME_LEN]; /* Peer Name as defined in config file */ + uint32_t id; /* map to tsap id */ + uint16_t transport_type; /* transport type */ +}sng_mg_transport_profile_t; + + +typedef enum{ + SNG_MG_TPT_NONE, + SNG_MG_TPT_UDP, + SNG_MG_TPT_TCP, + SNG_MG_TPT_SCTP, + SNG_MG_TPT_MTP3 +}sng_mg_transport_types_e; + +typedef enum{ + SNG_MG_NONE, + SNG_MG_MGCP, + SNG_MG_MEGACO, +}sng_mg_protocol_types_e; + +typedef enum{ + SNG_MG_ENCODING_NONE, + SNG_MG_ENCODING_TEXT, + SNG_MG_ENCODING_BINARY, +}sng_mg_encoding_types_e; + + + +/* each profile is corresponds to each MG Instance */ +typedef struct sng_mg_cfg{ + char name[MAX_NAME_LEN]; /* MG(Virtual MG) Name as defined in config file */ + uint32_t id; /* Id - map to MG SAP ID */ + uint8_t mid[MAX_MID_LEN]; /* MG H.248 MID */ + uint8_t my_domain[MAX_DOMAIN_LEN]; /* local domain name */ + uint8_t my_ipaddr[MAX_DOMAIN_LEN]; /* local domain name */ + uint32_t port; /* port */ + uint16_t peer_id; /* MGC Peer ID */ + uint16_t transport_prof_id; /* Transport profile id ..this also will be the spId for MG SAP*/ + uint16_t protocol_type; /* MEGACO/MGCP */ +}sng_mg_cfg_t; + + +typedef struct sng_mg_gbl_cfg{ + sng_mg_cfg_t mgCfg[MAX_MG_PROFILES + 1]; + sng_mg_transport_profile_t mgTptProf[MG_MAX_PEERS+1]; /* transport profile */ + sng_mg_peers_t mgPeer; +}sng_mg_gbl_cfg_t; + + +extern switch_status_t sng_parse_mg_peer_profile(switch_xml_t mg_peer_profile); +extern switch_status_t sng_parse_mg_tpt_profile(switch_xml_t mg_tpt_profile); +extern switch_status_t sng_parse_mg_profile(switch_xml_t mg_interface); + + +void handle_sng_log(uint8_t level, char *fmt, ...); +void handle_mgco_sta_ind(Pst *pst, SuId suId, MgMgtSta* msg); +void handle_mgco_txn_sta_ind(Pst *pst, SuId suId, MgMgcoInd* msg); +void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* msg); +void handle_mgco_cntrl_cfm(Pst *pst, SuId suId, MgMgtCntrl* cntrl, Reason reason); +void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg); +void handle_mgco_audit_cfm(Pst *pst, SuId suId, MgMgtAudit* audit, Reason reason); +void handle_mg_alarm(Pst *pst, MgMngmt *sta); +void handle_tucl_alarm(Pst *pst, HiMngmt *sta); + +#endif /* _MEGACO_CFG_H_ */ diff --git a/src/mod/endpoints/mod_megaco/megaco_xml.c b/src/mod/endpoints/mod_megaco/megaco_xml.c new file mode 100644 index 0000000000..506cc3b29e --- /dev/null +++ b/src/mod/endpoints/mod_megaco/megaco_xml.c @@ -0,0 +1,219 @@ +/* +* Copyright (c) 2012, Sangoma Technologies +* Kapil Gupta +* All rights reserved. +* +* +*/ +#include "mod_megaco.h" + + +switch_status_t sng_parse_mg_profile(switch_xml_t mg_interface) +{ + int i = 0x00; + const char *prof_name = NULL; + switch_xml_t param; + + /*************************************************************************/ + prof_name = switch_xml_attr_soft(mg_interface, "name"); + + /*************************************************************************/ + for (param = switch_xml_child(mg_interface, "param"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + if (!var || !val) { + continue; + } + + /******************************************************************************************/ + if(!strcasecmp(var, "id")){ + i = atoi(val); + megaco_globals.g_mg_cfg.mgCfg[i].id = i; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mg_interface Id[%d] \n", i); + /*******************************************************************************************/ + }else if(!strcasecmp(var, "protocol")){ + /********************************************************************************************/ + if(!strcasecmp(val,"MEGACO")) { + megaco_globals.g_mg_cfg.mgCfg[i].protocol_type = SNG_MG_MEGACO; + }else if(!strcasecmp(val,"MGCP")){ + megaco_globals.g_mg_cfg.mgCfg[i].protocol_type = SNG_MG_MGCP; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MGCP Protocol Not Yet Supported \n"); + return SWITCH_STATUS_FALSE; + }else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Protocol Value[%s] \n",val); + return SWITCH_STATUS_FALSE; + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mg_interface protocol[%d] \n", + megaco_globals.g_mg_cfg.mgCfg[i].protocol_type); + /********************************************************************************************/ + }else if(!strcasecmp(var, "transportProfileId")){ + /********************************************************************************************/ + megaco_globals.g_mg_cfg.mgCfg[i].transport_prof_id = atoi(val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mg_interface transport_prof_id[%d] \n", + megaco_globals.g_mg_cfg.mgCfg[i].transport_prof_id); + /********************************************************************************************/ + }else if(!strcasecmp(var, "localIp")){ + /***********************************************************************i*********************/ + strcpy((char*)&megaco_globals.g_mg_cfg.mgCfg[i].my_ipaddr[0],val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mg_interface my_ipaddr[%s] \n", + megaco_globals.g_mg_cfg.mgCfg[i].my_ipaddr); + /********************************************************************************************/ + }else if(!strcasecmp(var, "port")){ + /********************************************************************************************/ + megaco_globals.g_mg_cfg.mgCfg[i].port = atoi(val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + " mg_interface my_port[%d] \n", megaco_globals.g_mg_cfg.mgCfg[i].port); + /********************************************************************************************/ + }else if(!strcasecmp(var, "myDomainName")){ + /********************************************************************************************/ + strcpy((char*)&megaco_globals.g_mg_cfg.mgCfg[i].my_domain[0],val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + " mg_interface myDomainName[%s] \n", megaco_globals.g_mg_cfg.mgCfg[i].my_domain); + /********************************************************************************************/ + }else if(!strcasecmp(var, "mid")){ + /********************************************************************************************/ + strcpy((char*)&megaco_globals.g_mg_cfg.mgCfg[i].mid[0],val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + " mg_interface mid[%s] \n", megaco_globals.g_mg_cfg.mgCfg[i].mid); + /********************************************************************************************/ + }else if(!strcasecmp(var, "peerId")){ + /********************************************************************************************/ + megaco_globals.g_mg_cfg.mgCfg[i].peer_id = atoi(val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + " mg_interface peerId[%d] \n", megaco_globals.g_mg_cfg.mgCfg[i].peer_id); + /********************************************************************************************/ + }else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " Invalid var[%s] in mg_interface \n", var); + return SWITCH_STATUS_FALSE; + } + } + + strcpy((char*)&megaco_globals.g_mg_cfg.mgCfg[i].name[0], prof_name); + + return SWITCH_STATUS_SUCCESS; +} + +/***********************************************************************************************************/ + +switch_status_t sng_parse_mg_tpt_profile(switch_xml_t mg_tpt_profile) +{ + int i = 0x00; + switch_xml_t param; + const char *prof_name = NULL; + + /*************************************************************************/ + prof_name = switch_xml_attr_soft(mg_tpt_profile, "name"); + + /*************************************************************************/ + for (param = switch_xml_child(mg_tpt_profile, "param"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + if (!var || !val) { + continue; + } + + /******************************************************************************************/ + if(!strcasecmp(var, "id")){ + /*******************************************************************************************/ + i = atoi(val); + megaco_globals.g_mg_cfg.mgTptProf[i].id = i; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mg_tpt_profile Id[%d] \n", i); + /*******************************************************************************************/ + }else if(!strcasecmp(var, "transportType")){ + /*******************************************************************************************/ + if(!strcasecmp(val,"UDP")) { + megaco_globals.g_mg_cfg.mgTptProf[i].transport_type = SNG_MG_TPT_UDP; + }else if(!strcasecmp(val,"TCP")){ + megaco_globals.g_mg_cfg.mgTptProf[i].transport_type = SNG_MG_TPT_TCP; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "TCP Transport for H.248 Protocol Not Yet Supported \n"); + return SWITCH_STATUS_FALSE; + }else if(!strcasecmp(val,"STCP")){ + megaco_globals.g_mg_cfg.mgTptProf[i].transport_type = SNG_MG_TPT_SCTP; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "STCP Transport for H.248 Protocol Not Yet Supported \n"); + return SWITCH_STATUS_FALSE; + }else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Protocol Value[%s] \n",val); + return SWITCH_STATUS_FALSE; + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mg_tpt_profile transport_type[%d] \n", + megaco_globals.g_mg_cfg.mgTptProf[i].transport_type); + /********************************************************************************************/ + }else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " Invalid var[%s] in mg_transport \n", var); + return SWITCH_STATUS_FALSE; + } + } + + strcpy((char*)&megaco_globals.g_mg_cfg.mgTptProf[i].name[0], prof_name); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + " mg_tpt_profile Name[%s] \n", &megaco_globals.g_mg_cfg.mgTptProf[i].name[0]); + + return SWITCH_STATUS_SUCCESS; +} +/***********************************************************************************************************/ + +switch_status_t sng_parse_mg_peer_profile(switch_xml_t mg_peer_profile) +{ + int i = 0x00; + switch_xml_t param; + const char *prof_name = NULL; + + /*************************************************************************/ + prof_name = switch_xml_attr_soft(mg_peer_profile, "name"); + + for (param = switch_xml_child(mg_peer_profile, "param"); param; param = param->next) { + /***********************************************************************************************************/ + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + if (!var || !val) { + continue; + } + + /***********************************************************************************************************/ + if(!strcasecmp(var, "id")){ + /***********************************************************************************************************/ + i = atoi(val); + megaco_globals.g_mg_cfg.mgPeer.peers[i].id = i; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mg_peer_profile Id[%d] \n", i); + /***********************************************************************************************************/ + }else if(!strcasecmp(var, "port")){ + /***********************************************************************************************************/ + megaco_globals.g_mg_cfg.mgPeer.peers[i].port = atoi(val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + " mg_peer_profile port[%d] \n", megaco_globals.g_mg_cfg.mgPeer.peers[i].port); + /***********************************************************************************************************/ + }else if(!strcasecmp(var, "encodingScheme")){ + /***********************************************************************************************************/ + if(!strcasecmp(val, "TEXT")){ + megaco_globals.g_mg_cfg.mgPeer.peers[i].encoding_type = SNG_MG_ENCODING_TEXT; + } else if(!strcasecmp(val, "BINARY")){ + megaco_globals.g_mg_cfg.mgPeer.peers[i].encoding_type = SNG_MG_ENCODING_BINARY; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Encoding Type[%s] \n",val); + return SWITCH_STATUS_FALSE; + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + " mg_peer_profile encodingScheme[%d] \n", megaco_globals.g_mg_cfg.mgPeer.peers[i].encoding_type); + /***********************************************************************************************************/ + }else if(!strcasecmp(var, "mid")){ + /***********************************************************************************************************/ + strcpy((char*)&megaco_globals.g_mg_cfg.mgPeer.peers[i].mid[0],val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + " mg_peer_profile mid[%s] \n", megaco_globals.g_mg_cfg.mgPeer.peers[i].mid); + /***********************************************************************************************************/ + }else if(!strcasecmp(var, "ip")){ + /***********************************************************************************************************/ + strcpy((char*)&megaco_globals.g_mg_cfg.mgPeer.peers[i].ipaddr[0],val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + " mg_peer_profile ip[%s] \n", megaco_globals.g_mg_cfg.mgPeer.peers[i].ipaddr); + /***********************************************************************************************************/ + }else{ + /***********************************************************************************************************/ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " Invalid var[%s] in mg_peer \n", var); + return SWITCH_STATUS_FALSE; + } + } + + return SWITCH_STATUS_SUCCESS; +} +/***********************************************************************************************************/ diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.c b/src/mod/endpoints/mod_megaco/mod_megaco.c index bf23077e00..bda8e53ec0 100644 --- a/src/mod/endpoints/mod_megaco/mod_megaco.c +++ b/src/mod/endpoints/mod_megaco/mod_megaco.c @@ -9,6 +9,7 @@ #include "mod_megaco.h" struct megaco_globals megaco_globals; +static sng_isup_event_interface_t sng_event; SWITCH_MODULE_LOAD_FUNCTION(mod_megaco_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_megaco_shutdown); @@ -115,9 +116,25 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_megaco_load) switch_console_set_complete("add megaco profile ::megaco::list_profiles start"); switch_console_set_complete("add megaco profile ::megaco::list_profiles stop"); switch_console_add_complete_func("::megaco::list_profiles", list_profiles); - - /* TODO: Kapil: Insert stack global startup code here */ - + + + /* Initialize MEGACO Stack */ + sng_event.mg.sng_mgco_txn_ind = handle_mgco_txn_ind; + sng_event.mg.sng_mgco_cmd_ind = handle_mgco_cmd_ind; + sng_event.mg.sng_mgco_txn_sta_ind = handle_mgco_txn_sta_ind; + sng_event.mg.sng_mgco_sta_ind = handle_mgco_sta_ind; + sng_event.mg.sng_mgco_cntrl_cfm = handle_mgco_cntrl_cfm; + sng_event.mg.sng_mgco_audit_cfm = handle_mgco_audit_cfm; + + /* Alarm CB */ + sng_event.sm.sng_mg_alarm = handle_mg_alarm; + sng_event.sm.sng_tucl_alarm = handle_tucl_alarm; + + /* Log */ + sng_event.sm.sng_log = handle_sng_log; + + /* initalize sng_mg library */ + sng_isup_init_gen(&sng_event); return SWITCH_STATUS_SUCCESS; } @@ -128,6 +145,85 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_megaco_shutdown) return SWITCH_STATUS_SUCCESS; } +/*****************************************************************************************************************************/ +void handle_sng_log(uint8_t level, char *fmt, ...) +{ + int log_level; + char print_buf[1024]; + va_list ptr; + + memset(&print_buf[0],0,sizeof(1024)); + + va_start(ptr, fmt); + + switch(level) + { + case SNG_LOGLEVEL_DEBUG: log_level = SWITCH_LOG_DEBUG; break; + case SNG_LOGLEVEL_INFO: log_level = SWITCH_LOG_INFO; break; + case SNG_LOGLEVEL_WARN: log_level = SWITCH_LOG_WARNING; break; + case SNG_LOGLEVEL_ERROR: log_level = SWITCH_LOG_ERROR; break; + case SNG_LOGLEVEL_CRIT: log_level = SWITCH_LOG_CRIT; break; + default: log_level = SWITCH_LOG_DEBUG; break; + }; + + vsprintf(&print_buf[0], fmt, ptr); + + switch_log_printf(SWITCH_CHANNEL_LOG, log_level, " MOD_MEGACO: %s \n", &print_buf[0]); + + va_end(ptr); +} + +/*****************************************************************************************************************************/ + +void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) +{ + /*TODO*/ +} + +/*****************************************************************************************************************************/ +void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) +{ + /*TODO*/ +} + +/*****************************************************************************************************************************/ +void handle_mgco_sta_ind(Pst *pst, SuId suId, MgMgtSta* sta) +{ + /*TODO*/ +} + +/*****************************************************************************************************************************/ + +void handle_mgco_txn_sta_ind(Pst *pst, SuId suId, MgMgcoInd* txn_sta_ind) +{ + /*TODO*/ +} + +/*****************************************************************************************************************************/ +void handle_mgco_cntrl_cfm(Pst *pst, SuId suId, MgMgtCntrl* cntrl, Reason reason) +{ + /*TODO*/ +} + +/*****************************************************************************************************************************/ +void handle_mgco_audit_cfm(Pst *pst, SuId suId, MgMgtAudit* audit, Reason reason) +{ + /*TODO*/ +} + +/*****************************************************************************************************************************/ +void handle_mg_alarm(Pst *pst, MgMngmt *sta) +{ + /*TODO*/ +} + +/*****************************************************************************************************************************/ +void handle_tucl_alarm(Pst *pst, HiMngmt *sta) +{ + /*TODO*/ +} + +/*****************************************************************************************************************************/ /* For Emacs: * Local Variables: diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.h b/src/mod/endpoints/mod_megaco/mod_megaco.h index b12982de8c..3efa48e3bc 100644 --- a/src/mod/endpoints/mod_megaco/mod_megaco.h +++ b/src/mod/endpoints/mod_megaco/mod_megaco.h @@ -11,12 +11,13 @@ #define MOD_MEGACO_H #include +#include "megaco_cfg.h" struct megaco_globals { - switch_memory_pool_t *pool; - switch_hash_t *profile_hash; - switch_thread_rwlock_t *profile_rwlock; - /* TODO: Kapil: add global variables here */ + switch_memory_pool_t *pool; + switch_hash_t *profile_hash; + switch_thread_rwlock_t *profile_rwlock; + sng_mg_gbl_cfg_t g_mg_cfg; }; extern struct megaco_globals megaco_globals; /* < defined in mod_megaco.c */ @@ -25,12 +26,10 @@ typedef enum { } megaco_profile_flags_t; typedef struct megaco_profile_s { - char *name; - switch_memory_pool_t *pool; - switch_thread_rwlock_t *rwlock; /* < Reference counting rwlock */ - megaco_profile_flags_t flags; - - /* TODO: Kapil: Insert interface-specific stack elements here */ + char *name; + switch_memory_pool_t *pool; + switch_thread_rwlock_t *rwlock; /* < Reference counting rwlock */ + megaco_profile_flags_t flags; } megaco_profile_t; From df76709e95241e7971e380e99f66853838902397 Mon Sep 17 00:00:00 2001 From: kapil Date: Thu, 17 May 2012 16:14:05 +0530 Subject: [PATCH 194/822] Adding code to bring up MEGACO stack --- src/mod/endpoints/mod_megaco/Makefile | 10 +- src/mod/endpoints/mod_megaco/megaco.c | 13 +- src/mod/endpoints/mod_megaco/megaco_stack.c | 964 ++++++++++++++++++ .../{megaco_cfg.h => megaco_stack.h} | 39 +- src/mod/endpoints/mod_megaco/megaco_xml.c | 1 + src/mod/endpoints/mod_megaco/mod_megaco.c | 15 +- src/mod/endpoints/mod_megaco/mod_megaco.h | 2 +- 7 files changed, 1031 insertions(+), 13 deletions(-) create mode 100644 src/mod/endpoints/mod_megaco/megaco_stack.c rename src/mod/endpoints/mod_megaco/{megaco_cfg.h => megaco_stack.h} (71%) diff --git a/src/mod/endpoints/mod_megaco/Makefile b/src/mod/endpoints/mod_megaco/Makefile index 29349edca1..4564a420e9 100644 --- a/src/mod/endpoints/mod_megaco/Makefile +++ b/src/mod/endpoints/mod_megaco/Makefile @@ -1,4 +1,12 @@ +ifndef ARCH + ARCH=$(shell uname -m) +endif + +ifeq ($(ARCH),x86_64) + LOCAL_CFLAGS+=-DBIT_64 -DALIGN_64BIT +endif + BASE=../../../.. -LOCAL_OBJS=megaco.o megaco_cfg.o +LOCAL_OBJS=megaco.o megaco_stack.o megaco_xml.o LOCAL_LDFLAGS=-lsng_megaco include $(BASE)/build/modmake.rules diff --git a/src/mod/endpoints/mod_megaco/megaco.c b/src/mod/endpoints/mod_megaco/megaco.c index 20024ace87..84bf70963b 100644 --- a/src/mod/endpoints/mod_megaco/megaco.c +++ b/src/mod/endpoints/mod_megaco/megaco.c @@ -96,7 +96,12 @@ static switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t r } } - status = SWITCH_STATUS_SUCCESS; + + /* configure the MEGACO stack */ + status = sng_mgco_cfg(profile->name); + + /* we should break from here , profile name should be unique */ + break; } done: @@ -131,6 +136,12 @@ switch_status_t megaco_profile_start(const char *profilename) goto fail; } + /* start MEGACP stack */ + if(SWITCH_STATUS_FALSE == sng_mgco_start(profilename)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error starting MEGACO Stack for profile %s\n", profile->name); + goto fail; + } + switch_core_hash_insert_wrlock(megaco_globals.profile_hash, profile->name, profile, megaco_globals.profile_rwlock); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Started profile: %s\n", profile->name); diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.c b/src/mod/endpoints/mod_megaco/megaco_stack.c new file mode 100644 index 0000000000..4ba2cd05f6 --- /dev/null +++ b/src/mod/endpoints/mod_megaco/megaco_stack.c @@ -0,0 +1,964 @@ +/* +* Copyright (c) 2012, Sangoma Technologies +* Kapil Gupta +* All rights reserved. +* +* +*/ + +/* INCLUDES *******************************************************************/ +#include "mod_megaco.h" +/******************************************************************************/ + +/* DEFINES ********************************************************************/ + +/* FUNCTION PROTOTYPES ********************************************************/ +int mgco_mg_gen_config(void); +int mgco_mu_gen_config(void); +int mgco_tucl_gen_config(void); +int mgco_mu_ssap_config(int idx); +int mgco_mg_tsap_config(int idx); +int mgco_mg_enble_debug(void); +int mgco_mg_ssap_config(int idx); +int mgco_mg_peer_config(int idx); +int mgco_mg_tpt_server_config(int idx); +int mgco_tucl_sap_config(int idx); + +int mgco_mg_tsap_bind_cntrl(int idx); +int mgco_mg_tsap_enable_cntrl(int idx); +int mgco_mg_ssap_cntrl(int idx); +int mgco_mu_ssap_cntrl(int idx); +int mgco_mg_tpt_server(int idx); + +switch_status_t sng_mgco_stack_gen_cfg(); + +/******************************************************************************/ + +/* FUNCTIONS ******************************************************************/ + +switch_status_t sng_mgco_init(sng_isup_event_interface_t* event) +{ + uint32_t major, minor, build; + + switch_assert(event); + + /* initalize sng_mg library */ + sng_isup_init_gen(event); + + /* print the version of the library being used */ + sng_isup_version(&major, &minor, &build); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"Loaded LibSng-MEGACO %d.%d.%d\n", major, minor, build); + + /* start up the stack manager */ + if (sng_isup_init_sm()) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"Failed to start Stack Manager\n"); + return SWITCH_STATUS_FALSE; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"Started Stack Manager!\n"); + } + + if (sng_isup_init_tucl()) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,"Failed to start TUCL\n"); + return SWITCH_STATUS_FALSE; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"Started TUCL!\n"); + } + + if (sng_isup_init_mg()) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,"Failed to start MG\n"); + return SWITCH_STATUS_FALSE; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"Started MG!\n"); + } + + if (sng_isup_init_mu()) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,"Failed to start MU\n"); + return SWITCH_STATUS_FALSE; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"Started MU!\n"); + } + + + /* gen config for all the layers of megaco */ + return sng_mgco_stack_gen_cfg(); +} + +/*****************************************************************************************************************/ +switch_status_t sng_mgco_stack_shutdown() +{ + /* free MEGACO Application */ + sng_isup_free_mu(); + + /* free MEGACO */ + sng_isup_free_mg(); + + /* free TUCL */ + sng_isup_free_tucl(); + + /* free SM */ + sng_isup_free_sm(); + + /* free gen */ + sng_isup_free_gen(); + + return SWITCH_STATUS_SUCCESS; +} + +/*****************************************************************************************************************/ +switch_status_t sng_mgco_stack_gen_cfg() +{ + if(mgco_mg_gen_config()) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,"MG Gen Config FAILED \n"); + return SWITCH_STATUS_FALSE; + } + else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"MG Gen Config SUCCESS \n"); + } + + if(mgco_mu_gen_config()) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,"MU(MG-Application) Gen Config FAILED \n"); + return SWITCH_STATUS_FALSE; + } + else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"MU(MG-Application) Gen Config SUCCESS \n"); + } + + if(mgco_tucl_gen_config()) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," TUCL Gen Config FAILED \n"); + return SWITCH_STATUS_FALSE; + } + else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," TUCL Gen Config SUCCESS \n"); + } + + return SWITCH_STATUS_SUCCESS; +} + + +/*****************************************************************************************************************/ + +switch_status_t sng_mgco_cfg(const char* profilename) +{ + int idx = 0x00; + + switch_assert(profilename); + + GET_MG_CFG_IDX(profilename, idx); + + if(!idx || (idx == MAX_MG_PROFILES)){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG configuration found against profilename[%s]\n",profilename); + return SWITCH_STATUS_FALSE; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," Starting MG configuration for idx[%d] against profilename[%s]\n", idx, profilename); + + if(mgco_tucl_sap_config(idx)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," mgco_tucl_sap_config FAILED \n"); + return SWITCH_STATUS_FALSE; + } + else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," mgco_tucl_sap_config SUCCESS \n"); + } + + + if(mgco_mu_ssap_config(idx)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," mgco_mu_ssap_config FAILED \n"); + return SWITCH_STATUS_FALSE; + } + else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," mgco_mu_ssap_config SUCCESS \n"); + } + + + if(mgco_mg_tsap_config(idx)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," mgco_mg_tsap_config FAILED \n"); + return SWITCH_STATUS_FALSE; + } + else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," mgco_mg_tsap_config SUCCESS \n"); + } + + if(mgco_mg_ssap_config(idx)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " mgco_mg_ssap_config FAILED \n"); + return SWITCH_STATUS_FALSE; + } + else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mgco_mg_ssap_config SUCCESS \n"); + } + + if(mgco_mg_peer_config(idx)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " mgco_mg_peer_config FAILED \n"); + return SWITCH_STATUS_FALSE; + } + else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mgco_mg_peer_config SUCCESS \n"); + } + + if(mgco_mg_tpt_server_config(idx)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " mgco_mg_tpt_server_config FAILED \n"); + return SWITCH_STATUS_FALSE; + } + else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mgco_mg_tpt_server_config SUCCESS \n"); + } + + return SWITCH_STATUS_SUCCESS; +} + +/*****************************************************************************************************************/ + +switch_status_t sng_mgco_start(const char* profilename) +{ + int idx = 0x00; + + switch_assert(profilename); + + GET_MG_CFG_IDX(profilename, idx); + + if(!idx || (idx == MAX_MG_PROFILES)){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG configuration found against profilename[%s]\n",profilename); + return SWITCH_STATUS_FALSE; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," Starting MG stack for idx[%d] against profilename[%s]\n", idx, profilename); + + if(mgco_mu_ssap_cntrl(idx)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " mgco_mu_ssap_cntrl FAILED \n"); + return SWITCH_STATUS_FALSE; + } + else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mgco_mu_ssap_cntrl SUCCESS \n"); + } + + if(mgco_mg_tsap_bind_cntrl(idx)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " mgco_mg_tsap_bind_cntrl FAILED \n"); + return SWITCH_STATUS_FALSE; + } + else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mgco_mg_tsap_bind_cntrl SUCCESS \n"); + } + + if(mgco_mg_ssap_cntrl(idx)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " mgco_mg_ssap_cntrl FAILED \n"); + return SWITCH_STATUS_FALSE; + } + else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mgco_mg_ssap_cntrl SUCCESS \n"); + } + + if(mgco_mg_tsap_enable_cntrl(idx)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " mgco_mg_tsap_enable_cntrl FAILED \n"); + return SWITCH_STATUS_FALSE; + } + else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mgco_mg_tsap_enable_cntrl SUCCESS \n"); + } + + return SWITCH_STATUS_SUCCESS; +} + +/*****************************************************************************************************************/ +int mgco_mg_tsap_bind_cntrl(int idx) +{ + MgMngmt mgMngmt; + Pst pst; /* Post for layer manager */ + MgCntrl *cntrl; + + memset(&mgMngmt, 0, sizeof(mgMngmt)); + + cntrl = &(mgMngmt.t.cntrl); + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTMG; + + /*fill in the specific fields of the header */ + mgMngmt.hdr.msgType = TCNTRL; + mgMngmt.hdr.entId.ent = ENTMG; + mgMngmt.hdr.entId.inst = S_INST; + mgMngmt.hdr.elmId.elmnt = STTSAP; + + cntrl->action = ABND_ENA; + cntrl->subAction = SAELMNT; + cntrl->spId = GET_TPT_ID(idx); + + return(sng_cntrl_mg(&pst, &mgMngmt)); +} + +/*****************************************************************************************************************/ + +int mgco_mg_tsap_enable_cntrl(int idx) +{ + MgMngmt mgMngmt; + Pst pst; /* Post for layer manager */ + MgCntrl *cntrl; + + memset(&mgMngmt, 0, sizeof(mgMngmt)); + + cntrl = &(mgMngmt.t.cntrl); + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTMG; + + /*fill in the specific fields of the header */ + mgMngmt.hdr.msgType = TCNTRL; + mgMngmt.hdr.entId.ent = ENTMG; + mgMngmt.hdr.entId.inst = S_INST; + mgMngmt.hdr.elmId.elmnt = STTSAP; + + cntrl->action = AENA; + cntrl->subAction = SAELMNT; + cntrl->spId = GET_TPT_ID(idx); + + return(sng_cntrl_mg(&pst, &mgMngmt)); +} + +/*****************************************************************************************************************/ + +int mgco_mg_tpt_server(int idx) +{ + MgMngmt mgMngmt; + Pst pst; /* Post for layer manager */ + MgCntrl *cntrl; + MgTptCntrl *tptCntrl = &mgMngmt.t.cntrl.s.tptCntrl; + CmInetIpAddr ipAddr = 0; + sng_mg_cfg_t* mgCfg = &megaco_globals.g_mg_cfg.mgCfg[idx]; + + cntrl = &(mgMngmt.t.cntrl); + + memset(&mgMngmt, 0, sizeof(mgMngmt)); + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTMG; + + tptCntrl->transportType = GET_TPT_TYPE(idx); + + tptCntrl->serverAddr.type = CM_INET_IPV4ADDR_TYPE; + tptCntrl->serverAddr.u.ipv4TptAddr.port = mgCfg->port; + if(ROK == cmInetAddr((S8*)mgCfg->my_ipaddr, &ipAddr)) + { + tptCntrl->serverAddr.u.ipv4TptAddr.address = ntohl(ipAddr); + } + + /*fill in the specific fields of the header */ + mgMngmt.hdr.msgType = TCNTRL; + mgMngmt.hdr.entId.ent = ENTMG; + mgMngmt.hdr.entId.inst = S_INST; + mgMngmt.hdr.elmId.elmnt = STSERVER; + + cntrl->action = AENA; + cntrl->subAction = SAELMNT; + cntrl->spId = (SpId)0x01; + + return(sng_cntrl_mg(&pst, &mgMngmt)); +} + +/*****************************************************************************************************************/ + +int mgco_mu_ssap_cntrl(int idx) +{ + MuMngmt mgMngmt; + Pst pst; /* Post for layer manager */ + MuCntrl *cntrl; + + memset(&mgMngmt, 0, sizeof(mgMngmt)); + + cntrl = &(mgMngmt.t.cntrl); + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTMU; + + /*fill in the specific fields of the header */ + mgMngmt.hdr.msgType = TCNTRL; + mgMngmt.hdr.entId.ent = ENTMG; + mgMngmt.hdr.entId.inst = S_INST; + mgMngmt.hdr.elmId.elmnt = STSSAP; + mgMngmt.hdr.elmId.elmntInst1 = GET_MU_SAP_ID(idx); + + cntrl->action = ABND_ENA; + cntrl->subAction = SAELMNT; + + return(sng_cntrl_mu(&pst, &mgMngmt)); +} + +/*****************************************************************************************************************/ + +int mgco_mg_ssap_cntrl(int idx) +{ + MgMngmt mgMngmt; + Pst pst; /* Post for layer manager */ + MgCntrl *cntrl; + + memset(&mgMngmt, 0, sizeof(mgMngmt)); + + cntrl = &(mgMngmt.t.cntrl); + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTMG; + + /*fill in the specific fields of the header */ + mgMngmt.hdr.msgType = TCNTRL; + mgMngmt.hdr.entId.ent = ENTMG; + mgMngmt.hdr.entId.inst = S_INST; + mgMngmt.hdr.elmId.elmnt = STSSAP; + + cntrl->action = AENA; + cntrl->subAction = SAELMNT; + cntrl->spId = (SpId)1; + + return(sng_cntrl_mg(&pst, &mgMngmt)); +} +/******************************************************************************/ + +int mgco_mg_enble_debug() +{ + MgMngmt mgMngmt; + Pst pst; /* Post for layer manager */ + MgCntrl* cntrl; + + memset(&mgMngmt, 0, sizeof(mgMngmt)); + cntrl = &mgMngmt.t.cntrl; + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTMG; + mgMngmt.hdr.msgType = TCFG; + mgMngmt.hdr.entId.ent = ENTHI; + mgMngmt.hdr.entId.inst = S_INST; + mgMngmt.hdr.elmId.elmnt = STGEN; + + cntrl->action = AENA; + cntrl->subAction = SADBG; + cntrl->s.dbg.genDbgMask = 0xfffffdff; + + return(sng_cntrl_mg(&pst, &mgMngmt)); +} + +/******************************************************************************/ +int mgco_tucl_gen_config(void) +{ + HiMngmt cfg; + Pst pst; + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTHI; + + /* clear the configuration structure */ + memset(&cfg, 0, sizeof(cfg)); + + /* fill in the post structure */ + set_dest_sm_pst(&cfg.t.cfg.s.hiGen.lmPst); + /*fill in the specific fields of the header */ + cfg.hdr.msgType = TCFG; + cfg.hdr.entId.ent = ENTHI; + cfg.hdr.entId.inst = S_INST; + cfg.hdr.elmId.elmnt = STGEN; + + cfg.t.cfg.s.hiGen.numSaps = HI_MAX_SAPS; /* number of SAPs */ + cfg.t.cfg.s.hiGen.numCons = HI_MAX_NUM_OF_CON; /* maximum num of connections */ + cfg.t.cfg.s.hiGen.numFdsPerSet = HI_MAX_NUM_OF_FD_PER_SET; /* maximum num of fds to use per set */ + cfg.t.cfg.s.hiGen.numFdBins = HI_MAX_NUM_OF_FD_HASH_BINS; /* for fd hash lists */ + cfg.t.cfg.s.hiGen.numClToAccept = HI_MAX_NUM_OF_CLIENT_TO_ACCEPT; /* clients to accept simultaneously */ + cfg.t.cfg.s.hiGen.permTsk = TRUE; /* schedule as perm task or timer */ + cfg.t.cfg.s.hiGen.schdTmrVal = HI_MAX_SCHED_TMR_VALUE; /* if !permTsk - probably ignored */ + cfg.t.cfg.s.hiGen.selTimeout = HI_MAX_SELECT_TIMEOUT_VALUE; /* select() timeout */ + + /* number of raw/UDP messages to read in one iteration */ + cfg.t.cfg.s.hiGen.numRawMsgsToRead = HI_MAX_RAW_MSG_TO_READ; + cfg.t.cfg.s.hiGen.numUdpMsgsToRead = HI_MAX_UDP_MSG_TO_READ; + + /* thresholds for congestion on the memory pool */ + cfg.t.cfg.s.hiGen.poolStrtThr = HI_MEM_POOL_START_THRESHOLD; + cfg.t.cfg.s.hiGen.poolDropThr = HI_MEM_POOL_DROP_THRESHOLD; + cfg.t.cfg.s.hiGen.poolStopThr = HI_MEM_POOL_STOP_THRESHOLD; + + cfg.t.cfg.s.hiGen.timeRes = SI_PERIOD; /* time resolution */ + +#ifdef HI_SPECIFY_GENSOCK_ADDR + cfg.t.cfg.s.hiGen.ipv4GenSockAddr.address = CM_INET_INADDR_ANY; + cfg.t.cfg.s.hiGen.ipv4GenSockAddr.port = 0; /* DAVIDY - why 0? */ +#ifdef IPV6_SUPPORTED + cfg.t.cfg.s.hiGen.ipv6GenSockAddr.address = CM_INET_INADDR6_ANY; + cfg.t.cfg.s.hiGen.ipv4GenSockAddr.port = 0; +#endif +#endif + + return(sng_cfg_tucl(&pst, &cfg)); +} + +/******************************************************************************/ + +int mgco_tucl_sap_config(int idx) +{ + HiMngmt cfg; + Pst pst; + HiSapCfg *pCfg; + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTHI; + + /* clear the configuration structure */ + memset(&cfg, 0, sizeof(cfg)); + + /* fill in the post structure */ + set_dest_sm_pst(&cfg.t.cfg.s.hiGen.lmPst); + /*fill in the specific fields of the header */ + cfg.hdr.msgType = TCFG; + cfg.hdr.entId.ent = ENTHI; + cfg.hdr.entId.inst = S_INST; + cfg.hdr.elmId.elmnt = STTSAP; + + pCfg = &cfg.t.cfg.s.hiSap; + + pCfg->spId = GET_TPT_ID(idx); + pCfg->uiSel = 0x00; /*loosley coupled */ + pCfg->flcEnb = TRUE; + pCfg->txqCongStrtLim = HI_SAP_TXN_QUEUE_CONG_START_LIMIT; + pCfg->txqCongDropLim = HI_SAP_TXN_QUEUE_CONG_DROP_LIMIT; + pCfg->txqCongStopLim = HI_SAP_TXN_QUEUE_CONG_STOP_LIMIT; + pCfg->numBins = 10; + + pCfg->uiMemId.region = S_REG; + pCfg->uiMemId.pool = S_POOL; + pCfg->uiPrior = PRIOR0; + pCfg->uiRoute = RTESPEC; + + return(sng_cfg_tucl(&pst, &cfg)); +} + +/******************************************************************************/ + +int mgco_mg_gen_config(void) +{ + MgMngmt mgMngmt; + MgGenCfg *cfg; + Pst pst; /* Post for layer manager */ + + memset(&mgMngmt, 0, sizeof(mgMngmt)); + cfg = &(mgMngmt.t.cfg.c.genCfg); + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTMG; + + /* fill in the post structure */ + set_dest_sm_pst(&mgMngmt.t.cfg.c.genCfg.lmPst); + /*fill in the specific fields of the header */ + mgMngmt.hdr.msgType = TCFG; + mgMngmt.hdr.entId.ent = ENTMG; + mgMngmt.hdr.entId.inst = S_INST; + mgMngmt.hdr.elmId.elmnt = STGEN; + + + /*----------- Fill General Configuration Parameters ---------*/ + cfg->maxSSaps = (U16)MG_MAX_SSAPS; + cfg->maxTSaps = (U32)MG_MAX_TSAPS; + cfg->maxServers = (U16)MG_MAX_SERVERS; + cfg->maxConn = (U32)10; + cfg->maxTxn = (U16)MG_MAX_OUTSTANDING_TRANSACTIONS; + cfg->maxPeer = (U32)MG_MAX_PEER; + cfg->resThUpper = (Status)7; + cfg->resThLower = (Status)3; +#if (defined(GCP_MGCP) || defined(TDS_ROLL_UPGRADE_SUPPORT)) + cfg->timeResTTL = (Ticks)10000; +#endif + + cfg->timeRes = (Ticks)10; + cfg->reCfg.rspAckEnb = MG_LMG_GET_RSPACK_MGCO; + cfg->numBlks = (U32)MG_NUM_BLK; + cfg->maxBlkSize = (Size)MG_MAXBLKSIZE; + cfg->numBinsTxnIdHl = (U16)149; + cfg->numBinsNameHl = (U16)149; + cfg->entType = LMG_ENT_GW; + cfg->numBinsTptSrvrHl = (U16)149; + cfg->indicateRetx = TRUE; /* Assume environment to be lossy */ + cfg->resOrder = LMG_RES_IPV4; /* IPV4 only */ + +#ifdef CM_ABNF_MT_LIB + cfg->firstInst = 1; + cfg->edEncTmr.enb = FALSE; + cfg->edEncTmr.val = (U16)50; + cfg->edDecTmr.enb = TRUE; + cfg->edDecTmr.val = (U16)50; + cfg->noEDInst = 1; +#endif /* CM_ABNF_MT_LIB */ + +#ifdef GCP_CH + cfg->numBinsPeerCmdHl = 20; + cfg->numBinsTransReqHl = 50; + cfg->numBinsTransIndRspCmdHl = 50; +#endif /* GCP_CH */ + +#ifdef GCP_MG + cfg->maxMgCmdTimeOut.enb =TRUE; + cfg->maxMgCmdTimeOut.val =20; +#endif /* GCP_MG */ + +#ifdef GCP_MG + cfg->maxMgCmdTimeOut.enb =TRUE; + cfg->maxMgCmdTimeOut.val =20; +#endif /* GCP_MG */ + +#ifdef GCP_MGC + cfg->maxMgcCmdTimeOut.enb =TRUE; + cfg->maxMgcCmdTimeOut.val =20; +#endif /* GCP_MG */ + +#if (defined(GCP_MGCO) && (defined GCP_VER_2_1)) + cfg->reCfg.segRspTmr.enb = TRUE; + cfg->reCfg.segRspTmr.val = (U16)50; + cfg->reCfg.segRspAckTmr.enb = TRUE; + cfg->reCfg.segRspAckTmr.val = (U16)25; +#endif + +#ifdef GCP_PKG_MGCO_ROOT + cfg->limit.pres.pres = PRSNT_NODEF; + cfg->limit.mgcOriginatedPendingLimit = 20000; + cfg->limit.mgOriginatedPendingLimit = 20000; +#endif /* GCP_PKG_MGCO_ROOT */ + + return(sng_cfg_mg(&pst, &mgMngmt)); +} + +/******************************************************************************/ + +int mgco_mu_gen_config(void) +{ + MuMngmt mgmt; + MuGenCfg *cfg; + Pst pst; /* Post for layer manager */ + + memset(&mgmt, 0, sizeof(mgmt)); + cfg = &(mgmt.t.cfg); + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTMU; + + /*fill in the specific fields of the header */ + mgmt.hdr.msgType = TCFG; + mgmt.hdr.entId.ent = ENTMU; + mgmt.hdr.entId.inst = S_INST; + mgmt.hdr.elmId.elmnt = STGEN; + + return(sng_cfg_mu(&pst, &mgmt)); +} + +/******************************************************************************/ + +int mgco_mu_ssap_config(int idx) +{ + MuMngmt mgmt; + MuSAP_t *cfg; + Pst pst; /* Post for layer manager */ + + memset(&mgmt, 0, sizeof(mgmt)); + cfg = &(mgmt.t.sapCfg); + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTMU; + + /*fill in the specific fields of the header */ + mgmt.hdr.msgType = TCFG; + mgmt.hdr.entId.ent = ENTMU; + mgmt.hdr.entId.inst = S_INST; + mgmt.hdr.elmId.elmnt = STSSAP; + + /* fill lower layer i.e. MG PST */ + cfg->ssapId = GET_MU_SAP_ID(idx); /* SSAP ID */ + cfg->spId = GET_MU_SAP_ID(idx); /* SSAP ID */ + + cfg->mem.region = S_REG; + cfg->mem.pool = S_POOL; + cfg->dstProcId = SFndProcId(); + cfg->dstEnt = ENTMG; + cfg->dstInst = S_INST; + cfg->dstPrior = PRIOR0; + cfg->dstRoute = RTESPEC; + cfg->selector = 0x00; /* Loosely coupled */ + + return(sng_cfg_mu(&pst, &mgmt)); +} + +/******************************************************************************/ + +int mgco_mg_ssap_config(int idx) +{ + MgMngmt mgMngmt; + MgSSAPCfg *pCfg; + Pst pst; /* Post for layer manager */ + CmInetIpAddr ipAddr; + int len = 0x00; + sng_mg_cfg_t* mgCfg = &megaco_globals.g_mg_cfg.mgCfg[idx]; + + memset(&mgMngmt, 0, sizeof(mgMngmt)); + pCfg = &(mgMngmt.t.cfg.c.sSAPCfg); + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTMG; + + /*fill in the specific fields of the header */ + mgMngmt.hdr.msgType = TCFG; + mgMngmt.hdr.entId.ent = ENTMG; + mgMngmt.hdr.entId.inst = S_INST; + mgMngmt.hdr.elmId.elmnt = STSSAP; + + /* FILL SAP config */ + + pCfg->sSAPId = mgCfg->id; /* SSAP ID */ + pCfg->sel = 0x00 ; /* Loosely coupled */ + pCfg->memId.region = S_REG; + pCfg->memId.pool = S_POOL; + pCfg->prior = PRIOR0; + pCfg->route = RTESPEC; + + pCfg->protocol = mgCfg->protocol_type; + + pCfg->startTxnNum = 50; + pCfg->endTxnNum = 60; + + pCfg->initReg = TRUE; + pCfg->mwdTimer = (U16)10; + + pCfg->minMgcoVersion = LMG_VER_PROF_MGCO_H248_1_0; + pCfg->maxMgcoVersion = LMG_VER_PROF_MGCO_H248_3_0; + + pCfg->userInfo.pres.pres = PRSNT_NODEF; + pCfg->userInfo.id.pres = NOTPRSNT; + pCfg->userInfo.mid.pres = PRSNT_NODEF; + pCfg->userInfo.dname.namePres.pres = PRSNT_NODEF; + + pCfg->userInfo.mid.len = (U8)strlen((char*)mgCfg->mid); + strncpy((char*)pCfg->userInfo.mid.val, (char*)mgCfg->mid, MAX_MID_LEN); + + len = (U32)strlen((char*)mgCfg->my_domain); + memcpy( (U8*)(pCfg->userInfo.dname.name), + (CONSTANT U8*)(mgCfg->my_domain), len ); + pCfg->userInfo.dname.name[len] = '\0'; + + pCfg->userInfo.dname.netAddr.type = CM_TPTADDR_IPV4; + memset(&ipAddr,'\0',sizeof(ipAddr)); + if(ROK == cmInetAddr((S8*)mgCfg->my_ipaddr,&ipAddr)) + { + pCfg->userInfo.dname.netAddr.u.ipv4NetAddr = ntohl(ipAddr); + } + + pCfg->reCfg.initRetxTmr.enb = TRUE; + pCfg->reCfg.initRetxTmr.val = MG_INIT_RTT; + pCfg->reCfg.provRspTmr.enb = TRUE; + pCfg->reCfg.provRspTmr.val = (U16)50; /* In timer resolution */ + pCfg->reCfg.provRspDelay = 2; + pCfg->reCfg.atMostOnceTmr.enb = TRUE; + pCfg->reCfg.atMostOnceTmr.val = (U16)30; + + return(sng_cfg_mg(&pst, &mgMngmt)); +} + +/******************************************************************************/ + +int mgco_mg_tsap_config(int idx) +{ + MgMngmt mgMngmt; + /* local variables */ + MgTSAPCfg *cfg; + Pst pst; /* Post for layer manager */ + sng_mg_cfg_t* mgCfg = &megaco_globals.g_mg_cfg.mgCfg[idx]; + + memset(&mgMngmt, 0, sizeof(mgMngmt)); + cfg = &(mgMngmt.t.cfg.c.tSAPCfg); + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTMG; + + /*fill in the specific fields of the header */ + mgMngmt.hdr.msgType = TCFG; + mgMngmt.hdr.entId.ent = ENTMG; + mgMngmt.hdr.entId.inst = S_INST; + mgMngmt.hdr.elmId.elmnt = STTSAP; + + /* FILL TSAP config */ + cfg->tSAPId = mgCfg->id; + cfg->spId = GET_TPT_ID(idx); + cfg->provType = GET_TPT_TYPE(idx); + + /* FILL TUCL Information */ + cfg->memId.region = S_REG; + cfg->memId.pool = S_POOL; + cfg->dstProcId = SFndProcId(); + cfg->dstEnt = ENTHI; + cfg->dstInst = S_INST; + cfg->dstPrior = PRIOR0; + cfg->dstRoute = RTESPEC; + cfg->dstSel = 0x00; /* Loosely coupled */ + cfg->bndTmrCfg.enb = TRUE; + cfg->bndTmrCfg.val = 5; /* 5 seconds */ + + + /* Disable DNS as of now */ + cfg->reCfg.idleTmr.enb = FALSE; + cfg->reCfg.dnsCfg.dnsAccess = LMG_DNS_DISABLED; + cfg->reCfg.dnsCfg.dnsAddr.type = CM_TPTADDR_IPV4; + cfg->reCfg.dnsCfg.dnsAddr.u.ipv4TptAddr.port = (U16)53; + cfg->reCfg.dnsCfg.dnsAddr.u.ipv4TptAddr.address = (CmInetIpAddr)MG_DNS_IP; + + cfg->reCfg.dnsCfg.dnsRslvTmr.enb = FALSE; + cfg->reCfg.dnsCfg.dnsRslvTmr.val = 60; /* 60 sec */ + cfg->reCfg.dnsCfg.maxRetxCnt = 4; + + cfg->reCfg.tMax = 1000; + cfg->reCfg.tptParam.type = CM_TPTPARAM_SOCK; + cfg->reCfg.tptParam.u.sockParam.listenQSize = 5; + cfg->reCfg.tptParam.u.sockParam.numOpts = 0; + + + return(sng_cfg_mg(&pst, &mgMngmt)); +} + +/******************************************************************************/ + +int mgco_mg_peer_config(int idx) +{ + MgMngmt mgMngmt; + MgGcpEntCfg *cfg; + Pst pst; /* Post for layer manager */ + U32 peerIdx = 0; + CmInetIpAddr ipAddr = 0; + sng_mg_cfg_t* mgCfg = &megaco_globals.g_mg_cfg.mgCfg[idx]; + sng_mg_peer_t* mgPeer = &megaco_globals.g_mg_cfg.mgPeer.peers[mgCfg->peer_id]; + + memset(&mgMngmt, 0, sizeof(mgMngmt)); + cfg = &(mgMngmt.t.cfg.c.mgGcpEntCfg); + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTMG; + + /*fill in the specific fields of the header */ + mgMngmt.hdr.msgType = TCFG; + mgMngmt.hdr.entId.ent = ENTMG; + mgMngmt.hdr.entId.inst = S_INST; + mgMngmt.hdr.elmId.elmnt = STGCPENT; + + cfg->numPeer = megaco_globals.g_mg_cfg.mgPeer.total_peer; + cfg->peerCfg[peerIdx].sSAPId = mgCfg->id; /* SSAP ID */; + cfg->peerCfg[peerIdx].port = mgPeer->port; + cfg->peerCfg[peerIdx].tsapId = GET_TPT_ID(idx); + + cfg->peerCfg[peerIdx].mtuSize = MG_MAX_MTU_SIZE; + + + cfg->peerCfg[peerIdx].peerAddrTbl.count = 1; + cfg->peerCfg[peerIdx].peerAddrTbl.netAddr[0].type = + CM_NETADDR_IPV4; + + if(ROK == cmInetAddr((S8*)&mgPeer->ipaddr[0],&ipAddr)) + { + cfg->peerCfg[peerIdx].peerAddrTbl.netAddr[0].u.ipv4NetAddr = ntohl(ipAddr); + } + else + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "cmInetAddr failed \n"); + cfg->peerCfg[peerIdx].peerAddrTbl.count = 0; + } + +#ifdef GCP_MG + cfg->peerCfg[peerIdx].transportType = GET_TPT_TYPE(idx); + cfg->peerCfg[peerIdx].encodingScheme = GET_ENCODING_TYPE(idx); + cfg->peerCfg[peerIdx].mgcPriority = 0; + cfg->peerCfg[peerIdx].useAHScheme = FALSE; + cfg->peerCfg[peerIdx].mid.pres = PRSNT_NODEF; + cfg->peerCfg[peerIdx].mid.len = strlen((char*)mgPeer->mid); + cmMemcpy((U8 *)cfg->peerCfg[peerIdx].mid.val, + (CONSTANT U8*)(char*)mgPeer->mid, + cfg->peerCfg[peerIdx].mid.len); + +#endif /* GCP_MG */ + + return(sng_cfg_mg(&pst, &mgMngmt)); +} + +/******************************************************************************/ + +int mgco_mg_tpt_server_config(int idx) +{ + MgMngmt mgMngmt; + MgTptSrvrCfg *cfg; + Pst pst; /* Post for layer manager */ + CmInetIpAddr ipAddr = 0; + sng_mg_cfg_t* mgCfg = &megaco_globals.g_mg_cfg.mgCfg[idx]; + int srvIdx = 0; + + memset(&mgMngmt, 0, sizeof(mgMngmt)); + cfg = &(mgMngmt.t.cfg.c.tptSrvrCfg); + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTMG; + + /*fill in the specific fields of the header */ + mgMngmt.hdr.msgType = TCFG; + mgMngmt.hdr.entId.ent = ENTMG; + mgMngmt.hdr.entId.inst = S_INST; + mgMngmt.hdr.elmId.elmnt = STSERVER; + + cfg->count = 1; + cfg->srvr[srvIdx].isDefault = TRUE; + cfg->srvr[srvIdx].sSAPId = mgCfg->id; + cfg->srvr[srvIdx].tSAPId = GET_TPT_ID(idx); + cfg->srvr[srvIdx].protocol = mgCfg->protocol_type; + cfg->srvr[srvIdx].transportType = GET_TPT_TYPE(idx); + cfg->srvr[srvIdx].encodingScheme = GET_ENCODING_TYPE(idx); + + cfg->srvr[srvIdx].tptParam.type = CM_TPTPARAM_SOCK; + cfg->srvr[srvIdx].tptParam.u.sockParam.listenQSize = 5; + cfg->srvr[srvIdx].tptParam.u.sockParam.numOpts = 0; + cfg->srvr[srvIdx].lclTptAddr.type = CM_TPTADDR_IPV4; + cfg->srvr[srvIdx].lclTptAddr.u.ipv4TptAddr.port = mgCfg->port; + if(ROK == cmInetAddr((S8*)mgCfg->my_ipaddr, &ipAddr)) + { + cfg->srvr[srvIdx].lclTptAddr.u.ipv4TptAddr.address = ntohl(ipAddr); + } + + return(sng_cfg_mg(&pst, &mgMngmt)); +} + +/******************************************************************************/ diff --git a/src/mod/endpoints/mod_megaco/megaco_cfg.h b/src/mod/endpoints/mod_megaco/megaco_stack.h similarity index 71% rename from src/mod/endpoints/mod_megaco/megaco_cfg.h rename to src/mod/endpoints/mod_megaco/megaco_stack.h index 54bf310b29..24cf6e26ca 100644 --- a/src/mod/endpoints/mod_megaco/megaco_cfg.h +++ b/src/mod/endpoints/mod_megaco/megaco_stack.h @@ -51,12 +51,21 @@ typedef enum{ SNG_MG_MEGACO, }sng_mg_protocol_types_e; +#define PRNT_PROTOCOL_TYPE(_val)\ + ((_val == SNG_MG_MGCP)?"SNG_MG_MGCP":\ + (_val == SNG_MG_MEGACO)?"SNG_MG_MEGACO":\ + "SNG_MG_NONE") + typedef enum{ SNG_MG_ENCODING_NONE, - SNG_MG_ENCODING_TEXT, SNG_MG_ENCODING_BINARY, + SNG_MG_ENCODING_TEXT, }sng_mg_encoding_types_e; +#define PRNT_ENCODING_TYPE(_val)\ + ((_val == SNG_MG_ENCODING_TEXT)?"SNG_MG_ENCODING_TEXT":\ + (_val == SNG_MG_ENCODING_BINARY)?"SNG_MG_ENCODING_BINARY":\ + "SNG_MG_ENCODING_NONE") /* each profile is corresponds to each MG Instance */ @@ -95,4 +104,32 @@ void handle_mgco_audit_cfm(Pst *pst, SuId suId, MgMgtAudit* audit, Reason reason void handle_mg_alarm(Pst *pst, MgMngmt *sta); void handle_tucl_alarm(Pst *pst, HiMngmt *sta); + +switch_status_t sng_mgco_init(sng_isup_event_interface_t* event); +switch_status_t sng_mgco_cfg(const char* profilename); +switch_status_t sng_mgco_start(const char* profilename); +switch_status_t sng_mgco_stack_shutdown(void); + +/*****************************************************************************************************/ + +#define GET_MG_CFG_IDX(_profilename, _idx){\ + for(idx=0; idx < MAX_MG_PROFILES; idx++){\ + /* id zero is not acceptable */\ + if(megaco_globals.g_mg_cfg.mgCfg[idx].id){\ + if (strcmp(megaco_globals.g_mg_cfg.mgCfg[idx].name, profilename)) {\ + continue;\ + } else{\ + break;\ + }\ + }\ + }\ +} + +#define GET_TPT_ID(_id) megaco_globals.g_mg_cfg.mgTptProf[megaco_globals.g_mg_cfg.mgCfg[_id].transport_prof_id].id +#define GET_MU_SAP_ID(_id) megaco_globals.g_mg_cfg.mgCfg[_id].id + +#define GET_TPT_TYPE(_id) megaco_globals.g_mg_cfg.mgTptProf[megaco_globals.g_mg_cfg.mgCfg[_id].transport_prof_id].transport_type + +#define GET_ENCODING_TYPE(_id) megaco_globals.g_mg_cfg.mgPeer.peers[megaco_globals.g_mg_cfg.mgCfg[_id].peer_id].encoding_type + #endif /* _MEGACO_CFG_H_ */ diff --git a/src/mod/endpoints/mod_megaco/megaco_xml.c b/src/mod/endpoints/mod_megaco/megaco_xml.c index 506cc3b29e..e7addf5875 100644 --- a/src/mod/endpoints/mod_megaco/megaco_xml.c +++ b/src/mod/endpoints/mod_megaco/megaco_xml.c @@ -214,6 +214,7 @@ switch_status_t sng_parse_mg_peer_profile(switch_xml_t mg_peer_profile) } } + megaco_globals.g_mg_cfg.mgPeer.total_peer++; return SWITCH_STATUS_SUCCESS; } /***********************************************************************************************************/ diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.c b/src/mod/endpoints/mod_megaco/mod_megaco.c index bda8e53ec0..332392c59a 100644 --- a/src/mod/endpoints/mod_megaco/mod_megaco.c +++ b/src/mod/endpoints/mod_megaco/mod_megaco.c @@ -123,25 +123,22 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_megaco_load) sng_event.mg.sng_mgco_cmd_ind = handle_mgco_cmd_ind; sng_event.mg.sng_mgco_txn_sta_ind = handle_mgco_txn_sta_ind; sng_event.mg.sng_mgco_sta_ind = handle_mgco_sta_ind; - sng_event.mg.sng_mgco_cntrl_cfm = handle_mgco_cntrl_cfm; - sng_event.mg.sng_mgco_audit_cfm = handle_mgco_audit_cfm; - + sng_event.mg.sng_mgco_cntrl_cfm = handle_mgco_cntrl_cfm; + sng_event.mg.sng_mgco_audit_cfm = handle_mgco_audit_cfm; /* Alarm CB */ sng_event.sm.sng_mg_alarm = handle_mg_alarm; sng_event.sm.sng_tucl_alarm = handle_tucl_alarm; - /* Log */ sng_event.sm.sng_log = handle_sng_log; - /* initalize sng_mg library */ - sng_isup_init_gen(&sng_event); - - return SWITCH_STATUS_SUCCESS; + /* initualize MEGACO stack */ + return sng_mgco_init(&sng_event); } SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_megaco_shutdown) { - /* TODO: Kapil: Insert stack global shutdown code here */ + sng_mgco_stack_shutdown(); + return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.h b/src/mod/endpoints/mod_megaco/mod_megaco.h index 3efa48e3bc..7c21610639 100644 --- a/src/mod/endpoints/mod_megaco/mod_megaco.h +++ b/src/mod/endpoints/mod_megaco/mod_megaco.h @@ -11,7 +11,7 @@ #define MOD_MEGACO_H #include -#include "megaco_cfg.h" +#include "megaco_stack.h" struct megaco_globals { switch_memory_pool_t *pool; From ce46a57b857c3648ec5518fcd23a7ad66fd16cd9 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Thu, 17 May 2012 17:56:50 -0400 Subject: [PATCH 195/822] ss7: Adding support of Access Transport IE in IAM message Adding sip x-header and channel variable to set the value of Access Transport IE --- libs/freetdm/mod_freetdm/mod_freetdm.c | 10 +++++ .../ftmod_sangoma_ss7_handle.c | 1 + .../ftmod_sangoma_ss7_main.h | 2 + .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 10 ++++- .../ftmod_sangoma_ss7_support.c | 43 +++++++++++++++++++ 5 files changed, 65 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 6a32098b44..51fbeca6cc 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1400,6 +1400,11 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi if (sipvar) { ftdm_set_string(caller_data.loc.digits, sipvar); } + + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-Access-Transport"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_access_transport_urlenc", sipvar); + } sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-LOC-Screen"); if (sipvar) { @@ -1865,6 +1870,11 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-Plan", "%d", channel_caller_data->rdnis.plan); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-CPC", "%s", ftdm_calling_party_category2str(channel_caller_data->cpc)); + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_access_transport_urlenc"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-Access-Transport", "%s", var_value); + } + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdinfo_indicator"); if (!ftdm_strlen_zero(var_value)) { switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDINF-Indicator", "%s", var_value); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index d0d6c32867..48e4bc4735 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -221,6 +221,7 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ } else { SS7_INFO_CHAN(ftdmchan,"No Called party (DNIS) information in IAM!%s\n", " "); } + copy_access_transport_from_sngss7(ftdmchan, &siConEvnt->accTrnspt); copy_ocn_from_sngss7(ftdmchan, &siConEvnt->origCdNum); copy_redirgNum_from_sngss7(ftdmchan, &siConEvnt->redirgNum); copy_redirgInfo_from_sngss7(ftdmchan, &siConEvnt->redirInfo); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 4ccf4efe0e..a6dde4d704 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -916,6 +916,8 @@ ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *r ftdm_status_t copy_ocn_to_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum); ftdm_status_t copy_ocn_from_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum); +ftdm_status_t copy_access_transport_from_sngss7(ftdm_channel_t *ftdmchan, SiAccTrnspt *accTrnspt); +ftdm_status_t copy_access_transport_to_sngss7(ftdm_channel_t *ftdmchan, SiAccTrnspt *accTrnspt); ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum); ftdm_status_t copy_locPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum); ftdm_status_t copy_genNmb_to_sngss7(ftdm_channel_t *ftdmchan, SiGenNum *genNmb); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index 9ba11ada58..bf693c0999 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -138,6 +138,7 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* Original Called Number */ copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum); } + copy_access_transport_to_sngss7(ftdmchan, &iam.accTrnspt); } } else if (sngss7_info->circuit->transparent_iam && sngss7_retrieve_iam(ftdmchan, &iam) == FTDM_SUCCESS) { @@ -160,6 +161,8 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* Original Called Number */ copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum); + + copy_access_transport_to_sngss7(ftdmchan, &iam.accTrnspt); } else { /* Nature of Connection Indicators */ copy_natConInd_to_sngss7(ftdmchan, &iam.natConInd); @@ -199,8 +202,13 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* Original Called Number */ copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum); - /* Access Transport */ + /* Access Transport - old implementation, taking from channel variable of ss7_clg_subaddr */ copy_accTrnspt_to_sngss7(ftdmchan, &iam.accTrnspt); + + /* Access Transport - taking from channel variable of ss7_access_transport_urlenc. + This will overwirte the IE value set be above old implementation. + */ + copy_access_transport_to_sngss7(ftdmchan, &iam.accTrnspt); SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM clg = \"%s\" (NADI=%d), cld = \"%s\" (NADI=%d), loc = %s (NADI=%d)\n", sngss7_info->circuit->cic, diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 96359ba595..fd70f13290 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -637,6 +637,49 @@ ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *r return FTDM_SUCCESS; } +ftdm_status_t copy_access_transport_from_sngss7(ftdm_channel_t *ftdmchan, SiAccTrnspt *accTrnspt) +{ + char *val=NULL; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + if (accTrnspt->eh.pres != PRSNT_NODEF || accTrnspt->infoElmts.pres !=PRSNT_NODEF) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No Access Transport IE available\n"); + return FTDM_SUCCESS; + } + + val = ftdm_malloc(3*accTrnspt->infoElmts.len); + ftdm_url_encode((const char*)accTrnspt->infoElmts.val, val, accTrnspt->infoElmts.len); + sngss7_add_var (sngss7_info, "ss7_access_transport_urlenc", val); + ftdm_safe_free(val); + + return FTDM_SUCCESS; +} +ftdm_status_t copy_access_transport_to_sngss7(ftdm_channel_t *ftdmchan, SiAccTrnspt *accTrnspt) +{ + const char *val = NULL; + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_access_transport_urlenc"); + if (ftdm_strlen_zero(val)) { + accTrnspt->eh.pres = NOTPRSNT; + accTrnspt->infoElmts.pres = NOTPRSNT; + } + else { + char *val_dec = NULL; + int val_len = strlen (val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found Access Transport IE encoded : %s\n", val); + + accTrnspt->eh.pres = PRSNT_NODEF; + accTrnspt->infoElmts.pres = PRSNT_NODEF; + + val_dec = ftdm_strdup(val); + ftdm_url_decode(val_dec, (ftdm_size_t*)&val_len); + memcpy (accTrnspt->infoElmts.val, val_dec, val_len); + accTrnspt->infoElmts.len = val_len; + ftdm_safe_free(val_dec); + } + return FTDM_SUCCESS; +} + ftdm_status_t copy_ocn_from_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum) { char val[20]; From 23ca7f8fed32b8679564e06fccf970f92ae645f3 Mon Sep 17 00:00:00 2001 From: kapil Date: Fri, 18 May 2012 12:05:25 +0530 Subject: [PATCH 196/822] adding m2ua stack config/control code --- libs/freetdm/Makefile.am | 2 + libs/freetdm/mod_freetdm/mod_freetdm.c | 100 +- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c | 166 +- .../ftmod_sangoma_ss7_cntrl.c | 54 +- .../ftmod_sangoma_ss7_logger.c | 30 + .../ftmod_sangoma_ss7_m2ua.c | 1335 +++++++++++++++++ .../ftmod_sangoma_ss7_m2ua.h | 125 ++ .../ftmod_sangoma_ss7_m2ua_xml.c | 671 +++++++++ .../ftmod_sangoma_ss7_main.c | 21 +- .../ftmod_sangoma_ss7_main.h | 41 + .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 153 +- 11 files changed, 2560 insertions(+), 138 deletions(-) create mode 100644 libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c create mode 100644 libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h create mode 100644 libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c diff --git a/libs/freetdm/Makefile.am b/libs/freetdm/Makefile.am index 35f1cecd1e..2038871de4 100644 --- a/libs/freetdm/Makefile.am +++ b/libs/freetdm/Makefile.am @@ -213,6 +213,8 @@ ftmod_sangoma_ss7_la_SOURCES = \ $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_sta.c \ $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_sts.c \ $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c \ + $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c \ + $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c \ $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c ftmod_sangoma_ss7_la_CFLAGS = $(FTDM_CFLAGS) $(AM_CFLAGS) -D_GNU_SOURCE diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index b6a6f49ca1..2e4f7e1e5f 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -55,6 +55,8 @@ /* How many consecutive IO errors before giving up */ #define FTDM_MAX_READ_WRITE_ERRORS 10 +#define get_ss7_config_node(_cfg, _confname) _get_ss7_config_node(cfg, confname, "ISUP") + SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_freetdm_shutdown); SWITCH_MODULE_DEFINITION(mod_freetdm, mod_freetdm_load, mod_freetdm_shutdown, NULL); @@ -2865,11 +2867,12 @@ static int add_config_list_nodes(switch_xml_t swnode, ftdm_conf_node_t *rootnode return 0; } -static ftdm_conf_node_t *get_ss7_config_node(switch_xml_t cfg, const char *confname) +static ftdm_conf_node_t *_get_ss7_config_node(switch_xml_t cfg, const char *confname, const char *operatingMode) { switch_xml_t signode, ss7configs, isup, gen, param; ftdm_conf_node_t *rootnode, *list; char *var, *val; + int is_isup = 0x00; /* try to find the conf in the hash first */ rootnode = switch_core_hash_find(globals.ss7_configs, confname); @@ -2913,6 +2916,23 @@ static ftdm_conf_node_t *get_ss7_config_node(switch_xml_t cfg, const char *confn return NULL; } + /* operating mode , M2UA or ISUP */ + if(operatingMode && ('\0' != operatingMode[0])) { + if(!strcasecmp(operatingMode, "ISUP")) { + is_isup = 0x01; + } + else if(!strcasecmp(operatingMode, "M2UA_SG")) { + is_isup = 0x00; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid operating Mode[%s] \n", operatingMode); + ftdm_conf_node_destroy(rootnode); + return NULL; + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Operating mode not specified, default to ISUP \n"); + is_isup = 0x01; + } + /* add sng_gen */ gen = switch_xml_child(isup, "sng_gen"); if (gen == NULL) { @@ -2954,11 +2974,14 @@ static ftdm_conf_node_t *get_ss7_config_node(switch_xml_t cfg, const char *confn return NULL; } - /* add mtp3 links */ - if (add_config_list_nodes(isup, rootnode, "mtp3_links", "mtp3_link", NULL, NULL)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process mtp3_links for sng_isup config %s\n", confname); - ftdm_conf_node_destroy(rootnode); - return NULL; + /* If ISUP is operating mode then only include mtp3_links/isup links */ + if(is_isup) { + /* add mtp3 links */ + if (add_config_list_nodes(isup, rootnode, "mtp3_links", "mtp3_link", NULL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process mtp3_links for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } } /* add mtp linksets */ @@ -2975,18 +2998,53 @@ static ftdm_conf_node_t *get_ss7_config_node(switch_xml_t cfg, const char *confn return NULL; } - /* add isup interfaces */ - if (add_config_list_nodes(isup, rootnode, "isup_interfaces", "isup_interface", NULL, NULL)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process isup_interfaces for sng_isup config %s\n", confname); - ftdm_conf_node_destroy(rootnode); - return NULL; - } + if(is_isup) { + /* add isup interfaces */ + if (add_config_list_nodes(isup, rootnode, "isup_interfaces", "isup_interface", NULL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process isup_interfaces for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } + + /* add cc spans */ + if (add_config_list_nodes(isup, rootnode, "cc_spans", "cc_span", NULL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process cc_spans for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } + } + else { + /* add sctp links */ + if (add_config_list_nodes(isup, rootnode, "sng_sctp_interfaces", "sng_sctp_interface", NULL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process sng_sctp_interface for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } + + if (add_config_list_nodes(isup, rootnode, "sng_nif_interfaces", "sng_nif_interface", NULL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process sng_nif_interfaces for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } + + if (add_config_list_nodes(isup, rootnode, "sng_m2ua_interfaces", "sng_m2ua_interface", NULL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process sng_m2ua_interfaces for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } + + if (add_config_list_nodes(isup, rootnode, "sng_m2ua_peer_interfaces", "sng_m2ua_peer_interface", NULL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process sng_m2ua_peer_interfaces for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } + + if (add_config_list_nodes(isup, rootnode, "sng_m2ua_cluster_interfaces", "sng_m2ua_cluster_interface", NULL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process sng_m2ua_cluster_interfaces for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } - /* add cc spans */ - if (add_config_list_nodes(isup, rootnode, "cc_spans", "cc_span", NULL, NULL)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process cc_spans for sng_isup config %s\n", confname); - ftdm_conf_node_destroy(rootnode); - return NULL; } switch_core_hash_insert(globals.ss7_configs, confname, rootnode); @@ -3223,6 +3281,7 @@ static switch_status_t load_config(void) char *id = (char *) switch_xml_attr(myspan, "id"); char *name = (char *) switch_xml_attr(myspan, "name"); char *configname = (char *) switch_xml_attr(myspan, "cfgprofile"); + char *operatingMode = (char *) switch_xml_attr(myspan, "operating_mode"); ftdm_span_t *span = NULL; uint32_t span_id = 0; unsigned paramindex = 0; @@ -3256,7 +3315,7 @@ static switch_status_t load_config(void) span_id = ftdm_span_get_id(span); } - ss7confnode = get_ss7_config_node(cfg, configname); + ss7confnode = _get_ss7_config_node(cfg, configname, operatingMode); if (!ss7confnode) { CONFIG_ERROR("Error finding ss7config '%s' for FreeTDM span id: %s\n", configname, switch_str_nil(id)); continue; @@ -3264,6 +3323,11 @@ static switch_status_t load_config(void) memset(spanparameters, 0, sizeof(spanparameters)); paramindex = 0; + if(operatingMode){ + spanparameters[paramindex].var = "operatingMode"; + spanparameters[paramindex].val = operatingMode; + paramindex++; + } spanparameters[paramindex].var = "confnode"; spanparameters[paramindex].ptr = ss7confnode; paramindex++; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c index 327ca40f05..170f03f8f3 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c @@ -262,94 +262,103 @@ int ft_to_sngss7_cfg_all(void) /* no configs above mtp2 for relay */ if (g_ftdm_sngss7_data.cfg.procId == 1) { x = 1; - while (x < (MAX_MTP_LINKS)) { - /* check if this link has been configured already */ - if ((g_ftdm_sngss7_data.cfg.mtp3Link[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.mtp3Link[x].flags & SNGSS7_CONFIGURED))) { + while (x < (MAX_MTP_LINKS)) { + /* check if this link has been configured already */ + if ((g_ftdm_sngss7_data.cfg.mtp3Link[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.mtp3Link[x].flags & SNGSS7_CONFIGURED))) { - /* configure mtp3 */ - if (ftmod_ss7_mtp3_dlsap_config(x)) { - SS7_CRITICAL("MTP3 DLSAP %d configuration FAILED!\n", x); - return 1;; - } else { - SS7_INFO("MTP3 DLSAP %d configuration DONE!\n", x); + /* configure mtp3 */ + if (ftmod_ss7_mtp3_dlsap_config(x)) { + SS7_CRITICAL("MTP3 DLSAP %d configuration FAILED!\n", x); + return 1;; + } else { + SS7_INFO("MTP3 DLSAP %d configuration DONE!\n", x); + } + + /* set the SNGSS7_CONFIGURED flag */ + g_ftdm_sngss7_data.cfg.mtp3Link[x].flags |= SNGSS7_CONFIGURED; } - /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.mtp3Link[x].flags |= SNGSS7_CONFIGURED; + x++; + } /* while (x < (MAX_MTP_LINKS+1)) */ + + /* in M2UA_SG mode there will not be any MTP3 layer */ + if(SNG_SS7_OPR_MODE_M2UA_SG != g_ftdm_operating_mode){ + x = 1; + while (x < (MAX_NSAPS)) { + /* check if this link has been configured already */ + if ((g_ftdm_sngss7_data.cfg.nsap[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.nsap[x].flags & SNGSS7_CONFIGURED))) { + + ret = ftmod_ss7_mtp3_nsap_config(x); + if (ret) { + SS7_CRITICAL("MTP3 NSAP %d configuration FAILED!(%s)\n", x, DECODE_LCM_REASON(ret)); + return 1; + } else { + SS7_INFO("MTP3 NSAP %d configuration DONE!\n", x); + } + + ret = ftmod_ss7_isup_nsap_config(x); + if (ret) { + SS7_CRITICAL("ISUP NSAP %d configuration FAILED!(%s)\n", x, DECODE_LCM_REASON(ret)); + return 1; + } else { + SS7_INFO("ISUP NSAP %d configuration DONE!\n", x); + } + + /* set the SNGSS7_CONFIGURED flag */ + g_ftdm_sngss7_data.cfg.nsap[x].flags |= SNGSS7_CONFIGURED; + } /* if !SNGSS7_CONFIGURED */ + + x++; + } /* while (x < (MAX_NSAPS)) */ } - - x++; - } /* while (x < (MAX_MTP_LINKS+1)) */ - x = 1; - while (x < (MAX_NSAPS)) { - /* check if this link has been configured already */ - if ((g_ftdm_sngss7_data.cfg.nsap[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.nsap[x].flags & SNGSS7_CONFIGURED))) { + /* in M2UA_SG mode there will not be any MTP3 layer */ + if(SNG_SS7_OPR_MODE_M2UA_SG != g_ftdm_operating_mode){ + x = 1; + while (x < (MAX_MTP_LINKSETS+1)) { + /* check if this link has been configured already */ + if ((g_ftdm_sngss7_data.cfg.mtpLinkSet[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags & SNGSS7_CONFIGURED))) { - ret = ftmod_ss7_mtp3_nsap_config(x); - if (ret) { - SS7_CRITICAL("MTP3 NSAP %d configuration FAILED!(%s)\n", x, DECODE_LCM_REASON(ret)); - return 1; - } else { - SS7_INFO("MTP3 NSAP %d configuration DONE!\n", x); - } + if (ftmod_ss7_mtp3_linkset_config(x)) { + SS7_CRITICAL("MTP3 LINKSET %d configuration FAILED!\n", x); + return 1; + } else { + SS7_INFO("MTP3 LINKSET %d configuration DONE!\n", x); + } - ret = ftmod_ss7_isup_nsap_config(x); - if (ret) { - SS7_CRITICAL("ISUP NSAP %d configuration FAILED!(%s)\n", x, DECODE_LCM_REASON(ret)); - return 1; - } else { - SS7_INFO("ISUP NSAP %d configuration DONE!\n", x); - } + /* set the SNGSS7_CONFIGURED flag */ + g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags |= SNGSS7_CONFIGURED; + } /* if !SNGSS7_CONFIGURED */ - /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.nsap[x].flags |= SNGSS7_CONFIGURED; - } /* if !SNGSS7_CONFIGURED */ - - x++; - } /* while (x < (MAX_NSAPS)) */ + x++; + } /* while (x < (MAX_MTP_LINKSETS+1)) */ + } - x = 1; - while (x < (MAX_MTP_LINKSETS+1)) { - /* check if this link has been configured already */ - if ((g_ftdm_sngss7_data.cfg.mtpLinkSet[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags & SNGSS7_CONFIGURED))) { + /* in M2UA_SG mode there will not be any MTP3 layer */ + if(SNG_SS7_OPR_MODE_M2UA_SG != g_ftdm_operating_mode){ + x = 1; + while (x < (MAX_MTP_ROUTES+1)) { + /* check if this link has been configured already */ + if ((g_ftdm_sngss7_data.cfg.mtpRoute[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.mtpRoute[x].flags & SNGSS7_CONFIGURED))) { - if (ftmod_ss7_mtp3_linkset_config(x)) { - SS7_CRITICAL("MTP3 LINKSET %d configuration FAILED!\n", x); - return 1; - } else { - SS7_INFO("MTP3 LINKSET %d configuration DONE!\n", x); - } + if (ftmod_ss7_mtp3_route_config(x)) { + SS7_CRITICAL("MTP3 ROUTE %d configuration FAILED!\n", x); + return 1; + } else { + SS7_INFO("MTP3 ROUTE %d configuration DONE!\n",x); + } - /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags |= SNGSS7_CONFIGURED; - } /* if !SNGSS7_CONFIGURED */ - - x++; - } /* while (x < (MAX_MTP_LINKSETS+1)) */ + /* set the SNGSS7_CONFIGURED flag */ + g_ftdm_sngss7_data.cfg.mtpRoute[x].flags |= SNGSS7_CONFIGURED; + } /* if !SNGSS7_CONFIGURED */ - x = 1; - while (x < (MAX_MTP_ROUTES+1)) { - /* check if this link has been configured already */ - if ((g_ftdm_sngss7_data.cfg.mtpRoute[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.mtpRoute[x].flags & SNGSS7_CONFIGURED))) { - - if (ftmod_ss7_mtp3_route_config(x)) { - SS7_CRITICAL("MTP3 ROUTE %d configuration FAILED!\n", x); - return 1; - } else { - SS7_INFO("MTP3 ROUTE %d configuration DONE!\n",x); - } - - /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.mtpRoute[x].flags |= SNGSS7_CONFIGURED; - } /* if !SNGSS7_CONFIGURED */ - - x++; - } /* while (x < (MAX_MTP_ROUTES+1)) */ + x++; + } /* while (x < (MAX_MTP_ROUTES+1)) */ + } x = 1; while (x < (MAX_ISAPS)) { @@ -441,6 +450,11 @@ int ft_to_sngss7_cfg_all(void) } /* if !SNGSS7_CONFIGURED */ x++; } /* while (x < (MAX_RELAY_CHANNELS)) */ + + + if(SNG_SS7_OPR_MODE_M2UA_SG == g_ftdm_operating_mode){ + return ftmod_ss7_m2ua_cfg(); + } return 0; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c index c5aca9aa73..0fcef7d90b 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c @@ -60,7 +60,7 @@ int ft_to_sngss7_activate_all(void) while (x < (MAX_ISAPS)) { /* check if this link has already been actived */ if ((g_ftdm_sngss7_data.cfg.isap[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.isap[x].flags & SNGSS7_ACTIVE))) { + (!(g_ftdm_sngss7_data.cfg.isap[x].flags & SNGSS7_ACTIVE))) { if (ftmod_ss7_enable_isap(x)) { SS7_CRITICAL("ISAP %d Enable: NOT OK\n", x); @@ -72,15 +72,16 @@ int ft_to_sngss7_activate_all(void) /* set the SNGSS7_ACTIVE flag */ g_ftdm_sngss7_data.cfg.isap[x].flags |= SNGSS7_ACTIVE; } /* if !SNGSS7_ACTIVE */ - + x++; } /* while (x < (MAX_ISAPS)) */ + if(SNG_SS7_OPR_MODE_M2UA_SG != g_ftdm_operating_mode){ x = 1; while (x < (MAX_NSAPS)) { /* check if this link has already been actived */ if ((g_ftdm_sngss7_data.cfg.nsap[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.nsap[x].flags & SNGSS7_ACTIVE))) { + (!(g_ftdm_sngss7_data.cfg.nsap[x].flags & SNGSS7_ACTIVE))) { if (ftmod_ss7_enable_nsap(x)) { SS7_CRITICAL("NSAP %d Enable: NOT OK\n", x); @@ -92,30 +93,35 @@ int ft_to_sngss7_activate_all(void) /* set the SNGSS7_ACTIVE flag */ g_ftdm_sngss7_data.cfg.nsap[x].flags |= SNGSS7_ACTIVE; } /* if !SNGSS7_ACTIVE */ - + x++; } /* while (x < (MAX_NSAPS)) */ - if (g_ftdm_sngss7_data.cfg.mtpRoute[1].id != 0) { - x = 1; - while (x < (MAX_MTP_LINKSETS+1)) { - /* check if this link has already been actived */ - if ((g_ftdm_sngss7_data.cfg.mtpLinkSet[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags & SNGSS7_ACTIVE))) { - - if (ftmod_ss7_enable_mtpLinkSet(x)) { - SS7_CRITICAL("LinkSet \"%s\" Enable: NOT OK\n", g_ftdm_sngss7_data.cfg.mtpLinkSet[x].name); - return 1; - } else { - SS7_INFO("LinkSet \"%s\" Enable: OK\n", g_ftdm_sngss7_data.cfg.mtpLinkSet[x].name); - } - - /* set the SNGSS7_ACTIVE flag */ - g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags |= SNGSS7_ACTIVE; - } /* if !SNGSS7_ACTIVE */ - - x++; - } /* while (x < (MAX_MTP_LINKSETS+1)) */ + if (g_ftdm_sngss7_data.cfg.mtpRoute[1].id != 0) { + x = 1; + while (x < (MAX_MTP_LINKSETS+1)) { + /* check if this link has already been actived */ + if ((g_ftdm_sngss7_data.cfg.mtpLinkSet[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags & SNGSS7_ACTIVE))) { + + if (ftmod_ss7_enable_mtpLinkSet(x)) { + SS7_CRITICAL("LinkSet \"%s\" Enable: NOT OK\n", g_ftdm_sngss7_data.cfg.mtpLinkSet[x].name); + return 1; + } else { + SS7_INFO("LinkSet \"%s\" Enable: OK\n", g_ftdm_sngss7_data.cfg.mtpLinkSet[x].name); + } + + /* set the SNGSS7_ACTIVE flag */ + g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags |= SNGSS7_ACTIVE; + } /* if !SNGSS7_ACTIVE */ + + x++; + } /* while (x < (MAX_MTP_LINKSETS+1)) */ + } + } + + if(SNG_SS7_OPR_MODE_M2UA_SG == g_ftdm_operating_mode){ + return ftmod_ss7_m2ua_start(); } return 0; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c index 176de9e627..5d4e183b20 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c @@ -824,6 +824,36 @@ void handle_sng_relay_alarm(Pst *pst, RyMngmt *sta) return; } +/******************************************************************************/ +void handle_sng_m2ua_alarm(Pst *pst, MwMgmt *sta) +{ + ftdm_log(FTDM_LOG_ERROR," handle_sng_m2ua_alarm Not Yet Implement \n"); + +} /* handle_sng_m2ua_alarm */ + +/******************************************************************************/ +void handle_sng_nif_alarm(Pst *pst, NwMgmt *sta) +{ + ftdm_log(FTDM_LOG_ERROR," handle_sng_nif_alarm Not Yet Implement \n"); + +} /* handle_sng_nif_alarm */ + +/******************************************************************************/ +void handle_sng_tucl_alarm(Pst *pst, HiMngmt *sta) +{ + ftdm_log(FTDM_LOG_ERROR," handle_sng_tucl_alarm Not Yet Implement \n"); + +} /* handle_sng_tucl_alarm */ + +/******************************************************************************/ +void handle_sng_sctp_alarm(Pst *pst, SbMgmt *sta) +{ + ftdm_log(FTDM_LOG_ERROR," handle_sng_sctp_alarm Not Yet Implement \n"); + +} /* handle_sng_sctp_alarm */ +/******************************************************************************/ + + /******************************************************************************/ /* For Emacs: * Local Variables: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c new file mode 100644 index 0000000000..375be9f35a --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c @@ -0,0 +1,1335 @@ +/* + * Copyright (c) 2012, Kapil Gupta + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Contributors: + * + * + */ + +/* INCLUDE ********************************************************************/ +#include "ftmod_sangoma_ss7_main.h" +/******************************************************************************/ + +/* DEFINES ********************************************************************/ +/******************************************************************************/ +/* FUNCTION PROTOTYPES ********************************************************/ +static int ftmod_sigtran_tucl_gen_config(void); +static int ftmod_sigtran_tucl_sap_config(void); + +static int ftmod_sigtran_sctp_gen_config(void); +ftdm_status_t ftmod_sigtran_cfg_sctp(void); +int ftmod_sigtran_sctp_config(int id); +ftdm_status_t ftmod_sigtran_sctp_sap_config(int id); +ftdm_status_t ftmod_sigtran_sctp_tsap_config(int id); +static S16 ftmod_sigtran_m2ua_gen_config(void); +static S16 ftmod_sigtran_m2ua_sctsap_config(void); +static S16 ftmod_sigtran_m2ua_peer_config(void); +static S16 ftmod_sigtran_m2ua_cluster_config(void); +static S16 ftmod_sigtran_m2ua_dlsap_config(U32 idx); + +static S16 ftmod_sigtran_nif_gen_config(void); +static S16 ftmod_sigtran_nif_dlsap_config(U32 idx); + + +static U32 ftmod_parse_conv_ipaddr(S8 *ptr); + +ftdm_status_t sng_m2ua_init(void); +ftdm_status_t sng_m2ua_cfg(void); + + +static S16 ftmod_sigtran_tsap_bnd(void); +static S16 ftmod_sigtran_sctsap_bnd(void); +static S16 ftmod_sigtran_dlsap_bnd(U32 id); +static S16 ftmod_ss7_dlsap_bnd(U32 id); + +/******************************************************************************/ +/******************************************************************************/ + +ftdm_status_t ftmod_ss7_m2ua_cfg(void) +{ + + if(FTDM_SUCCESS != sng_m2ua_init()){ + ftdm_log (FTDM_LOG_ERROR, " sng_m2ua_init FAILED \n"); + return FTDM_FAIL; + } + + if(FTDM_SUCCESS != sng_m2ua_cfg()){ + ftdm_log (FTDM_LOG_ERROR, " sng_m2ua_cfg FAILED \n"); + return FTDM_FAIL; + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ + +ftdm_status_t sng_m2ua_init(void) +{ + if (sng_isup_init_nif()) { + ftdm_log (FTDM_LOG_ERROR , "Failed to start NIF\n"); + return FTDM_FAIL; + } else { + ftdm_log (FTDM_LOG_INFO ,"Started NIF!\n"); + } + + if (sng_isup_init_m2ua()) { + ftdm_log (FTDM_LOG_ERROR ,"Failed to start M2UA\n"); + return FTDM_FAIL; + } else { + ftdm_log (FTDM_LOG_INFO ,"Started M2UA!\n"); + } + + if (sng_isup_init_sctp()) { + ftdm_log (FTDM_LOG_ERROR ,"Failed to start SCTP\n"); + return FTDM_FAIL; + } else { + ftdm_log (FTDM_LOG_INFO ,"Started SCTP!\n"); + } + + if (sng_isup_init_tucl()) { + ftdm_log (FTDM_LOG_ERROR ,"Failed to start TUCL\n"); + return FTDM_FAIL; + } else { + ftdm_log (FTDM_LOG_INFO ,"Started TUCL!\n"); + } + + + return FTDM_SUCCESS; +} + +/******************************************************************************/ + +ftdm_status_t sng_m2ua_cfg(void) +{ + S16 ret = ROK; + + /* TUCL */ + if(ftmod_sigtran_tucl_gen_config()){ + ftdm_log (FTDM_LOG_ERROR ,"TUCL GEN configuration: NOT OK\n"); + return FTDM_FAIL; + } else { + ftdm_log (FTDM_LOG_INFO ,"TUCL GEN configuration: OK\n"); + } + + if(ftmod_sigtran_tucl_sap_config()){ + ftdm_log (FTDM_LOG_ERROR ,"TUCL SAP configuration: NOT OK\n"); + return FTDM_FAIL; + } else { + ftdm_log (FTDM_LOG_INFO ,"TUCL SAP configuration: OK\n"); + } + /*********************************************************************************************/ + + /* SCTP */ + if(ftmod_sigtran_sctp_gen_config()){ + ftdm_log (FTDM_LOG_ERROR ,"SCTP GEN configuration: NOT OK\n"); + return FTDM_FAIL; + } else { + ftdm_log (FTDM_LOG_INFO ,"SCTP GEN configuration: OK\n"); + } + + if(ftmod_sigtran_cfg_sctp()){ + ftdm_log (FTDM_LOG_ERROR ,"ftmod_sigtran_cfg_sctp : NOT OK\n"); + return FTDM_FAIL; + } else { + ftdm_log (FTDM_LOG_INFO ,"ftmod_sigtran_cfg_sctp : OK\n"); + } + /*********************************************************************************************/ + + /* M2UA and NIF configurations */ + + /* Send the general configuration request for M2UA layer */ + if((ret = ftmod_sigtran_m2ua_gen_config()) != ROK) + { + ftdm_log (FTDM_LOG_ERROR ,"M2UA General configuration: NOT OK\n"); + return FTDM_FAIL; + } + else + { + ftdm_log (FTDM_LOG_INFO ,"M2UA General configuration: OK\n"); + } + + /* Send the SCTSAP configuration request for M2UA layer */ + if((ret = ftmod_sigtran_m2ua_sctsap_config()) != ROK) + { + ftdm_log (FTDM_LOG_ERROR ,"M2UA SCTSAP configuration: NOT OK\n"); + return FTDM_FAIL; + } + else + { + ftdm_log (FTDM_LOG_INFO ,"M2UA SCTSAP configuration: OK\n"); + } + + /* Send the peer configuration request for M2UA layer */ + if((ret = ftmod_sigtran_m2ua_peer_config()) != ROK) + { + ftdm_log (FTDM_LOG_ERROR ,"M2UA PEER configuration: NOT OK\n"); + return FTDM_FAIL; + } + else + { + ftdm_log (FTDM_LOG_INFO ,"M2UA PEER configuration: OK\n"); + } + + /* Send the cluster configuration request for M2UA layer */ + if((ret = ftmod_sigtran_m2ua_cluster_config()) != ROK) + { + ftdm_log (FTDM_LOG_ERROR ,"M2UA CLUSTER configuration: NOT OK\n"); + return FTDM_FAIL; + } + else + { + ftdm_log (FTDM_LOG_INFO ,"M2UA CLUSTER configuration: OK\n"); + } + + + /* Send the USAP (DLSAP) configuration request for M2UA layer; fill the number + * of saps required to be configured. Max is 3 */ + /*for( idx = 0; idx < 3; idx++)*/ + { + if((ret = ftmod_sigtran_m2ua_dlsap_config(1)) != ROK) + { + ftdm_log (FTDM_LOG_ERROR ,"M2UA DLSAP configuration: NOT OK\n"); + return FTDM_FAIL; + } + else + { + ftdm_log (FTDM_LOG_INFO ,"M2UA DLSAP configuration: OK\n"); + } + } + + /* Send the general configuration request for NIF */ + if((ret = ftmod_sigtran_nif_gen_config()) != ROK) + { + ftdm_log (FTDM_LOG_ERROR ,"NIF General configuration: NOT OK\n"); + return FTDM_FAIL; + } + else + { + ftdm_log (FTDM_LOG_INFO ,"NIF General configuration: OK\n"); + } + + /* Send the USAP (DLSAP) configuration request for NIF layer; fill the number + * of saps required to be configured. Max is 3 + for( idx = 0; idx < 3; idx++) */ + { + if( (ret = ftmod_sigtran_nif_dlsap_config(1)) != ROK) + { + ftdm_log (FTDM_LOG_ERROR ,"NIF DLSAP configuration: NOT OK\n"); + return FTDM_FAIL; + } + else + { + ftdm_log (FTDM_LOG_INFO ,"NIF DLSAP configuration: OK\n"); + } + } + + + /********************************************************************************************/ + + return 0; +} + +/******************************************************************************/ +static int ftmod_sigtran_tucl_gen_config(void) +{ + HiMngmt cfg; + Pst pst; + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTHI; + + /* clear the configuration structure */ + memset(&cfg, 0, sizeof(cfg)); + + /* fill in the post structure */ + smPstInit(&cfg.t.cfg.s.hiGen.lmPst); + /*fill in the specific fields of the header */ + cfg.hdr.msgType = TCFG; + cfg.hdr.entId.ent = ENTHI; + cfg.hdr.entId.inst = S_INST; + cfg.hdr.elmId.elmnt = STGEN; + + cfg.t.cfg.s.hiGen.numSaps = HI_MAX_SAPS; /* number of SAPs */ + cfg.t.cfg.s.hiGen.numCons = HI_MAX_NUM_OF_CON; /* maximum num of connections */ + cfg.t.cfg.s.hiGen.numFdsPerSet = HI_MAX_NUM_OF_FD_PER_SET; /* maximum num of fds to use per set */ + cfg.t.cfg.s.hiGen.numFdBins = HI_MAX_NUM_OF_FD_HASH_BINS; /* for fd hash lists */ + cfg.t.cfg.s.hiGen.numClToAccept = HI_MAX_NUM_OF_CLIENT_TO_ACCEPT; /* clients to accept simultaneously */ + cfg.t.cfg.s.hiGen.permTsk = TRUE; /* schedule as perm task or timer */ + cfg.t.cfg.s.hiGen.schdTmrVal = HI_MAX_SCHED_TMR_VALUE; /* if !permTsk - probably ignored */ + cfg.t.cfg.s.hiGen.selTimeout = HI_MAX_SELECT_TIMEOUT_VALUE; /* select() timeout */ + + /* number of raw/UDP messages to read in one iteration */ + cfg.t.cfg.s.hiGen.numRawMsgsToRead = HI_MAX_RAW_MSG_TO_READ; + cfg.t.cfg.s.hiGen.numUdpMsgsToRead = HI_MAX_UDP_MSG_TO_READ; + + /* thresholds for congestion on the memory pool */ + cfg.t.cfg.s.hiGen.poolStrtThr = HI_MEM_POOL_START_THRESHOLD; + cfg.t.cfg.s.hiGen.poolDropThr = HI_MEM_POOL_DROP_THRESHOLD; + cfg.t.cfg.s.hiGen.poolStopThr = HI_MEM_POOL_STOP_THRESHOLD; + + cfg.t.cfg.s.hiGen.timeRes = SI_PERIOD; /* time resolution */ + +#ifdef HI_SPECIFY_GENSOCK_ADDR + cfg.t.cfg.s.hiGen.ipv4GenSockAddr.address = CM_INET_INADDR_ANY; + cfg.t.cfg.s.hiGen.ipv4GenSockAddr.port = 0; /* DAVIDY - why 0? */ +#ifdef IPV6_SUPPORTED + cfg.t.cfg.s.hiGen.ipv6GenSockAddr.address = CM_INET_INADDR6_ANY; + cfg.t.cfg.s.hiGen.ipv4GenSockAddr.port = 0; +#endif +#endif + + return(sng_cfg_tucl(&pst, &cfg)); +} + +static int ftmod_sigtran_tucl_sap_config(void) +{ + HiMngmt cfg; + Pst pst; + HiSapCfg *pCfg; + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTHI; + + /* clear the configuration structure */ + memset(&cfg, 0, sizeof(cfg)); + + /*fill LM post structure*/ + cfg.t.cfg.s.hiGen.lmPst.dstProcId = SFndProcId(); + cfg.t.cfg.s.hiGen.lmPst.dstInst = S_INST; + + cfg.t.cfg.s.hiGen.lmPst.dstProcId = SFndProcId(); + cfg.t.cfg.s.hiGen.lmPst.dstEnt = ENTSM; + cfg.t.cfg.s.hiGen.lmPst.dstInst = S_INST; + + cfg.t.cfg.s.hiGen.lmPst.prior = PRIOR0; + cfg.t.cfg.s.hiGen.lmPst.route = RTESPEC; + cfg.t.cfg.s.hiGen.lmPst.region = S_REG; + cfg.t.cfg.s.hiGen.lmPst.pool = S_POOL; + cfg.t.cfg.s.hiGen.lmPst.selector = 0; + + + /*fill in the specific fields of the header */ + cfg.hdr.msgType = TCFG; + cfg.hdr.entId.ent = ENTHI; + cfg.hdr.entId.inst = 0; + cfg.hdr.elmId.elmnt = STTSAP; + + pCfg = &cfg.t.cfg.s.hiSap; + + pCfg->spId = 0x01 ; /* KAPIL - TODO - should be from configured value.but hardcoding as of now */ + pCfg->uiSel = 0x00; /*loosley coupled */ + pCfg->flcEnb = TRUE; + pCfg->txqCongStrtLim = HI_SAP_TXN_QUEUE_CONG_START_LIMIT; + pCfg->txqCongDropLim = HI_SAP_TXN_QUEUE_CONG_DROP_LIMIT; + pCfg->txqCongStopLim = HI_SAP_TXN_QUEUE_CONG_STOP_LIMIT; + pCfg->numBins = 10; + + pCfg->uiMemId.region = S_REG; + pCfg->uiMemId.pool = S_POOL; + pCfg->uiPrior = PRIOR0; + pCfg->uiRoute = RTESPEC; + + return(sng_cfg_tucl(&pst, &cfg)); +} + +static int ftmod_sigtran_sctp_gen_config(void) +{ + SbMgmt cfg; + Pst pst; + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTSB; + + /* clear the configuration structure */ + memset(&cfg, 0, sizeof(cfg)); + + /* fill in the post structure */ + smPstInit(&cfg.t.cfg.s.genCfg.smPst); + /*fill in the specific fields of the header */ + cfg.hdr.msgType = TCFG; + cfg.hdr.entId.ent = ENTSB; + cfg.hdr.entId.inst = S_INST; + cfg.hdr.elmId.elmnt = STSBGEN; + +#ifdef SB_IPV6_SUPPORTED + /* U8 ipv6SrvcReqdFlg; */ /* IPV6 service required for sctp */ +#endif + + cfg.t.cfg.s.genCfg.serviceType = HI_SRVC_RAW_SCTP; /* Usr packetized TCP Data */ /* TUCL transport protocol (IP/UDP) */ + cfg.t.cfg.s.genCfg.maxNmbSctSaps = SB_MAX_SCT_SAPS; /* max no. SCT SAPS */ + cfg.t.cfg.s.genCfg.maxNmbTSaps = SB_MAX_T_SAPS; /* max no. Transport SAPS */ + cfg.t.cfg.s.genCfg.maxNmbEndp = SB_MAX_NUM_OF_ENDPOINTS; /* max no. endpoints */ + cfg.t.cfg.s.genCfg.maxNmbAssoc = SB_MAX_NUM_OF_ASSOC; /* max no. associations */ + cfg.t.cfg.s.genCfg.maxNmbDstAddr = SB_MAX_NUM_OF_DST_ADDR; /* max no. dest. addresses */ + cfg.t.cfg.s.genCfg.maxNmbSrcAddr = SB_MAX_NUM_OF_SRC_ADDR; /* max no. src. addresses */ + cfg.t.cfg.s.genCfg.maxNmbTxChunks = SB_MAX_NUM_OF_TX_CHUNKS; + cfg.t.cfg.s.genCfg.maxNmbRxChunks = SB_MAX_NUM_OF_RX_CHUNKS; + cfg.t.cfg.s.genCfg.maxNmbInStrms = SB_MAX_INC_STREAMS; + cfg.t.cfg.s.genCfg.maxNmbOutStrms = SB_MAX_OUT_STREAMS; + cfg.t.cfg.s.genCfg.initARwnd = SB_MAX_RWND_SIZE; + cfg.t.cfg.s.genCfg.mtuInitial = SB_MTU_INITIAL; + cfg.t.cfg.s.genCfg.mtuMinInitial = SB_MTU_MIN_INITIAL; + cfg.t.cfg.s.genCfg.mtuMaxInitial = SB_MTU_MAX_INITIAL; + cfg.t.cfg.s.genCfg.performMtu = FALSE; + cfg.t.cfg.s.genCfg.timeRes = 1; + sprintf((char*)cfg.t.cfg.s.genCfg.hostname, "www.sangoma.com"); /* DAVIDY - Fix this later, probably ignored */ + cfg.t.cfg.s.genCfg.useHstName = FALSE; /* Flag whether hostname is to be used in INIT and INITACK msg */ + cfg.t.cfg.s.genCfg.reConfig.maxInitReTx = 8; + cfg.t.cfg.s.genCfg.reConfig.maxAssocReTx = 10; + cfg.t.cfg.s.genCfg.reConfig.maxPathReTx = 10; + cfg.t.cfg.s.genCfg.reConfig.altAcceptFlg = TRUE; + cfg.t.cfg.s.genCfg.reConfig.keyTm = 600; /* initial value for MD5 Key expiry timer */ + cfg.t.cfg.s.genCfg.reConfig.alpha = 12; + cfg.t.cfg.s.genCfg.reConfig.beta = 25; +#ifdef SB_ECN + cfg.t.cfg.s.genCfg.reConfig.ecnFlg = TRUE; +#endif + + return(sng_cfg_sctp(&pst, &cfg)); +} + +ftdm_status_t ftmod_sigtran_cfg_sctp(void) +{ + int x=0; + for (x=1; g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[x].id !=0; x++) + { + if (!(g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[x].flags & SNGSS7_CONFIGURED)) { + + if ( ftmod_sigtran_sctp_config(x) == FTDM_FAIL) { + SS7_CRITICAL("SCTP %d configuration FAILED!\n", x); + return FTDM_FAIL; + } else { + SS7_INFO("SCTP %d configuration DONE!\n", x); + } + } + } + return FTDM_SUCCESS; +} + + +int ftmod_sigtran_sctp_config(int id) +{ + if (ftmod_sigtran_sctp_tsap_config(id) != FTDM_SUCCESS) + return FTDM_FAIL; + + if (ftmod_sigtran_sctp_sap_config(id) != FTDM_SUCCESS) + return FTDM_FAIL; + + return FTDM_SUCCESS; +} + +ftdm_status_t ftmod_sigtran_sctp_tsap_config(int id) +{ + Pst pst; + SbMgmt cfg; + SbTSapCfg *c; + + int i = 0; + int ret = -1; + + sng_sctp_link_t *k = &g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[id]; + + smPstInit(&pst); + pst.dstEnt = ENTSB; + + memset(&cfg, 0x0, sizeof(cfg)); + smHdrInit(&cfg.hdr); + + cfg.hdr.msgType = TCFG; + cfg.hdr.entId.ent = ENTSB; + cfg.hdr.entId.inst = S_INST; + cfg.hdr.elmId.elmnt = STSBTSAP; + cfg.hdr.elmId.elmntInst1= k->id; + + c = &cfg.t.cfg.s.tSapCfg; + c->swtch = LSB_SW_RFC_REL0; + c->suId = 1; + c->sel = 0; + c->ent = ENTHI; + c->inst = S_INST; + c->procId = g_ftdm_sngss7_data.cfg.procId; + c->memId.region = S_REG; + c->memId.pool = S_POOL; + c->prior = PRIOR1; + c->route = RTESPEC; + c->srcNAddrLst.nmb = k->numSrcAddr; + for (i=0; i <= (k->numSrcAddr-1); i++) { + c->srcNAddrLst.nAddr[i].type = CM_NETADDR_IPV4; + c->srcNAddrLst.nAddr[i].u.ipv4NetAddr = k->srcAddrList[i+1]; + } + + c->reConfig.spId = 1; + c->reConfig.maxBndRetry = 3; + c->reConfig.tIntTmr = 200; + + ret = sng_cfg_sctp(&pst, &cfg); + if (ret==0) { + SS7_INFO("SCTP TSAP %d configuration DONE!\n", id); + return FTDM_SUCCESS; + } else { + SS7_CRITICAL("SCTP TSAP %d configuration FAILED!\n", id); + return FTDM_FAIL; + } +} + +ftdm_status_t ftmod_sigtran_sctp_sap_config(int id) +{ + Pst pst; + SbMgmt cfg; + SbSctSapCfg *c; + + int ret = -1; + sng_sctp_link_t *k = &g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[id]; + + smPstInit(&pst); + pst.dstEnt = ENTSB; + + memset(&cfg, 0x0, sizeof(cfg)); + smHdrInit(&cfg.hdr); + + cfg.hdr.msgType = TCFG; + cfg.hdr.entId.ent = ENTSB; + cfg.hdr.entId.inst = S_INST; + cfg.hdr.elmId.elmnt = STSBSCTSAP; + cfg.hdr.elmId.elmntInst1= k->id; + + c = &cfg.t.cfg.s.sctSapCfg; + c->swtch = LSB_SW_RFC_REL0; + c->spId = 1; /* Service Provider SAP Id */ + c->sel = 0; + c->memId.region = S_REG; + c->memId.pool = S_POOL; + c->prior = PRIOR1; + c->route = RTESPEC; + + /* Maximum time to wait before the SCTP layer must send a Selective Acknowledgement (SACK) message. Valid range is 1 -165535. */ + c->reConfig.maxAckDelayTm = 200; + /* Maximum number of messages to receive before the SCTP layer must send a SACK message. Valid range is 1 - 165535. */ + c->reConfig.maxAckDelayDg = 2; + /* Initial value of the retransmission timer (RTO). The SCTP layer retransmits data after waiting for feedback during this time period. Valid range is 1 - 65535. */ + c->reConfig.rtoInitial = 3000; + /* Minimum value used for the RTO. If the computed value of RTO is less than rtoMin, the computed value is rounded up to this value. */ + c->reConfig.rtoMin = 1000; + /* Maxiumum value used for RTO. If the computed value of RTO is greater than rtoMax, the computed value is rounded down to this value. */ + c->reConfig.rtoMax = 10000; + /* Default Freeze timer value */ + c->reConfig.freezeTm = 3000; + /* Base cookie lifetime for the cookie in the Initiation Acknowledgement (INIT ACK) message. */ + c->reConfig.cookieLife = 60000; + /* Default heartbeat interval timer. Valid range is 1 - 65535. */ + c->reConfig.intervalTm = 3000; + /* Maximum burst value. Valid range is 1 - 65535. */ + c->reConfig.maxBurst = 4; + /*Maximum number of heartbeats sent at each retransmission timeout (RTO). Valid range is 1 - 65535. */ + c->reConfig.maxHbBurst = 1; + /*Shutdown guard timer value for graceful shutdowns. */ + c->reConfig.t5SdownGrdTm = 15000; + /* Action to take when the receiver's number of incoming streams is less than the sender's number of outgoing streams. Valid values are: + TRUE = Accept incoming stream and continue association. + FALSE = Abort the association. + */ + c->reConfig.negAbrtFlg = FALSE; + /* Whether to enable or disable heartbeat by default. Valid values are: + TRUE = Enable heartbeat. + FALSE = Disable heartbeat. + */ + c->reConfig.hBeatEnable = TRUE; + /* Flow control start threshold. When the number of messages in SCTPÂ’s message queue reaches this value, flow control starts. */ + c->reConfig.flcUpThr = 8; + /* Flow control stop threshold. When the number of messages in SCTPÂ’s message queue reaches this value, flow control stops. */ + c->reConfig.flcLowThr = 6; + + c->reConfig.handleInitFlg = FALSE; + + ret = sng_cfg_sctp(&pst, &cfg); + if (ret==0) { + SS7_INFO("SCTP SAP %d configuration DONE!\n", id); + return FTDM_SUCCESS; + } else { + SS7_CRITICAL("SCTP SAP %d configuration FAILED!\n", id); + return FTDM_FAIL; + } +} + +/**********************************************************************************************/ +/* M2UA - General configuration */ +static S16 ftmod_sigtran_m2ua_gen_config(void) +{ + Pst pst; + MwMgmt cfg; + + memset((U8 *)&cfg, 0, sizeof(MwMgmt)); + memset((U8 *)&pst, 0, sizeof(Pst)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.entId.ent = ENTMW; /* entity */ + cfg.hdr.entId.inst = 0; /* instance */ + cfg.hdr.elmId.elmnt = STMWGEN; /* General */ + cfg.hdr.transId = 0; /* transaction identifier */ + + cfg.hdr.response.selector = 0; + cfg.hdr.response.prior = PRIOR0; + cfg.hdr.response.route = RTESPEC; + cfg.hdr.response.mem.region = S_REG; + cfg.hdr.response.mem.pool = S_POOL; + + + + cfg.t.cfg.s.genCfg.nodeType = LMW_TYPE_SGP; /* NodeType == SGP or ASP */ + cfg.t.cfg.s.genCfg.maxNmbIntf = MW_MAX_NUM_OF_INTF; + cfg.t.cfg.s.genCfg.maxNmbCluster = MW_MAX_NUM_OF_CLUSTER; + cfg.t.cfg.s.genCfg.maxNmbPeer = MW_MAX_NUM_OF_PEER; + cfg.t.cfg.s.genCfg.maxNmbSctSap = MW_MAX_NUM_OF_SCT_SAPS; + cfg.t.cfg.s.genCfg.timeRes = 1; /* timer resolution */ + cfg.t.cfg.s.genCfg.maxClusterQSize = MW_MAX_CLUSTER_Q_SIZE; + cfg.t.cfg.s.genCfg.maxIntfQSize = MW_MAX_INTF_Q_SIZE; + +#ifdef LCMWMILMW + cfg.t.cfg.s.genCfg.reConfig.smPst.selector = 0; /* selector */ +#else /* LCSBMILSB */ + cfg.t.cfg.s.genCfg.reConfig.smPst.selector = 1; /* selector */ +#endif /* LCSBMILSB */ + + cfg.t.cfg.s.genCfg.reConfig.smPst.region = S_REG; /* region */ + cfg.t.cfg.s.genCfg.reConfig.smPst.pool = S_POOL; /* pool */ + cfg.t.cfg.s.genCfg.reConfig.smPst.prior = PRIOR0; /* priority */ + cfg.t.cfg.s.genCfg.reConfig.smPst.route = RTESPEC; /* route */ + + cfg.t.cfg.s.genCfg.reConfig.smPst.dstEnt = ENTSM; /* dst entity */ + cfg.t.cfg.s.genCfg.reConfig.smPst.dstInst = 0; /* dst inst */ + cfg.t.cfg.s.genCfg.reConfig.smPst.dstProcId = SFndProcId(); /* src proc id */ + + cfg.t.cfg.s.genCfg.reConfig.smPst.srcEnt = ENTMW; /* src entity */ + cfg.t.cfg.s.genCfg.reConfig.smPst.srcInst = 0; /* src inst */ + cfg.t.cfg.s.genCfg.reConfig.smPst.srcProcId = SFndProcId(); /* src proc id */ + + cfg.t.cfg.s.genCfg.reConfig.tmrFlcPoll.enb = TRUE; /* SCTP Flc Poll timer */ + cfg.t.cfg.s.genCfg.reConfig.tmrFlcPoll.val = 10; + +#ifdef MWASP + cfg.t.cfg.s.genCfg.reConfig.tmrAspm.enb = TRUE; /* ASPM timer */ + cfg.t.cfg.s.genCfg.reConfig.tmrAspm.val = 10; + cfg.t.cfg.s.genCfg.reConfig.tmrHeartBeat.enb = TRUE; /* Heartbeat timer */ + cfg.t.cfg.s.genCfg.reConfig.tmrHeartBeat.val = 10; +#endif + +#ifdef MWSG + cfg.t.cfg.s.genCfg.reConfig.tmrAsPend.enb = TRUE; /* AS-PENDING timer */ + cfg.t.cfg.s.genCfg.reConfig.tmrAsPend.val = 10; + cfg.t.cfg.s.genCfg.reConfig.tmrCongPoll.enb = TRUE; /* SS7 Congestion poll timer */ + cfg.t.cfg.s.genCfg.reConfig.tmrCongPoll.val = 10; + cfg.t.cfg.s.genCfg.reConfig.tmrHeartBeat.enb = FALSE; /* HBtimer only at ASP */ +#endif + cfg.t.cfg.s.genCfg.reConfig.aspmRetry = 5; + + return (sng_cfg_m2ua (&pst, &cfg)); +} + +/**********************************************************************************************/ + + +/* M2UA - SCTSAP configuration */ +static S16 ftmod_sigtran_m2ua_sctsap_config(void) +{ + + Pst pst; + MwMgmt cfg; + + memset((U8 *)&cfg, 0, sizeof(MwMgmt)); + memset((U8 *)&pst, 0, sizeof(Pst)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.entId.ent = ENTMW; /* entity */ + cfg.hdr.entId.inst = 0; /* instance */ + cfg.hdr.elmId.elmnt = STMWSCTSAP; /* SCTSAP */ + cfg.hdr.transId = 0; /* transaction identifier */ + + cfg.hdr.response.selector = 0; + cfg.hdr.response.prior = PRIOR0; + cfg.hdr.response.route = RTESPEC; + cfg.hdr.response.mem.region = S_REG; + cfg.hdr.response.mem.pool = S_POOL; + + + + cfg.t.cfg.s.sctSapCfg.reConfig.selector = 0; + + /* service user SAP ID */ + cfg.t.cfg.s.sctSapCfg.suId = 0; + /* service provider ID */ + cfg.t.cfg.s.sctSapCfg.spId = 1; /* TUCL sct sap id is 1 */ + /* source port number */ + cfg.t.cfg.s.sctSapCfg.srcPort = 0; + /* interface address */ + /*For multiple IP address support */ +#ifdef SCT_ENDP_MULTI_IPADDR + cfg.t.cfg.s.sctSapCfg.srcAddrLst.nmb = 1; + cfg.t.cfg.s.sctSapCfg.srcAddrLst.nAddr[0].type = CM_NETADDR_IPV4; + cfg.t.cfg.s.sctSapCfg.srcAddrLst.nAddr[0].u.ipv4NetAddr = ftmod_parse_conv_ipaddr((S8*)"192.168.1.100"); +#else + cfg.t.cfg.s.sctSapCfg.intfAddr.type = CM_NETADDR_IPV4; + cfg.t.cfg.s.sctSapCfg.intfAddr.u.ipv4NetAddr = ftmod_parse_conv_ipaddr((S8*)"192.168.1.100"); +#endif + + /* lower SAP primitive timer */ + cfg.t.cfg.s.sctSapCfg.reConfig.tmrPrim.enb = TRUE; + cfg.t.cfg.s.sctSapCfg.reConfig.tmrPrim.val = 10; + /* Association primitive timer */ + cfg.t.cfg.s.sctSapCfg.reConfig.tmrAssoc.enb = TRUE; + cfg.t.cfg.s.sctSapCfg.reConfig.tmrAssoc.val = 10; + /* maxnumber of retries */ + cfg.t.cfg.s.sctSapCfg.reConfig.nmbMaxPrimRetry = 5; + /* Life Time of Packets */ + cfg.t.cfg.s.sctSapCfg.reConfig.lifeTime = 200; + /* priority */ + cfg.t.cfg.s.sctSapCfg.reConfig.prior = PRIOR0; + /* route */ + cfg.t.cfg.s.sctSapCfg.reConfig.route = RTESPEC; + cfg.t.cfg.s.sctSapCfg.reConfig.ent = ENTSB; + cfg.t.cfg.s.sctSapCfg.reConfig.inst = 0; + cfg.t.cfg.s.sctSapCfg.reConfig.procId = SFndProcId(); + /* memory region and pool ID */ + cfg.t.cfg.s.sctSapCfg.reConfig.mem.region = S_REG; + cfg.t.cfg.s.sctSapCfg.reConfig.mem.pool = S_POOL; + + return (sng_cfg_m2ua (&pst, &cfg)); + +} + +/**********************************************************************************************/ + + +/* M2UA - Peer configuration */ +static S16 ftmod_sigtran_m2ua_peer_config(void) +{ + Pst pst; + MwMgmt cfg; + + memset((U8 *)&cfg, 0, sizeof(MwMgmt)); + memset((U8 *)&pst, 0, sizeof(Pst)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.entId.ent = ENTMW; /* entity */ + cfg.hdr.entId.inst = 0; /* instance */ + cfg.hdr.elmId.elmnt = STMWPEER; /* Peer */ + cfg.hdr.transId = 0; /* transaction identifier */ + + cfg.hdr.response.selector = 0; + cfg.hdr.response.prior = PRIOR0; + cfg.hdr.response.route = RTESPEC; + cfg.hdr.response.mem.region = S_REG; + cfg.hdr.response.mem.pool = S_POOL; + + + + cfg.t.cfg.s.peerCfg.peerId = 1; /* peer id */ + cfg.t.cfg.s.peerCfg.aspIdFlag = FALSE; /* aspId flag */ +#ifdef MWASP + cfg.t.cfg.s.peerCfg.selfAspId = 1; /* aspId */ +#endif + cfg.t.cfg.s.peerCfg.assocCfg.suId = 0; /* SCTSAP ID */ + cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nmb = 1; /* destination address list*/ + cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[0].type = CM_NETADDR_IPV4; + cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[0].u.ipv4NetAddr = ftmod_parse_conv_ipaddr((S8*)"192.168.1.100");/* TODO */; +#if 0 + cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[1].type = CM_NETADDR_IPV4; + cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[1].u.ipv4NetAddr = ftmod_parse_conv_ipaddr("172.25.0.93"); /* TODO */; +#endif +#ifdef MW_CFG_DSTPORT + cfg.t.cfg.s.peerCfg.assocCfg.dstPort = /* TODO */ 2904; /* Port on which M2UA runs */ +#endif + cfg.t.cfg.s.peerCfg.assocCfg.srcAddrLst.nmb = 1; /* source address list */ + cfg.t.cfg.s.peerCfg.assocCfg.srcAddrLst.nAddr[0].type = CM_NETADDR_IPV4; + cfg.t.cfg.s.peerCfg.assocCfg.srcAddrLst.nAddr[0].u.ipv4NetAddr = ftmod_parse_conv_ipaddr((S8*)"192.168.1.100");/* TODO */; + + cfg.t.cfg.s.peerCfg.assocCfg.priDstAddr.type = CM_NETADDR_IPV4; + cfg.t.cfg.s.peerCfg.assocCfg.priDstAddr.u.ipv4NetAddr = cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[0].u.ipv4NetAddr; + + cfg.t.cfg.s.peerCfg.assocCfg.locOutStrms = 10; +#ifdef SCT3 + cfg.t.cfg.s.peerCfg.assocCfg.tos = 0; +#endif + + return (sng_cfg_m2ua (&pst, &cfg)); +} +/**********************************************************************************************/ + + +/* M2UA - Cluster configuration */ +static S16 ftmod_sigtran_m2ua_cluster_config(void) +{ + Pst pst; + MwMgmt cfg; + + memset((U8 *)&cfg, 0, sizeof(MwMgmt)); + memset((U8 *)&pst, 0, sizeof(Pst)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.entId.ent = ENTMW; /* entity */ + cfg.hdr.entId.inst = 0; /* instance */ + cfg.hdr.elmId.elmnt = STMWCLUSTER; /* Cluster */ + cfg.hdr.transId = 0; /* transaction identifier */ + + cfg.hdr.response.selector = 0; + cfg.hdr.response.prior = PRIOR0; + cfg.hdr.response.route = RTESPEC; + cfg.hdr.response.mem.region = S_REG; + cfg.hdr.response.mem.pool = S_POOL; + + + + cfg.t.cfg.s.clusterCfg.clusterId = 0; + cfg.t.cfg.s.clusterCfg.trfMode = LMW_TRF_MODE_LOADSHARE; + cfg.t.cfg.s.clusterCfg.loadshareMode = LMW_LOADSH_RR; + cfg.t.cfg.s.clusterCfg.reConfig.nmbPeer = 1; + cfg.t.cfg.s.clusterCfg.reConfig.peer[0] = 1; +#if 0 + cfg.t.cfg.s.clusterCfg.reConfig.peer[1] = 2; +#endif + + return (sng_cfg_m2ua (&pst, &cfg)); + +} +/**********************************************************************************************/ + +/* M2UA - DLSAP configuration */ +static S16 ftmod_sigtran_m2ua_dlsap_config(U32 id) +{ + Pst pst; + MwMgmt cfg; + + memset((U8 *)&cfg, 0, sizeof(MwMgmt)); + memset((U8 *)&pst, 0, sizeof(Pst)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.entId.ent = ENTMW; /* entity */ + cfg.hdr.entId.inst = 0; /* instance */ + cfg.hdr.elmId.elmnt = STMWDLSAP; /* DLSAP */ + cfg.hdr.transId = 0; /* transaction identifier */ + + cfg.hdr.response.selector = 0; + cfg.hdr.response.prior = PRIOR0; + cfg.hdr.response.route = RTESPEC; + cfg.hdr.response.mem.region = S_REG; + cfg.hdr.response.mem.pool = S_POOL; + + + switch(id) + { + case 0: + { + cfg.t.cfg.s.dlSapCfg.lnkNmb = 0; /* SapId */ + cfg.t.cfg.s.dlSapCfg.intfId.type = LMW_INTFID_INT; + cfg.t.cfg.s.dlSapCfg.intfId.id.intId = 0; + break; + } + case 1: + { + cfg.t.cfg.s.dlSapCfg.lnkNmb = 1; /* SapId */ + cfg.t.cfg.s.dlSapCfg.intfId.type = LMW_INTFID_INT; + cfg.t.cfg.s.dlSapCfg.intfId.id.intId = 1; + break; + } + + case 2: + { + cfg.t.cfg.s.dlSapCfg.lnkNmb = 2; /* SapId */ + cfg.t.cfg.s.dlSapCfg.intfId.type = LMW_INTFID_INT; + cfg.t.cfg.s.dlSapCfg.intfId.id.intId = 2; + break; + } + default: + break; + } + + cfg.t.cfg.s.dlSapCfg.swtch = LMW_SAP_ITU; + + + + cfg.t.cfg.s.dlSapCfg.reConfig.clusterId = 0; + cfg.t.cfg.s.dlSapCfg.reConfig.selector = 0; /* Loosely couple mode */ + /* memory region and pool id*/ + cfg.t.cfg.s.dlSapCfg.reConfig.mem.region = S_REG; + cfg.t.cfg.s.dlSapCfg.reConfig.mem.pool = S_POOL; + /* priority */ + cfg.t.cfg.s.dlSapCfg.reConfig.prior = PRIOR0; + /* route */ + cfg.t.cfg.s.dlSapCfg.reConfig.route = RTESPEC; + + return (sng_cfg_m2ua (&pst, &cfg)); + +} +/*****************************************************************************/ + +/* NIF configurations */ + +/* NIF - General configuration */ +static S16 ftmod_sigtran_nif_gen_config(void) +{ + Pst pst; + NwMgmt cfg; + + memset((U8 *)&cfg, 0, sizeof(NwMgmt)); + memset((U8 *)&pst, 0, sizeof(Pst)); + + smPstInit(&pst); + + pst.dstEnt = ENTNW; + + /* prepare header */ + cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.entId.ent = ENTNW; /* entity */ + cfg.hdr.entId.inst = 0; /* instance */ + cfg.hdr.elmId.elmnt = STNWGEN; /* DLSAP */ + cfg.hdr.transId = 0; /* transaction identifier */ + + cfg.hdr.response.selector = 0; + cfg.hdr.response.prior = PRIOR0; + cfg.hdr.response.route = RTESPEC; + cfg.hdr.response.mem.region = S_REG; + cfg.hdr.response.mem.pool = S_POOL; + + cfg.t.cfg.s.genCfg.maxNmbDlSap = NW_MAX_NUM_OF_DLSAPS; + cfg.t.cfg.s.genCfg.timeRes = 1; /* timer resolution */ + + cfg.t.cfg.s.genCfg.reConfig.maxNmbRetry = NW_MAX_NUM_OF_RETRY; + cfg.t.cfg.s.genCfg.reConfig.tmrRetry.enb = TRUE; /* SS7 Congestion poll timer */ + cfg.t.cfg.s.genCfg.reConfig.tmrRetry.val = NW_RETRY_TMR_VALUE; + +#ifdef LCNWMILNW + cfg.t.cfg.s.genCfg.reConfig.smPst.selector = 0; /* selector */ +#else /* LCSBMILSB */ + cfg.t.cfg.s.genCfg.reConfig.smPst.selector = 1; /* selector */ +#endif /* LCSBMILSB */ + + cfg.t.cfg.s.genCfg.reConfig.smPst.region = S_REG; /* region */ + cfg.t.cfg.s.genCfg.reConfig.smPst.pool = S_POOL; /* pool */ + cfg.t.cfg.s.genCfg.reConfig.smPst.prior = PRIOR0; /* priority */ + cfg.t.cfg.s.genCfg.reConfig.smPst.route = RTESPEC; /* route */ + + cfg.t.cfg.s.genCfg.reConfig.smPst.dstEnt = ENTSM; /* dst entity */ + cfg.t.cfg.s.genCfg.reConfig.smPst.dstInst = 0; /* dst inst */ + cfg.t.cfg.s.genCfg.reConfig.smPst.dstProcId = SFndProcId(); /* src proc id */ + + cfg.t.cfg.s.genCfg.reConfig.smPst.srcEnt = ENTNW; /* src entity */ + cfg.t.cfg.s.genCfg.reConfig.smPst.srcInst = 0; /* src inst */ + cfg.t.cfg.s.genCfg.reConfig.smPst.srcProcId = SFndProcId(); /* src proc id */ + + return (sng_cfg_nif (&pst, &cfg)); + +} + +/* NIF - DLSAP configuration */ +static S16 ftmod_sigtran_nif_dlsap_config(U32 id) +{ + Pst pst; + NwMgmt cfg; + + memset((U8 *)&cfg, 0, sizeof(NwMgmt)); + memset((U8 *)&pst, 0, sizeof(Pst)); + + smPstInit(&pst); + + pst.dstEnt = ENTNW; + + /* prepare header */ + cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.entId.ent = ENTNW; /* entity */ + cfg.hdr.entId.inst = 0; /* instance */ + cfg.hdr.elmId.elmnt = STNWDLSAP; /* DLSAP */ + cfg.hdr.transId = 0; /* transaction identifier */ + + cfg.hdr.response.selector = 0; + cfg.hdr.response.prior = PRIOR0; + cfg.hdr.response.route = RTESPEC; + cfg.hdr.response.mem.region = S_REG; + cfg.hdr.response.mem.pool = S_POOL; + +#if 0 + switch(id) + { + case 0: + { + cfg.t.cfg.s.dlSapCfg.suId = 0; /*ACC_DLSAP_0 */ + cfg.t.cfg.s.dlSapCfg.m2uaLnkNmb = 0; /*ACC_DLSAP_0 */ + cfg.t.cfg.s.dlSapCfg.mtp2LnkNmb = 0; /* ACC_DLSAP_0 */ + break; + } + case 1: + { + cfg.t.cfg.s.dlSapCfg.suId = 1; /*ACC_DLSAP_0 */ + cfg.t.cfg.s.dlSapCfg.m2uaLnkNmb = 1; /*ACC_DLSAP_0 */ + cfg.t.cfg.s.dlSapCfg.mtp2LnkNmb = /* TODO */1; /* ACC_DLSAP_0 */ + break; + } + case 2: + { + cfg.t.cfg.s.dlSapCfg.suId = 2; /*ACC_DLSAP_0 */ + cfg.t.cfg.s.dlSapCfg.m2uaLnkNmb = 2; /*ACC_DLSAP_0 */ + cfg.t.cfg.s.dlSapCfg.mtp2LnkNmb = /* TODO */ 2; /* ACC_DLSAP_0 */ + break; + } + + default: + break; + + } +#endif + + cfg.t.cfg.s.dlSapCfg.suId = 1; /*ACC_DLSAP_0 */ + cfg.t.cfg.s.dlSapCfg.m2uaLnkNmb = 1; /*ACC_DLSAP_0 */ + cfg.t.cfg.s.dlSapCfg.mtp2LnkNmb = 1; /* TODO */ /* ACC_DLSAP_0 */ + + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.selector = 0; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.region = S_REG; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.pool = S_POOL; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.route = RTESPEC; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.prior = PRIOR0; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.srcEnt = ENTNW; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.srcInst = 0; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.srcProcId = SFndProcId(); + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.dstEnt = ENTMW; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.dstInst = 0; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.dstProcId = SFndProcId(); + + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.selector = 0; + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.region = S_REG; + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.pool = S_POOL; + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.route = RTESPEC; + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.prior = PRIOR0; + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.srcEnt = ENTNW; + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.srcInst = 0; + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.srcProcId = SFndProcId(); + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.dstEnt = ENTSD; + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.dstInst = 0; + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.dstProcId = SFndProcId(); + + return (sng_cfg_nif (&pst, &cfg)); +} + +static U32 ftmod_atoi(S8 *str) +{ + U32 idx = 0; + U32 value = 0; + + while(str[idx] != '\0') + { + value = (10 * value) + (str[idx] - '0'); + idx++; + } + return(value); +} + +static U32 ftmod_parse_conv_ipaddr(S8 *ptr) +{ + + U32 ipAddr = 0; + U32 idx = 0; + U32 tmpCnt = 0; + U32 len_ipAddr = 0; + S8 tmpStr[8] = { 0, 0, 0, 0, 0, 0, 0, 0}; + + len_ipAddr = strlen(ptr); + + idx = 0; + tmpCnt = 0; + while(idx < len_ipAddr) + { + if( ptr[idx] != '.' ) + { + tmpStr[tmpCnt++] = ptr[idx]; + } + else + { + tmpStr[tmpCnt] = '\0'; + ipAddr |= ftmod_atoi(tmpStr); + ipAddr <<= 8; + tmpCnt = 0; + } + idx++; + } + + tmpStr[tmpCnt] = '\0'; + ipAddr |= ftmod_atoi(tmpStr); + + return(ipAddr); +} + +uint32_t iptoul(const char *ip) +{ + char i,*tmp; + int strl; + char strIp[16]; + unsigned long val=0, cvt; + if (!ip) + return 0; + + memset(strIp, 0, sizeof(char)*16); + strl = strlen(ip); + strncpy(strIp, ip, strl>=15?15:strl); + + + tmp=strtok(strIp, "."); + for (i=0;i<4;i++) + { + sscanf(tmp, "%lu", &cvt); + val <<= 8; + val |= (unsigned char)cvt; + tmp=strtok(NULL,"."); + } + return (uint32_t)val; +} + +/***********************************************************************************************************************/ + +int ftmod_ss7_m2ua_start(void){ + + + S16 ret = 0x00; + + /* Send a control request to bind the TSAP between SCTP and TUCL */ + if( (ret = ftmod_sigtran_tsap_bnd()) != ROK) + { + ftdm_log (FTDM_LOG_ERROR ,"\nControl request to bind TSAP of SCTP and TUCL : NOT OK\n"); + return 1; + } + else + { + ftdm_log (FTDM_LOG_INFO ,"\nControl request to bind TSAP of SCTP and TUCL: OK\n"); + } + + /* Send a control request to bind the SCTSAP between SCTP and M2UA */ + if( (ret = ftmod_sigtran_sctsap_bnd()) != ROK) + { + ftdm_log (FTDM_LOG_ERROR ,"Control request to bind SCTSAP of M2UA and SCTP : NOT OK\n"); + return 1; + } + else + { + ftdm_log (FTDM_LOG_INFO ,"Control request to bind SCTSAP of M2UA and SCTP: OK\n"); + } + + /* Send a control request to bind the DLSAP between NIF, M2UA and MTP-2 + for(idx = 0; idx < 3; idx++) */ + { + if( (ret = ftmod_sigtran_dlsap_bnd(1)) != ROK) + { + ftdm_log (FTDM_LOG_ERROR ,"Control request to bind DLSAP between NIF and M2UA: NOT OK\n"); + return 1; + } + else + { + ftdm_log (FTDM_LOG_INFO ,"Control request to bind DLSAP between NIF and M2UA : OK\n"); + } + + if( (ret = ftmod_ss7_dlsap_bnd(0x01)) != ROK) + { + ftdm_log (FTDM_LOG_ERROR ,"Control request to bind DLSAP between NIF and MTP2 : NOT OK\n"); + return 1; + } + else + { + ftdm_log (FTDM_LOG_INFO ,"Control request to bind DLSAP between NIF and MTP2 : OK\n"); + } + } + return 0; +} + + + +static S16 ftmod_sigtran_tsap_bnd(void) +{ + + Pst pst; + SbMgmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(SbMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTSB; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTSB; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STSBTSAP; /* General */ + cntrl.hdr.transId = 1; /* transaction identifier */ + + cntrl.hdr.response.selector = 0; + + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = ABND_ENA; + cntrl.t.cntrl.sapId = 1; /* SCT sap id configured at SCTP layer */ + + return (sng_cntrl_sctp (&pst, &cntrl)); + +} + +static S16 ftmod_sigtran_sctsap_bnd(void) +{ + Pst pst; + MwMgmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(MwMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTMW; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STMWSCTSAP; /* General */ + cntrl.hdr.transId = 1; /* transaction identifier */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + + cntrl.t.cntrl.action = ABND; + cntrl.t.cntrl.s.suId = 0; /* M2UA sct sap Id */ + + return (sng_cntrl_m2ua (&pst, &cntrl)); + +} + + +static S16 ftmod_sigtran_dlsap_bnd(U32 id) +{ + Pst pst; + NwMgmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(NwMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTNW; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTNW; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STNWDLSAP; /* General */ + cntrl.hdr.transId = 1; /* transaction identifier */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = ABND; + cntrl.t.cntrl.suId = id; /* NIF DL sap Id */ + cntrl.t.cntrl.entity = ENTMW; /* M2UA */ + + return (sng_cntrl_nif (&pst, &cntrl)); + +} + +static S16 ftmod_ss7_dlsap_bnd(U32 id) +{ + Pst pst; + NwMgmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(NwMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTNW; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTNW; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STNWDLSAP; /* General */ + cntrl.hdr.transId = 1; /* transaction identifier */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = ABND; + cntrl.t.cntrl.suId = id; /* NIF DL sap Id */ + cntrl.t.cntrl.entity = ENTSD; /* MTP2 */ + + return (sng_cntrl_nif (&pst, &cntrl)); +} diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h new file mode 100644 index 0000000000..1dc9a1f944 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2012, Kapil Gupta + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Contributors: + * + */ +/******************************************************************************/ +#ifndef __FTMOD_SNG_SS7_M2UA_H__ +#define __FTMOD_SNG_SS7_M2UA_H__ +/******************************************************************************/ +#include "private/ftdm_core.h" + +#define MAX_NAME_LEN 25 + +typedef struct sng_nif_cfg{ + char name[MAX_NAME_LEN]; + uint32_t flags; + uint32_t id; + uint32_t m2uaLnkNmb; + uint32_t mtp2LnkNmb; +}sng_nif_cfg_t; + +typedef enum{ + SNG_M2UA_NODE_TYPE_SGP = 1, /* type SG */ + SNG_M2UA_NODE_TYPE_ASP = 2, /* type ASP */ +}sng_m2ua_node_types_e; + +typedef struct sng_m2ua_cfg{ + char name[MAX_NAME_LEN]; + uint32_t flags; + uint32_t id; /* ID */ + uint8_t nodeType; /*Node Type SG/ASP */ + uint16_t sctpId; /* idx to sctp profile */ + uint16_t peerdId; /* idx to m2ua_peer profile */ + uint16_t clusterId; /* idx to m2ua_cluster profile */ +}sng_m2ua_cfg_t; + +typedef struct sng_m2ua_peer_cfg{ + char name[MAX_NAME_LEN]; + uint32_t flags; + uint32_t id; /* ID */ + uint8_t aspIdFlag; /* Flag used to indicate whether include the ASP ID in the ASP UP message */ + uint16_t selfAspId; /* Self ASP ID. ASP identifier for this ASP node if the aspIdFlag is TRUE. */ + uint32_t numDestAddr; /* Number of destination address defined */ + uint16_t sctpId; /* idx to sctp profile */ + uint32_t destAddrList[SCT_MAX_NET_ADDRS+1]; /* Destination adddress list */ + uint16_t locOutStrms; /*Number of outgoing streams supported by this association*/ +}sng_m2ua_peer_cfg_t; + +typedef enum{ + SNG_M2UA_LOAD_SHARE_ALGO_RR = 0x1, /* Round Robin Mode*/ + SNG_M2UA_LOAD_SHARE_ALGO_LS = 0x2, /* Link Specified */ + SNG_M2UA_LOAD_SHARE_ALGO_CS = 0x3, /* Customer Specified */ +}sng_m2ua_load_share_algo_types_e; + + +/* Possible values of Traffic mode */ +typedef enum{ + SNG_M2UA_TRF_MODE_OVERRIDE = 0x1, /* Override Mode */ + SNG_M2UA_TRF_MODE_LOADSHARE = 0x2, /* Loadshare Mode */ + SNG_M2UA_TRF_MODE_BROADCAST = 0x3, /* Broadcast Mode */ + SNG_M2UA_TRF_MODE_ANY = 0x0, /* ANY Mode */ +}sng_m2ua_traffic_mode_types_e; + +typedef struct sng_m2ua_cluster_cfg{ + char name[MAX_NAME_LEN]; + uint32_t flags; + uint32_t id; /* ID */ + uint8_t trfMode; /* Traffic mode. This parameter defines the mode in which this m2ua cluster is supposed to work */ + uint8_t loadShareAlgo; /* This parameter defines the M2UA load share algorithm which is used to distribute the traffic */ + uint16_t numOfPeers; /* idx to m2ua_peer profile */ + uint16_t peerIdLst[MW_MAX_NUM_OF_PEER]; /* idx to m2ua_peer profile */ +}sng_m2ua_cluster_cfg_t; + +typedef struct sng_m2ua_gbl_cfg{ + sng_nif_cfg_t nif[MW_MAX_NUM_OF_INTF]; + sng_m2ua_cfg_t m2ua[MW_MAX_NUM_OF_INTF]; + sng_m2ua_peer_cfg_t m2ua_peer[MW_MAX_NUM_OF_PEER]; + sng_m2ua_cluster_cfg_t m2ua_clus[MW_MAX_NUM_OF_CLUSTER]; +}sng_m2ua_gbl_cfg_t; + +/* m2ua xml parsing APIs */ +int ftmod_ss7_parse_nif_interfaces(ftdm_conf_node_t *nif_interfaces); +int ftmod_ss7_parse_m2ua_interfaces(ftdm_conf_node_t *m2ua_interfaces); +int ftmod_ss7_parse_m2ua_peer_interfaces(ftdm_conf_node_t *m2ua_peer_interfaces); +int ftmod_ss7_parse_m2ua_clust_interfaces(ftdm_conf_node_t *m2ua_clust_interfaces); +ftdm_status_t ftmod_m3ua_parse_sctp_links(ftdm_conf_node_t *node); +uint32_t iptoul(const char *ip); + +int ftmod_ss7_m2ua_start(void); + +ftdm_status_t ftmod_ss7_m2ua_cfg(void); + + +#endif /*__FTMOD_SNG_SS7_M2UA_H__*/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c new file mode 100644 index 0000000000..70af479482 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c @@ -0,0 +1,671 @@ +/* + * Copyright (c) 2012, Kapil Gupta + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Contributors: + * + * + */ + +/* INCLUDE ********************************************************************/ +#include "ftmod_sangoma_ss7_main.h" +/******************************************************************************/ + +/* DEFINES ********************************************************************/ +/******************************************************************************/ + +static int ftmod_ss7_parse_nif_interface(ftdm_conf_node_t *nif_interface); +static int ftmod_ss7_parse_m2ua_interface(ftdm_conf_node_t *m2ua_interface); +static int ftmod_ss7_parse_m2ua_peer_interface(ftdm_conf_node_t *m2ua_peer_interface); +static int ftmod_ss7_parse_m2ua_clust_interface(ftdm_conf_node_t *m2ua_clust_interface); +static int ftmod_ss7_fill_in_nif_interface(sng_nif_cfg_t *nif_iface); +static int ftmod_ss7_fill_in_m2ua_interface(sng_m2ua_cfg_t *m2ua_iface); +static int ftmod_ss7_fill_in_m2ua_peer_interface(sng_m2ua_peer_cfg_t *m2ua_peer_face); +static int ftmod_ss7_fill_in_m2ua_clust_interface(sng_m2ua_cluster_cfg_t *m2ua_cluster_face); + +static ftdm_status_t ftmod_m3ua_parse_sctp_link(ftdm_conf_node_t *node); + +/******************************************************************************/ +int ftmod_ss7_parse_nif_interfaces(ftdm_conf_node_t *nif_interfaces) +{ + ftdm_conf_node_t *nif_interface = NULL; + + /* confirm that we are looking at sng_nif_interfaces */ + if (strcasecmp(nif_interfaces->name, "sng_nif_interfaces")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"sng_nif_interfaces\"!\n",nif_interfaces->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"nif_interfaces\"...\n"); + } + + /* extract the isup_interfaces */ + nif_interface = nif_interfaces->child; + + while (nif_interface != NULL) { + /* parse the found mtp_route */ + if (ftmod_ss7_parse_nif_interface(nif_interface)) { + SS7_ERROR("Failed to parse \"nif_interface\"\n"); + return FTDM_FAIL; + } + + /* go to the next nif_interface */ + nif_interface = nif_interface->next; + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_parse_nif_interface(ftdm_conf_node_t *nif_interface) +{ + sng_nif_cfg_t sng_nif; + ftdm_conf_parameter_t *parm = nif_interface->parameters; + int num_parms = nif_interface->n_parameters; + int i; + + /* initalize the nif intf and isap structure */ + memset(&sng_nif, 0x0, sizeof(sng_nif)); + + /* confirm that we are looking at an nif_interface */ + if (strcasecmp(nif_interface->name, "sng_nif_interface")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"nif_interface\"!\n",nif_interface->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"nif_interface\"...\n"); + } + + + for (i = 0; i < num_parms; i++) { + /**************************************************************************/ + + /* try to match the parameter to what we expect */ + if (!strcasecmp(parm->var, "name")) { + /**********************************************************************/ + strcpy((char *)sng_nif.name, parm->val); + SS7_DEBUG("Found an nif_interface named = %s\n", sng_nif.name); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "id")) { + /**********************************************************************/ + sng_nif.id = atoi(parm->val); + SS7_DEBUG("Found an nif id = %d\n", sng_nif.id); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "m2uaLnkNmb")) { + /**********************************************************************/ + sng_nif.m2uaLnkNmb = atoi(parm->val); + SS7_DEBUG("Found an nif m2uaLnkNmb = %d\n", sng_nif.m2uaLnkNmb); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp2LnkNmb")) { + /**********************************************************************/ + sng_nif.mtp2LnkNmb=atoi(parm->val); + + SS7_DEBUG("Found an nif mtp2LnkNmb = %d\n", sng_nif.mtp2LnkNmb); + /**********************************************************************/ + } else { + /**********************************************************************/ + SS7_ERROR("Found an invalid parameter %s!\n", parm->var); + return FTDM_FAIL; + /**********************************************************************/ + } + + /* move to the next parameter */ + parm = parm + 1; + /**************************************************************************/ + } /* for (i = 0; i < num_parms; i++) */ + + /* default the interface to paused state */ + sngss7_set_flag(&sng_nif, SNGSS7_PAUSED); + + /* fill in the nif interface */ + ftmod_ss7_fill_in_nif_interface(&sng_nif); + + return FTDM_SUCCESS; +} +/******************************************************************************/ +static int ftmod_ss7_fill_in_nif_interface(sng_nif_cfg_t *nif_iface) +{ + int i = nif_iface->id; + + strncpy((char *)g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[i].name, (char *)nif_iface->name, MAX_NAME_LEN-1); + + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[i].id = nif_iface->id; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[i].m2uaLnkNmb = nif_iface->m2uaLnkNmb; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[i].mtp2LnkNmb = nif_iface->mtp2LnkNmb; + + return 0; +} + +/******************************************************************************/ +int ftmod_ss7_parse_m2ua_interfaces(ftdm_conf_node_t *m2ua_interfaces) +{ + ftdm_conf_node_t *m2ua_interface = NULL; + + /* confirm that we are looking at sng_m2ua_interfaces */ + if (strcasecmp(m2ua_interfaces->name, "sng_m2ua_interfaces")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"m2ua_nif_interfaces\"!\n",m2ua_interfaces->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"m2ua_interfaces\"...\n"); + } + + /* extract the isup_interfaces */ + m2ua_interface = m2ua_interfaces->child; + + while (m2ua_interface != NULL) { + /* parse the found mtp_route */ + if (ftmod_ss7_parse_m2ua_interface(m2ua_interface)) { + SS7_ERROR("Failed to parse \"m2ua_interface\"\n"); + return FTDM_FAIL; + } + + /* go to the next m2ua_interface */ + m2ua_interface = m2ua_interface->next; + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_parse_m2ua_interface(ftdm_conf_node_t *m2ua_interface) +{ + sng_m2ua_cfg_t sng_m2ua; + ftdm_conf_parameter_t *parm = m2ua_interface->parameters; + int num_parms = m2ua_interface->n_parameters; + int i; + + /* initalize the m2ua intf */ + memset(&sng_m2ua, 0x0, sizeof(sng_m2ua)); + + /* confirm that we are looking at an nif_interface */ + if (strcasecmp(m2ua_interface->name, "sng_m2ua_interface")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"m2ua_interface\"!\n",m2ua_interface->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"m2ua_interface\"...\n"); + } + + + for (i = 0; i < num_parms; i++) { + /**************************************************************************/ + + /* try to match the parameter to what we expect */ + if (!strcasecmp(parm->var, "name")) { + /**********************************************************************/ + strcpy((char *)sng_m2ua.name, parm->val); + SS7_DEBUG("Found an m2ua_interface named = %s\n", sng_m2ua.name); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "id")) { + /**********************************************************************/ + sng_m2ua.id = atoi(parm->val); + SS7_DEBUG("Found an m2ua id = %d\n", sng_m2ua.id); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "nodeType")) { + /**********************************************************************/ + if(!strcasecmp(parm->val, "SGP")){ + sng_m2ua.nodeType = SNG_M2UA_NODE_TYPE_SGP; + } else if(!strcasecmp(parm->val, "ASP")){ + SS7_ERROR(" NodeType = ASP Not Supported Yet \n"); + return FTDM_FAIL; + } else { + SS7_ERROR("Found an invalid NodeType Parameter Value[%s]\n", parm->val); + return FTDM_FAIL; + } + SS7_DEBUG("Found an nif nodeType = %d\n", sng_m2ua.nodeType); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "sctpId")) { + /**********************************************************************/ + sng_m2ua.sctpId=atoi(parm->val); + + SS7_DEBUG("Found an m2ua sctpId = %d\n", sng_m2ua.sctpId); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "peerdId")) { + /**********************************************************************/ + sng_m2ua.peerdId=atoi(parm->val); + + SS7_DEBUG("Found an m2ua peerdId = %d\n", sng_m2ua.peerdId); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "clusterId")) { + /**********************************************************************/ + sng_m2ua.clusterId=atoi(parm->val); + + SS7_DEBUG("Found an m2ua clusterId = %d\n", sng_m2ua.clusterId); + /**********************************************************************/ + } else { + /**********************************************************************/ + SS7_ERROR("Found an invalid parameter %s!\n", parm->var); + return FTDM_FAIL; + /**********************************************************************/ + } + + /* move to the next parameter */ + parm = parm + 1; + /**************************************************************************/ + } /* for (i = 0; i < num_parms; i++) */ + + /* default the interface to paused state */ + sngss7_set_flag(&sng_m2ua, SNGSS7_PAUSED); + + /* fill in the nif interface */ + ftmod_ss7_fill_in_m2ua_interface(&sng_m2ua); + + return FTDM_SUCCESS; +} +/******************************************************************************/ +static int ftmod_ss7_fill_in_m2ua_interface(sng_m2ua_cfg_t *m2ua_iface) +{ + int i = m2ua_iface->id; + + strncpy((char *)g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].name, (char *)m2ua_iface->name, MAX_NAME_LEN-1); + + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].id = m2ua_iface->id; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].nodeType = m2ua_iface->nodeType; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].sctpId = m2ua_iface->sctpId; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].peerdId = m2ua_iface->peerdId; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].clusterId = m2ua_iface->clusterId; + + return 0; +} + +/******************************************************************************/ +int ftmod_ss7_parse_m2ua_peer_interfaces(ftdm_conf_node_t *m2ua_peer_interfaces) +{ + ftdm_conf_node_t *m2ua_peer_interface = NULL; + + /* confirm that we are looking at m2ua_peer_interfaces */ + if (strcasecmp(m2ua_peer_interfaces->name, "sng_m2ua_peer_interfaces")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"m2ua_peer_interfaces\"!\n",m2ua_peer_interfaces->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"m2ua_peer_interfaces\"...\n"); + } + + /* extract the m2ua_peer_interfaces */ + m2ua_peer_interface = m2ua_peer_interfaces->child; + + while (m2ua_peer_interface != NULL) { + /* parse the found mtp_route */ + if (ftmod_ss7_parse_m2ua_peer_interface(m2ua_peer_interface)) { + SS7_ERROR("Failed to parse \"m2ua_peer_interface\"\n"); + return FTDM_FAIL; + } + + /* go to the next m2ua_peer_interface */ + m2ua_peer_interface = m2ua_peer_interface->next; + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_parse_m2ua_peer_interface(ftdm_conf_node_t *m2ua_peer_interface) +{ + sng_m2ua_peer_cfg_t sng_m2ua_peer; + ftdm_conf_parameter_t *parm = m2ua_peer_interface->parameters; + int num_parms = m2ua_peer_interface->n_parameters; + int i; + + /* initalize the m2ua intf */ + memset(&sng_m2ua_peer, 0x0, sizeof(sng_m2ua_peer)); + + /* confirm that we are looking at an m2ua_peer_interface */ + if (strcasecmp(m2ua_peer_interface->name, "sng_m2ua_peer_interface")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"m2ua_peer_interface\"!\n",m2ua_peer_interface->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"m2ua_peer_interface\"...\n"); + } + + + for (i = 0; i < num_parms; i++) { + /**************************************************************************/ + + /* try to match the parameter to what we expect */ + if (!strcasecmp(parm->var, "name")) { + /**********************************************************************/ + strcpy((char *)sng_m2ua_peer.name, parm->val); + SS7_DEBUG("Found an sng_m2ua_peer named = %s\n", sng_m2ua_peer.name); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "id")) { + /**********************************************************************/ + sng_m2ua_peer.id = atoi(parm->val); + SS7_DEBUG("Found an sng_m2ua_peer id = %d\n", sng_m2ua_peer.id); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "aspIdFlag")) { + /**********************************************************************/ + if(!strcasecmp(parm->val, "TRUE")){ + sng_m2ua_peer.aspIdFlag = 0x01; + } else if(!strcasecmp(parm->val, "FALSE")){ + sng_m2ua_peer.aspIdFlag = 0x00; + } else { + SS7_ERROR("Found an invalid aspIdFlag Parameter Value[%s]\n", parm->val); + return FTDM_FAIL; + } + SS7_DEBUG("Found an sng_m2ua_peer aspIdFlag = %d\n", sng_m2ua_peer.aspIdFlag); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "selfAspId")) { + /**********************************************************************/ + sng_m2ua_peer.selfAspId=atoi(parm->val); + + SS7_DEBUG("Found an sng_m2ua_peer selfAspId = %d\n", sng_m2ua_peer.selfAspId); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "DestAddr")) { + /**********************************************************************/ + if (sng_m2ua_peer.numDestAddr < SCT_MAX_NET_ADDRS) { + sng_m2ua_peer.destAddrList[sng_m2ua_peer.numDestAddr] = iptoul (parm->val); + sng_m2ua_peer.numDestAddr++; + SS7_DEBUG("sng_m2ua_peer - Parsing with dest IP Address = %s\n", parm->val); + } else { + SS7_ERROR("sng_m2ua_peer - too many dest address configured. dropping %s \n", parm->val); + } + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "locOutStrms")) { + /**********************************************************************/ + sng_m2ua_peer.locOutStrms=atoi(parm->val); + + SS7_DEBUG("Found an sng_m2ua_peer locOutStrms = %d\n", sng_m2ua_peer.locOutStrms); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "sctpId")) { + /**********************************************************************/ + sng_m2ua_peer.sctpId=atoi(parm->val); + + SS7_DEBUG("Found an sng_m2ua_peer sctpId = %d\n", sng_m2ua_peer.sctpId); + /**********************************************************************/ + } else { + /**********************************************************************/ + SS7_ERROR("Found an invalid parameter %s!\n", parm->var); + return FTDM_FAIL; + /**********************************************************************/ + } + + /* move to the next parameter */ + parm = parm + 1; + /**************************************************************************/ + } /* for (i = 0; i < num_parms; i++) */ + + /* default the interface to paused state */ + sngss7_set_flag(&sng_m2ua_peer, SNGSS7_PAUSED); + + /* fill in the sng_m2ua_peer interface */ + ftmod_ss7_fill_in_m2ua_peer_interface(&sng_m2ua_peer); + + return FTDM_SUCCESS; +} +/******************************************************************************/ +static int ftmod_ss7_fill_in_m2ua_peer_interface(sng_m2ua_peer_cfg_t *m2ua_peer_iface) +{ + int k = 0x00; + int i = m2ua_peer_iface->id; + + strncpy((char *)g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].name, (char *)m2ua_peer_iface->name, MAX_NAME_LEN-1); + + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].id = m2ua_peer_iface->id; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].aspIdFlag = m2ua_peer_iface->aspIdFlag; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].selfAspId = m2ua_peer_iface->selfAspId; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].locOutStrms = m2ua_peer_iface->locOutStrms; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].numDestAddr = m2ua_peer_iface->numDestAddr; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].sctpId = m2ua_peer_iface->sctpId; + for (k=1; k<=m2ua_peer_iface->numDestAddr; k++) { + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].destAddrList[k] = m2ua_peer_iface->destAddrList[k]; + } + + + return 0; +} + +/******************************************************************************/ +int ftmod_ss7_parse_m2ua_clust_interfaces(ftdm_conf_node_t *m2ua_cluster_interfaces) +{ + ftdm_conf_node_t *m2ua_cluster_interface = NULL; + + /* confirm that we are looking at m2ua_cluster_interfaces */ + if (strcasecmp(m2ua_cluster_interfaces->name, "sng_m2ua_cluster_interfaces")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"m2ua_cluster_interfaces\"!\n",m2ua_cluster_interfaces->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"m2ua_cluster_interfaces\"...\n"); + } + + /* extract the m2ua_cluster_interfaces */ + m2ua_cluster_interface = m2ua_cluster_interfaces->child; + + while (m2ua_cluster_interface != NULL) { + /* parse the found m2ua_cluster_interface */ + if (ftmod_ss7_parse_m2ua_clust_interface(m2ua_cluster_interface)) { + SS7_ERROR("Failed to parse \"m2ua_cluster_interface\"\n"); + return FTDM_FAIL; + } + + /* go to the next m2ua_cluster_interface */ + m2ua_cluster_interface = m2ua_cluster_interface->next; + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_parse_m2ua_clust_interface(ftdm_conf_node_t *m2ua_cluster_interface) +{ + sng_m2ua_cluster_cfg_t sng_m2ua_cluster; + ftdm_conf_parameter_t *parm = m2ua_cluster_interface->parameters; + int num_parms = m2ua_cluster_interface->n_parameters; + int i; + + /* initalize the m2ua_cluster_interface */ + memset(&sng_m2ua_cluster, 0x0, sizeof(sng_m2ua_cluster)); + + /* confirm that we are looking at an m2ua_cluster_interface */ + if (strcasecmp(m2ua_cluster_interface->name, "sng_m2ua_cluster_interface")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"m2ua_cluster_interface\"!\n",m2ua_cluster_interface->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"m2ua_cluster_interface\"...\n"); + } + + + for (i = 0; i < num_parms; i++) { + /**************************************************************************/ + + /* try to match the parameter to what we expect */ + if (!strcasecmp(parm->var, "name")) { + /**********************************************************************/ + strcpy((char *)sng_m2ua_cluster.name, parm->val); + SS7_DEBUG("Found an sng_m2ua_cluster named = %s\n", sng_m2ua_cluster.name); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "id")) { + /**********************************************************************/ + sng_m2ua_cluster.id = atoi(parm->val); + SS7_DEBUG("Found an sng_m2ua_cluster id = %d\n", sng_m2ua_cluster.id); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "trfMode")) { + /**********************************************************************/ + if(!strcasecmp(parm->val, "LOADSHARE")){ + sng_m2ua_cluster.trfMode = SNG_M2UA_TRF_MODE_LOADSHARE; + } else if(!strcasecmp(parm->val, "OVERRIDE")){ + sng_m2ua_cluster.trfMode = SNG_M2UA_TRF_MODE_OVERRIDE; + } else if(!strcasecmp(parm->val, "BROADCAST")){ + sng_m2ua_cluster.trfMode = SNG_M2UA_TRF_MODE_BROADCAST; + } else { + SS7_ERROR("Found an invalid trfMode Parameter Value[%s]..adding default one[ANY]\n", parm->val); + sng_m2ua_cluster.trfMode = SNG_M2UA_TRF_MODE_ANY; + } + SS7_DEBUG("Found an sng_m2ua_cluster.trfMode = %d\n", sng_m2ua_cluster.trfMode); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "loadShareAlgo")) { + /**********************************************************************/ + if(!strcasecmp(parm->val, "Round_Robin")){ + sng_m2ua_cluster.loadShareAlgo = SNG_M2UA_LOAD_SHARE_ALGO_RR; + } else if(!strcasecmp(parm->val, "Link_Specified")){ + sng_m2ua_cluster.loadShareAlgo = SNG_M2UA_LOAD_SHARE_ALGO_LS; + } else if(!strcasecmp(parm->val, "Customer_Specified")){ + sng_m2ua_cluster.loadShareAlgo = SNG_M2UA_LOAD_SHARE_ALGO_CS; + } else { + SS7_ERROR("Found an invalid loadShareAlgo Parameter Value[%s]\n", parm->val); + return FTDM_FAIL; + } + + SS7_DEBUG("Found an sng_m2ua_cluster.loadShareAlgo = %d\n", sng_m2ua_cluster.loadShareAlgo); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "peerId")) { + /**********************************************************************/ + if(sng_m2ua_cluster.numOfPeers < MW_MAX_NUM_OF_PEER) { + sng_m2ua_cluster.peerIdLst[sng_m2ua_cluster.numOfPeers] = atoi(parm->val); + sng_m2ua_cluster.numOfPeers++; + SS7_DEBUG("Found an sng_m2ua_cluster peerId[%d], Total numOfPeers[%d] \n", + sng_m2ua_cluster.peerIdLst[sng_m2ua_cluster.numOfPeers], + sng_m2ua_cluster.numOfPeers); + }else{ + SS7_ERROR("Peer List excedding max[%d] limit \n", MW_MAX_NUM_OF_PEER); + return FTDM_FAIL; + } + /**********************************************************************/ + } else { + /**********************************************************************/ + SS7_ERROR("Found an invalid parameter %s!\n", parm->var); + return FTDM_FAIL; + /**********************************************************************/ + } + + /* move to the next parameter */ + parm = parm + 1; + /**************************************************************************/ + } /* for (i = 0; i < num_parms; i++) */ + + /* default the interface to paused state */ + sngss7_set_flag(&sng_m2ua_cluster, SNGSS7_PAUSED); + + /* fill in the sng_m2ua_peer interface */ + ftmod_ss7_fill_in_m2ua_clust_interface(&sng_m2ua_cluster); + + return FTDM_SUCCESS; +} +/******************************************************************************/ +static int ftmod_ss7_fill_in_m2ua_clust_interface(sng_m2ua_cluster_cfg_t *m2ua_cluster_iface) +{ + int k = 0x00; + int i = m2ua_cluster_iface->id; + + strncpy((char *)g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].name, (char *)m2ua_cluster_iface->name, MAX_NAME_LEN-1); + + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[i].id = m2ua_cluster_iface->id; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[i].trfMode = m2ua_cluster_iface->trfMode; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[i].loadShareAlgo = m2ua_cluster_iface->loadShareAlgo; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[i].numOfPeers = m2ua_cluster_iface->numOfPeers; + for(k=0;knumOfPeers;k++){ + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[i].peerIdLst[k] = m2ua_cluster_iface->peerIdLst[k]; + } + + return 0; +} + +/******************************************************************************/ +ftdm_status_t ftmod_m3ua_parse_sctp_links(ftdm_conf_node_t *node) +{ + ftdm_conf_node_t *node_sctp_link = NULL; + + if (!node) + return FTDM_FAIL; + + if (strcasecmp(node->name, "sng_sctp_interfaces")) { + SS7_ERROR("SCTP - We're looking at <%s>...but we're supposed to be looking at !\n", node->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("SCTP - Parsing configurations\n"); + } + + for (node_sctp_link = node->child; node_sctp_link != NULL; node_sctp_link = node_sctp_link->next) { + if (ftmod_m3ua_parse_sctp_link(node_sctp_link) != FTDM_SUCCESS) { + SS7_ERROR("SCTP - Failed to parse . \n"); + return FTDM_FAIL; + } + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t ftmod_m3ua_parse_sctp_link(ftdm_conf_node_t *node) +{ + ftdm_conf_parameter_t *param = NULL; + int num_params = 0; + int i=0; + + if (!node) + return FTDM_FAIL; + + param = node->parameters; + num_params = node->n_parameters; + + sng_sctp_link_t t_link; + memset (&t_link, 0, sizeof(sng_sctp_link_t)); + + if (strcasecmp(node->name, "sng_sctp_interface")) { + SS7_ERROR("SCTP - We're looking at <%s>...but we're supposed to be looking at !\n", node->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("SCTP - Parsing configurations\n"); + } + + for (i=0; ivar, "name")) { + int n_strlen = strlen(param->val); + strncpy((char*)t_link.name, param->val, (n_strlen>MAX_NAME_LEN)?MAX_NAME_LEN:n_strlen); + SS7_DEBUG("SCTP - Parsing with name = %s\n", param->val); + } + else if (!strcasecmp(param->var, "id")) { + t_link.id = atoi(param->val); + SS7_DEBUG("SCTP - Parsing with id = %s\n", param->val); + } + else if (!strcasecmp(param->var, "srcAddr")) { + if (t_link.numSrcAddr < SCT_MAX_NET_ADDRS) { + t_link.srcAddrList[t_link.numSrcAddr+1] = iptoul (param->val); + t_link.numSrcAddr++; + SS7_DEBUG("SCTP - Parsing with source IP Address = %s\n", param->val); + } else { + SS7_ERROR("SCTP - too many source address configured. dropping %s \n", param->val); + } + } + else { + SS7_ERROR("SCTP - Found an unknown parameter <%s>. Skipping it.\n", param->var); + } + } + + g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].id = t_link.id; + g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].tuclId = t_link.id; + strncpy((char*)g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].name, t_link.name, strlen(t_link.name) ); + g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].flags = 0; + g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].numSrcAddr = t_link.numSrcAddr; + for (i=1; i<=t_link.numSrcAddr; i++) { + g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].srcAddrList[i] = t_link.srcAddrList[i]; + } + + return FTDM_SUCCESS; +} +/******************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 1098126890..3c71b67411 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -50,6 +50,7 @@ static sng_isup_event_interface_t sng_event; static ftdm_io_interface_t g_ftdm_sngss7_interface; ftdm_sngss7_data_t g_ftdm_sngss7_data; +ftdm_sngss7_opr_mode g_ftdm_operating_mode; /******************************************************************************/ @@ -355,6 +356,15 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) /* set IN_THREAD flag so that we know this thread is running */ ftdm_set_flag (ftdmspan, FTDM_SPAN_IN_THREAD); + if(SNG_SS7_OPR_MODE_M2UA_SG == g_ftdm_operating_mode){ + ftdm_log (FTDM_LOG_INFO, "FreeTDM running as M2UA_SG mode, freetdm dont have to do anything \n"); + + while (ftdm_running () && !(ftdm_test_flag (ftdmspan, FTDM_SPAN_STOP_THREAD))) { + continue; + } + goto ftdm_sangoma_ss7_stop; + } + /* get an interrupt queue for this span for channel state changes */ if (ftdm_queue_get_interrupt (ftdmspan->pendingchans, &ftdm_sangoma_ss7_int[0]) != FTDM_SUCCESS) { SS7_CRITICAL ("Failed to get a ftdm_interrupt for span = %d for channel state changes!\n", ftdmspan->span_id); @@ -497,10 +507,12 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) /**********************************************************************/ } } +ftdm_sangoma_ss7_stop: /* clear the IN_THREAD flag so that we know the thread is done */ ftdm_clear_flag (ftdmspan, FTDM_SPAN_IN_THREAD); + ftdm_log (FTDM_LOG_INFO,"ftmod_sangoma_ss7 monitor thread for span=%u stopping.\n",ftdmspan->span_id); return NULL; @@ -2496,6 +2508,8 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config) /* set the flag to indicate that this span uses sig event queues */ ftdm_set_flag (span, FTDM_SPAN_USE_SIGNALS_QUEUE); + + /* parse the configuration and apply to the global config structure */ if (ftmod_ss7_parse_xml(ftdm_parameters, span)) { ftdm_log (FTDM_LOG_CRIT, "Failed to parse configuration!\n"); @@ -2503,8 +2517,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config) return FTDM_FAIL; } - /* configure libsngss7 */ - if (ft_to_sngss7_cfg_all()) { + if (ft_to_sngss7_cfg_all()) { /* configure libsngss7 */ ftdm_log (FTDM_LOG_CRIT, "Failed to configure LibSngSS7!\n"); ftdm_sleep (100); return FTDM_FAIL; @@ -2566,6 +2579,10 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_ss7_init) sng_event.sm.sng_isup_alarm = handle_sng_isup_alarm; sng_event.sm.sng_cc_alarm = handle_sng_cc_alarm; sng_event.sm.sng_relay_alarm = handle_sng_relay_alarm; + sng_event.sm.sng_m2ua_alarm = handle_sng_m2ua_alarm; + sng_event.sm.sng_nif_alarm = handle_sng_nif_alarm; + sng_event.sm.sng_tucl_alarm = handle_sng_tucl_alarm; + sng_event.sm.sng_sctp_alarm = handle_sng_sctp_alarm; /* initalize sng_ss7 library */ sng_isup_init_gen(&sng_event); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 4ccf4efe0e..fc6a6e61b5 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -52,6 +52,7 @@ #include "private/ftdm_core.h" #include "sng_ss7/sng_ss7.h" +#include "ftmod_sangoma_ss7_m2ua.h" /******************************************************************************/ @@ -60,6 +61,7 @@ #define MAX_CIC_LENGTH 5 #define MAX_CIC_MAP_LENGTH 1000 +#define MAX_SCTP_LINK 100 #define SNGSS7_EVENT_QUEUE_SIZE 100 #define SNGSS7_PEER_CHANS_QUEUE_SIZE 100 @@ -449,6 +451,29 @@ typedef struct sng_relay { uint32_t procId; } sng_relay_t; +/********************************************** +sctp structures and data definitions +**********************************************/ + +typedef struct sng_sctp_gen_cfg { +} sng_sctp_gen_cfg_t; + +typedef struct sng_sctp_link { + char name[MAX_NAME_LEN]; + uint32_t flags; + uint32_t id; + uint32_t tuclId; + uint32_t numSrcAddr; + uint32_t srcAddrList[SCT_MAX_NET_ADDRS+1]; +} sng_sctp_link_t; + +typedef struct sng_sctp_cfg { + sng_sctp_gen_cfg_t genCfg; + sng_sctp_link_t linkCfg[MAX_SCTP_LINK+1]; +} sng_sctp_cfg_t; + + + typedef struct sng_ss7_cfg { uint32_t spc; uint32_t procId; @@ -468,6 +493,8 @@ typedef struct sng_ss7_cfg { sng_isap_t isap[MAX_ISAPS+1]; sng_glare_resolution glareResolution; uint32_t force_inr; + sng_m2ua_gbl_cfg_t g_m2ua_cfg; + sng_sctp_cfg_t sctpCfg; } sng_ss7_cfg_t; typedef struct ftdm_sngss7_data { @@ -480,6 +507,14 @@ typedef struct ftdm_sngss7_data { fio_signal_cb_t sig_cb; } ftdm_sngss7_data_t; +typedef enum{ + SNG_SS7_OPR_MODE_NONE, + SNG_SS7_OPR_MODE_M2UA_SG, + SNG_SS7_OPR_MODE_ISUP, +}ftdm_sngss7_operating_modes_e; + +typedef ftdm_sngss7_operating_modes_e ftdm_sngss7_opr_mode; + typedef struct sngss7_timer_data { ftdm_timer_id_t hb_timer_id; int beat; @@ -728,6 +763,7 @@ typedef enum { /* GLOBALS ********************************************************************/ extern ftdm_sngss7_data_t g_ftdm_sngss7_data; +extern ftdm_sngss7_opr_mode g_ftdm_operating_mode; extern sng_ssf_type_t sng_ssf_type_map[]; extern sng_switch_type_t sng_switch_type_map[]; extern sng_link_type_t sng_link_type_map[]; @@ -750,6 +786,10 @@ void handle_sng_mtp3_alarm(Pst *pst, SnMngmt *sta); void handle_sng_isup_alarm(Pst *pst, SiMngmt *sta); void handle_sng_cc_alarm(Pst *pst, CcMngmt *sta); void handle_sng_relay_alarm(Pst *pst, RyMngmt *sta); +void handle_sng_m2ua_alarm(Pst *pst, MwMgmt *sta); +void handle_sng_nif_alarm(Pst *pst, NwMgmt *sta); +void handle_sng_tucl_alarm(Pst *pst, HiMngmt *sta); +void handle_sng_sctp_alarm(Pst *pst, SbMgmt *sta); /* in ftmod_sangoma_ss7_relay.c */ ftdm_status_t handle_relay_connect(RyMngmt *sta); @@ -974,6 +1014,7 @@ void handle_isup_t35(void *userdata); void handle_isup_t10(void *userdata); void handle_isup_t39(void *userdata); + /******************************************************************************/ /* MACROS *********************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index f64356dd1f..32ebdc52b9 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -220,11 +220,32 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa /* clean out the self route */ memset(&self_route, 0x0, sizeof(self_route)); + var = ftdm_parameters[i].var; + val = ftdm_parameters[i].val; + + printf("var[%s], val[%s]\n",var,val); + /* confirm that the first parameter is the "operatingMode" */ + if(!strcasecmp(var, "operatingMode")){ + /**********************************************************************/ + if(!strcasecmp(val, "ISUP")) { + g_ftdm_operating_mode = SNG_SS7_OPR_MODE_ISUP; + } + else if(!strcasecmp(val, "M2UA_SG")) { + g_ftdm_operating_mode = SNG_SS7_OPR_MODE_M2UA_SG; + } else { + SS7_ERROR("Invalid operating Mode[%s] \n", val); + return FTDM_FAIL; + } + /**********************************************************************/ + } + + i++; + var = ftdm_parameters[i].var; val = ftdm_parameters[i].val; ptr = (ftdm_conf_node_t *)ftdm_parameters[i].ptr; - /* confirm that the first parameter is the "confnode" */ + /* confirm that the 2nd parameter is the "confnode" */ if (!strcasecmp(var, "confnode")) { /* parse the confnode and fill in the global libsng_ss7 config structure */ if (ftmod_ss7_parse_sng_isup(ptr)) { @@ -239,6 +260,7 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa } i++; + while (ftdm_parameters[i].var != NULL) { /**************************************************************************/ @@ -269,10 +291,12 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa /* fill the pointer to span into isupCkt */ sngSpan.span = span; - /* setup the circuits structure */ - if(ftmod_ss7_fill_in_circuits(&sngSpan)) { - SS7_ERROR("Failed to fill in circuits structure!\n"); - goto ftmod_ss7_parse_xml_error; + if(SNG_SS7_OPR_MODE_ISUP == g_ftdm_operating_mode){ + /* setup the circuits structure */ + if(ftmod_ss7_fill_in_circuits(&sngSpan)) { + SS7_ERROR("Failed to fill in circuits structure!\n"); + goto ftmod_ss7_parse_xml_error; + } } return FTDM_SUCCESS; @@ -294,6 +318,11 @@ static int ftmod_ss7_parse_sng_isup(ftdm_conf_node_t *sng_isup) ftdm_conf_node_t *isup_interfaces = NULL; ftdm_conf_node_t *cc_spans = NULL; ftdm_conf_node_t *tmp_node = NULL; + ftdm_conf_node_t *nif_ifaces = NULL; + ftdm_conf_node_t *m2ua_ifaces = NULL; + ftdm_conf_node_t *m2ua_peer_ifaces = NULL; + ftdm_conf_node_t *m2ua_clust_ifaces = NULL; + ftdm_conf_node_t *sctp_ifaces = NULL; /* confirm that we are looking at sng_isup */ if (strcasecmp(sng_isup->name, "sng_isup")) { @@ -399,12 +428,62 @@ static int ftmod_ss7_parse_sng_isup(ftdm_conf_node_t *sng_isup) return FTDM_FAIL; } /**********************************************************************/ + } else if (!strcasecmp(tmp_node->name, "sng_nif_interfaces")) { + /**********************************************************************/ + if (nif_ifaces == NULL) { + nif_ifaces = tmp_node; + SS7_DEBUG("Found a \"sng_nif_interfaces\" section!\n"); + } else { + SS7_ERROR("Found a second \"sng_nif_interfaces\" section\n!"); + return FTDM_FAIL; + } + /**********************************************************************/ + } else if (!strcasecmp(tmp_node->name, "sng_m2ua_interfaces")) { + /**********************************************************************/ + if (m2ua_ifaces == NULL) { + m2ua_ifaces = tmp_node; + SS7_DEBUG("Found a \"sng_m2ua_interfaces\" section!\n"); + } else { + SS7_ERROR("Found a second \"sng_m2ua_interfaces\" section\n!"); + return FTDM_FAIL; + } + /**********************************************************************/ + } else if (!strcasecmp(tmp_node->name, "sng_m2ua_peer_interfaces")) { + /**********************************************************************/ + if (m2ua_peer_ifaces == NULL) { + m2ua_peer_ifaces = tmp_node; + SS7_DEBUG("Found a \"sng_m2ua_peer_interfaces\" section!\n"); + } else { + SS7_ERROR("Found a second \"sng_m2ua_peer_interfaces\" section\n!"); + return FTDM_FAIL; + } + /**********************************************************************/ + } else if (!strcasecmp(tmp_node->name, "sng_m2ua_cluster_interfaces")) { + /**********************************************************************/ + if (m2ua_clust_ifaces == NULL) { + m2ua_clust_ifaces = tmp_node; + SS7_DEBUG("Found a \"sng_m2ua_cluster_interfaces\" section!\n"); + } else { + SS7_ERROR("Found a second \"sng_m2ua_peer_interfaces\" section\n!"); + return FTDM_FAIL; + } + /**********************************************************************/ + } else if (!strcasecmp(tmp_node->name, "sng_sctp_interfaces")) { + /**********************************************************************/ + if (sctp_ifaces == NULL) { + sctp_ifaces = tmp_node; + SS7_DEBUG("Found a section!\n"); + } else { + SS7_ERROR("Found a second section!\n"); + return FTDM_FAIL; + } + /**********************************************************************/ } else { /**********************************************************************/ SS7_ERROR("\tFound an unknown section \"%s\"!\n", tmp_node->name); return FTDM_FAIL; /**********************************************************************/ - } + } /* go to the next sibling */ tmp_node = tmp_node->next; @@ -431,11 +510,6 @@ static int ftmod_ss7_parse_sng_isup(ftdm_conf_node_t *sng_isup) return FTDM_FAIL; } - if (ftmod_ss7_parse_mtp3_links(mtp3_links)) { - SS7_ERROR("Failed to parse \"mtp3_links\"!\n"); - return FTDM_FAIL; - } - if (ftmod_ss7_parse_mtp_linksets(mtp_linksets)) { SS7_ERROR("Failed to parse \"mtp_linksets\"!\n"); return FTDM_FAIL; @@ -446,14 +520,57 @@ static int ftmod_ss7_parse_sng_isup(ftdm_conf_node_t *sng_isup) return FTDM_FAIL; } - if (ftmod_ss7_parse_isup_interfaces(isup_interfaces)) { - SS7_ERROR("Failed to parse \"isup_interfaces\"!\n"); - return FTDM_FAIL; - } + switch(g_ftdm_operating_mode) + { + case SNG_SS7_OPR_MODE_ISUP: + { + if (mtp3_links && ftmod_ss7_parse_mtp3_links(mtp3_links)) { + SS7_ERROR("Failed to parse \"mtp3_links\"!\n"); + return FTDM_FAIL; + } + + if (isup_interfaces && ftmod_ss7_parse_isup_interfaces(isup_interfaces)) { + SS7_ERROR("Failed to parse \"isup_interfaces\"!\n"); + return FTDM_FAIL; + } + + if (cc_spans && ftmod_ss7_parse_cc_spans(cc_spans)) { + SS7_ERROR("Failed to parse \"cc_spans\"!\n"); + return FTDM_FAIL; + } + break; + } + case SNG_SS7_OPR_MODE_M2UA_SG: + { + if (ftmod_m3ua_parse_sctp_links(sctp_ifaces) != FTDM_SUCCESS) { + SS7_ERROR("Failed to parse !\n"); + return FTDM_FAIL; + } + SS7_INFO("Finished ftmod_m3ua_parse_sctp_links!\n"); + + if (nif_ifaces && ftmod_ss7_parse_nif_interfaces(nif_ifaces)) { + SS7_ERROR("Failed to parse \"nif_ifaces\"!\n"); + return FTDM_FAIL; + } + + if (m2ua_ifaces && ftmod_ss7_parse_m2ua_interfaces(m2ua_ifaces)) { + SS7_ERROR("Failed to parse \"m2ua_ifaces\"!\n"); + return FTDM_FAIL; + } + if (m2ua_peer_ifaces && ftmod_ss7_parse_m2ua_peer_interfaces(m2ua_peer_ifaces)) { + SS7_ERROR("Failed to parse \"m2ua_peer_ifaces\"!\n"); + return FTDM_FAIL; + } + if (m2ua_clust_ifaces && ftmod_ss7_parse_m2ua_clust_interfaces(m2ua_clust_ifaces)) { + SS7_ERROR("Failed to parse \"m2ua_clust_ifaces\"!\n"); + return FTDM_FAIL; + } + break; + } + default: + SS7_ERROR("Invalid operating mode[%d]\n",g_ftdm_operating_mode); + break; - if (ftmod_ss7_parse_cc_spans(cc_spans)) { - SS7_ERROR("Failed to parse \"cc_spans\"!\n"); - return FTDM_FAIL; } return FTDM_SUCCESS; From 4a99dc7fc75155018f61769967fd346e124b7bbc Mon Sep 17 00:00:00 2001 From: kapil Date: Fri, 18 May 2012 12:24:27 +0530 Subject: [PATCH 197/822] added code to ftdm_sangoma_ss7_run api to avoid code execution for M2UA SG --- .../ftmod_sangoma_ss7_main.c | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 3c71b67411..dbb1c1974c 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -356,14 +356,7 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) /* set IN_THREAD flag so that we know this thread is running */ ftdm_set_flag (ftdmspan, FTDM_SPAN_IN_THREAD); - if(SNG_SS7_OPR_MODE_M2UA_SG == g_ftdm_operating_mode){ - ftdm_log (FTDM_LOG_INFO, "FreeTDM running as M2UA_SG mode, freetdm dont have to do anything \n"); - while (ftdm_running () && !(ftdm_test_flag (ftdmspan, FTDM_SPAN_STOP_THREAD))) { - continue; - } - goto ftdm_sangoma_ss7_stop; - } /* get an interrupt queue for this span for channel state changes */ if (ftdm_queue_get_interrupt (ftdmspan->pendingchans, &ftdm_sangoma_ss7_int[0]) != FTDM_SUCCESS) { @@ -377,6 +370,40 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) goto ftdm_sangoma_ss7_run_exit; } + if(SNG_SS7_OPR_MODE_M2UA_SG == g_ftdm_operating_mode){ + ftdm_log (FTDM_LOG_INFO, "FreeTDM running as M2UA_SG mode, freetdm dont have to do anything \n"); + + while (ftdm_running () && !(ftdm_test_flag (ftdmspan, FTDM_SPAN_STOP_THREAD))) { + + switch ((ftdm_interrupt_multiple_wait(ftdm_sangoma_ss7_int, ftdm_array_len(ftdm_sangoma_ss7_int), 100))) { + + case FTDM_SUCCESS: /* process all pending state changes */ + + SS7_DEVEL_DEBUG ("ftdm_interrupt_wait FTDM_SUCCESS on span = %d\n",ftdmspan->span_id); + + /**********************************************************************/ + case FTDM_TIMEOUT: + SS7_DEVEL_DEBUG ("ftdm_interrupt_wait timed-out on span = %d\n",ftdmspan->span_id); + + break; + /**********************************************************************/ + case FTDM_FAIL: + SS7_ERROR ("ftdm_interrupt_wait returned error!\non span = %d\n", ftdmspan->span_id); + + break; + /**********************************************************************/ + default: + SS7_ERROR("ftdm_interrupt_wait returned with unknown code on span = %d\n",ftdmspan->span_id); + + break; + /**********************************************************************/ + } + + + } + goto ftdm_sangoma_ss7_stop; + } + while (ftdm_running () && !(ftdm_test_flag (ftdmspan, FTDM_SPAN_STOP_THREAD))) { int x = 0; if (b_alarm_test) { From c36b5f0ccafd2c54a9a0782dfea5ced3f0027f14 Mon Sep 17 00:00:00 2001 From: kapil Date: Fri, 18 May 2012 13:46:50 +0530 Subject: [PATCH 198/822] fixing megaco conf xml error --- src/mod/endpoints/mod_megaco/conf/megaco.conf.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml b/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml index ed849030bf..d386e055a9 100644 --- a/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml +++ b/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml @@ -6,10 +6,10 @@ - + - + - + - + From e91e4d68163368371461e9db451790667c90947b Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 18 May 2012 09:57:51 -0400 Subject: [PATCH 199/822] renamed sip_h_X-FreeTDM-Access-Transport to sip_h_X-FreeTDM-Access-Transport-URLENC --- libs/freetdm/mod_freetdm/mod_freetdm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 51fbeca6cc..90de796b43 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1401,7 +1401,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi ftdm_set_string(caller_data.loc.digits, sipvar); } - sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-Access-Transport"); + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-Access-Transport-URLENC"); if (sipvar) { ftdm_usrmsg_add_var(&usrmsg, "ss7_access_transport_urlenc", sipvar); } @@ -1872,7 +1872,7 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_access_transport_urlenc"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-Access-Transport", "%s", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-Access-Transport-URLENC", "%s", var_value); } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdinfo_indicator"); From 91dfa062bf41ce8005696987a20f3c4648c0e888 Mon Sep 17 00:00:00 2001 From: James Date: Mon, 28 May 2012 16:53:45 -0400 Subject: [PATCH 200/822] ss7: adding iam_fwd_ind_HEX channel variable to set forward indicator IE's heximal value. - add to dialplan with expected hex value. If the outgoing ftdm channel's forward indicator needs to be changed, "export" needs to be put in the incoming channel's dialplan to set this variable value accordingly. - this implementation takes bits of A, CB, D, E, F, HG, I from the hex value. Bits of KJ, L, P-M are not taken from the hex. - How to calculate hex value with wanted bits: . the hex value is H-A-P-I, H is the highest bit to A, and next is P-I. I is the lowest bit in the whole field, and H is the highest bit in the whole field. Refer to Q.763 chapter 3.23. . use a text pad to fill in the bits with 0 and 1. eventually fill all the 16 bits . copy the binary value into a calculator and convert it to hex --- libs/freetdm/mod_freetdm/mod_freetdm.c | 5 + .../ftmod_sangoma_ss7_support.c | 136 ++++++++++++++++-- 2 files changed, 128 insertions(+), 13 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 90de796b43..430ace829f 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1593,6 +1593,11 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi if ((var = channel_get_variable(session, var_event, "freetdm_calling_party_category"))) { ftdm_set_calling_party_category(var, (uint8_t *)&caller_data.cpc); } + + if ((var = channel_get_variable(session, var_event, "iam_fwd_ind_HEX"))) { + ftdm_usrmsg_add_var(&usrmsg, "iam_fwd_ind_HEX", var); + } + if (!zstr(dest)) { ftdm_set_string(caller_data.dnis.digits, dest); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index fd70f13290..39134f9925 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -87,7 +87,7 @@ FTDM_STR2ENUM(ftmod_ss7_blk_state2flag, ftmod_ss7_blk_flag2str, sng_ckt_block_fl /* FUNCTIONS ******************************************************************/ static uint8_t get_trillium_val(ftdm2trillium_t *vals, uint8_t ftdm_val, uint8_t default_val); static uint8_t get_ftdm_val(ftdm2trillium_t *vals, uint8_t trillium_val, uint8_t default_val); - +ftdm_status_t four_char_to_hex(const char* in, uint16_t* out) ; /* Maps generic FreeTDM CPC codes to SS7 CPC codes */ @@ -248,9 +248,9 @@ ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *loc sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; - if (!strcasecmp(caller_data->loc.digits, "NULL")) { - pres_val = NOTPRSNT; - } + if (!strcasecmp(caller_data->loc.digits, "NULL")) { + pres_val = NOTPRSNT; + } locPtyNum->eh.pres = pres_val; locPtyNum->natAddrInd.pres = pres_val; @@ -896,6 +896,86 @@ ftdm_status_t copy_natConInd_to_sngss7(ftdm_channel_t *ftdmchan, SiNatConInd *na return FTDM_SUCCESS; } +ftdm_status_t four_char_to_hex(const char* in, uint16_t* out) +{ + int i= 4; + char a, b, c, d; + if (!in || 4>strlen(in)) { + return FTDM_FAIL; + } + while(i) + { + switch((char)*(in+(4-i))) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (i==4) { + d = *(in+(4-i)) - 48; + } else if (i==3) { + c = *(in+(4-i)) - 48; + } else if (i==2) { + b = *(in+(4-i)) - 48; + } else { + a = *(in+(4-i)) - 48; + } + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + if (i==4) { + d = *(in+(4-i)) - 55; + } else if (i==3) { + c = *(in+(4-i)) - 55; + } else if (i==2) { + b = *(in+(4-i)) - 55; + } else { + a = *(in+(4-i)) - 55; + } + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + if (i==4) { + d = *(in+(4-i)) - 87; + } else if (i==3) { + c = *(in+(4-i)) - 87; + } else if (i==2) { + b = *(in+(4-i)) - 87; + } else { + a = *(in+(4-i)) - 87; + } + break; + default: + SS7_ERROR("Invalid character found when decoding hex string, %c!\n", *(in+(4-i)) ); + break; + } + i--; + }; + + *out |= d; + *out = *out<<4; + *out |= c; + *out = *out<<4; + *out |= b; + *out = *out<<4; + *out |= a; + + return FTDM_SUCCESS; +} + ftdm_status_t copy_fwdCallInd_to_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd *fwdCallInd) { const char *val = NULL; @@ -904,27 +984,56 @@ ftdm_status_t copy_fwdCallInd_to_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd * fwdCallInd->eh.pres = PRSNT_NODEF; fwdCallInd->natIntCallInd.pres = PRSNT_NODEF; - fwdCallInd->natIntCallInd.val = 0x00; fwdCallInd->end2EndMethInd.pres = PRSNT_NODEF; - fwdCallInd->end2EndMethInd.val = E2EMTH_NOMETH; fwdCallInd->intInd.pres = PRSNT_NODEF; - fwdCallInd->intInd.val = INTIND_NOINTW; fwdCallInd->end2EndInfoInd.pres = PRSNT_NODEF; - fwdCallInd->end2EndInfoInd.val = E2EINF_NOINFO; fwdCallInd->isdnUsrPrtInd.pres = PRSNT_NODEF; - fwdCallInd->isdnUsrPrtInd.val = ISUP_USED; fwdCallInd->isdnUsrPrtPrfInd.pres = PRSNT_NODEF; - fwdCallInd->isdnUsrPrtPrfInd.val = PREF_PREFAW; fwdCallInd->isdnAccInd.pres = PRSNT_NODEF; + fwdCallInd->sccpMethInd.pres = PRSNT_NODEF; + fwdCallInd->sccpMethInd.val = SCCPMTH_NOIND; + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "iam_fwd_ind_HEX"); + if (!ftdm_strlen_zero(val)) { + uint16_t val_hex = 0; + if (four_char_to_hex (val, &val_hex) == FTDM_FAIL) { + SS7_ERROR ("Wrong value set in iam_fwd_ind_HEX variable. Please correct the error. Setting to default values.\n" ); + } else { + fwdCallInd->natIntCallInd.val = (val_hex & 0x100)>>8; + fwdCallInd->end2EndMethInd.val = (val_hex & 0x600)>>9; + fwdCallInd->intInd.val = (val_hex & 0x800)>>11; + fwdCallInd->end2EndInfoInd.val = (val_hex & 0x1000)>>12; + fwdCallInd->isdnUsrPrtInd.val = (val_hex & 0x2000)>>13; + fwdCallInd->isdnUsrPrtPrfInd.val = (val_hex & 0xC000)>>14; + fwdCallInd->isdnUsrPrtPrfInd.val = (fwdCallInd->isdnUsrPrtPrfInd.val==0x03)?0x0:fwdCallInd->isdnUsrPrtPrfInd.val; + fwdCallInd->isdnAccInd.val = val_hex & 0x1; + + if ((g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS88) || + (g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS92) || + (g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS95)) { + + /* include only if we're running ANSI */ + fwdCallInd->transCallNInd.pres = PRSNT_NODEF; + fwdCallInd->transCallNInd.val = 0x0; + } + + return FTDM_SUCCESS; + } + } + + fwdCallInd->natIntCallInd.val = 0x00; + fwdCallInd->end2EndMethInd.val = E2EMTH_NOMETH; + fwdCallInd->intInd.val = INTIND_NOINTW; + fwdCallInd->end2EndInfoInd.val = E2EINF_NOINFO; + fwdCallInd->isdnUsrPrtInd.val = ISUP_USED; + fwdCallInd->isdnUsrPrtPrfInd.val = PREF_PREFAW; val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "iam_fwd_ind_isdn_access_ind"); if (!ftdm_strlen_zero(val)) { acc_val = (int)atoi(val); } - fwdCallInd->isdnAccInd.val = acc_val; - fwdCallInd->sccpMethInd.pres = PRSNT_NODEF; - fwdCallInd->sccpMethInd.val = SCCPMTH_NOIND; + fwdCallInd->isdnAccInd.val = acc_val; if ((g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS88) || (g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS92) || @@ -934,6 +1043,7 @@ ftdm_status_t copy_fwdCallInd_to_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd * fwdCallInd->transCallNInd.pres = PRSNT_NODEF; fwdCallInd->transCallNInd.val = 0x0; } + return FTDM_SUCCESS; } From a941cad15ddf0b144de47ae04c7d638cb0e7b889 Mon Sep 17 00:00:00 2001 From: Kapil Date: Tue, 29 May 2012 15:06:25 +0530 Subject: [PATCH 201/822] adding M2UA SG open endpoint request code --- .../ftmod_sangoma_ss7_m2ua.c | 54 +++++++++++++++++-- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c index 375be9f35a..c6c1689ddc 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c @@ -69,6 +69,7 @@ ftdm_status_t sng_m2ua_cfg(void); static S16 ftmod_sigtran_tsap_bnd(void); static S16 ftmod_sigtran_sctsap_bnd(void); +static S16 ftmod_sigtran_open_endpoint(void); static S16 ftmod_sigtran_dlsap_bnd(U32 id); static S16 ftmod_ss7_dlsap_bnd(U32 id); @@ -708,16 +709,16 @@ static S16 ftmod_sigtran_m2ua_sctsap_config(void) /* service provider ID */ cfg.t.cfg.s.sctSapCfg.spId = 1; /* TUCL sct sap id is 1 */ /* source port number */ - cfg.t.cfg.s.sctSapCfg.srcPort = 0; + cfg.t.cfg.s.sctSapCfg.srcPort = 2904; /* interface address */ /*For multiple IP address support */ #ifdef SCT_ENDP_MULTI_IPADDR cfg.t.cfg.s.sctSapCfg.srcAddrLst.nmb = 1; cfg.t.cfg.s.sctSapCfg.srcAddrLst.nAddr[0].type = CM_NETADDR_IPV4; - cfg.t.cfg.s.sctSapCfg.srcAddrLst.nAddr[0].u.ipv4NetAddr = ftmod_parse_conv_ipaddr((S8*)"192.168.1.100"); + cfg.t.cfg.s.sctSapCfg.srcAddrLst.nAddr[0].u.ipv4NetAddr = ftmod_parse_conv_ipaddr((S8*)"192.168.1.102"); #else cfg.t.cfg.s.sctSapCfg.intfAddr.type = CM_NETADDR_IPV4; - cfg.t.cfg.s.sctSapCfg.intfAddr.u.ipv4NetAddr = ftmod_parse_conv_ipaddr((S8*)"192.168.1.100"); + cfg.t.cfg.s.sctSapCfg.intfAddr.u.ipv4NetAddr = ftmod_parse_conv_ipaddr((S8*)"192.168.1.102"); #endif /* lower SAP primitive timer */ @@ -784,7 +785,7 @@ static S16 ftmod_sigtran_m2ua_peer_config(void) cfg.t.cfg.s.peerCfg.assocCfg.suId = 0; /* SCTSAP ID */ cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nmb = 1; /* destination address list*/ cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[0].type = CM_NETADDR_IPV4; - cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[0].u.ipv4NetAddr = ftmod_parse_conv_ipaddr((S8*)"192.168.1.100");/* TODO */; + cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[0].u.ipv4NetAddr = ftmod_parse_conv_ipaddr((S8*)"192.168.1.101");/* TODO */; #if 0 cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[1].type = CM_NETADDR_IPV4; cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[1].u.ipv4NetAddr = ftmod_parse_conv_ipaddr("172.25.0.93"); /* TODO */; @@ -794,7 +795,7 @@ static S16 ftmod_sigtran_m2ua_peer_config(void) #endif cfg.t.cfg.s.peerCfg.assocCfg.srcAddrLst.nmb = 1; /* source address list */ cfg.t.cfg.s.peerCfg.assocCfg.srcAddrLst.nAddr[0].type = CM_NETADDR_IPV4; - cfg.t.cfg.s.peerCfg.assocCfg.srcAddrLst.nAddr[0].u.ipv4NetAddr = ftmod_parse_conv_ipaddr((S8*)"192.168.1.100");/* TODO */; + cfg.t.cfg.s.peerCfg.assocCfg.srcAddrLst.nAddr[0].u.ipv4NetAddr = ftmod_parse_conv_ipaddr((S8*)"192.168.1.102");/* TODO */; cfg.t.cfg.s.peerCfg.assocCfg.priDstAddr.type = CM_NETADDR_IPV4; cfg.t.cfg.s.peerCfg.assocCfg.priDstAddr.u.ipv4NetAddr = cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[0].u.ipv4NetAddr; @@ -1196,10 +1197,53 @@ int ftmod_ss7_m2ua_start(void){ ftdm_log (FTDM_LOG_INFO ,"Control request to bind DLSAP between NIF and MTP2 : OK\n"); } } + + /* Send a control request to open endpoint */ + if( (ret = ftmod_sigtran_open_endpoint()) != ROK) + { + ftdm_log (FTDM_LOG_ERROR ,"ftmod_sigtran_open_endpoint FAIL \n"); + return 1; + } + else + { + ftdm_log (FTDM_LOG_ERROR ,"ftmod_sigtran_open_endpoint SUCCESS \n"); + } + return 0; } +static S16 ftmod_sigtran_open_endpoint(void) +{ + Pst pst; + MwMgmt cntrl; + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(MwMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTMW; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STMWSCTSAP; /* General */ + cntrl.hdr.transId = 1; /* transaction identifier */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + + cntrl.t.cntrl.action = AMWENDPOPEN; + cntrl.t.cntrl.s.suId = 0; /* M2UA sct sap Id */ + + return (sng_cntrl_m2ua (&pst, &cntrl)); + +} static S16 ftmod_sigtran_tsap_bnd(void) { From 076d9fbe67ef4282d528ade20fe79fb69f7045e4 Mon Sep 17 00:00:00 2001 From: kapil Date: Wed, 30 May 2012 07:45:59 +0530 Subject: [PATCH 202/822] M2UA xml configuration parsing code --- .../ftmod_sangoma_ss7_m2ua.h | 2 +- .../ftmod_sangoma_ss7_m2ua_xml.c | 106 +++++++++++------- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 32 ++++-- 3 files changed, 86 insertions(+), 54 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h index 1dc9a1f944..db13a1635b 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h @@ -114,7 +114,7 @@ int ftmod_ss7_parse_nif_interfaces(ftdm_conf_node_t *nif_interfaces); int ftmod_ss7_parse_m2ua_interfaces(ftdm_conf_node_t *m2ua_interfaces); int ftmod_ss7_parse_m2ua_peer_interfaces(ftdm_conf_node_t *m2ua_peer_interfaces); int ftmod_ss7_parse_m2ua_clust_interfaces(ftdm_conf_node_t *m2ua_clust_interfaces); -ftdm_status_t ftmod_m3ua_parse_sctp_links(ftdm_conf_node_t *node); +int ftmod_ss7_parse_sctp_links(ftdm_conf_node_t *node); uint32_t iptoul(const char *ip); int ftmod_ss7_m2ua_start(void); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c index 70af479482..333f616628 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c @@ -52,7 +52,7 @@ static int ftmod_ss7_fill_in_m2ua_interface(sng_m2ua_cfg_t *m2ua_iface); static int ftmod_ss7_fill_in_m2ua_peer_interface(sng_m2ua_peer_cfg_t *m2ua_peer_face); static int ftmod_ss7_fill_in_m2ua_clust_interface(sng_m2ua_cluster_cfg_t *m2ua_cluster_face); -static ftdm_status_t ftmod_m3ua_parse_sctp_link(ftdm_conf_node_t *node); +static int ftmod_ss7_parse_sctp_link(ftdm_conf_node_t *node); /******************************************************************************/ int ftmod_ss7_parse_nif_interfaces(ftdm_conf_node_t *nif_interfaces) @@ -95,6 +95,11 @@ static int ftmod_ss7_parse_nif_interface(ftdm_conf_node_t *nif_interface) /* initalize the nif intf and isap structure */ memset(&sng_nif, 0x0, sizeof(sng_nif)); + if(!nif_interface){ + SS7_ERROR("ftmod_ss7_parse_nif_interface: Null XML Node pointer \n"); + return FTDM_FAIL; + } + /* confirm that we are looking at an nif_interface */ if (strcasecmp(nif_interface->name, "sng_nif_interface")) { SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"nif_interface\"!\n",nif_interface->name); @@ -118,16 +123,16 @@ static int ftmod_ss7_parse_nif_interface(ftdm_conf_node_t *nif_interface) sng_nif.id = atoi(parm->val); SS7_DEBUG("Found an nif id = %d\n", sng_nif.id); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "m2uaLnkNmb")) { + } else if (!strcasecmp(parm->var, "m2ua_link_nmb")) { /**********************************************************************/ sng_nif.m2uaLnkNmb = atoi(parm->val); - SS7_DEBUG("Found an nif m2uaLnkNmb = %d\n", sng_nif.m2uaLnkNmb); + SS7_DEBUG("Found an nif m2ua_link_nmb = %d\n", sng_nif.m2uaLnkNmb); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "mtp2LnkNmb")) { + } else if (!strcasecmp(parm->var, "mtp2_link_nmb")) { /**********************************************************************/ sng_nif.mtp2LnkNmb=atoi(parm->val); - SS7_DEBUG("Found an nif mtp2LnkNmb = %d\n", sng_nif.mtp2LnkNmb); + SS7_DEBUG("Found an nif mtp2_link_nmb = %d\n", sng_nif.mtp2LnkNmb); /**********************************************************************/ } else { /**********************************************************************/ @@ -204,6 +209,11 @@ static int ftmod_ss7_parse_m2ua_interface(ftdm_conf_node_t *m2ua_interface) /* initalize the m2ua intf */ memset(&sng_m2ua, 0x0, sizeof(sng_m2ua)); + if(!m2ua_interface){ + SS7_ERROR("ftmod_ss7_parse_m2ua_interface: Null XML Node pointer \n"); + return FTDM_FAIL; + } + /* confirm that we are looking at an nif_interface */ if (strcasecmp(m2ua_interface->name, "sng_m2ua_interface")) { SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"m2ua_interface\"!\n",m2ua_interface->name); @@ -227,7 +237,7 @@ static int ftmod_ss7_parse_m2ua_interface(ftdm_conf_node_t *m2ua_interface) sng_m2ua.id = atoi(parm->val); SS7_DEBUG("Found an m2ua id = %d\n", sng_m2ua.id); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "nodeType")) { + } else if (!strcasecmp(parm->var, "node_type")) { /**********************************************************************/ if(!strcasecmp(parm->val, "SGP")){ sng_m2ua.nodeType = SNG_M2UA_NODE_TYPE_SGP; @@ -238,25 +248,25 @@ static int ftmod_ss7_parse_m2ua_interface(ftdm_conf_node_t *m2ua_interface) SS7_ERROR("Found an invalid NodeType Parameter Value[%s]\n", parm->val); return FTDM_FAIL; } - SS7_DEBUG("Found an nif nodeType = %d\n", sng_m2ua.nodeType); + SS7_DEBUG("Found an nif node_type = %d\n", sng_m2ua.nodeType); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "sctpId")) { + } else if (!strcasecmp(parm->var, "sctp_id")) { /**********************************************************************/ sng_m2ua.sctpId=atoi(parm->val); - SS7_DEBUG("Found an m2ua sctpId = %d\n", sng_m2ua.sctpId); + SS7_DEBUG("Found an m2ua sctp_id = %d\n", sng_m2ua.sctpId); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "peerdId")) { + } else if (!strcasecmp(parm->var, "peerd_id")) { /**********************************************************************/ sng_m2ua.peerdId=atoi(parm->val); - SS7_DEBUG("Found an m2ua peerdId = %d\n", sng_m2ua.peerdId); + SS7_DEBUG("Found an m2ua peerd_id = %d\n", sng_m2ua.peerdId); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "clusterId")) { + } else if (!strcasecmp(parm->var, "cluster_id")) { /**********************************************************************/ sng_m2ua.clusterId=atoi(parm->val); - SS7_DEBUG("Found an m2ua clusterId = %d\n", sng_m2ua.clusterId); + SS7_DEBUG("Found an m2ua cluster_id = %d\n", sng_m2ua.clusterId); /**********************************************************************/ } else { /**********************************************************************/ @@ -335,6 +345,11 @@ static int ftmod_ss7_parse_m2ua_peer_interface(ftdm_conf_node_t *m2ua_peer_inter /* initalize the m2ua intf */ memset(&sng_m2ua_peer, 0x0, sizeof(sng_m2ua_peer)); + if(!m2ua_peer_interface){ + SS7_ERROR("ftmod_ss7_parse_m2ua_peer_interface: Null XML Node pointer \n"); + return FTDM_FAIL; + } + /* confirm that we are looking at an m2ua_peer_interface */ if (strcasecmp(m2ua_peer_interface->name, "sng_m2ua_peer_interface")) { SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"m2ua_peer_interface\"!\n",m2ua_peer_interface->name); @@ -358,7 +373,7 @@ static int ftmod_ss7_parse_m2ua_peer_interface(ftdm_conf_node_t *m2ua_peer_inter sng_m2ua_peer.id = atoi(parm->val); SS7_DEBUG("Found an sng_m2ua_peer id = %d\n", sng_m2ua_peer.id); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "aspIdFlag")) { + } else if (!strcasecmp(parm->var, "asp_id_flag")) { /**********************************************************************/ if(!strcasecmp(parm->val, "TRUE")){ sng_m2ua_peer.aspIdFlag = 0x01; @@ -370,13 +385,19 @@ static int ftmod_ss7_parse_m2ua_peer_interface(ftdm_conf_node_t *m2ua_peer_inter } SS7_DEBUG("Found an sng_m2ua_peer aspIdFlag = %d\n", sng_m2ua_peer.aspIdFlag); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "selfAspId")) { + } else if (!strcasecmp(parm->var, "self_asp_id")) { /**********************************************************************/ sng_m2ua_peer.selfAspId=atoi(parm->val); - SS7_DEBUG("Found an sng_m2ua_peer selfAspId = %d\n", sng_m2ua_peer.selfAspId); + SS7_DEBUG("Found an sng_m2ua_peer self_asp_id = %d\n", sng_m2ua_peer.selfAspId); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "DestAddr")) { + } else if (!strcasecmp(parm->var, "sctp_id")) { + /**********************************************************************/ + sng_m2ua_peer.sctpId = atoi(parm->val); + + SS7_DEBUG("Found an sng_m2ua_peer sctp_id = %d\n", sng_m2ua_peer.sctpId); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "dest_addr")) { /**********************************************************************/ if (sng_m2ua_peer.numDestAddr < SCT_MAX_NET_ADDRS) { sng_m2ua_peer.destAddrList[sng_m2ua_peer.numDestAddr] = iptoul (parm->val); @@ -386,17 +407,11 @@ static int ftmod_ss7_parse_m2ua_peer_interface(ftdm_conf_node_t *m2ua_peer_inter SS7_ERROR("sng_m2ua_peer - too many dest address configured. dropping %s \n", parm->val); } /**********************************************************************/ - } else if (!strcasecmp(parm->var, "locOutStrms")) { + } else if (!strcasecmp(parm->var, "loc_out_strms")) { /**********************************************************************/ sng_m2ua_peer.locOutStrms=atoi(parm->val); - SS7_DEBUG("Found an sng_m2ua_peer locOutStrms = %d\n", sng_m2ua_peer.locOutStrms); - /**********************************************************************/ - } else if (!strcasecmp(parm->var, "sctpId")) { - /**********************************************************************/ - sng_m2ua_peer.sctpId=atoi(parm->val); - - SS7_DEBUG("Found an sng_m2ua_peer sctpId = %d\n", sng_m2ua_peer.sctpId); + SS7_DEBUG("Found an sng_m2ua_peer loc_out_strms = %d\n", sng_m2ua_peer.locOutStrms); /**********************************************************************/ } else { /**********************************************************************/ @@ -481,6 +496,11 @@ static int ftmod_ss7_parse_m2ua_clust_interface(ftdm_conf_node_t *m2ua_cluster_i /* initalize the m2ua_cluster_interface */ memset(&sng_m2ua_cluster, 0x0, sizeof(sng_m2ua_cluster)); + if (!m2ua_cluster_interface){ + SS7_ERROR("ftmod_ss7_parse_m2ua_clust_interface - NULL XML Node pointer \n"); + return FTDM_FAIL; + } + /* confirm that we are looking at an m2ua_cluster_interface */ if (strcasecmp(m2ua_cluster_interface->name, "sng_m2ua_cluster_interface")) { SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"m2ua_cluster_interface\"!\n",m2ua_cluster_interface->name); @@ -504,13 +524,13 @@ static int ftmod_ss7_parse_m2ua_clust_interface(ftdm_conf_node_t *m2ua_cluster_i sng_m2ua_cluster.id = atoi(parm->val); SS7_DEBUG("Found an sng_m2ua_cluster id = %d\n", sng_m2ua_cluster.id); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "trfMode")) { + } else if (!strcasecmp(parm->var, "trf_mode")) { /**********************************************************************/ - if(!strcasecmp(parm->val, "LOADSHARE")){ + if(!strcasecmp(parm->val, "loadshare")){ sng_m2ua_cluster.trfMode = SNG_M2UA_TRF_MODE_LOADSHARE; - } else if(!strcasecmp(parm->val, "OVERRIDE")){ + } else if(!strcasecmp(parm->val, "override")){ sng_m2ua_cluster.trfMode = SNG_M2UA_TRF_MODE_OVERRIDE; - } else if(!strcasecmp(parm->val, "BROADCAST")){ + } else if(!strcasecmp(parm->val, "broadcast")){ sng_m2ua_cluster.trfMode = SNG_M2UA_TRF_MODE_BROADCAST; } else { SS7_ERROR("Found an invalid trfMode Parameter Value[%s]..adding default one[ANY]\n", parm->val); @@ -518,13 +538,13 @@ static int ftmod_ss7_parse_m2ua_clust_interface(ftdm_conf_node_t *m2ua_cluster_i } SS7_DEBUG("Found an sng_m2ua_cluster.trfMode = %d\n", sng_m2ua_cluster.trfMode); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "loadShareAlgo")) { + } else if (!strcasecmp(parm->var, "load_share_algo")) { /**********************************************************************/ - if(!strcasecmp(parm->val, "Round_Robin")){ + if(!strcasecmp(parm->val, "roundrobin")){ sng_m2ua_cluster.loadShareAlgo = SNG_M2UA_LOAD_SHARE_ALGO_RR; - } else if(!strcasecmp(parm->val, "Link_Specified")){ + } else if(!strcasecmp(parm->val, "linkspecified")){ sng_m2ua_cluster.loadShareAlgo = SNG_M2UA_LOAD_SHARE_ALGO_LS; - } else if(!strcasecmp(parm->val, "Customer_Specified")){ + } else if(!strcasecmp(parm->val, "customerspecified")){ sng_m2ua_cluster.loadShareAlgo = SNG_M2UA_LOAD_SHARE_ALGO_CS; } else { SS7_ERROR("Found an invalid loadShareAlgo Parameter Value[%s]\n", parm->val); @@ -533,7 +553,7 @@ static int ftmod_ss7_parse_m2ua_clust_interface(ftdm_conf_node_t *m2ua_cluster_i SS7_DEBUG("Found an sng_m2ua_cluster.loadShareAlgo = %d\n", sng_m2ua_cluster.loadShareAlgo); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "peerId")) { + } else if (!strcasecmp(parm->var, "peer_id")) { /**********************************************************************/ if(sng_m2ua_cluster.numOfPeers < MW_MAX_NUM_OF_PEER) { sng_m2ua_cluster.peerIdLst[sng_m2ua_cluster.numOfPeers] = atoi(parm->val); @@ -586,7 +606,7 @@ static int ftmod_ss7_fill_in_m2ua_clust_interface(sng_m2ua_cluster_cfg_t *m2ua_c } /******************************************************************************/ -ftdm_status_t ftmod_m3ua_parse_sctp_links(ftdm_conf_node_t *node) +int ftmod_ss7_parse_sctp_links(ftdm_conf_node_t *node) { ftdm_conf_node_t *node_sctp_link = NULL; @@ -601,7 +621,7 @@ ftdm_status_t ftmod_m3ua_parse_sctp_links(ftdm_conf_node_t *node) } for (node_sctp_link = node->child; node_sctp_link != NULL; node_sctp_link = node_sctp_link->next) { - if (ftmod_m3ua_parse_sctp_link(node_sctp_link) != FTDM_SUCCESS) { + if (ftmod_ss7_parse_sctp_link(node_sctp_link) != FTDM_SUCCESS) { SS7_ERROR("SCTP - Failed to parse . \n"); return FTDM_FAIL; } @@ -611,14 +631,16 @@ ftdm_status_t ftmod_m3ua_parse_sctp_links(ftdm_conf_node_t *node) } /******************************************************************************/ -static ftdm_status_t ftmod_m3ua_parse_sctp_link(ftdm_conf_node_t *node) +static int ftmod_ss7_parse_sctp_link(ftdm_conf_node_t *node) { ftdm_conf_parameter_t *param = NULL; int num_params = 0; int i=0; - if (!node) + if (!node){ + SS7_ERROR("SCTP - NULL XML Node pointer \n"); return FTDM_FAIL; + } param = node->parameters; num_params = node->n_parameters; @@ -637,17 +659,17 @@ static ftdm_status_t ftmod_m3ua_parse_sctp_link(ftdm_conf_node_t *node) if (!strcasecmp(param->var, "name")) { int n_strlen = strlen(param->val); strncpy((char*)t_link.name, param->val, (n_strlen>MAX_NAME_LEN)?MAX_NAME_LEN:n_strlen); - SS7_DEBUG("SCTP - Parsing with name = %s\n", param->val); + SS7_DEBUG("SCTP - Parsing with name = %s\n", param->val); } else if (!strcasecmp(param->var, "id")) { t_link.id = atoi(param->val); - SS7_DEBUG("SCTP - Parsing with id = %s\n", param->val); + SS7_DEBUG("SCTP - Parsing with id = %s\n", param->val); } - else if (!strcasecmp(param->var, "srcAddr")) { + else if (!strcasecmp(param->var, "src_addr")) { if (t_link.numSrcAddr < SCT_MAX_NET_ADDRS) { t_link.srcAddrList[t_link.numSrcAddr+1] = iptoul (param->val); t_link.numSrcAddr++; - SS7_DEBUG("SCTP - Parsing with source IP Address = %s\n", param->val); + SS7_DEBUG("SCTP - Parsing with source IP Address = %s\n", param->val); } else { SS7_ERROR("SCTP - too many source address configured. dropping %s \n", param->val); } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 32ebdc52b9..4b51bfc0e7 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -510,15 +510,6 @@ static int ftmod_ss7_parse_sng_isup(ftdm_conf_node_t *sng_isup) return FTDM_FAIL; } - if (ftmod_ss7_parse_mtp_linksets(mtp_linksets)) { - SS7_ERROR("Failed to parse \"mtp_linksets\"!\n"); - return FTDM_FAIL; - } - - if (ftmod_ss7_parse_mtp_routes(mtp_routes)) { - SS7_ERROR("Failed to parse \"mtp_routes\"!\n"); - return FTDM_FAIL; - } switch(g_ftdm_operating_mode) { @@ -529,6 +520,16 @@ static int ftmod_ss7_parse_sng_isup(ftdm_conf_node_t *sng_isup) return FTDM_FAIL; } + if (ftmod_ss7_parse_mtp_linksets(mtp_linksets)) { + SS7_ERROR("Failed to parse \"mtp_linksets\"!\n"); + return FTDM_FAIL; + } + + if (ftmod_ss7_parse_mtp_routes(mtp_routes)) { + SS7_ERROR("Failed to parse \"mtp_routes\"!\n"); + return FTDM_FAIL; + } + if (isup_interfaces && ftmod_ss7_parse_isup_interfaces(isup_interfaces)) { SS7_ERROR("Failed to parse \"isup_interfaces\"!\n"); return FTDM_FAIL; @@ -542,11 +543,20 @@ static int ftmod_ss7_parse_sng_isup(ftdm_conf_node_t *sng_isup) } case SNG_SS7_OPR_MODE_M2UA_SG: { - if (ftmod_m3ua_parse_sctp_links(sctp_ifaces) != FTDM_SUCCESS) { + if (ftmod_ss7_parse_mtp_linksets(mtp_linksets)) { + SS7_ERROR("Failed to parse \"mtp_linksets\"!\n"); + return FTDM_FAIL; + } + + if (ftmod_ss7_parse_mtp_routes(mtp_routes)) { + SS7_ERROR("Failed to parse \"mtp_routes\"!\n"); + return FTDM_FAIL; + } + + if (ftmod_ss7_parse_sctp_links(sctp_ifaces) != FTDM_SUCCESS) { SS7_ERROR("Failed to parse !\n"); return FTDM_FAIL; } - SS7_INFO("Finished ftmod_m3ua_parse_sctp_links!\n"); if (nif_ifaces && ftmod_ss7_parse_nif_interfaces(nif_ifaces)) { SS7_ERROR("Failed to parse \"nif_ifaces\"!\n"); From 69501d091c9e1816829fa5b4500dfc073b0e0b92 Mon Sep 17 00:00:00 2001 From: kapil Date: Wed, 30 May 2012 12:31:25 +0530 Subject: [PATCH 203/822] adding M2UA configuration/alarm handling code --- libs/freetdm/configure.ac | 2 +- .../ftmod_sangoma_ss7_logger.c | 273 +++++- .../ftmod_sangoma_ss7_m2ua.c | 844 +++++++++--------- .../ftmod_sangoma_ss7_m2ua.h | 2 +- .../ftmod_sangoma_ss7_m2ua_xml.c | 6 +- 5 files changed, 676 insertions(+), 451 deletions(-) diff --git a/libs/freetdm/configure.ac b/libs/freetdm/configure.ac index 292c1e7cfa..80f0c73070 100644 --- a/libs/freetdm/configure.ac +++ b/libs/freetdm/configure.ac @@ -316,7 +316,7 @@ if test "${HAVE_SNG_SS7}" = "yes"; then case "${host}" in x86_64-*) # X86_64 machines need additional flags when compiling against libsng_isdn - CFLAGS="$CFLAGS -DBIT_64 -DALIGN_64BIT" + CFLAGS="$CFLAGS -DBIT_64 -DALIGN_64BIT -DDEBUGP" ;; esac fi diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c index 5d4e183b20..5a6cc31907 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c @@ -827,28 +827,293 @@ void handle_sng_relay_alarm(Pst *pst, RyMngmt *sta) /******************************************************************************/ void handle_sng_m2ua_alarm(Pst *pst, MwMgmt *sta) { - ftdm_log(FTDM_LOG_ERROR," handle_sng_m2ua_alarm Not Yet Implement \n"); + /* To print the general information */ + ftdm_log(FTDM_LOG_INFO, "Recieved a status indication from M2UA layer \n\n"); + ftdm_log(FTDM_LOG_INFO," Category = %d , event = %d , cause = %d\n", + sta->t.usta.alarm.category, sta->t.usta.alarm.event, sta->t.usta.alarm.cause); + + + /* To print the affected element value */ + switch(sta->hdr.elmId.elmnt) + { + case STMWDLSAP: + { + ftdm_log(FTDM_LOG_INFO," STMWDLSAP: with lnkNmb (%d) \n\n", + sta->t.usta.s.lnkNmb); + break; + } + case STMWSCTSAP: + { + ftdm_log(FTDM_LOG_INFO," STMWSCTSAP: suId (%d) \n\n", + sta->t.usta.s.suId); + break; + } + case STMWPEER: + { + ftdm_log(FTDM_LOG_INFO," STMWPEER: peerId (%d) \n\n", + sta->t.usta.s.peerId); + break; + } + case STMWCLUSTER: + { + ftdm_log(FTDM_LOG_INFO," STMWCLUSTER: clusterId (%d) \n\n", + sta->t.usta.s.peerId); + break; + } + default: + { + ftdm_log(FTDM_LOG_ERROR, "[MW_USTA]: Invalid element \n\n"); + break; + } + } + + /* To print the event specific information */ + switch(sta->t.usta.alarm.event) + { + case LMW_EVENT_ESTABLISH_OK: + { + ftdm_log(FTDM_LOG_INFO," M2UA : LMW_EVENT_ESTABLISH_OK Event raised on peerId[%d]\n",sta->t.usta.s.peerId); + break; + } + case LMW_EVENT_ESTABLISH_FAIL: + { + ftdm_log(FTDM_LOG_INFO," M2UA : LMW_EVENT_ESTABLISH_FAIL Event raised on peerId[%d]\n",sta->t.usta.s.peerId); + break; + } + case LMW_EVENT_ASPM: + { + ftdm_log(FTDM_LOG_INFO," M2UA : LMW_EVENT_ASPM Event raised with peerId (%d), aspId (%d)," + " msgType (%d)\n\n",sta->t.usta.s.peerId, + sta->t.usta.t.aspm.msgType); + break; + } + case LMW_EVENT_CLUSTER: + { + ftdm_log(FTDM_LOG_INFO," M2UA : LMW_EVENT_CLUSTER Event raised on clusterId (%d), state (%d)\n\n", + sta->t.usta.s.clusterId, sta->t.usta.t.cluster.state); + + break; + } + case LMW_EVENT_NOTIFY: + { + ftdm_log(FTDM_LOG_INFO," M2UA : LMW_EVENT_NOTIFY: peerId (%d), aspId (%d), ntfy status type (%d)," + " ntfy status id (%d)\n\n", sta->t.usta.s.peerId, + sta->t.usta.t.ntfy.aspId, sta->t.usta.t.ntfy.stType, + sta->t.usta.t.ntfy.stId); + + break; + } + + + case LMW_EVENT_M2UA_PROTO_ERROR: + { + ftdm_log(FTDM_LOG_ERROR, " M2UA : LMW_EVENT_M2UA_PROTO_ERROR with errorCode (%d)\n\n", + sta->t.usta.t.error.errCode); + break; + } + default: + break; + } } /* handle_sng_m2ua_alarm */ /******************************************************************************/ void handle_sng_nif_alarm(Pst *pst, NwMgmt *sta) { - ftdm_log(FTDM_LOG_ERROR," handle_sng_nif_alarm Not Yet Implement \n"); + /* To print the general information */ + ftdm_log(FTDM_LOG_INFO," Recieved a status indication from NIF layer\n"); + ftdm_log(FTDM_LOG_INFO," Category = %d , event = %d , cause = %d\n", sta->t.usta.alarm.category, + sta->t.usta.alarm.event, sta->t.usta.alarm.cause); + switch(sta->hdr.elmId.elmnt) + { + case STNWDLSAP: + { + ftdm_log(FTDM_LOG_INFO," Recieved STNWDLSAP status indication for suId (%d) \n", sta->t.usta.suId); + switch(sta->t.usta.alarm.event) + { + case LCM_EVENT_LI_INV_EVT: + { + switch(sta->t.usta.alarm.cause) + { + case LCM_CAUSE_INV_SAP: + { + ftdm_log(FTDM_LOG_ERROR, " LCM_CAUSE_INV_SAP Alarm \n"); + break; + } + case LCM_CAUSE_INV_STATE: + { + ftdm_log(FTDM_LOG_ERROR, " LCM_CAUSE_INV_STATE Alarm \n"); + break; + } + default: + break; + } + break; + } + case LCM_EVENT_BND_OK: + { + ftdm_log(FTDM_LOG_INFO," NIF: LCM_EVENT_BND_OK Alarm \n"); + break; + } + case LCM_EVENT_BND_FAIL: + { + ftdm_log(FTDM_LOG_INFO," NIF: LCM_EVENT_BND_FAIL Alarm \n"); + break; + } + default: + break; + } + break; + } + default: + break; + } } /* handle_sng_nif_alarm */ /******************************************************************************/ void handle_sng_tucl_alarm(Pst *pst, HiMngmt *sta) { - ftdm_log(FTDM_LOG_ERROR," handle_sng_tucl_alarm Not Yet Implement \n"); + /* To print the general information */ + ftdm_log(FTDM_LOG_INFO, "Recieved a status indication from TUCL layer \n\n"); + ftdm_log(FTDM_LOG_INFO, " Category = %d , event = %d , cause = %d\n", + sta->t.usta.alarm.category, + sta->t.usta.alarm.event, sta->t.usta.alarm.cause); + + switch(sta->t.usta.alarm.event) + { + case LCM_EVENT_INV_EVT: + { + ftdm_log(FTDM_LOG_INFO," [HI_USTA]: LCM_EVENT_INV_EVT with type (%d)\n\n", + sta->t.usta.info.type); + break; + } + case LHI_EVENT_BNDREQ: + { + ftdm_log(FTDM_LOG_INFO," [HI_USTA]: LHI_EVENT_BNDREQ with type (%d) spId (%d)\n\n", + sta->t.usta.info.type, sta->t.usta.info.spId); + break; + } + case LHI_EVENT_SERVOPENREQ: + case LHI_EVENT_DATREQ: + case LHI_EVENT_UDATREQ: + case LHI_EVENT_CONREQ: + case LHI_EVENT_DISCREQ: +#if(defined(HI_TLS) && defined(HI_TCP_TLS)) + case LHI_EVENT_TLS_ESTREQ: +#endif + { + ftdm_log(FTDM_LOG_INFO," [HI_USTA]: partype (%d) type(%d)\n\n", + sta->t.usta.info.inf.parType, sta->t.usta.info.type); + break; + } + case LCM_EVENT_DMEM_ALLOC_FAIL: + case LCM_EVENT_SMEM_ALLOC_FAIL: + { + ftdm_log(FTDM_LOG_ERROR," [HI_USTA]: MEM_ALLOC_FAIL with region(%d) pool (%d) type(%d)\n\n", + sta->t.usta.info.inf.mem.region, sta->t.usta.info.inf.mem.pool, + sta->t.usta.info.type); + break; + } + default: + break; + } } /* handle_sng_tucl_alarm */ /******************************************************************************/ void handle_sng_sctp_alarm(Pst *pst, SbMgmt *sta) { - ftdm_log(FTDM_LOG_ERROR," handle_sng_sctp_alarm Not Yet Implement \n"); + ftdm_log(FTDM_LOG_INFO, "Recieved a status indication from SCTP layer \n\n"); + ftdm_log(FTDM_LOG_INFO," Category = %d , event = %d , cause = %d " + " [SB_USTA]: sapId (%d) and swtch (%d)\n", + sta->t.usta.alarm.category, + sta->t.usta.alarm.event, sta->t.usta.alarm.cause, + sta->t.usta.sapId, sta->t.usta.swtch); + + switch(sta->t.usta.alarm.category) + { + case LCM_CATEGORY_INTERFACE: + { + switch(sta->t.usta.alarm.cause) + { + case LCM_CAUSE_INV_SPID: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LCM_CAUSE_INV_SPID Alarm \n"); + break; + } + case LCM_CAUSE_SWVER_NAVAIL: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LCM_CAUSE_SWVER_NAVAIL Alarm\n"); + break; + } + case LCM_CAUSE_INV_PAR_VAL: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LCM_CAUSE_INV_PAR_VAL Alarm\n"); + break; + } + case LCM_CAUSE_INV_SUID: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LCM_CAUSE_INV_SUID Alarm\n"); + break; + } + case LCM_CAUSE_INV_SAP: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LCM_CAUSE_INV_SAP Alarm\n"); + break; + } + default: + break; + } + + break; + } + case LCM_CATEGORY_RESOURCE: + { + switch(sta->t.usta.alarm.cause) + { + case LCM_CAUSE_MEM_ALLOC_FAIL: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LCM_CAUSE_MEM_ALLOC_FAIL Alarm \n"); + break; + } + case LSB_CAUSE_NUM_ADDR_EXCEED: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LSB_CAUSE_NUM_ADDR_EXCEED Alarm\n"); + break; + } + default: + break; + } + break; + } + case LCM_CATEGORY_PROTOCOL: + { + switch(sta->t.usta.alarm.cause) + { + case LSB_CAUSE_PATH_FAILURE: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LSB_CAUSE_PATH_FAILURE Alarm \n"); + break; + } + case LSB_CAUSE_PATH_ACTIVE: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LSB_CAUSE_PATH_ACTIVE Alarm \n"); + break; + } + case LSB_CAUSE_UNRSLVD_ADDR: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LSB_CAUSE_UNRSLVD_ADDR Alarm \n"); + break; + } + default: + break; + } + break; + } + default: + break; + } } /* handle_sng_sctp_alarm */ /******************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c index c6c1689ddc..f7836ed629 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c @@ -43,42 +43,35 @@ /* DEFINES ********************************************************************/ /******************************************************************************/ /* FUNCTION PROTOTYPES ********************************************************/ -static int ftmod_sigtran_tucl_gen_config(void); -static int ftmod_sigtran_tucl_sap_config(void); - -static int ftmod_sigtran_sctp_gen_config(void); -ftdm_status_t ftmod_sigtran_cfg_sctp(void); -int ftmod_sigtran_sctp_config(int id); -ftdm_status_t ftmod_sigtran_sctp_sap_config(int id); -ftdm_status_t ftmod_sigtran_sctp_tsap_config(int id); -static S16 ftmod_sigtran_m2ua_gen_config(void); -static S16 ftmod_sigtran_m2ua_sctsap_config(void); -static S16 ftmod_sigtran_m2ua_peer_config(void); -static S16 ftmod_sigtran_m2ua_cluster_config(void); -static S16 ftmod_sigtran_m2ua_dlsap_config(U32 idx); - -static S16 ftmod_sigtran_nif_gen_config(void); -static S16 ftmod_sigtran_nif_dlsap_config(U32 idx); - - -static U32 ftmod_parse_conv_ipaddr(S8 *ptr); +static int ftmod_tucl_gen_config(void); +static int ftmod_tucl_sap_config(int id); +static int ftmod_sctp_gen_config(void); +static int ftmod_cfg_sctp(void); +static int ftmod_sctp_config(int id); +static ftdm_status_t ftmod_sctp_sap_config(int id); +static ftdm_status_t ftmod_sctp_tsap_config(int id); +static int ftmod_m2ua_gen_config(void); +static int ftmod_m2ua_sctsap_config(int id); +static int ftmod_m2ua_peer_config(int id); +static int ftmod_m2ua_cluster_config(int idx); +static int ftmod_m2ua_dlsap_config(int idx); +static int ftmod_nif_gen_config(void); +static int ftmod_nif_dlsap_config(int idx); +static int ftmod_sctp_tucl_tsap_bind(int idx); +static int ftmod_m2ua_sctp_sctsap_bind(int idx); +static int ftmod_open_endpoint(int idx); +static int ftmod_nif_m2ua_dlsap_bind(int id); +static int ftmod_nif_mtp2_dlsap_bind(int id); +static int ftmod_m2ua_enable_debug(void); +static int ftmod_tucl_enable_debug(void); ftdm_status_t sng_m2ua_init(void); ftdm_status_t sng_m2ua_cfg(void); - -static S16 ftmod_sigtran_tsap_bnd(void); -static S16 ftmod_sigtran_sctsap_bnd(void); -static S16 ftmod_sigtran_open_endpoint(void); -static S16 ftmod_sigtran_dlsap_bnd(U32 id); -static S16 ftmod_ss7_dlsap_bnd(U32 id); - -/******************************************************************************/ /******************************************************************************/ ftdm_status_t ftmod_ss7_m2ua_cfg(void) { - if(FTDM_SUCCESS != sng_m2ua_init()){ ftdm_log (FTDM_LOG_ERROR, " sng_m2ua_init FAILED \n"); return FTDM_FAIL; @@ -124,144 +117,122 @@ ftdm_status_t sng_m2ua_init(void) ftdm_log (FTDM_LOG_INFO ,"Started TUCL!\n"); } - return FTDM_SUCCESS; } -/******************************************************************************/ +/****************************************************************************************************/ ftdm_status_t sng_m2ua_cfg(void) { - S16 ret = ROK; + int x=0; + /****************************************************************************************************/ /* TUCL */ - if(ftmod_sigtran_tucl_gen_config()){ + if(ftmod_tucl_gen_config()){ ftdm_log (FTDM_LOG_ERROR ,"TUCL GEN configuration: NOT OK\n"); return FTDM_FAIL; } else { ftdm_log (FTDM_LOG_INFO ,"TUCL GEN configuration: OK\n"); } - if(ftmod_sigtran_tucl_sap_config()){ - ftdm_log (FTDM_LOG_ERROR ,"TUCL SAP configuration: NOT OK\n"); - return FTDM_FAIL; - } else { - ftdm_log (FTDM_LOG_INFO ,"TUCL SAP configuration: OK\n"); - } - /*********************************************************************************************/ - + /****************************************************************************************************/ /* SCTP */ - if(ftmod_sigtran_sctp_gen_config()){ + if(ftmod_sctp_gen_config()){ ftdm_log (FTDM_LOG_ERROR ,"SCTP GEN configuration: NOT OK\n"); return FTDM_FAIL; } else { ftdm_log (FTDM_LOG_INFO ,"SCTP GEN configuration: OK\n"); } - - if(ftmod_sigtran_cfg_sctp()){ - ftdm_log (FTDM_LOG_ERROR ,"ftmod_sigtran_cfg_sctp : NOT OK\n"); + /****************************************************************************************************/ + /* SCTP configuration */ + if(ftmod_cfg_sctp()){ + ftdm_log (FTDM_LOG_ERROR ,"SCTP Configuration : NOT OK\n"); return FTDM_FAIL; } else { - ftdm_log (FTDM_LOG_INFO ,"ftmod_sigtran_cfg_sctp : OK\n"); + ftdm_log (FTDM_LOG_INFO ,"SCTP Configuration : OK\n"); } - /*********************************************************************************************/ + /****************************************************************************************************/ + /* M2UA configurations */ - /* M2UA and NIF configurations */ - - /* Send the general configuration request for M2UA layer */ - if((ret = ftmod_sigtran_m2ua_gen_config()) != ROK) - { + if(ftmod_m2ua_gen_config()) { ftdm_log (FTDM_LOG_ERROR ,"M2UA General configuration: NOT OK\n"); return FTDM_FAIL; - } - else - { + }else { ftdm_log (FTDM_LOG_INFO ,"M2UA General configuration: OK\n"); } + /****************************************************************************************************/ + /* M2UA SCTP SAP configurations */ + for (x=1; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].id !=0; x++) { + if (!(g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].flags & SNGSS7_CONFIGURED)) { - /* Send the SCTSAP configuration request for M2UA layer */ - if((ret = ftmod_sigtran_m2ua_sctsap_config()) != ROK) - { - ftdm_log (FTDM_LOG_ERROR ,"M2UA SCTSAP configuration: NOT OK\n"); - return FTDM_FAIL; - } - else - { - ftdm_log (FTDM_LOG_INFO ,"M2UA SCTSAP configuration: OK\n"); - } + if(ftmod_m2ua_sctsap_config(x)) { + ftdm_log (FTDM_LOG_ERROR ,"M2UA SCTSAP[%d] configuration: NOT OK\n", x); + return FTDM_FAIL; + }else { + ftdm_log (FTDM_LOG_INFO ,"M2UA SCTSAP[%d] configuration: OK\n", x); + } - /* Send the peer configuration request for M2UA layer */ - if((ret = ftmod_sigtran_m2ua_peer_config()) != ROK) - { - ftdm_log (FTDM_LOG_ERROR ,"M2UA PEER configuration: NOT OK\n"); - return FTDM_FAIL; - } - else - { - ftdm_log (FTDM_LOG_INFO ,"M2UA PEER configuration: OK\n"); - } + /****************************************************************************************************/ + /* M2UA PEER configurations */ - /* Send the cluster configuration request for M2UA layer */ - if((ret = ftmod_sigtran_m2ua_cluster_config()) != ROK) - { - ftdm_log (FTDM_LOG_ERROR ,"M2UA CLUSTER configuration: NOT OK\n"); - return FTDM_FAIL; - } - else - { - ftdm_log (FTDM_LOG_INFO ,"M2UA CLUSTER configuration: OK\n"); - } - - - /* Send the USAP (DLSAP) configuration request for M2UA layer; fill the number - * of saps required to be configured. Max is 3 */ - /*for( idx = 0; idx < 3; idx++)*/ - { - if((ret = ftmod_sigtran_m2ua_dlsap_config(1)) != ROK) - { - ftdm_log (FTDM_LOG_ERROR ,"M2UA DLSAP configuration: NOT OK\n"); + if(ftmod_m2ua_peer_config(x)) { + ftdm_log (FTDM_LOG_ERROR ,"M2UA PEER configuration for M2UA INTF[%d] : NOT OK\n", x); return FTDM_FAIL; - } - else - { - ftdm_log (FTDM_LOG_INFO ,"M2UA DLSAP configuration: OK\n"); + }else { + ftdm_log (FTDM_LOG_INFO ,"M2UA PEER configuration for M2UA INTF[%d] : OK\n", x); } - } + /****************************************************************************************************/ + /* M2UA Cluster configurations */ - /* Send the general configuration request for NIF */ - if((ret = ftmod_sigtran_nif_gen_config()) != ROK) - { + if(ftmod_m2ua_cluster_config(x)) { + ftdm_log (FTDM_LOG_ERROR ,"M2UA CLUSTER configuration for M2UA INTF[%d] : NOT OK\n", x); + return FTDM_FAIL; + }else { + ftdm_log (FTDM_LOG_INFO ,"M2UA CLUSTER configuration for M2UA INTF[%d]: OK\n", x); + } + + /****************************************************************************************************/ + + /* Send the USAP (DLSAP) configuration request for M2UA layer; fill the number + * of saps required to be configured. Max is 3 */ + if(ftmod_m2ua_dlsap_config(x)) { + ftdm_log (FTDM_LOG_ERROR ,"M2UA DLSAP[%d] configuration: NOT OK\n", x); + return FTDM_FAIL; + }else { + ftdm_log (FTDM_LOG_INFO ,"M2UA DLSAP[%d] configuration: OK\n", x); + } + } /* END - SNGSS7_CONFIGURED */ + }/* END - M2UA Interfaces for loop*/ +/****************************************************************************************************/ + /* NIF */ + if(ftmod_nif_gen_config()){ ftdm_log (FTDM_LOG_ERROR ,"NIF General configuration: NOT OK\n"); return FTDM_FAIL; - } - else - { + }else { ftdm_log (FTDM_LOG_INFO ,"NIF General configuration: OK\n"); } - /* Send the USAP (DLSAP) configuration request for NIF layer; fill the number - * of saps required to be configured. Max is 3 - for( idx = 0; idx < 3; idx++) */ - { - if( (ret = ftmod_sigtran_nif_dlsap_config(1)) != ROK) - { - ftdm_log (FTDM_LOG_ERROR ,"NIF DLSAP configuration: NOT OK\n"); - return FTDM_FAIL; - } - else - { - ftdm_log (FTDM_LOG_INFO ,"NIF DLSAP configuration: OK\n"); +/****************************************************************************************************/ + /* NIF DLSAP */ + + for (x=1; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[x].id !=0; x++) { + if (!(g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[x].flags & SNGSS7_CONFIGURED)) { + if(ftmod_nif_dlsap_config(x)) { + ftdm_log (FTDM_LOG_ERROR ,"NIF DLSAP[%d] configuration: NOT OK\n", x); + return FTDM_FAIL; + }else{ + ftdm_log (FTDM_LOG_INFO ,"NIF DLSAP[%d] configuration: OK\n", x); + } } } - - /********************************************************************************************/ +/****************************************************************************************************/ return 0; } -/******************************************************************************/ -static int ftmod_sigtran_tucl_gen_config(void) +/****************************************************************************************************/ +static int ftmod_tucl_gen_config(void) { HiMngmt cfg; Pst pst; @@ -314,13 +285,16 @@ static int ftmod_sigtran_tucl_gen_config(void) return(sng_cfg_tucl(&pst, &cfg)); } +/****************************************************************************************************/ -static int ftmod_sigtran_tucl_sap_config(void) +static int ftmod_tucl_sap_config(int id) { HiMngmt cfg; Pst pst; HiSapCfg *pCfg; + sng_sctp_link_t *k = &g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[id]; + /* initalize the post structure */ smPstInit(&pst); @@ -353,8 +327,8 @@ static int ftmod_sigtran_tucl_sap_config(void) pCfg = &cfg.t.cfg.s.hiSap; - pCfg->spId = 0x01 ; /* KAPIL - TODO - should be from configured value.but hardcoding as of now */ - pCfg->uiSel = 0x00; /*loosley coupled */ + pCfg->spId = k->id ; /* each SCTP link there will be one tucl sap */ + pCfg->uiSel = 0x00; /*loosley coupled */ pCfg->flcEnb = TRUE; pCfg->txqCongStrtLim = HI_SAP_TXN_QUEUE_CONG_START_LIMIT; pCfg->txqCongDropLim = HI_SAP_TXN_QUEUE_CONG_DROP_LIMIT; @@ -368,8 +342,10 @@ static int ftmod_sigtran_tucl_sap_config(void) return(sng_cfg_tucl(&pst, &cfg)); } + +/****************************************************************************************************/ -static int ftmod_sigtran_sctp_gen_config(void) +static int ftmod_sctp_gen_config(void) { SbMgmt cfg; Pst pst; @@ -428,14 +404,14 @@ static int ftmod_sigtran_sctp_gen_config(void) return(sng_cfg_sctp(&pst, &cfg)); } -ftdm_status_t ftmod_sigtran_cfg_sctp(void) +/****************************************************************************************************/ +static int ftmod_cfg_sctp(void) { int x=0; - for (x=1; g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[x].id !=0; x++) - { + for (x=1; g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[x].id !=0; x++) { if (!(g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[x].flags & SNGSS7_CONFIGURED)) { - if ( ftmod_sigtran_sctp_config(x) == FTDM_FAIL) { + if ( ftmod_sctp_config(x) == FTDM_FAIL) { SS7_CRITICAL("SCTP %d configuration FAILED!\n", x); return FTDM_FAIL; } else { @@ -446,19 +422,28 @@ ftdm_status_t ftmod_sigtran_cfg_sctp(void) return FTDM_SUCCESS; } - -int ftmod_sigtran_sctp_config(int id) +/****************************************************************************************************/ +int ftmod_sctp_config(int id) { - if (ftmod_sigtran_sctp_tsap_config(id) != FTDM_SUCCESS) - return FTDM_FAIL; - - if (ftmod_sigtran_sctp_sap_config(id) != FTDM_SUCCESS) - return FTDM_FAIL; - - return FTDM_SUCCESS; -} + if (FTDM_SUCCESS != ftmod_sctp_tsap_config(id)) + return FTDM_FAIL; -ftdm_status_t ftmod_sigtran_sctp_tsap_config(int id) + if (FTDM_SUCCESS != ftmod_sctp_sap_config(id)) + return FTDM_FAIL; + + /* each sctp link there will be one tucl sap */ + if(ftmod_tucl_sap_config(id)){ + ftdm_log (FTDM_LOG_ERROR ,"TUCL SAP[%d] configuration: NOT OK\n", id); + return FTDM_FAIL; + } else { + ftdm_log (FTDM_LOG_INFO ,"TUCL SAP[%d] configuration: OK\n", id); + } + + return FTDM_SUCCESS; +} +/****************************************************************************************************/ + +ftdm_status_t ftmod_sctp_tsap_config(int id) { Pst pst; SbMgmt cfg; @@ -475,44 +460,46 @@ ftdm_status_t ftmod_sigtran_sctp_tsap_config(int id) memset(&cfg, 0x0, sizeof(cfg)); smHdrInit(&cfg.hdr); - cfg.hdr.msgType = TCFG; + cfg.hdr.msgType = TCFG; cfg.hdr.entId.ent = ENTSB; cfg.hdr.entId.inst = S_INST; - cfg.hdr.elmId.elmnt = STSBTSAP; - cfg.hdr.elmId.elmntInst1= k->id; + cfg.hdr.elmId.elmnt = STSBTSAP; + cfg.hdr.elmId.elmntInst1 = k->id; c = &cfg.t.cfg.s.tSapCfg; - c->swtch = LSB_SW_RFC_REL0; - c->suId = 1; - c->sel = 0; - c->ent = ENTHI; - c->inst = S_INST; - c->procId = g_ftdm_sngss7_data.cfg.procId; - c->memId.region = S_REG; - c->memId.pool = S_POOL; - c->prior = PRIOR1; - c->route = RTESPEC; - c->srcNAddrLst.nmb = k->numSrcAddr; + c->swtch = LSB_SW_RFC_REL0; + c->suId = k->id; + c->sel = 0; + c->ent = ENTHI; + c->inst = S_INST; + c->procId = g_ftdm_sngss7_data.cfg.procId; + c->memId.region = S_REG; + c->memId.pool = S_POOL; + c->prior = PRIOR1; + c->route = RTESPEC; + c->srcNAddrLst.nmb = k->numSrcAddr; for (i=0; i <= (k->numSrcAddr-1); i++) { c->srcNAddrLst.nAddr[i].type = CM_NETADDR_IPV4; c->srcNAddrLst.nAddr[i].u.ipv4NetAddr = k->srcAddrList[i+1]; } - c->reConfig.spId = 1; - c->reConfig.maxBndRetry = 3; - c->reConfig.tIntTmr = 200; + c->reConfig.spId = k->id; + c->reConfig.maxBndRetry = 3; + c->reConfig.tIntTmr = 200; ret = sng_cfg_sctp(&pst, &cfg); - if (ret==0) { - SS7_INFO("SCTP TSAP %d configuration DONE!\n", id); + if (0 == ret) { + SS7_INFO("SCTP TSAP [%d] configuration DONE!\n", id); return FTDM_SUCCESS; } else { - SS7_CRITICAL("SCTP TSAP %d configuration FAILED!\n", id); + SS7_CRITICAL("SCTP TSAP [%d] configuration FAILED!\n", id); return FTDM_FAIL; } } -ftdm_status_t ftmod_sigtran_sctp_sap_config(int id) +/****************************************************************************************************/ + +ftdm_status_t ftmod_sctp_sap_config(int id) { Pst pst; SbMgmt cfg; @@ -527,73 +514,73 @@ ftdm_status_t ftmod_sigtran_sctp_sap_config(int id) memset(&cfg, 0x0, sizeof(cfg)); smHdrInit(&cfg.hdr); - cfg.hdr.msgType = TCFG; + cfg.hdr.msgType = TCFG; cfg.hdr.entId.ent = ENTSB; cfg.hdr.entId.inst = S_INST; - cfg.hdr.elmId.elmnt = STSBSCTSAP; - cfg.hdr.elmId.elmntInst1= k->id; + cfg.hdr.elmId.elmnt = STSBSCTSAP; + cfg.hdr.elmId.elmntInst1 = k->id; c = &cfg.t.cfg.s.sctSapCfg; - c->swtch = LSB_SW_RFC_REL0; - c->spId = 1; /* Service Provider SAP Id */ - c->sel = 0; - c->memId.region = S_REG; - c->memId.pool = S_POOL; - c->prior = PRIOR1; - c->route = RTESPEC; + c->swtch = LSB_SW_RFC_REL0; + c->spId = k->id; /* Service Provider SAP Id */ + c->sel = 0; + c->memId.region = S_REG; + c->memId.pool = S_POOL; + c->prior = PRIOR1; + c->route = RTESPEC; /* Maximum time to wait before the SCTP layer must send a Selective Acknowledgement (SACK) message. Valid range is 1 -165535. */ - c->reConfig.maxAckDelayTm = 200; + c->reConfig.maxAckDelayTm = 200; /* Maximum number of messages to receive before the SCTP layer must send a SACK message. Valid range is 1 - 165535. */ - c->reConfig.maxAckDelayDg = 2; + c->reConfig.maxAckDelayDg = 2; /* Initial value of the retransmission timer (RTO). The SCTP layer retransmits data after waiting for feedback during this time period. Valid range is 1 - 65535. */ - c->reConfig.rtoInitial = 3000; + c->reConfig.rtoInitial = 3000; /* Minimum value used for the RTO. If the computed value of RTO is less than rtoMin, the computed value is rounded up to this value. */ - c->reConfig.rtoMin = 1000; + c->reConfig.rtoMin = 1000; /* Maxiumum value used for RTO. If the computed value of RTO is greater than rtoMax, the computed value is rounded down to this value. */ - c->reConfig.rtoMax = 10000; + c->reConfig.rtoMax = 10000; /* Default Freeze timer value */ - c->reConfig.freezeTm = 3000; + c->reConfig.freezeTm = 3000; /* Base cookie lifetime for the cookie in the Initiation Acknowledgement (INIT ACK) message. */ - c->reConfig.cookieLife = 60000; + c->reConfig.cookieLife = 60000; /* Default heartbeat interval timer. Valid range is 1 - 65535. */ - c->reConfig.intervalTm = 3000; + c->reConfig.intervalTm = 3000; /* Maximum burst value. Valid range is 1 - 65535. */ - c->reConfig.maxBurst = 4; + c->reConfig.maxBurst = 4; /*Maximum number of heartbeats sent at each retransmission timeout (RTO). Valid range is 1 - 65535. */ - c->reConfig.maxHbBurst = 1; + c->reConfig.maxHbBurst = 1; /*Shutdown guard timer value for graceful shutdowns. */ - c->reConfig.t5SdownGrdTm = 15000; + c->reConfig.t5SdownGrdTm = 15000; /* Action to take when the receiver's number of incoming streams is less than the sender's number of outgoing streams. Valid values are: TRUE = Accept incoming stream and continue association. FALSE = Abort the association. */ - c->reConfig.negAbrtFlg = FALSE; + c->reConfig.negAbrtFlg = FALSE; /* Whether to enable or disable heartbeat by default. Valid values are: TRUE = Enable heartbeat. FALSE = Disable heartbeat. */ - c->reConfig.hBeatEnable = TRUE; + c->reConfig.hBeatEnable = TRUE; /* Flow control start threshold. When the number of messages in SCTPÂ’s message queue reaches this value, flow control starts. */ - c->reConfig.flcUpThr = 8; + c->reConfig.flcUpThr = 8; /* Flow control stop threshold. When the number of messages in SCTPÂ’s message queue reaches this value, flow control stops. */ - c->reConfig.flcLowThr = 6; + c->reConfig.flcLowThr = 6; - c->reConfig.handleInitFlg = FALSE; + c->reConfig.handleInitFlg = FALSE; ret = sng_cfg_sctp(&pst, &cfg); - if (ret==0) { - SS7_INFO("SCTP SAP %d configuration DONE!\n", id); + if (0 == ret) { + SS7_INFO("SCTP SAP [%d] configuration DONE!\n", id); return FTDM_SUCCESS; } else { - SS7_CRITICAL("SCTP SAP %d configuration FAILED!\n", id); + SS7_CRITICAL("SCTP SAP [%d] configuration FAILED!\n", id); return FTDM_FAIL; } } /**********************************************************************************************/ /* M2UA - General configuration */ -static S16 ftmod_sigtran_m2ua_gen_config(void) +static int ftmod_m2ua_gen_config(void) { Pst pst; MwMgmt cfg; @@ -641,11 +628,11 @@ static S16 ftmod_sigtran_m2ua_gen_config(void) cfg.t.cfg.s.genCfg.reConfig.smPst.route = RTESPEC; /* route */ cfg.t.cfg.s.genCfg.reConfig.smPst.dstEnt = ENTSM; /* dst entity */ - cfg.t.cfg.s.genCfg.reConfig.smPst.dstInst = 0; /* dst inst */ + cfg.t.cfg.s.genCfg.reConfig.smPst.dstInst = S_INST; /* dst inst */ cfg.t.cfg.s.genCfg.reConfig.smPst.dstProcId = SFndProcId(); /* src proc id */ cfg.t.cfg.s.genCfg.reConfig.smPst.srcEnt = ENTMW; /* src entity */ - cfg.t.cfg.s.genCfg.reConfig.smPst.srcInst = 0; /* src inst */ + cfg.t.cfg.s.genCfg.reConfig.smPst.srcInst = S_INST; /* src inst */ cfg.t.cfg.s.genCfg.reConfig.smPst.srcProcId = SFndProcId(); /* src proc id */ cfg.t.cfg.s.genCfg.reConfig.tmrFlcPoll.enb = TRUE; /* SCTP Flc Poll timer */ @@ -671,14 +658,13 @@ static S16 ftmod_sigtran_m2ua_gen_config(void) } /**********************************************************************************************/ - - -/* M2UA - SCTSAP configuration */ -static S16 ftmod_sigtran_m2ua_sctsap_config(void) +static int ftmod_m2ua_sctsap_config(int id) { - + int i; Pst pst; MwMgmt cfg; + sng_m2ua_cfg_t* m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; + sng_sctp_link_t *sctp = &g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[m2ua->sctpId]; memset((U8 *)&cfg, 0, sizeof(MwMgmt)); memset((U8 *)&pst, 0, sizeof(Pst)); @@ -700,25 +686,26 @@ static S16 ftmod_sigtran_m2ua_sctsap_config(void) cfg.hdr.response.mem.region = S_REG; cfg.hdr.response.mem.pool = S_POOL; - - cfg.t.cfg.s.sctSapCfg.reConfig.selector = 0; /* service user SAP ID */ - cfg.t.cfg.s.sctSapCfg.suId = 0; + cfg.t.cfg.s.sctSapCfg.suId = m2ua->id; /* service provider ID */ - cfg.t.cfg.s.sctSapCfg.spId = 1; /* TUCL sct sap id is 1 */ + cfg.t.cfg.s.sctSapCfg.spId = m2ua->sctpId; /* source port number */ cfg.t.cfg.s.sctSapCfg.srcPort = 2904; /* interface address */ /*For multiple IP address support */ #ifdef SCT_ENDP_MULTI_IPADDR - cfg.t.cfg.s.sctSapCfg.srcAddrLst.nmb = 1; - cfg.t.cfg.s.sctSapCfg.srcAddrLst.nAddr[0].type = CM_NETADDR_IPV4; - cfg.t.cfg.s.sctSapCfg.srcAddrLst.nAddr[0].u.ipv4NetAddr = ftmod_parse_conv_ipaddr((S8*)"192.168.1.102"); + cfg.t.cfg.s.sctSapCfg.srcAddrLst.nmb = sctp->numSrcAddr; + for (i=0; i <= (sctp->numSrcAddr-1); i++) { + cfg.t.cfg.s.sctSapCfg.srcAddrLst.nAddr[i].type = CM_NETADDR_IPV4; + cfg.t.cfg.s.sctSapCfg.srcAddrLst.nAddr[i].u.ipv4NetAddr = sctp->srcAddrList[i+1]; + } #else + /* for single ip support ,src address will always be one */ cfg.t.cfg.s.sctSapCfg.intfAddr.type = CM_NETADDR_IPV4; - cfg.t.cfg.s.sctSapCfg.intfAddr.u.ipv4NetAddr = ftmod_parse_conv_ipaddr((S8*)"192.168.1.102"); + cfg.t.cfg.s.sctSapCfg.intfAddr.u.ipv4NetAddr = sctp->srcAddrList[1]; #endif /* lower SAP primitive timer */ @@ -746,14 +733,17 @@ static S16 ftmod_sigtran_m2ua_sctsap_config(void) } -/**********************************************************************************************/ - +/****************************************************************************************************/ /* M2UA - Peer configuration */ -static S16 ftmod_sigtran_m2ua_peer_config(void) +static int ftmod_m2ua_peer_config(int id) { + int i; Pst pst; MwMgmt cfg; + sng_m2ua_cfg_t* m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; + sng_m2ua_peer_cfg_t* peer = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[m2ua->peerId]; + sng_sctp_link_t *sctp = &g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[peer->sctpId]; memset((U8 *)&cfg, 0, sizeof(MwMgmt)); memset((U8 *)&pst, 0, sizeof(Pst)); @@ -763,7 +753,7 @@ static S16 ftmod_sigtran_m2ua_peer_config(void) pst.dstEnt = ENTMW; /* prepare header */ - cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.msgType = TCFG; /* message type */ cfg.hdr.entId.ent = ENTMW; /* entity */ cfg.hdr.entId.inst = 0; /* instance */ cfg.hdr.elmId.elmnt = STMWPEER; /* Peer */ @@ -777,30 +767,30 @@ static S16 ftmod_sigtran_m2ua_peer_config(void) - cfg.t.cfg.s.peerCfg.peerId = 1; /* peer id */ - cfg.t.cfg.s.peerCfg.aspIdFlag = FALSE; /* aspId flag */ + cfg.t.cfg.s.peerCfg.peerId = peer->id; /* peer id */ + cfg.t.cfg.s.peerCfg.aspIdFlag = peer->aspIdFlag; /* aspId flag */ #ifdef MWASP - cfg.t.cfg.s.peerCfg.selfAspId = 1; /* aspId */ + cfg.t.cfg.s.peerCfg.selfAspId = peer->selfAspId; /* aspId */ #endif - cfg.t.cfg.s.peerCfg.assocCfg.suId = 0; /* SCTSAP ID */ - cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nmb = 1; /* destination address list*/ - cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[0].type = CM_NETADDR_IPV4; - cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[0].u.ipv4NetAddr = ftmod_parse_conv_ipaddr((S8*)"192.168.1.101");/* TODO */; -#if 0 - cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[1].type = CM_NETADDR_IPV4; - cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[1].u.ipv4NetAddr = ftmod_parse_conv_ipaddr("172.25.0.93"); /* TODO */; -#endif + cfg.t.cfg.s.peerCfg.assocCfg.suId = peer->sctpId; /* SCTSAP ID */ + cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nmb = peer->numDestAddr; + for (i=0; i <= (peer->numDestAddr); i++) { + cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[i].type = CM_NETADDR_IPV4; + cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[i].u.ipv4NetAddr = peer->destAddrList[i]; + } #ifdef MW_CFG_DSTPORT cfg.t.cfg.s.peerCfg.assocCfg.dstPort = /* TODO */ 2904; /* Port on which M2UA runs */ #endif - cfg.t.cfg.s.peerCfg.assocCfg.srcAddrLst.nmb = 1; /* source address list */ - cfg.t.cfg.s.peerCfg.assocCfg.srcAddrLst.nAddr[0].type = CM_NETADDR_IPV4; - cfg.t.cfg.s.peerCfg.assocCfg.srcAddrLst.nAddr[0].u.ipv4NetAddr = ftmod_parse_conv_ipaddr((S8*)"192.168.1.102");/* TODO */; + cfg.t.cfg.s.peerCfg.assocCfg.srcAddrLst.nmb = sctp->numSrcAddr; /* source address list */ + for (i=0; i <= (sctp->numSrcAddr-1); i++) { + cfg.t.cfg.s.peerCfg.assocCfg.srcAddrLst.nAddr[i].type = CM_NETADDR_IPV4; + cfg.t.cfg.s.peerCfg.assocCfg.srcAddrLst.nAddr[i].u.ipv4NetAddr = sctp->srcAddrList[i+1]; + } cfg.t.cfg.s.peerCfg.assocCfg.priDstAddr.type = CM_NETADDR_IPV4; cfg.t.cfg.s.peerCfg.assocCfg.priDstAddr.u.ipv4NetAddr = cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[0].u.ipv4NetAddr; - cfg.t.cfg.s.peerCfg.assocCfg.locOutStrms = 10; + cfg.t.cfg.s.peerCfg.assocCfg.locOutStrms = peer->locOutStrms; #ifdef SCT3 cfg.t.cfg.s.peerCfg.assocCfg.tos = 0; #endif @@ -808,13 +798,14 @@ static S16 ftmod_sigtran_m2ua_peer_config(void) return (sng_cfg_m2ua (&pst, &cfg)); } /**********************************************************************************************/ - - /* M2UA - Cluster configuration */ -static S16 ftmod_sigtran_m2ua_cluster_config(void) +static int ftmod_m2ua_cluster_config(int id) { + int i; Pst pst; MwMgmt cfg; + sng_m2ua_cfg_t* m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; + sng_m2ua_cluster_cfg_t* clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[m2ua->clusterId]; memset((U8 *)&cfg, 0, sizeof(MwMgmt)); memset((U8 *)&pst, 0, sizeof(Pst)); @@ -824,7 +815,7 @@ static S16 ftmod_sigtran_m2ua_cluster_config(void) pst.dstEnt = ENTMW; /* prepare header */ - cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.msgType = TCFG; /* message type */ cfg.hdr.entId.ent = ENTMW; /* entity */ cfg.hdr.entId.inst = 0; /* instance */ cfg.hdr.elmId.elmnt = STMWCLUSTER; /* Cluster */ @@ -837,26 +828,25 @@ static S16 ftmod_sigtran_m2ua_cluster_config(void) cfg.hdr.response.mem.pool = S_POOL; - - cfg.t.cfg.s.clusterCfg.clusterId = 0; - cfg.t.cfg.s.clusterCfg.trfMode = LMW_TRF_MODE_LOADSHARE; - cfg.t.cfg.s.clusterCfg.loadshareMode = LMW_LOADSH_RR; - cfg.t.cfg.s.clusterCfg.reConfig.nmbPeer = 1; - cfg.t.cfg.s.clusterCfg.reConfig.peer[0] = 1; -#if 0 - cfg.t.cfg.s.clusterCfg.reConfig.peer[1] = 2; -#endif + cfg.t.cfg.s.clusterCfg.clusterId = clust->id; + cfg.t.cfg.s.clusterCfg.trfMode = clust->trfMode; + cfg.t.cfg.s.clusterCfg.loadshareMode = clust->loadShareAlgo; + cfg.t.cfg.s.clusterCfg.reConfig.nmbPeer = clust->numOfPeers; + for(i=0; i<(clust->numOfPeers);i++) { + cfg.t.cfg.s.clusterCfg.reConfig.peer[i] = clust->peerIdLst[i]; + } return (sng_cfg_m2ua (&pst, &cfg)); - } + /**********************************************************************************************/ /* M2UA - DLSAP configuration */ -static S16 ftmod_sigtran_m2ua_dlsap_config(U32 id) +static int ftmod_m2ua_dlsap_config(int id) { Pst pst; MwMgmt cfg; + sng_m2ua_cfg_t* m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; memset((U8 *)&cfg, 0, sizeof(MwMgmt)); memset((U8 *)&pst, 0, sizeof(Pst)); @@ -866,7 +856,7 @@ static S16 ftmod_sigtran_m2ua_dlsap_config(U32 id) pst.dstEnt = ENTMW; /* prepare header */ - cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.msgType = TCFG; /* message type */ cfg.hdr.entId.ent = ENTMW; /* entity */ cfg.hdr.entId.inst = 0; /* instance */ cfg.hdr.elmId.elmnt = STMWDLSAP; /* DLSAP */ @@ -879,39 +869,13 @@ static S16 ftmod_sigtran_m2ua_dlsap_config(U32 id) cfg.hdr.response.mem.pool = S_POOL; - switch(id) - { - case 0: - { - cfg.t.cfg.s.dlSapCfg.lnkNmb = 0; /* SapId */ - cfg.t.cfg.s.dlSapCfg.intfId.type = LMW_INTFID_INT; - cfg.t.cfg.s.dlSapCfg.intfId.id.intId = 0; - break; - } - case 1: - { - cfg.t.cfg.s.dlSapCfg.lnkNmb = 1; /* SapId */ - cfg.t.cfg.s.dlSapCfg.intfId.type = LMW_INTFID_INT; - cfg.t.cfg.s.dlSapCfg.intfId.id.intId = 1; - break; - } - - case 2: - { - cfg.t.cfg.s.dlSapCfg.lnkNmb = 2; /* SapId */ - cfg.t.cfg.s.dlSapCfg.intfId.type = LMW_INTFID_INT; - cfg.t.cfg.s.dlSapCfg.intfId.id.intId = 2; - break; - } - default: - break; - } + cfg.t.cfg.s.dlSapCfg.lnkNmb = id; /* SapId */ + cfg.t.cfg.s.dlSapCfg.intfId.type = LMW_INTFID_INT; + cfg.t.cfg.s.dlSapCfg.intfId.id.intId = id; cfg.t.cfg.s.dlSapCfg.swtch = LMW_SAP_ITU; - - - cfg.t.cfg.s.dlSapCfg.reConfig.clusterId = 0; + cfg.t.cfg.s.dlSapCfg.reConfig.clusterId = m2ua->clusterId; cfg.t.cfg.s.dlSapCfg.reConfig.selector = 0; /* Loosely couple mode */ /* memory region and pool id*/ cfg.t.cfg.s.dlSapCfg.reConfig.mem.region = S_REG; @@ -925,11 +889,8 @@ static S16 ftmod_sigtran_m2ua_dlsap_config(U32 id) } /*****************************************************************************/ - -/* NIF configurations */ - /* NIF - General configuration */ -static S16 ftmod_sigtran_nif_gen_config(void) +static int ftmod_nif_gen_config(void) { Pst pst; NwMgmt cfg; @@ -942,7 +903,7 @@ static S16 ftmod_sigtran_nif_gen_config(void) pst.dstEnt = ENTNW; /* prepare header */ - cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.msgType = TCFG; /* message type */ cfg.hdr.entId.ent = ENTNW; /* entity */ cfg.hdr.entId.inst = 0; /* instance */ cfg.hdr.elmId.elmnt = STNWGEN; /* DLSAP */ @@ -984,11 +945,14 @@ static S16 ftmod_sigtran_nif_gen_config(void) } +/*****************************************************************************/ + /* NIF - DLSAP configuration */ -static S16 ftmod_sigtran_nif_dlsap_config(U32 id) +static int ftmod_nif_dlsap_config(int id) { Pst pst; NwMgmt cfg; + sng_nif_cfg_t* nif = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[id]; memset((U8 *)&cfg, 0, sizeof(NwMgmt)); memset((U8 *)&pst, 0, sizeof(Pst)); @@ -998,7 +962,7 @@ static S16 ftmod_sigtran_nif_dlsap_config(U32 id) pst.dstEnt = ENTNW; /* prepare header */ - cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.msgType = TCFG; /* message type */ cfg.hdr.entId.ent = ENTNW; /* entity */ cfg.hdr.entId.inst = 0; /* instance */ cfg.hdr.elmId.elmnt = STNWDLSAP; /* DLSAP */ @@ -1009,42 +973,10 @@ static S16 ftmod_sigtran_nif_dlsap_config(U32 id) cfg.hdr.response.route = RTESPEC; cfg.hdr.response.mem.region = S_REG; cfg.hdr.response.mem.pool = S_POOL; - -#if 0 - switch(id) - { - case 0: - { - cfg.t.cfg.s.dlSapCfg.suId = 0; /*ACC_DLSAP_0 */ - cfg.t.cfg.s.dlSapCfg.m2uaLnkNmb = 0; /*ACC_DLSAP_0 */ - cfg.t.cfg.s.dlSapCfg.mtp2LnkNmb = 0; /* ACC_DLSAP_0 */ - break; - } - case 1: - { - cfg.t.cfg.s.dlSapCfg.suId = 1; /*ACC_DLSAP_0 */ - cfg.t.cfg.s.dlSapCfg.m2uaLnkNmb = 1; /*ACC_DLSAP_0 */ - cfg.t.cfg.s.dlSapCfg.mtp2LnkNmb = /* TODO */1; /* ACC_DLSAP_0 */ - break; - } - case 2: - { - cfg.t.cfg.s.dlSapCfg.suId = 2; /*ACC_DLSAP_0 */ - cfg.t.cfg.s.dlSapCfg.m2uaLnkNmb = 2; /*ACC_DLSAP_0 */ - cfg.t.cfg.s.dlSapCfg.mtp2LnkNmb = /* TODO */ 2; /* ACC_DLSAP_0 */ - break; - } - - default: - break; - - } -#endif - - cfg.t.cfg.s.dlSapCfg.suId = 1; /*ACC_DLSAP_0 */ - cfg.t.cfg.s.dlSapCfg.m2uaLnkNmb = 1; /*ACC_DLSAP_0 */ - cfg.t.cfg.s.dlSapCfg.mtp2LnkNmb = 1; /* TODO */ /* ACC_DLSAP_0 */ - + cfg.t.cfg.s.dlSapCfg.suId = nif->id; + cfg.t.cfg.s.dlSapCfg.m2uaLnkNmb = nif->m2uaLnkNmb; + cfg.t.cfg.s.dlSapCfg.mtp2LnkNmb = nif->mtp2LnkNmb; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.selector = 0; cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.region = S_REG; cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.pool = S_POOL; @@ -1072,54 +1004,7 @@ static S16 ftmod_sigtran_nif_dlsap_config(U32 id) return (sng_cfg_nif (&pst, &cfg)); } -static U32 ftmod_atoi(S8 *str) -{ - U32 idx = 0; - U32 value = 0; - - while(str[idx] != '\0') - { - value = (10 * value) + (str[idx] - '0'); - idx++; - } - return(value); -} - -static U32 ftmod_parse_conv_ipaddr(S8 *ptr) -{ - - U32 ipAddr = 0; - U32 idx = 0; - U32 tmpCnt = 0; - U32 len_ipAddr = 0; - S8 tmpStr[8] = { 0, 0, 0, 0, 0, 0, 0, 0}; - - len_ipAddr = strlen(ptr); - - idx = 0; - tmpCnt = 0; - while(idx < len_ipAddr) - { - if( ptr[idx] != '.' ) - { - tmpStr[tmpCnt++] = ptr[idx]; - } - else - { - tmpStr[tmpCnt] = '\0'; - ipAddr |= ftmod_atoi(tmpStr); - ipAddr <<= 8; - tmpCnt = 0; - } - idx++; - } - - tmpStr[tmpCnt] = '\0'; - ipAddr |= ftmod_atoi(tmpStr); - - return(ipAddr); -} - +/*****************************************************************************/ uint32_t iptoul(const char *ip) { char i,*tmp; @@ -1144,78 +1029,85 @@ uint32_t iptoul(const char *ip) } return (uint32_t)val; } - /***********************************************************************************************************************/ int ftmod_ss7_m2ua_start(void){ + int x=0; +/***********************************************************************************************************************/ + /* Enable DEBUGs*/ + ftmod_m2ua_enable_debug(); + ftmod_tucl_enable_debug(); - S16 ret = 0x00; - - /* Send a control request to bind the TSAP between SCTP and TUCL */ - if( (ret = ftmod_sigtran_tsap_bnd()) != ROK) - { - ftdm_log (FTDM_LOG_ERROR ,"\nControl request to bind TSAP of SCTP and TUCL : NOT OK\n"); - return 1; - } - else - { - ftdm_log (FTDM_LOG_INFO ,"\nControl request to bind TSAP of SCTP and TUCL: OK\n"); - } +/***********************************************************************************************************************/ + for (x=1; g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[x].id !=0; x++) { + if (!(g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[x].flags & SNGSS7_CONFIGURED)) { - /* Send a control request to bind the SCTSAP between SCTP and M2UA */ - if( (ret = ftmod_sigtran_sctsap_bnd()) != ROK) - { - ftdm_log (FTDM_LOG_ERROR ,"Control request to bind SCTSAP of M2UA and SCTP : NOT OK\n"); - return 1; - } - else - { - ftdm_log (FTDM_LOG_INFO ,"Control request to bind SCTSAP of M2UA and SCTP: OK\n"); - } + /* Send a control request to bind the TSAP between SCTP and TUCL */ + if(ftmod_sctp_tucl_tsap_bind(x)) { + ftdm_log (FTDM_LOG_ERROR ,"\nControl request to bind TSAP[%d] of SCTP and TUCL : NOT OK\n", x); + return 1; + } else { + ftdm_log (FTDM_LOG_INFO ,"\nControl request to bind TSAP[%d] of SCTP and TUCL: OK\n", x); + } + } + } - /* Send a control request to bind the DLSAP between NIF, M2UA and MTP-2 - for(idx = 0; idx < 3; idx++) */ - { - if( (ret = ftmod_sigtran_dlsap_bnd(1)) != ROK) - { - ftdm_log (FTDM_LOG_ERROR ,"Control request to bind DLSAP between NIF and M2UA: NOT OK\n"); - return 1; - } - else - { - ftdm_log (FTDM_LOG_INFO ,"Control request to bind DLSAP between NIF and M2UA : OK\n"); - } +/***********************************************************************************************************************/ + /* Send a control request to bind the SCTSAP between SCTP and M2UA */ + for (x=1; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].id !=0; x++) { + if (!(g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].flags & SNGSS7_CONFIGURED)) { + if(ftmod_m2ua_sctp_sctsap_bind(x)) { + ftdm_log (FTDM_LOG_ERROR ,"Control request to bind SCTSAP[%d] of M2UA and SCTP : NOT OK\n", x); + return 1; + } else { + ftdm_log (FTDM_LOG_INFO ,"Control request to bind SCTSAP[%d] of M2UA and SCTP: OK\n", x); + } + } + }/* END - M2UA Interfaces for loop*/ +/***********************************************************************************************************************/ - if( (ret = ftmod_ss7_dlsap_bnd(0x01)) != ROK) - { - ftdm_log (FTDM_LOG_ERROR ,"Control request to bind DLSAP between NIF and MTP2 : NOT OK\n"); - return 1; - } - else - { - ftdm_log (FTDM_LOG_INFO ,"Control request to bind DLSAP between NIF and MTP2 : OK\n"); - } - } + for (x=1; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[x].id !=0; x++) { + if (!(g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[x].flags & SNGSS7_CONFIGURED)) { + /* Send a control request to bind the DLSAP between NIF, M2UA and MTP-2 */ + if(ftmod_nif_m2ua_dlsap_bind(x)) { + ftdm_log (FTDM_LOG_ERROR ,"Control request to bind DLSAP[%d] between NIF and M2UA: NOT OK\n", x); + return 1; + }else { + ftdm_log (FTDM_LOG_INFO ,"Control request to bind DLSAP[%d] between NIF and M2UA : OK\n", x); + } + if(ftmod_nif_mtp2_dlsap_bind(x)) { + ftdm_log (FTDM_LOG_ERROR ,"Control request to bind DLSAP[%d] between NIF and MTP2: NOT OK\n", x); + return 1; + }else { + ftdm_log (FTDM_LOG_INFO ,"Control request to bind DLSAP[%d] between NIF and MTP2 : OK\n", x); + } + } + }/* END - NIF Interfaces for loop*/ - /* Send a control request to open endpoint */ - if( (ret = ftmod_sigtran_open_endpoint()) != ROK) - { - ftdm_log (FTDM_LOG_ERROR ,"ftmod_sigtran_open_endpoint FAIL \n"); - return 1; - } - else - { - ftdm_log (FTDM_LOG_ERROR ,"ftmod_sigtran_open_endpoint SUCCESS \n"); - } +/***********************************************************************************************************************/ - return 0; + for (x=1; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].id !=0; x++) { + if (!(g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].flags & SNGSS7_CONFIGURED)) { + /* Send a control request to open endpoint */ + if(ftmod_open_endpoint(x)) { + ftdm_log (FTDM_LOG_ERROR ,"ftmod_open_endpoint FAIL \n"); + return 1; + }else { + ftdm_log (FTDM_LOG_INFO ,"ftmod_open_endpoint SUCCESS \n"); + } + } + } + + return 0; } +/***********************************************************************************************************************/ -static S16 ftmod_sigtran_open_endpoint(void) +static int ftmod_open_endpoint(int id) { Pst pst; MwMgmt cntrl; + sng_m2ua_cfg_t* m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; memset((U8 *)&pst, 0, sizeof(Pst)); memset((U8 *)&cntrl, 0, sizeof(MwMgmt)); @@ -1239,17 +1131,18 @@ static S16 ftmod_sigtran_open_endpoint(void) cntrl.t.cntrl.action = AMWENDPOPEN; - cntrl.t.cntrl.s.suId = 0; /* M2UA sct sap Id */ + cntrl.t.cntrl.s.suId = m2ua->id; /* M2UA sct sap Id */ return (sng_cntrl_m2ua (&pst, &cntrl)); } -static S16 ftmod_sigtran_tsap_bnd(void) +/***********************************************************************************************************************/ +static int ftmod_sctp_tucl_tsap_bind(int id) { - Pst pst; SbMgmt cntrl; + sng_sctp_link_t *k = &g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[id]; memset((U8 *)&pst, 0, sizeof(Pst)); memset((U8 *)&cntrl, 0, sizeof(SbMgmt)); @@ -1273,16 +1166,17 @@ static S16 ftmod_sigtran_tsap_bnd(void) cntrl.hdr.response.mem.pool = S_POOL; cntrl.t.cntrl.action = ABND_ENA; - cntrl.t.cntrl.sapId = 1; /* SCT sap id configured at SCTP layer */ + cntrl.t.cntrl.sapId = k->id; /* SCT sap id configured at SCTP layer */ return (sng_cntrl_sctp (&pst, &cntrl)); - } +/***********************************************************************************************************************/ -static S16 ftmod_sigtran_sctsap_bnd(void) +static int ftmod_m2ua_sctp_sctsap_bind(int id) { Pst pst; MwMgmt cntrl; + sng_m2ua_cfg_t* m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; memset((U8 *)&pst, 0, sizeof(Pst)); memset((U8 *)&cntrl, 0, sizeof(MwMgmt)); @@ -1304,19 +1198,18 @@ static S16 ftmod_sigtran_sctsap_bnd(void) cntrl.hdr.response.mem.region = S_REG; cntrl.hdr.response.mem.pool = S_POOL; - cntrl.t.cntrl.action = ABND; - cntrl.t.cntrl.s.suId = 0; /* M2UA sct sap Id */ + cntrl.t.cntrl.s.suId = m2ua->id; return (sng_cntrl_m2ua (&pst, &cntrl)); } - - -static S16 ftmod_sigtran_dlsap_bnd(U32 id) +/***********************************************************************************************************************/ +static int ftmod_nif_m2ua_dlsap_bind(int id) { Pst pst; NwMgmt cntrl; + sng_nif_cfg_t* nif = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[id]; memset((U8 *)&pst, 0, sizeof(Pst)); memset((U8 *)&cntrl, 0, sizeof(NwMgmt)); @@ -1326,7 +1219,7 @@ static S16 ftmod_sigtran_dlsap_bnd(U32 id) pst.dstEnt = ENTNW; /* prepare header */ - cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.msgType = TCNTRL; /* message type */ cntrl.hdr.entId.ent = ENTNW; /* entity */ cntrl.hdr.entId.inst = 0; /* instance */ cntrl.hdr.elmId.elmnt = STNWDLSAP; /* General */ @@ -1339,27 +1232,29 @@ static S16 ftmod_sigtran_dlsap_bnd(U32 id) cntrl.hdr.response.mem.pool = S_POOL; cntrl.t.cntrl.action = ABND; - cntrl.t.cntrl.suId = id; /* NIF DL sap Id */ + cntrl.t.cntrl.suId = nif->id; /* NIF DL sap Id */ cntrl.t.cntrl.entity = ENTMW; /* M2UA */ return (sng_cntrl_nif (&pst, &cntrl)); } -static S16 ftmod_ss7_dlsap_bnd(U32 id) +/***********************************************************************************************************************/ +static int ftmod_nif_mtp2_dlsap_bind(int id) { - Pst pst; - NwMgmt cntrl; + Pst pst; + NwMgmt cntrl; + sng_nif_cfg_t* nif = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[id]; - memset((U8 *)&pst, 0, sizeof(Pst)); - memset((U8 *)&cntrl, 0, sizeof(NwMgmt)); + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(NwMgmt)); - smPstInit(&pst); + smPstInit(&pst); - pst.dstEnt = ENTNW; + pst.dstEnt = ENTNW; - /* prepare header */ - cntrl.hdr.msgType = TCNTRL; /* message type */ + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ cntrl.hdr.entId.ent = ENTNW; /* entity */ cntrl.hdr.entId.inst = 0; /* instance */ cntrl.hdr.elmId.elmnt = STNWDLSAP; /* General */ @@ -1372,8 +1267,73 @@ static S16 ftmod_ss7_dlsap_bnd(U32 id) cntrl.hdr.response.mem.pool = S_POOL; cntrl.t.cntrl.action = ABND; - cntrl.t.cntrl.suId = id; /* NIF DL sap Id */ - cntrl.t.cntrl.entity = ENTSD; /* MTP2 */ + cntrl.t.cntrl.suId = nif->id; /* NIF DL sap Id */ + cntrl.t.cntrl.entity = ENTSD; /* MTP2 */ return (sng_cntrl_nif (&pst, &cntrl)); + } + +/***********************************************************************************************************************/ +static int ftmod_m2ua_enable_debug() +{ + Pst pst; + MwMgmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(MwMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTMW; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STMWGEN; /* General */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = AENA; + cntrl.t.cntrl.subAction = SADBG; + cntrl.t.cntrl.s.dbgMask = 0xFFFF; + + return (sng_cntrl_m2ua (&pst, &cntrl)); +} +/***********************************************************************************************************************/ +static int ftmod_tucl_enable_debug() +{ + Pst pst; + HiMngmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(HiMngmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTHI; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTHI; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STGEN; /* General */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = AENA; + cntrl.t.cntrl.subAction = SADBG; + cntrl.t.cntrl.ctlType.hiDbg.dbgMask = 0xFFFF; + + return (sng_cntrl_tucl (&pst, &cntrl)); +} +/***********************************************************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h index db13a1635b..9eb727ea02 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h @@ -61,7 +61,7 @@ typedef struct sng_m2ua_cfg{ uint32_t id; /* ID */ uint8_t nodeType; /*Node Type SG/ASP */ uint16_t sctpId; /* idx to sctp profile */ - uint16_t peerdId; /* idx to m2ua_peer profile */ + uint16_t peerId; /* idx to m2ua_peer profile */ uint16_t clusterId; /* idx to m2ua_cluster profile */ }sng_m2ua_cfg_t; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c index 333f616628..96f3cafc97 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c @@ -258,9 +258,9 @@ static int ftmod_ss7_parse_m2ua_interface(ftdm_conf_node_t *m2ua_interface) /**********************************************************************/ } else if (!strcasecmp(parm->var, "peerd_id")) { /**********************************************************************/ - sng_m2ua.peerdId=atoi(parm->val); + sng_m2ua.peerId=atoi(parm->val); - SS7_DEBUG("Found an m2ua peerd_id = %d\n", sng_m2ua.peerdId); + SS7_DEBUG("Found an m2ua peerd_id = %d\n", sng_m2ua.peerId); /**********************************************************************/ } else if (!strcasecmp(parm->var, "cluster_id")) { /**********************************************************************/ @@ -298,7 +298,7 @@ static int ftmod_ss7_fill_in_m2ua_interface(sng_m2ua_cfg_t *m2ua_iface) g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].id = m2ua_iface->id; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].nodeType = m2ua_iface->nodeType; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].sctpId = m2ua_iface->sctpId; - g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].peerdId = m2ua_iface->peerdId; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].peerId = m2ua_iface->peerId; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].clusterId = m2ua_iface->clusterId; return 0; From 889a0be2b3fa9ccb6a02af5a8a1b8b800d2f37b6 Mon Sep 17 00:00:00 2001 From: Kapil Date: Wed, 30 May 2012 16:41:31 +0530 Subject: [PATCH 204/822] issue fix --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c index 96f3cafc97..9d47a33dbb 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c @@ -447,7 +447,7 @@ static int ftmod_ss7_fill_in_m2ua_peer_interface(sng_m2ua_peer_cfg_t *m2ua_peer_ g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].locOutStrms = m2ua_peer_iface->locOutStrms; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].numDestAddr = m2ua_peer_iface->numDestAddr; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].sctpId = m2ua_peer_iface->sctpId; - for (k=1; k<=m2ua_peer_iface->numDestAddr; k++) { + for (k=0; knumDestAddr; k++) { g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].destAddrList[k] = m2ua_peer_iface->destAddrList[k]; } From f1f78a86537bad866a6eb70bdee20fa1a52acb9e Mon Sep 17 00:00:00 2001 From: kapil Date: Wed, 30 May 2012 20:20:58 +0530 Subject: [PATCH 205/822] adding m2ua stack free code while unloading freetdm module --- .../ftmod_sangoma_ss7_logger.c | 5 + .../ftmod_sangoma_ss7_m2ua.c | 137 ++++++++++++++++++ .../ftmod_sangoma_ss7_m2ua.h | 1 + .../ftmod_sangoma_ss7_main.c | 4 + 4 files changed, 147 insertions(+) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c index 5a6cc31907..922200629f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c @@ -870,6 +870,11 @@ void handle_sng_m2ua_alarm(Pst *pst, MwMgmt *sta) /* To print the event specific information */ switch(sta->t.usta.alarm.event) { + case LMW_EVENT_ENDPOPEN_OK: + { + ftdm_log(FTDM_LOG_INFO," M2UA : LMW_EVENT_ENDPOPEN_OK: \n"); + break; + } case LMW_EVENT_ESTABLISH_OK: { ftdm_log(FTDM_LOG_INFO," M2UA : LMW_EVENT_ESTABLISH_OK Event raised on peerId[%d]\n",sta->t.usta.s.peerId); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c index f7836ed629..39e9bba658 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c @@ -64,10 +64,114 @@ static int ftmod_nif_m2ua_dlsap_bind(int id); static int ftmod_nif_mtp2_dlsap_bind(int id); static int ftmod_m2ua_enable_debug(void); static int ftmod_tucl_enable_debug(void); +static int ftmod_sctp_enable_debug(void); + +static int ftmod_ss7_sctp_shutdown(void); +static int ftmod_ss7_m2ua_shutdown(void); +static int ftmod_ss7_tucl_shutdown(void); ftdm_status_t sng_m2ua_init(void); ftdm_status_t sng_m2ua_cfg(void); +/******************************************************************************/ +void ftmod_ss7_m2ua_free() +{ + ftmod_ss7_m2ua_shutdown(); + ftmod_ss7_sctp_shutdown(); + ftmod_ss7_tucl_shutdown(); + + sng_isup_free_m2ua(); + sng_isup_free_sctp(); + sng_isup_free_tucl(); +} +/******************************************************************************/ +static int ftmod_ss7_tucl_shutdown() +{ + Pst pst; + HiMngmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(HiMngmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTHI; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTHI; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STGEN; /* General */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = ASHUTDOWN; + + return (sng_cntrl_tucl (&pst, &cntrl)); +} +/******************************************************************************/ +static int ftmod_ss7_m2ua_shutdown() +{ + Pst pst; + MwMgmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(MwMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTMW; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STMWGEN; /* General */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = ASHUTDOWN; + + return (sng_cntrl_m2ua (&pst, &cntrl)); +} +/***********************************************************************************************************************/ +static int ftmod_ss7_sctp_shutdown() +{ + Pst pst; + SbMgmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(SbMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTSB; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTSB; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STSBGEN; /* General */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = ASHUTDOWN; + + return (sng_cntrl_sctp (&pst, &cntrl)); +} + /******************************************************************************/ ftdm_status_t ftmod_ss7_m2ua_cfg(void) @@ -1036,6 +1140,7 @@ int ftmod_ss7_m2ua_start(void){ /***********************************************************************************************************************/ /* Enable DEBUGs*/ + ftmod_sctp_enable_debug(); ftmod_m2ua_enable_debug(); ftmod_tucl_enable_debug(); @@ -1275,6 +1380,38 @@ static int ftmod_nif_mtp2_dlsap_bind(int id) } /***********************************************************************************************************************/ +static int ftmod_sctp_enable_debug() +{ + Pst pst; + SbMgmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(SbMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTSB; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTSB; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STSBGEN; /* General */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = AENA; + cntrl.t.cntrl.subAction = SADBG; + cntrl.t.cntrl.dbgMask = 0xFFFF; + + return (sng_cntrl_sctp (&pst, &cntrl)); +} +/***********************************************************************************************************************/ + static int ftmod_m2ua_enable_debug() { Pst pst; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h index 9eb727ea02..a988b9c8db 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h @@ -118,6 +118,7 @@ int ftmod_ss7_parse_sctp_links(ftdm_conf_node_t *node); uint32_t iptoul(const char *ip); int ftmod_ss7_m2ua_start(void); +void ftmod_ss7_m2ua_free(void); ftdm_status_t ftmod_ss7_m2ua_cfg(void); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index dbb1c1974c..90202d3989 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -2687,6 +2687,10 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_sangoma_ss7_unload) sngss7_clear_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_RY_STARTED); } + if(SNG_SS7_OPR_MODE_ISUP != g_ftdm_operating_mode){ + ftmod_ss7_m2ua_free(); + } + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_SM_STARTED)) { sng_isup_free_sm(); From e05bd3fae8ed8edaddee6271b3d246a16a0b4234 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 30 May 2012 13:10:04 -0400 Subject: [PATCH 206/822] Some changes to ss7 variables to be more consistent --- libs/freetdm/mod_freetdm/mod_freetdm.c | 9 ++++----- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c | 9 +++++++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 430ace829f..e889d1ebba 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1554,6 +1554,10 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi if (sipvar) { ftdm_usrmsg_add_var(&usrmsg, "ss7_ocn_pres", sipvar); } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-IAM-FWD-IND-HEX"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_iam_fwd_ind_hex", sipvar); + } } if (switch_test_flag(outbound_profile, SWITCH_CPF_SCREEN)) { @@ -1594,11 +1598,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi ftdm_set_calling_party_category(var, (uint8_t *)&caller_data.cpc); } - if ((var = channel_get_variable(session, var_event, "iam_fwd_ind_HEX"))) { - ftdm_usrmsg_add_var(&usrmsg, "iam_fwd_ind_HEX", var); - } - - if (!zstr(dest)) { ftdm_set_string(caller_data.dnis.digits, dest); } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 39134f9925..b2edc2b497 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -993,7 +993,7 @@ ftdm_status_t copy_fwdCallInd_to_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd * fwdCallInd->sccpMethInd.pres = PRSNT_NODEF; fwdCallInd->sccpMethInd.val = SCCPMTH_NOIND; - val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "iam_fwd_ind_HEX"); + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_fwd_ind_hex"); if (!ftdm_strlen_zero(val)) { uint16_t val_hex = 0; if (four_char_to_hex (val, &val_hex) == FTDM_FAIL) { @@ -1028,7 +1028,12 @@ ftdm_status_t copy_fwdCallInd_to_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd * fwdCallInd->isdnUsrPrtInd.val = ISUP_USED; fwdCallInd->isdnUsrPrtPrfInd.val = PREF_PREFAW; - val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "iam_fwd_ind_isdn_access_ind"); + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_fwd_ind_isdn_access_ind"); + if (ftdm_strlen_zero(val)) { + /* Kept for backward compatibility */ + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "iam_fwd_ind_isdn_access_ind"); + } + if (!ftdm_strlen_zero(val)) { acc_val = (int)atoi(val); } From a7ac272595e16542ca1218aab61da66c8d6b1263 Mon Sep 17 00:00:00 2001 From: kapil Date: Thu, 31 May 2012 17:31:06 +0530 Subject: [PATCH 207/822] adding MEGACO Stack STOP/SHUTDOWN code --- src/mod/endpoints/mod_megaco/megaco.c | 8 +- src/mod/endpoints/mod_megaco/megaco_stack.c | 225 ++++++++++++++++++++ src/mod/endpoints/mod_megaco/megaco_stack.h | 1 + 3 files changed, 231 insertions(+), 3 deletions(-) diff --git a/src/mod/endpoints/mod_megaco/megaco.c b/src/mod/endpoints/mod_megaco/megaco.c index 84bf70963b..b73eaefec0 100644 --- a/src/mod/endpoints/mod_megaco/megaco.c +++ b/src/mod/endpoints/mod_megaco/megaco.c @@ -45,7 +45,7 @@ static switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t r goto done; } - /* iterate through MG Interface list to build all MG profiles */ + /* iterate through MG Interface list to build requested MG profile */ for (mg_interface = switch_xml_child(mg_interfaces, "sng_mg_interface"); mg_interface; mg_interface = mg_interface->next) { const char *name = switch_xml_attr_soft(mg_interface, "name"); @@ -161,9 +161,11 @@ switch_status_t megaco_profile_destroy(megaco_profile_t **profile) switch_thread_rwlock_wrlock((*profile)->rwlock); - /* TODO: Kapil: Insert stack per-interface shutdown code here */ + /* stop MEGACP stack */ + if(SWITCH_STATUS_FALSE == sng_mgco_stop((*profile)->name)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error stopping MEGACO Stack for profile %s\n", (*profile)->name); + } - switch_thread_rwlock_unlock((*profile)->rwlock); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Stopped profile: %s\n", (*profile)->name); diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.c b/src/mod/endpoints/mod_megaco/megaco_stack.c index 4ba2cd05f6..86d1f80268 100644 --- a/src/mod/endpoints/mod_megaco/megaco_stack.c +++ b/src/mod/endpoints/mod_megaco/megaco_stack.c @@ -29,6 +29,11 @@ int mgco_mg_tsap_enable_cntrl(int idx); int mgco_mg_ssap_cntrl(int idx); int mgco_mu_ssap_cntrl(int idx); int mgco_mg_tpt_server(int idx); +int sng_mgco_tucl_shutdown(); +int sng_mgco_mg_shutdown(); +int sng_mgco_mg_ssap_stop(int sapId); +int sng_mgco_mg_tpt_server_stop(int idx); +int sng_mgco_mg_app_ssap_stop(int idx); switch_status_t sng_mgco_stack_gen_cfg(); @@ -86,6 +91,12 @@ switch_status_t sng_mgco_init(sng_isup_event_interface_t* event) /*****************************************************************************************************************/ switch_status_t sng_mgco_stack_shutdown() { + /* shutdown MG */ + sng_mgco_mg_shutdown(); + + /* shutdown TUCL */ + sng_mgco_tucl_shutdown(); + /* free MEGACO Application */ sng_isup_free_mu(); @@ -258,6 +269,159 @@ switch_status_t sng_mgco_start(const char* profilename) } /*****************************************************************************************************************/ + +switch_status_t sng_mgco_stop(const char* profilename) +{ + int idx = 0x00; + sng_mg_cfg_t* mgCfg = NULL; + + switch_assert(profilename); + + GET_MG_CFG_IDX(profilename, idx); + + if(!idx || (idx == MAX_MG_PROFILES)){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG configuration found against profilename[%s]\n",profilename); + return SWITCH_STATUS_FALSE; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," Stopping MG stack for idx[%d] against profilename[%s]\n", idx, profilename); + + mgCfg = &megaco_globals.g_mg_cfg.mgCfg[idx]; + + /* MG STOP is as good as deleting that perticular mg(virtual mg instance) data from megaco stack */ + /* currently we are not supporting enable/disable MG stack */ + + if(sng_mgco_mg_ssap_stop(mgCfg->id)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " sng_mgco_mg_ssap_stop FAILED \n"); + return SWITCH_STATUS_FALSE; + } + else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " sng_mgco_mg_ssap_stop SUCCESS \n"); + } + + if(sng_mgco_mg_tpt_server_stop(idx)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " sng_mgco_mg_tpt_server_stop FAILED \n"); + return SWITCH_STATUS_FALSE; + } + else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " sng_mgco_mg_tpt_server_stop SUCCESS \n"); + } + + if(sng_mgco_mg_app_ssap_stop(idx)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " sng_mgco_mg_app_ssap_stop FAILED \n"); + return SWITCH_STATUS_FALSE; + } + else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " sng_mgco_mg_app_ssap_stop SUCCESS \n"); + } + + return SWITCH_STATUS_SUCCESS; +} + +/*****************************************************************************************************************/ +int sng_mgco_mg_app_ssap_stop(int idx) +{ + MuMngmt mgMngmt; + Pst pst; /* Post for layer manager */ + MuCntrl *cntrl; + + memset(&mgMngmt, 0, sizeof(mgMngmt)); + + cntrl = &(mgMngmt.t.cntrl); + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTMU; + + /*fill in the specific fields of the header */ + mgMngmt.hdr.msgType = TCNTRL; + mgMngmt.hdr.entId.ent = ENTMG; + mgMngmt.hdr.entId.inst = S_INST; + mgMngmt.hdr.elmId.elmnt = STSSAP; + mgMngmt.hdr.elmId.elmntInst1 = GET_MU_SAP_ID(idx); + + cntrl->action = ADEL; + cntrl->subAction = SAELMNT; + + return(sng_cntrl_mu(&pst, &mgMngmt)); +} +/*****************************************************************************************************************/ + +int sng_mgco_mg_ssap_stop(int sapId) +{ + Pst pst; + MgMngmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(MgCntrl)); + + smPstInit(&pst); + + pst.dstEnt = ENTMG; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTMG; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STSSAP; /* SSAP */ + cntrl.hdr.elmId.elmntInst1 = sapId; /* sap id */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = ADEL; + cntrl.t.cntrl.subAction = SAELMNT; + cntrl.t.cntrl.spId = sapId; + return (sng_cntrl_mg (&pst, &cntrl)); +} + +/*****************************************************************************************************************/ +int sng_mgco_mg_tpt_server_stop(int idx) +{ + MgMngmt mgMngmt; + Pst pst; /* Post for layer manager */ + MgCntrl *cntrl; + MgTptCntrl *tptCntrl = &mgMngmt.t.cntrl.s.tptCntrl; + CmInetIpAddr ipAddr = 0; + sng_mg_cfg_t* mgCfg = &megaco_globals.g_mg_cfg.mgCfg[idx]; + + cntrl = &(mgMngmt.t.cntrl); + + memset(&mgMngmt, 0, sizeof(mgMngmt)); + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTMG; + + tptCntrl->transportType = GET_TPT_TYPE(idx); + + tptCntrl->serverAddr.type = CM_INET_IPV4ADDR_TYPE; + tptCntrl->serverAddr.u.ipv4TptAddr.port = mgCfg->port; + if(ROK == cmInetAddr((S8*)mgCfg->my_ipaddr, &ipAddr)) + { + tptCntrl->serverAddr.u.ipv4TptAddr.address = ntohl(ipAddr); + } + + /*fill in the specific fields of the header */ + mgMngmt.hdr.msgType = TCNTRL; + mgMngmt.hdr.entId.ent = ENTMG; + mgMngmt.hdr.entId.inst = S_INST; + mgMngmt.hdr.elmId.elmnt = STSERVER; + + cntrl->action = ADEL; + cntrl->subAction = SAELMNT; + + return(sng_cntrl_mg(&pst, &mgMngmt)); +} +/*****************************************************************************************************************/ + int mgco_mg_tsap_bind_cntrl(int idx) { MgMngmt mgMngmt; @@ -962,3 +1126,64 @@ int mgco_mg_tpt_server_config(int idx) } /******************************************************************************/ +int sng_mgco_tucl_shutdown() +{ + Pst pst; + HiMngmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(HiMngmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTHI; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTHI; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STGEN; /* General */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = ASHUTDOWN; + + return (sng_cntrl_tucl (&pst, &cntrl)); +} +/******************************************************************************/ +int sng_mgco_mg_shutdown() +{ + Pst pst; + MgMngmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(MgCntrl)); + + smPstInit(&pst); + + pst.dstEnt = ENTMG; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTMG; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STGEN; /* General */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = ASHUTDOWN; + cntrl.t.cntrl.subAction = SAELMNT; + + return (sng_cntrl_mg (&pst, &cntrl)); +} +/******************************************************************************/ + + diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.h b/src/mod/endpoints/mod_megaco/megaco_stack.h index 24cf6e26ca..e7ef56db49 100644 --- a/src/mod/endpoints/mod_megaco/megaco_stack.h +++ b/src/mod/endpoints/mod_megaco/megaco_stack.h @@ -108,6 +108,7 @@ void handle_tucl_alarm(Pst *pst, HiMngmt *sta); switch_status_t sng_mgco_init(sng_isup_event_interface_t* event); switch_status_t sng_mgco_cfg(const char* profilename); switch_status_t sng_mgco_start(const char* profilename); +switch_status_t sng_mgco_stop(const char* profilename); switch_status_t sng_mgco_stack_shutdown(void); /*****************************************************************************************************/ From 529e7fd24a7db5708d201b454549985f8be5eca5 Mon Sep 17 00:00:00 2001 From: kapil Date: Thu, 31 May 2012 18:36:10 +0530 Subject: [PATCH 208/822] adding code to make "version" as configurable parameter --- .../endpoints/mod_megaco/conf/megaco.conf.xml | 5 +++-- src/mod/endpoints/mod_megaco/megaco_stack.c | 16 +++++++++++++++- src/mod/endpoints/mod_megaco/megaco_stack.h | 1 + src/mod/endpoints/mod_megaco/megaco_xml.c | 11 +++++++++++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml b/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml index d386e055a9..e21ab3a074 100644 --- a/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml +++ b/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml @@ -5,8 +5,9 @@ + - + @@ -35,7 +36,7 @@ - + diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.c b/src/mod/endpoints/mod_megaco/megaco_stack.c index 86d1f80268..d650aaa48a 100644 --- a/src/mod/endpoints/mod_megaco/megaco_stack.c +++ b/src/mod/endpoints/mod_megaco/megaco_stack.c @@ -917,7 +917,21 @@ int mgco_mg_ssap_config(int idx) pCfg->mwdTimer = (U16)10; pCfg->minMgcoVersion = LMG_VER_PROF_MGCO_H248_1_0; - pCfg->maxMgcoVersion = LMG_VER_PROF_MGCO_H248_3_0; + switch(mgCfg->protocol_version) + { + case 1: + pCfg->maxMgcoVersion = LMG_VER_PROF_MGCO_H248_1_0; + break; + case 2: + pCfg->maxMgcoVersion = LMG_VER_PROF_MGCO_H248_2_0; + break; + case 3: + pCfg->maxMgcoVersion = LMG_VER_PROF_MGCO_H248_3_0; + break; + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Protocol version[%d] \n",mgCfg->protocol_version); + return SWITCH_STATUS_FALSE; + } pCfg->userInfo.pres.pres = PRSNT_NODEF; pCfg->userInfo.id.pres = NOTPRSNT; diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.h b/src/mod/endpoints/mod_megaco/megaco_stack.h index e7ef56db49..64ef1f1ff2 100644 --- a/src/mod/endpoints/mod_megaco/megaco_stack.h +++ b/src/mod/endpoints/mod_megaco/megaco_stack.h @@ -76,6 +76,7 @@ typedef struct sng_mg_cfg{ uint8_t my_domain[MAX_DOMAIN_LEN]; /* local domain name */ uint8_t my_ipaddr[MAX_DOMAIN_LEN]; /* local domain name */ uint32_t port; /* port */ + uint16_t protocol_version; /* Protocol supported version */ uint16_t peer_id; /* MGC Peer ID */ uint16_t transport_prof_id; /* Transport profile id ..this also will be the spId for MG SAP*/ uint16_t protocol_type; /* MEGACO/MGCP */ diff --git a/src/mod/endpoints/mod_megaco/megaco_xml.c b/src/mod/endpoints/mod_megaco/megaco_xml.c index e7addf5875..a886546b9b 100644 --- a/src/mod/endpoints/mod_megaco/megaco_xml.c +++ b/src/mod/endpoints/mod_megaco/megaco_xml.c @@ -46,6 +46,17 @@ switch_status_t sng_parse_mg_profile(switch_xml_t mg_interface) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mg_interface protocol[%d] \n", megaco_globals.g_mg_cfg.mgCfg[i].protocol_type); /********************************************************************************************/ + }else if(!strcasecmp(var, "version")){ + /********************************************************************************************/ + megaco_globals.g_mg_cfg.mgCfg[i].protocol_version = atoi(val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mg_interface protocol version[%s] \n",val); + if((megaco_globals.g_mg_cfg.mgCfg[i].protocol_version < 1) + || (megaco_globals.g_mg_cfg.mgCfg[i].protocol_version > 3)) + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Protocol version[%s] , Supported values are [1/2/3] \n",val); + return SWITCH_STATUS_FALSE; + } + /********************************************************************************************/ }else if(!strcasecmp(var, "transportProfileId")){ /********************************************************************************************/ megaco_globals.g_mg_cfg.mgCfg[i].transport_prof_id = atoi(val); From a16ee3618732b26ec4c6bb89718056f8422d3121 Mon Sep 17 00:00:00 2001 From: kapil Date: Thu, 31 May 2012 20:20:51 +0530 Subject: [PATCH 209/822] adding code to handle TUCL/MEGACO Status(Alarm) Indication from MEGACO Stack --- src/mod/endpoints/mod_megaco/megaco_stack.c | 474 ++++++++++++++++++++ src/mod/endpoints/mod_megaco/mod_megaco.c | 10 - 2 files changed, 474 insertions(+), 10 deletions(-) diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.c b/src/mod/endpoints/mod_megaco/megaco_stack.c index d650aaa48a..516d857ec9 100644 --- a/src/mod/endpoints/mod_megaco/megaco_stack.c +++ b/src/mod/endpoints/mod_megaco/megaco_stack.c @@ -1199,5 +1199,479 @@ int sng_mgco_mg_shutdown() return (sng_cntrl_mg (&pst, &cntrl)); } /******************************************************************************/ +void handle_mg_alarm(Pst *pst, MgMngmt *usta) +{ + U16 ret; + int len = 0x00; + char prBuf[10024]; + memset(&prBuf[0], 0, sizeof(prBuf)); + + len = len + sprintf(prBuf+len,"MG Status Indication: received with Category = %d, Event = %d, Cause = %d \n", + usta->t.usta.alarm.category, usta->t.usta.alarm.event, + usta->t.usta.alarm.cause); + + len = len + sprintf(prBuf+len, "Category ( "); + + switch (usta->t.usta.alarm.category) + { + case LCM_CATEGORY_PROTOCOL: + { + len = len + sprintf(prBuf+len, "protocol related "); + break; + } + case LCM_CATEGORY_INTERFACE: + { + len = len + sprintf(prBuf+len, "interface related "); + break; + } + case LCM_CATEGORY_INTERNAL: + { + len = len + sprintf(prBuf+len, "internal "); + break; + } + case LCM_CATEGORY_RESOURCE: + { + len = len + sprintf(prBuf+len, "system resources related "); + break; + } + case LCM_CATEGORY_PSF_FTHA: + { + len = len + sprintf(prBuf+len, "fault tolerance / high availability PSF related "); + break; + } + case LCM_CATEGORY_LYR_SPECIFIC: + { + len = len + sprintf(prBuf+len, "MGCP related "); + break; + } + default: + { + len = len + sprintf(prBuf+len, "unknown: %d", (int)(usta->t.usta.alarm.category)); + break; + } + } + len = len + sprintf(prBuf+len, ") "); + + len = len + sprintf(prBuf+len, " Event ( "); + switch (usta->t.usta.alarm.event) + { + case LMG_EVENT_TSAP_RECVRY_SUCCESS: + { + len = len + sprintf(prBuf+len, "TSAP recovery success"); + break; + } + case LMG_EVENT_TSAP_RECVRY_FAILED: + { + len = len + sprintf(prBuf+len, "TSAP recovery failed"); + break; + } + case LCM_EVENT_UI_INV_EVT: + { + len = len + sprintf(prBuf+len, "upper interface invalid event"); + break; + } + case LCM_EVENT_LI_INV_EVT: + { + len = len + sprintf(prBuf+len, "lower interface invalid event"); + break; + } + case LCM_EVENT_PI_INV_EVT: + { + len = len + sprintf(prBuf+len, "peer interface invalid event"); + break; + } + case LCM_EVENT_INV_EVT: + { + len = len + sprintf(prBuf+len, "general invalid event"); + break; + } + case LCM_EVENT_INV_STATE: + { + len = len + sprintf(prBuf+len, "invalid internal state"); + break; + } + case LCM_EVENT_INV_TMR_EVT: + { + len = len + sprintf(prBuf+len, "invalid timer event"); + break; + } + case LCM_EVENT_MI_INV_EVT: + { + len = len + sprintf(prBuf+len, "management interface invalid event"); + break; + } + case LCM_EVENT_BND_FAIL: + { + len = len + sprintf(prBuf+len, "bind failure"); + break; + } + case LCM_EVENT_NAK: + { + len = len + sprintf(prBuf+len, "destination nack"); + break; + } + case LCM_EVENT_TIMEOUT: + { + len = len + sprintf(prBuf+len, "timeout"); + break; + } + case LCM_EVENT_BND_OK: + { + len = len + sprintf(prBuf+len, "bind ok"); + break; + } + case LCM_EVENT_SMEM_ALLOC_FAIL: + { + len = len + sprintf(prBuf+len, "static memory allocation failed"); + break; + } + case LCM_EVENT_DMEM_ALLOC_FAIL: + { + len = len + sprintf(prBuf+len, "dynamic mmemory allocation failed"); + break; + } + case LCM_EVENT_LYR_SPECIFIC: + { + len = len + sprintf(prBuf+len, "MGCP specific"); + break; + } + default: + { + len = len + sprintf(prBuf+len, "unknown event %d", (int)(usta->t.usta.alarm.event)); + break; + } + case LMG_EVENT_HIT_BNDCFM: + { + len = len + sprintf(prBuf+len, "HIT bind confirm"); + break; + } + case LMG_EVENT_HIT_CONCFM: + { + len = len + sprintf(prBuf+len, "HIT connect confirm"); + break; + } + case LMG_EVENT_HIT_DISCIND: + { + len = len + sprintf(prBuf+len, "HIT disconnect indication"); + break; + } + case LMG_EVENT_HIT_UDATIND: + { + len = len + sprintf(prBuf+len, "HIT unit data indication"); + break; + } + case LMG_EVENT_MGT_BNDREQ: + { + len = len + sprintf(prBuf+len, "MGT bind request"); + break; + } + case LMG_EVENT_PEER_CFG_FAIL: + { + len = len + sprintf(prBuf+len, "Peer Configuration Failed"); + break; + } + case LMG_EVENT_MGT_UBNDREQ: + { + len = len + sprintf(prBuf+len, "MGT unbind request"); + break; + } + case LMG_EVENT_MGT_MGCPTXNREQ: + { + len = len + sprintf(prBuf+len, "MGT MGCP transaction request"); + break; + } + case LMG_EVENT_MGT_MGCPTXNIND: + { + len = len + sprintf(prBuf+len, "MGT MGCP transaction indication"); + break; + } + + case LMG_EVENT_PEER_ENABLED: + { + len = len + sprintf(prBuf+len, "gateway enabled"); + break; + } + case LMG_EVENT_PEER_DISCOVERED: + { + len = len + sprintf(prBuf+len, "gateway discovered , notified entity"); + break; + } + case LMG_EVENT_PEER_REMOVED: + { + len = len + sprintf(prBuf+len, "gateway removed"); + break; + } + case LMG_EVENT_RES_CONG_ON: + { + len = len + sprintf(prBuf+len, "resource congestion ON"); + break; + } + case LMG_EVENT_RES_CONG_OFF: + { + len = len + sprintf(prBuf+len, "resource congestion OFF"); + break; + } + case LMG_EVENT_TPTSRV: + { + len = len + sprintf(prBuf+len, "transport service"); + break; + } + case LMG_EVENT_SSAP_ENABLED: + { + len = len + sprintf(prBuf+len, "SSAP enabled"); + break; + } + case LMG_EVENT_NS_NOT_RESPONDING: + { + len = len + sprintf(prBuf+len, "name server not responding"); + break; + } + case LMG_EVENT_TPT_FAILED: + { + len = len + sprintf(prBuf+len, "transport failure"); + break; + } + } + + len = len + sprintf(prBuf+len, " ) "); + + len = len + sprintf(prBuf+len, " cause ( "); + switch (usta->t.usta.alarm.cause) + { + case LCM_CAUSE_UNKNOWN: + { + len = len + sprintf(prBuf+len, "unknown"); + break; + } + case LCM_CAUSE_OUT_OF_RANGE: + { + len = len + sprintf(prBuf+len, "out of range"); + break; + } + case LCM_CAUSE_INV_SAP: + { + len = len + sprintf(prBuf+len, "NULL/unknown sap"); + break; + } + case LCM_CAUSE_INV_SPID: + { + len = len + sprintf(prBuf+len, "invalid service provider"); + break; + } + case LCM_CAUSE_INV_SUID: + { + len = len + sprintf(prBuf+len, "invalid service user"); + break; + } + case LCM_CAUSE_INV_NETWORK_MSG: + { + len = len + sprintf(prBuf+len, "invalid network message"); + break; + } + case LCM_CAUSE_DECODE_ERR: + { + len = len + sprintf(prBuf+len, "message decoding problem"); + break; + } + case LCM_CAUSE_USER_INITIATED: + { + len = len + sprintf(prBuf+len, "user initiated"); + break; + } + case LCM_CAUSE_MGMT_INITIATED: + { + len = len + sprintf(prBuf+len, "management initiated"); + break; + } + case LCM_CAUSE_INV_STATE: /* cause and event! */ + { + len = len + sprintf(prBuf+len, "invalid state"); + break; + } + case LCM_CAUSE_TMR_EXPIRED: /* cause and event! */ + { + len = len + sprintf(prBuf+len, "timer expired"); + break; + } + case LCM_CAUSE_INV_MSG_LENGTH: + { + len = len + sprintf(prBuf+len, "invalid message length"); + break; + } + case LCM_CAUSE_PROT_NOT_ACTIVE: + { + len = len + sprintf(prBuf+len, "protocol layer not active"); + break; + } + case LCM_CAUSE_INV_PAR_VAL: + { + len = len + sprintf(prBuf+len, "invalid parameter value"); + break; + } + case LCM_CAUSE_NEG_CFM: + { + len = len + sprintf(prBuf+len, "negative confirmation"); + break; + } + case LCM_CAUSE_MEM_ALLOC_FAIL: + { + len = len + sprintf(prBuf+len, "memory allocation failure"); + break; + } + case LCM_CAUSE_HASH_FAIL: + { + len = len + sprintf(prBuf+len, "hashing failure"); + break; + } + case LCM_CAUSE_LYR_SPECIFIC: + { + len = len + sprintf(prBuf+len, "MGCP specific"); + break; + } + default: + { + len = len + sprintf(prBuf+len, "unknown %d", (int)(usta->t.usta.alarm.cause)); + break; + } + case LMG_CAUSE_TPT_FAILURE: /* make up your mind - cause or event? */ + { + len = len + sprintf(prBuf+len, "transport failure"); + break; + } + case LMG_CAUSE_NS_NOT_RESPONDING: + { + len = len + sprintf(prBuf+len, "name server not responding"); + break; + } + } + len = len + sprintf(prBuf+len, " ) "); + + len = len + sprintf(prBuf+len, " Alarm parameters ( "); + ret = smmgGetAlarmInfoField(&usta->t.usta); + switch (ret) + { + case SMMG_UNKNOWNFIELD: + { + len = len + sprintf(prBuf+len, "invalid "); + + break; + } + case SMMG_PEERINFO: + { + /* + * Invoke the new function for printing the MgPeerInfo & + * delete all print code here + */ + smmgPrntPeerInfo(&(usta->t.usta.alarmInfo.u.peerInfo)); + break; + } + case SMMG_SAPID: + { + len = len + sprintf(prBuf+len, "SAP ID %d\n", (int)(usta->t.usta.alarmInfo.u.sapId)); + break; + } + case SMMG_MEM: + { + len = len + sprintf(prBuf+len, "memory region %d pool %d\n", + (int)(usta->t.usta.alarmInfo.u.mem.region), + (int)(usta->t.usta.alarmInfo.u.mem.pool)); + + break; + } + case SMMG_SRVSTA: + { + smmgPrntSrvSta(&usta->t.usta.alarmInfo.u.srvSta); + break; + } + case SMMG_PEERSTA: + { + smmgPrntPeerSta(&usta->t.usta.alarmInfo.u.peerSta); + break; + } + case SMMG_SSAPSTA: + { + smmgPrntSsapSta(&usta->t.usta.alarmInfo.u.ssapSta); + break; + } + case SMMG_PARID: + { + len = len + sprintf(prBuf+len, "parameter type: "); + switch (usta->t.usta.alarmInfo.u.parId.parType) + { + case LMG_PAR_TPTADDR: len = len + sprintf(prBuf+len, "transport address"); break; + case LMG_PAR_MBUF: len = len + sprintf(prBuf+len, "message buffer"); break; + case LMG_PAR_CHOICE: len = len + sprintf(prBuf+len, "choice"); break; + case LMG_PAR_SPID: len = len + sprintf(prBuf+len, "spId"); break; + default: len = len + sprintf(prBuf+len, "unknown"); break; + } + + len = len + sprintf(prBuf+len, ", value %d\n", + (int)(usta->t.usta.alarmInfo.u.parId.u.sapId)); + + break; + } + case SMMG_NOT_APPL: + { + len = len + sprintf(prBuf+len, "not applicable\n"); + break; + } + + /*TODO*/ + } + len = len + sprintf(prBuf+len, " ) "); + len = len + sprintf(prBuf+len, " \n "); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s \n", prBuf); +} + +/*****************************************************************************************************************************/ +void handle_tucl_alarm(Pst *pst, HiMngmt *sta) +{ + /* To print the general information */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Recieved a status indication from TUCL layer \n\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " Category = %d , event = %d , cause = %d\n", + sta->t.usta.alarm.category, + sta->t.usta.alarm.event, sta->t.usta.alarm.cause); + + switch(sta->t.usta.alarm.event) + { + case LCM_EVENT_INV_EVT: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," [HI_USTA]: LCM_EVENT_INV_EVT with type (%d)\n\n", + sta->t.usta.info.type); + break; + } + case LHI_EVENT_BNDREQ: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," [HI_USTA]: LHI_EVENT_BNDREQ with type (%d) spId (%d)\n\n", + sta->t.usta.info.type, sta->t.usta.info.spId); + break; + } + case LHI_EVENT_SERVOPENREQ: + case LHI_EVENT_DATREQ: + case LHI_EVENT_UDATREQ: + case LHI_EVENT_CONREQ: + case LHI_EVENT_DISCREQ: +#if(defined(HI_TLS) && defined(HI_TCP_TLS)) + case LHI_EVENT_TLS_ESTREQ: +#endif + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," [HI_USTA]: partype (%d) type(%d)\n\n", + sta->t.usta.info.inf.parType, sta->t.usta.info.type); + break; + } + case LCM_EVENT_DMEM_ALLOC_FAIL: + case LCM_EVENT_SMEM_ALLOC_FAIL: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " [HI_USTA]: MEM_ALLOC_FAIL with region(%d) pool (%d) type(%d)\n\n", + sta->t.usta.info.inf.mem.region, sta->t.usta.info.inf.mem.pool, + sta->t.usta.info.type); + break; + } + default: + break; + } + +} /* handle_sng_tucl_alarm */ +/******************************************************************************/ diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.c b/src/mod/endpoints/mod_megaco/mod_megaco.c index 332392c59a..3d9dc26b8d 100644 --- a/src/mod/endpoints/mod_megaco/mod_megaco.c +++ b/src/mod/endpoints/mod_megaco/mod_megaco.c @@ -209,16 +209,6 @@ void handle_mgco_audit_cfm(Pst *pst, SuId suId, MgMgtAudit* audit, Reason reason } /*****************************************************************************************************************************/ -void handle_mg_alarm(Pst *pst, MgMngmt *sta) -{ - /*TODO*/ -} - -/*****************************************************************************************************************************/ -void handle_tucl_alarm(Pst *pst, HiMngmt *sta) -{ - /*TODO*/ -} /*****************************************************************************************************************************/ From bac3b3bd365f1e58df7ce93e9d35888669a9d1dd Mon Sep 17 00:00:00 2001 From: kapil Date: Fri, 1 Jun 2012 20:35:38 +0530 Subject: [PATCH 210/822] adding status CLI command to fetch peer/sap/transport-server information from Trillium MEGACO stack. --- src/mod/endpoints/mod_megaco/megaco_stack.c | 138 ++++++++++++++++++++ src/mod/endpoints/mod_megaco/megaco_stack.h | 3 + src/mod/endpoints/mod_megaco/mod_megaco.c | 10 +- 3 files changed, 150 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.c b/src/mod/endpoints/mod_megaco/megaco_stack.c index 516d857ec9..e5572c19ef 100644 --- a/src/mod/endpoints/mod_megaco/megaco_stack.c +++ b/src/mod/endpoints/mod_megaco/megaco_stack.c @@ -1675,3 +1675,141 @@ void handle_tucl_alarm(Pst *pst, HiMngmt *sta) } /* handle_sng_tucl_alarm */ /******************************************************************************/ +int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, int mg_cfg_idx) +{ + Pst pst; + MgMngmt cntrl; + sng_mg_cfg_t* mgCfg = &megaco_globals.g_mg_cfg.mgCfg[mg_cfg_idx]; + sng_mg_peer_t* mgPeer = &megaco_globals.g_mg_cfg.mgPeer.peers[mgCfg->peer_id]; + CmInetIpAddr ipAddr = 0; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(MgCntrl)); + + smPstInit(&pst); + + pst.dstEnt = ENTMG; + + /* prepare header */ + /*cntrl.hdr.msgType = TCNTRL; */ /* message type */ + cntrl.hdr.entId.ent = ENTMG; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = elemId; /* General */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + switch(elemId) + { + case STGCPENT: + { + cntrl.t.ssta.s.mgPeerSta.peerId.pres = PRSNT_NODEF; + cntrl.t.ssta.s.mgPeerSta.peerId.val = mgCfg->peer_id; + + cntrl.t.ssta.s.mgPeerSta.mid.pres = PRSNT_NODEF; + cntrl.t.ssta.s.mgPeerSta.mid.len = strlen((char*)mgPeer->mid); + cmMemcpy((U8 *)cntrl.t.ssta.s.mgPeerSta.mid.val, + (CONSTANT U8*)(char*)mgPeer->mid, + cntrl.t.ssta.s.mgPeerSta.mid.len); + break; + } + case STSSAP: + { + cntrl.t.ssta.s.mgSSAPSta.sapId = mgCfg->id; + break; + } + case STTSAP: + { + cntrl.t.ssta.s.mgTSAPSta.tSapId = GET_TPT_ID(mg_cfg_idx); + break; + } + case STSERVER: + { + cntrl.t.ssta.s.mgTptSrvSta.tptAddr.type = CM_INET_IPV4ADDR_TYPE; + cntrl.t.ssta.s.mgTptSrvSta.tptAddr.u.ipv4TptAddr.port = ntohl(ipAddr); + if(ROK == cmInetAddr((S8*)mgCfg->my_ipaddr, &ipAddr)) + { + cntrl.t.ssta.s.mgTptSrvSta.tptAddr.u.ipv4TptAddr.address = ntohl(ipAddr); + } + + + break; + } + default: + break; + } + + return (sng_sta_mg (&pst, &cntrl, cfm)); +} +/******************************************************************************/ +switch_status_t megaco_profile_status(switch_stream_handle_t *stream, const char* profilename) +{ + int idx = 0x00; + int len = 0x00; + MgMngmt cfm; + char prntBuf[1024]; + + switch_assert(profilename); + + memset((U8 *)&cfm, 0, sizeof(cfm)); + memset((char *)&prntBuf, 0, sizeof(prntBuf)); + + GET_MG_CFG_IDX(profilename, idx); + + if(!idx || (idx == MAX_MG_PROFILES)){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG configuration found against profilename[%s]\n",profilename); + return SWITCH_STATUS_FALSE; + } + + /*stream->write_function(stream, "Collecting MG Profile[%s] status... \n",profilename);*/ + + /* Fetch data from Trillium MEGACO Stack * + * SystemId - Software version information * + * SSAP - MG SAP Information * + * TSAP - MG Transport SAP Information * + * Peer - MG Peer Information * + * TPT-Server - MG Transport Server information * + */ + +#if 0 + /* get System ID */ + sng_mgco_mg_get_status(STSID, &cfm, idx); + stream->write_function(stream, "***********************************************\n"); + stream->write_function(stream, "**** TRILLIUM MEGACO Software Information *****\n"); + stream->write_function(stream, "Version = %d \n", cfm.t.ssta.s.systemId.mVer); + stream->write_function(stream, "Version Revision = %d \n", cfm.t.ssta.s.systemId.mRev); + stream->write_function(stream, "Branch Version = %d \n", cfm.t.ssta.s.systemId.bVer); + stream->write_function(stream, "Branch Revision = %d \n", cfm.t.ssta.s.systemId.bRev); + stream->write_function(stream, "Part Number = %d \n", cfm.t.ssta.s.systemId.ptNmb); + stream->write_function(stream, "***********************************************\n"); +#endif + + /* MG Peer Information */ + sng_mgco_mg_get_status(STGCPENT, &cfm, idx); + smmgPrntPeerSta(&cfm.t.ssta.s.mgPeerSta); + + /* MG Peer Information */ + sng_mgco_mg_get_status(STSSAP, &cfm, idx); + smmgPrntSsapSta(&cfm.t.ssta.s.mgSSAPSta); + + /* MG Transport SAP Information */ + sng_mgco_mg_get_status(STTSAP, &cfm, idx); + len = len + sprintf(prntBuf+len,"***********************************************\n"); + len = len + sprintf(prntBuf+len,"**********MG TRANSPORT SAP Information**********\n"); + len = len + sprintf(prntBuf+len,"TSAP status:\n"); + len = len + sprintf(prntBuf+len,"state = %d, number of listeners %u\n", + (int)(cfm.t.ssta.s.mgTSAPSta.state), + (unsigned int)(cfm.t.ssta.s.mgTSAPSta.numServers)); + len = len + sprintf(prntBuf+len,"***********************************************\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"%s\n",prntBuf); + + /* MG Transport Server Information */ + sng_mgco_mg_get_status(STSERVER, &cfm, idx); + smmgPrntSrvSta(&cfm.t.ssta.s.mgTptSrvSta); + + return SWITCH_STATUS_SUCCESS; +} +/******************************************************************************/ diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.h b/src/mod/endpoints/mod_megaco/megaco_stack.h index 64ef1f1ff2..d8a1b55e47 100644 --- a/src/mod/endpoints/mod_megaco/megaco_stack.h +++ b/src/mod/endpoints/mod_megaco/megaco_stack.h @@ -84,6 +84,7 @@ typedef struct sng_mg_cfg{ typedef struct sng_mg_gbl_cfg{ + int num_of_mg_profiles; sng_mg_cfg_t mgCfg[MAX_MG_PROFILES + 1]; sng_mg_transport_profile_t mgTptProf[MG_MAX_PEERS+1]; /* transport profile */ sng_mg_peers_t mgPeer; @@ -111,6 +112,8 @@ switch_status_t sng_mgco_cfg(const char* profilename); switch_status_t sng_mgco_start(const char* profilename); switch_status_t sng_mgco_stop(const char* profilename); switch_status_t sng_mgco_stack_shutdown(void); +int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, int mg_cfg_idx); +switch_status_t megaco_profile_status(switch_stream_handle_t *stream, const char* profilename); /*****************************************************************************************************/ diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.c b/src/mod/endpoints/mod_megaco/mod_megaco.c index 3d9dc26b8d..7bc6320df9 100644 --- a/src/mod/endpoints/mod_megaco/mod_megaco.c +++ b/src/mod/endpoints/mod_megaco/mod_megaco.c @@ -16,7 +16,7 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_megaco_shutdown); SWITCH_MODULE_DEFINITION(mod_megaco, mod_megaco_load, mod_megaco_shutdown, NULL); -#define MEGACO_FUNCTION_SYNTAX "profile [name] [start | stop]" +#define MEGACO_FUNCTION_SYNTAX "profile [name] [start | stop] [status]" SWITCH_STANDARD_API(megaco_function) { int argc; @@ -56,6 +56,13 @@ SWITCH_STANDARD_API(megaco_function) } else { stream->write_function(stream, "-ERR No such profile\n"); } + }else if(!strcmp(argv[2], "status")) { + megaco_profile_t *profile = megaco_profile_locate(argv[1]); + if (profile) { + megaco_profile_status(stream, profile->name); + } else { + stream->write_function(stream, "-ERR No such profile\n"); + } } } @@ -115,6 +122,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_megaco_load) switch_console_set_complete("add megaco profile ::megaco::list_profiles start"); switch_console_set_complete("add megaco profile ::megaco::list_profiles stop"); + switch_console_set_complete("add megaco profile ::megaco::list_profiles status"); switch_console_add_complete_func("::megaco::list_profiles", list_profiles); From cffe95a97881ae62f23e0278ae6490a98fcb9f8b Mon Sep 17 00:00:00 2001 From: kapil Date: Mon, 4 Jun 2012 17:23:33 +0530 Subject: [PATCH 211/822] adding "xmlstatus" CLI command to dump MEGACO Stack data --- src/mod/endpoints/mod_megaco/megaco_stack.c | 275 ++++++++++++++++++++ src/mod/endpoints/mod_megaco/megaco_stack.h | 1 + src/mod/endpoints/mod_megaco/megaco_xml.c | 2 + src/mod/endpoints/mod_megaco/mod_megaco.c | 11 +- 4 files changed, 288 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.c b/src/mod/endpoints/mod_megaco/megaco_stack.c index e5572c19ef..f3a2015016 100644 --- a/src/mod/endpoints/mod_megaco/megaco_stack.c +++ b/src/mod/endpoints/mod_megaco/megaco_stack.c @@ -37,6 +37,8 @@ int sng_mgco_mg_app_ssap_stop(int idx); switch_status_t sng_mgco_stack_gen_cfg(); +void get_peer_xml_buffer(char* prntBuf, MgPeerSta* cfm); + /******************************************************************************/ /* FUNCTIONS ******************************************************************/ @@ -1764,6 +1766,7 @@ switch_status_t megaco_profile_status(switch_stream_handle_t *stream, const char return SWITCH_STATUS_FALSE; } + /*stream->write_function(stream, "Collecting MG Profile[%s] status... \n",profilename);*/ /* Fetch data from Trillium MEGACO Stack * @@ -1813,3 +1816,275 @@ switch_status_t megaco_profile_status(switch_stream_handle_t *stream, const char return SWITCH_STATUS_SUCCESS; } /******************************************************************************/ +switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const char* profilename) +{ + int idx = 0x00; + int len = 0x00; + MgMngmt cfm; + char* xmlhdr = ""; + char prntBuf[10024]; + sng_mg_cfg_t* mgCfg = NULL; + sng_mg_peer_t* mgPeer = NULL; + int i = 0x00; + + switch_assert(profilename); + + memset((U8 *)&cfm, 0, sizeof(cfm)); + memset((char *)&prntBuf, 0, sizeof(prntBuf)); + + GET_MG_CFG_IDX(profilename, idx); + + if(!idx || (idx == MAX_MG_PROFILES)){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG configuration found against profilename[%s]\n",profilename); + return SWITCH_STATUS_FALSE; + } + + mgCfg = &megaco_globals.g_mg_cfg.mgCfg[idx]; + mgPeer = &megaco_globals.g_mg_cfg.mgPeer.peers[mgCfg->peer_id]; + + + len = len + sprintf(&prntBuf[0] + len,"%s\n",xmlhdr); + + + len = len + sprintf(&prntBuf[0] + len,"\n"); + len = len + sprintf(&prntBuf[0] + len,"%s\n",mgCfg->name); + len = len + sprintf(&prntBuf[0] + len,"%s\n",profilename); +/****************************************************************************************************************/ +/* Print Peer Information ***************************************************************************************/ + + /* TODO - as of now supporting only one peer .. need to add logic to iterate through all the peers associated with this profile..*/ + + len = len + sprintf(&prntBuf[0] + len,"\n"); + len = len + sprintf(&prntBuf[0] + len,"\n",mgPeer->name); + + /* send request to MEGACO Trillium stack to get peer information*/ + sng_mgco_mg_get_status(STGCPENT, &cfm, idx); + + get_peer_xml_buffer(&prntBuf[0] + len, &cfm.t.ssta.s.mgPeerSta); + + len = len + sprintf(&prntBuf[0] + len,"\n"); + len = len + sprintf(&prntBuf[0] + len,"\n"); + + +/****************************************************************************************************************/ +/* Print MG SAP Information ***************************************************************************************/ + + len = len + sprintf(&prntBuf[0] + len,"\n"); + + /* MG SAP Information */ + sng_mgco_mg_get_status(STSSAP, &cfm, idx); + + len = len + sprintf(prntBuf+len, " %s \n", PRNT_SAP_STATE((int)(cfm.t.ssta.s.mgSSAPSta.state))); + len = len + sprintf(prntBuf+len, " %u \n", (unsigned int)(cfm.t.ssta.s.mgSSAPSta.numAssocPeer)); + len = len + sprintf(prntBuf+len, " %u \n", (unsigned int)(cfm.t.ssta.s.mgSSAPSta.numServers)); + len = len + sprintf(&prntBuf[0] + len,"\n"); + for (i = 0; i < cfm.t.ssta.s.mgSSAPSta.numAssocPeer; i++) + { + len = len + sprintf(&prntBuf[0] + len,"\n"); + if(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].dname.namePres.pres == PRSNT_NODEF) + { + len = len + sprintf(prntBuf+len, " %s \n", (char *)(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].dname.name)); + } + switch(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].dname.netAddr.type) + { + case CM_NETADDR_IPV4: + { + len = len + sprintf(prntBuf+len, "%lu\n", (long unsigned int)(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].dname.netAddr.u.ipv4NetAddr)); + break; + } + default: + len = len + sprintf(prntBuf+len, "invalid type \n"); + break; + } + +#ifdef GCP_MGCO + if (PRSNT_NODEF == cfm.t.ssta.s.mgSSAPSta.peerInfo[i].mid.pres) + { + len = len + sprintf(prntBuf+len, " %s \n", (char *)(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].mid.val)); + } +#endif /* GCP_MGCO */ + len = len + sprintf(&prntBuf[0] + len,"\n"); + } + len = len + sprintf(&prntBuf[0] + len,"\n"); + + len = len + sprintf(&prntBuf[0] + len,"\n"); + +/****************************************************************************************************************/ +/* Print MG Transport SAP Information ***************************************************************************************/ + + len = len + sprintf(&prntBuf[0] + len,"\n"); + /* MG Transport SAP Information */ + sng_mgco_mg_get_status(STTSAP, &cfm, idx); + len = len + sprintf(&prntBuf[0] + len," %s \n", PRNT_SAP_STATE(cfm.t.ssta.s.mgTSAPSta.state)); + len = len + sprintf(&prntBuf[0] + len," %u \n", (unsigned int)(cfm.t.ssta.s.mgTSAPSta.numServers)); + len = len + sprintf(&prntBuf[0] + len,"\n"); + +/****************************************************************************************************************/ +/* Print MG Transport Server Information ***************************************************************************************/ + + if(sng_mgco_mg_get_status(STSERVER, &cfm, idx)){ + len = len + sprintf(&prntBuf[0] + len," no established server found \n"); + } + else { + len = len + sprintf(&prntBuf[0] + len,"\n"); + len = len + sprintf(&prntBuf[0] + len," %s \n", PRNT_SAP_STATE(cfm.t.ssta.s.mgTptSrvSta.state)); + len = len + sprintf(prntBuf+len, ""); + + switch (cfm.t.ssta.s.mgTptSrvSta.tptAddr.type) + { + case CM_TPTADDR_NOTPRSNT: + { + len = len + sprintf(prntBuf+len, "none"); + break; + } + case CM_TPTADDR_IPV4: + { + len = len + sprintf(prntBuf+len, "IPv4 IP address #%lu, port %u", + (unsigned long)(cfm.t.ssta.s.mgTptSrvSta.tptAddr.u.ipv4TptAddr.address), + (unsigned int)(cfm.t.ssta.s.mgTptSrvSta.tptAddr.u.ipv4TptAddr.port)); + + break; + } + default: + len = len + sprintf(prntBuf+len, "unknown"); + break; + } + len = len + sprintf(prntBuf+len, "\n"); + len = len + sprintf(&prntBuf[0] + len,"\n"); + } + +/****************************************************************************************************************/ + len = len + sprintf(&prntBuf[0] + len,"\n"); + + stream->write_function(stream, "\n%s\n",&prntBuf[0]); + + return SWITCH_STATUS_SUCCESS; +} + +/******************************************************************************/ + +void get_peer_xml_buffer(char* prntBuf, MgPeerSta* cfm) +{ + int len = 0x00; + int i = 0x00; + if(PRSNT_NODEF == cfm->namePres.pres) + { + len = len + sprintf(prntBuf+len, " %s \n", (char *)(cfm->name)); + } + else + { + len = len + sprintf(prntBuf+len, " Not Present \n"); + } + + /* + * Print all IP addresses in the IP addr table + */ + for(i=0; ipeerAddrTbl.count; i++) + { + switch (cfm->peerAddrTbl.netAddr[i].type) + { + case CM_NETADDR_IPV4: + { + len = len + sprintf(prntBuf+len, "%lu\n", (unsigned long) + (cfm->peerAddrTbl.netAddr[i].u.ipv4NetAddr)); + break; + } + case CM_NETADDR_IPV6: + { + char ipv6_buf[128]; + int len1= 0; + int j = 0; + memset(&ipv6_buf[0], 0, sizeof(ipv6_buf)); + len1 = len1 + sprintf(ipv6_buf+len1, "IP V6 address : %2x", (unsigned int) + (cfm->peerAddrTbl.netAddr[i].u.ipv6NetAddr[0])); + + for (j = 1; j < CM_IPV6ADDR_SIZE; j++) + { + len1 = len1 + sprintf(ipv6_buf+len1, ":%2x", (unsigned int) + (cfm->peerAddrTbl.netAddr[i].u.ipv6NetAddr[j])); + } + len1 = len1 + sprintf(ipv6_buf+len1, "\n"); + len = len + sprintf(prntBuf+len, "%s\n", ipv6_buf); + break; + } + default: + { + len = len + sprintf(prntBuf+len, " Invalid address type[%d]\n", cfm->peerAddrTbl.netAddr[i].type); + break; + } + } + } /* End of for */ + + len = len + sprintf(prntBuf+len," %lu \n",(unsigned long)(cfm->numPendOgTxn)); + len = len + sprintf(prntBuf+len," %lu \n",(unsigned long)(cfm->numPendIcTxn)); + len = len + sprintf(prntBuf+len," %lu \n",(unsigned long)(cfm->rttEstimate)); + + switch(cfm->protocol) + { + case LMG_PROTOCOL_MGCP: + len = len + sprintf(prntBuf+len," MGCP \n"); + break; + + case LMG_PROTOCOL_MGCO: + len = len + sprintf(prntBuf+len," MEGACO \n"); + break; + + case LMG_PROTOCOL_NONE: + len = len + sprintf(prntBuf+len," MGCP/MEGACO \n"); + break; + + default: + len = len + sprintf(prntBuf+len," invalid \n"); + break; + } + + switch(cfm->transportType) + { + case LMG_TPT_UDP: + len = len + sprintf(prntBuf+len, "UDP\n"); + break; + + case LMG_TPT_TCP: + len = len + sprintf(prntBuf+len, "TCP\n"); + break; + + case LMG_TPT_NONE: + len = len + sprintf(prntBuf+len, "UDP/TCP\n"); + break; + + default: + len = len + sprintf(prntBuf+len, "invalid\n"); + break; + } +#ifdef GCP_MGCO + switch(cfm->encodingScheme) + { + case LMG_ENCODE_BIN: + len = len + sprintf(prntBuf+len, "BINARY\n"); + break; + + case LMG_ENCODE_TXT: + len = len + sprintf(prntBuf+len, "TEXT\n"); + break; + + case LMG_ENCODE_NONE: + len = len + sprintf(prntBuf+len, "TEXT/BINARY\n"); + break; + + default: + len = len + sprintf(prntBuf+len, "invalid\n"); + break; + } + + if(LMG_VER_PROF_MGCO_H248_1_0 == cfm->version){ + len = len + sprintf(prntBuf+len, "1.0 \n"); + } else if(LMG_VER_PROF_MGCO_H248_2_0 == cfm->version){ + len = len + sprintf(prntBuf+len, "2.0 \n"); + }else if(LMG_VER_PROF_MGCO_H248_3_0 == cfm->version){ + len = len + sprintf(prntBuf+len, "3.0 \n"); + } else{ + len = len + sprintf(prntBuf+len, "invalid \n"); + } +#endif + +} diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.h b/src/mod/endpoints/mod_megaco/megaco_stack.h index d8a1b55e47..8e1bc12bc1 100644 --- a/src/mod/endpoints/mod_megaco/megaco_stack.h +++ b/src/mod/endpoints/mod_megaco/megaco_stack.h @@ -114,6 +114,7 @@ switch_status_t sng_mgco_stop(const char* profilename); switch_status_t sng_mgco_stack_shutdown(void); int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, int mg_cfg_idx); switch_status_t megaco_profile_status(switch_stream_handle_t *stream, const char* profilename); +switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const char* profilename); /*****************************************************************************************************/ diff --git a/src/mod/endpoints/mod_megaco/megaco_xml.c b/src/mod/endpoints/mod_megaco/megaco_xml.c index a886546b9b..23ff23468d 100644 --- a/src/mod/endpoints/mod_megaco/megaco_xml.c +++ b/src/mod/endpoints/mod_megaco/megaco_xml.c @@ -225,6 +225,8 @@ switch_status_t sng_parse_mg_peer_profile(switch_xml_t mg_peer_profile) } } + strcpy((char*)&megaco_globals.g_mg_cfg.mgPeer.peers[i].name[0], prof_name); + megaco_globals.g_mg_cfg.mgPeer.total_peer++; return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.c b/src/mod/endpoints/mod_megaco/mod_megaco.c index 7bc6320df9..f8fa65a8ee 100644 --- a/src/mod/endpoints/mod_megaco/mod_megaco.c +++ b/src/mod/endpoints/mod_megaco/mod_megaco.c @@ -16,7 +16,7 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_megaco_shutdown); SWITCH_MODULE_DEFINITION(mod_megaco, mod_megaco_load, mod_megaco_shutdown, NULL); -#define MEGACO_FUNCTION_SYNTAX "profile [name] [start | stop] [status]" +#define MEGACO_FUNCTION_SYNTAX "profile [name] [start | stop] [status] [xmlstatus]" SWITCH_STANDARD_API(megaco_function) { int argc; @@ -63,7 +63,15 @@ SWITCH_STANDARD_API(megaco_function) } else { stream->write_function(stream, "-ERR No such profile\n"); } + }else if(!strcmp(argv[2], "xmlstatus")) { + megaco_profile_t *profile = megaco_profile_locate(argv[1]); + if (profile) { + megaco_profile_xmlstatus(stream, profile->name); + } else { + stream->write_function(stream, "-ERR No such profile\n"); + } } + } goto done; @@ -123,6 +131,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_megaco_load) switch_console_set_complete("add megaco profile ::megaco::list_profiles start"); switch_console_set_complete("add megaco profile ::megaco::list_profiles stop"); switch_console_set_complete("add megaco profile ::megaco::list_profiles status"); + switch_console_set_complete("add megaco profile ::megaco::list_profiles xmlstatus"); switch_console_add_complete_func("::megaco::list_profiles", list_profiles); From d914d99abe39f813d7dc6525d083aea7d314c820 Mon Sep 17 00:00:00 2001 From: kapil Date: Mon, 4 Jun 2012 17:29:07 +0530 Subject: [PATCH 212/822] fixing typo error --- src/mod/endpoints/mod_megaco/megaco_stack.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.c b/src/mod/endpoints/mod_megaco/megaco_stack.c index f3a2015016..5036797ddb 100644 --- a/src/mod/endpoints/mod_megaco/megaco_stack.c +++ b/src/mod/endpoints/mod_megaco/megaco_stack.c @@ -1877,10 +1877,10 @@ switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const c len = len + sprintf(prntBuf+len, " %s \n", PRNT_SAP_STATE((int)(cfm.t.ssta.s.mgSSAPSta.state))); len = len + sprintf(prntBuf+len, " %u \n", (unsigned int)(cfm.t.ssta.s.mgSSAPSta.numAssocPeer)); len = len + sprintf(prntBuf+len, " %u \n", (unsigned int)(cfm.t.ssta.s.mgSSAPSta.numServers)); - len = len + sprintf(&prntBuf[0] + len,"\n"); + len = len + sprintf(&prntBuf[0] + len,"\n"); for (i = 0; i < cfm.t.ssta.s.mgSSAPSta.numAssocPeer; i++) { - len = len + sprintf(&prntBuf[0] + len,"\n"); + len = len + sprintf(&prntBuf[0] + len,"\n"); if(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].dname.namePres.pres == PRSNT_NODEF) { len = len + sprintf(prntBuf+len, " %s \n", (char *)(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].dname.name)); @@ -1903,9 +1903,9 @@ switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const c len = len + sprintf(prntBuf+len, " %s \n", (char *)(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].mid.val)); } #endif /* GCP_MGCO */ - len = len + sprintf(&prntBuf[0] + len,"\n"); + len = len + sprintf(&prntBuf[0] + len,"\n"); } - len = len + sprintf(&prntBuf[0] + len,"\n"); + len = len + sprintf(&prntBuf[0] + len,"\n"); len = len + sprintf(&prntBuf[0] + len,"\n"); From 67373e787dff34a649163b9d258047956637a377 Mon Sep 17 00:00:00 2001 From: kapil Date: Mon, 4 Jun 2012 22:48:12 +0530 Subject: [PATCH 213/822] fixing ip address cli print --- src/mod/endpoints/mod_megaco/megaco_stack.c | 22 ++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.c b/src/mod/endpoints/mod_megaco/megaco_stack.c index 5036797ddb..74874e75d5 100644 --- a/src/mod/endpoints/mod_megaco/megaco_stack.c +++ b/src/mod/endpoints/mod_megaco/megaco_stack.c @@ -1205,7 +1205,7 @@ void handle_mg_alarm(Pst *pst, MgMngmt *usta) { U16 ret; int len = 0x00; - char prBuf[10024]; + char prBuf[3048]; memset(&prBuf[0], 0, sizeof(prBuf)); @@ -1826,6 +1826,8 @@ switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const c sng_mg_cfg_t* mgCfg = NULL; sng_mg_peer_t* mgPeer = NULL; int i = 0x00; + char *asciiAddr; + CmInetIpAddr ip; switch_assert(profilename); @@ -1845,7 +1847,6 @@ switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const c len = len + sprintf(&prntBuf[0] + len,"%s\n",xmlhdr); - len = len + sprintf(&prntBuf[0] + len,"\n"); len = len + sprintf(&prntBuf[0] + len,"%s\n",mgCfg->name); len = len + sprintf(&prntBuf[0] + len,"%s\n",profilename); @@ -1889,7 +1890,9 @@ switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const c { case CM_NETADDR_IPV4: { - len = len + sprintf(prntBuf+len, "%lu\n", (long unsigned int)(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].dname.netAddr.u.ipv4NetAddr)); + ip = ntohl(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].dname.netAddr.u.ipv4NetAddr); + cmInetNtoa(ip, &asciiAddr); + len = len + sprintf(prntBuf+len, "%s\n",asciiAddr); break; } default: @@ -1939,8 +1942,9 @@ switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const c } case CM_TPTADDR_IPV4: { - len = len + sprintf(prntBuf+len, "IPv4 IP address #%lu, port %u", - (unsigned long)(cfm.t.ssta.s.mgTptSrvSta.tptAddr.u.ipv4TptAddr.address), + ip = ntohl(cfm.t.ssta.s.mgTptSrvSta.tptAddr.u.ipv4TptAddr.address); + cmInetNtoa(ip, &asciiAddr); + len = len + sprintf(prntBuf+len, "IPv4 IP address #%s, port %u",asciiAddr, (unsigned int)(cfm.t.ssta.s.mgTptSrvSta.tptAddr.u.ipv4TptAddr.port)); break; @@ -1967,6 +1971,9 @@ void get_peer_xml_buffer(char* prntBuf, MgPeerSta* cfm) { int len = 0x00; int i = 0x00; + char *asciiAddr; + CmInetIpAddr ip; + if(PRSNT_NODEF == cfm->namePres.pres) { len = len + sprintf(prntBuf+len, " %s \n", (char *)(cfm->name)); @@ -1985,8 +1992,9 @@ void get_peer_xml_buffer(char* prntBuf, MgPeerSta* cfm) { case CM_NETADDR_IPV4: { - len = len + sprintf(prntBuf+len, "%lu\n", (unsigned long) - (cfm->peerAddrTbl.netAddr[i].u.ipv4NetAddr)); + ip = ntohl(cfm->peerAddrTbl.netAddr[i].u.ipv4NetAddr); + cmInetNtoa(ip, &asciiAddr); + len = len + sprintf(prntBuf+len, "%s\n",asciiAddr); break; } case CM_NETADDR_IPV6: From 117cbc1bf5e157982f6dc9d304f287e3b24b9d2f Mon Sep 17 00:00:00 2001 From: kapil Date: Mon, 4 Jun 2012 22:52:26 +0530 Subject: [PATCH 214/822] adding SCTP status CLI command --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 255 +++++++++++++++- .../ftmod_sangoma_ss7_m2ua.c | 283 +++++++++++++++--- .../ftmod_sangoma_ss7_m2ua.h | 15 +- .../ftmod_sangoma_ss7_m2ua_xml.c | 19 ++ .../ftmod_sangoma_ss7_main.h | 13 + 5 files changed, 536 insertions(+), 49 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index df872b260c..cfcfafac7b 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -119,6 +119,9 @@ static ftdm_status_t cli_ss7_show_all_channels_of_span(ftdm_stream_handle_t *str static ftdm_status_t cli_ss7_show_span_by_id(ftdm_stream_handle_t *stream, char *span_id); static ftdm_status_t cli_ss7_show_all_spans_general(ftdm_stream_handle_t *stream); static ftdm_status_t cli_ss7_show_all_spans_detail(ftdm_stream_handle_t *stream); +static ftdm_status_t handle_show_sctp(ftdm_stream_handle_t *stream); +static ftdm_status_t handle_show_m2ua(ftdm_stream_handle_t *stream); +int get_assoc_resp_buf(char* buf,SbMgmt* cfm); /******************************************************************************/ /* FUNCTIONS ******************************************************************/ @@ -383,6 +386,15 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha } else if (!strcasecmp(argv[c], "procid")) { /**********************************************************************/ handle_show_procId(stream); + + /**********************************************************************/ + } else if (!strcasecmp(argv[c], "m2ua")) { + /**********************************************************************/ + handle_show_m2ua(stream); + /**********************************************************************/ + } else if (!strcasecmp(argv[c], "sctp")) { + /**********************************************************************/ + handle_show_sctp(stream); /**********************************************************************/ } else { /**********************************************************************/ @@ -831,6 +843,13 @@ static ftdm_status_t handle_print_usage(ftdm_stream_handle_t *stream) stream->write_function(stream, "ftdm ss7 show relay\n"); stream->write_function(stream, "\n"); + stream->write_function(stream, "ftmod_sangoma_ss7 M2UA status:\n"); + stream->write_function(stream, "ftdm ss7 show sctp \n"); + stream->write_function(stream, "ftdm ss7 show sctp \n"); + stream->write_function(stream, "ftdm ss7 show m2ua \n"); + stream->write_function(stream, "ftdm ss7 show m2ua \n"); + stream->write_function(stream, "\n"); + stream->write_function(stream, "\n"); return FTDM_SUCCESS; @@ -2717,20 +2736,22 @@ static ftdm_status_t cli_ss7_show_general(ftdm_stream_handle_t *stream) stream->write_function(stream, "MTP2 status: \n"); cli_ss7_show_all_mtp2link(stream); - stream->write_function(stream, "\nMTP3 status: \n"); - cli_ss7_show_all_mtp3link(stream); + if(SNG_SS7_OPR_MODE_M2UA_SG != g_ftdm_operating_mode){ + stream->write_function(stream, "\nMTP3 status: \n"); + cli_ss7_show_all_mtp3link(stream); - stream->write_function(stream, "\nMTP3 linkset status: \n"); - cli_ss7_show_all_linkset(stream); + stream->write_function(stream, "\nMTP3 linkset status: \n"); + cli_ss7_show_all_linkset(stream); #if 0 - stream->write_function(stream, "\nMTP3 link route status: \n"); + stream->write_function(stream, "\nMTP3 link route status: \n"); - stream->write_function(stream, "\nISUP status: \n"); + stream->write_function(stream, "\nISUP status: \n"); #endif - stream->write_function(stream, "\nRelay status: \n"); - cli_ss7_show_all_relay(stream); + stream->write_function(stream, "\nRelay status: \n"); + cli_ss7_show_all_relay(stream); + } return FTDM_SUCCESS; } @@ -2947,6 +2968,224 @@ static ftdm_status_t cli_ss7_show_all_spans_general(ftdm_stream_handle_t *stream return FTDM_FAIL; } +/******************************************************************************/ +static ftdm_status_t handle_show_m2ua(ftdm_stream_handle_t *stream) +{ + /*char* xmlhdr = "";*/ + + /*iterate through all the m2ua links and prints all information */ + + return FTDM_FAIL; + +} +/******************************************************************************/ +static ftdm_status_t handle_show_sctp(ftdm_stream_handle_t *stream) +{ + char* xmlhdr = (char*)""; + char buf[2048]; + int x = 0x00; + int len = 0x00; + SbMgmt cfm; + + memset((U8 *)&cfm, 0, sizeof(SbMgmt)); + memset(&buf[0], 0, sizeof(buf)); + + len = len + sprintf(buf + len, "%s\n", xmlhdr); + len = len + sprintf(buf + len, "\n"); + + if(ftmod_sctp_ssta_req(STSBGEN, 0x00, &cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memSize); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memAlloc); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbAssoc); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbEndp); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbLocalAddr); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbPeerAddr); + len = len + sprintf(buf + len, "\n"); + } + +#ifdef LSB12 + if(ftmod_sctp_ssta_req(STSBTMR, 0x00, &cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.lifetimeTmr); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.ackDelayTmr); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.cookieTmr); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.keyTmr); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.freezeTmr); +#ifdef LSB4 + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.bundleTmr); +#endif + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.t1InitTmr); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.t2ShutdownTmr); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.hbeat); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.t3rtx); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.tIntTmr); + } + +#endif + + + /*iterate through all the sctp links and prints all information */ + x = 1; + while(x\n"); + + if(ftmod_sctp_ssta_req(STSBSCTSAP,x,&cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_SCTP_SAP_STATE(cfm.t.ssta.s.sapSta.hlSt)); + len = len + sprintf(buf + len," %s \n", PRNT_SCTP_PROTO_SWITCH(cfm.t.ssta.s.sapSta.swtch)); + len = len + sprintf(buf + len, "\n"); + } + + if(ftmod_sctp_ssta_req(STSBTSAP,x,&cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_SCTP_SAP_STATE(cfm.t.ssta.s.sapSta.hlSt)); + len = len + sprintf(buf + len," %s \n", PRNT_SCTP_PROTO_SWITCH(cfm.t.ssta.s.sapSta.swtch)); + len = len + sprintf(buf + len, "\n"); + } + + if(ftmod_sctp_ssta_req(STSBASSOC,x,&cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + get_assoc_resp_buf(buf + len, &cfm); + len = len + sprintf(buf + len, "\n"); + } + + /* TODO - STSBDTA */ + + len = len + sprintf(buf + len, "\n"); + } + x++; + } + + len = len + sprintf(buf + len, "\n"); + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_FAIL; +} + +int get_assoc_resp_buf(char* buf,SbMgmt* cfm) +{ + int len = 0x00; + int idx = 0x00; + char *asciiAddr; + CmInetIpAddr ip; + + len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.assocId); + len = len + sprintf(buf + len, " %s \n", PRNT_SCTP_ASSOC_STATE(cfm->t.ssta.s.assocSta.assocState)); + len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.dstPort); + len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.srcPort); + len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.dstNAddrLst.nmb); + for(idx =0; idx < cfm->t.ssta.s.assocSta.dstNAddrLst.nmb; idx++) + { + len = len + sprintf(buf + len, " \n"); + len = len + sprintf(buf + len, " %s \n", PRNT_CM_ADDR_TYPE(cfm->t.ssta.s.assocSta.dstNAddrLst.nAddr[idx].type)); + if(cfm->t.ssta.s.assocSta.dstNAddrLst.nAddr[idx].type == CM_IPV4ADDR_TYPE) + { + ip = ntohl(cfm->t.ssta.s.assocSta.dstNAddrLst.nAddr[idx].u.ipv4NetAddr); + cmInetNtoa(ip, &asciiAddr); + len = len + sprintf(buf + len, " %s \n",asciiAddr); + } + else + { + len = len + sprintf(buf + len, " %s \n", cfm->t.ssta.s.assocSta.dstNAddrLst.nAddr[idx].u.ipv6NetAddr); + } + len = len + sprintf(buf + len, " \n"); + } + + len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.srcNAddrLst.nmb); + for(idx =0; idx < cfm->t.ssta.s.assocSta.srcNAddrLst.nmb; idx++) + { + len = len + sprintf(buf + len, " \n"); + len = len + sprintf(buf + len, " %s \n", PRNT_CM_ADDR_TYPE(cfm->t.ssta.s.assocSta.srcNAddrLst.nAddr[idx].type)); + if(cfm->t.ssta.s.assocSta.srcNAddrLst.nAddr[idx].type == CM_IPV4ADDR_TYPE) + { + ip = ntohl(cfm->t.ssta.s.assocSta.srcNAddrLst.nAddr[idx].u.ipv4NetAddr); + cmInetNtoa(ip, &asciiAddr); + len = len + sprintf(buf + len, " %s \n", asciiAddr); + } + else + { + len = len + sprintf(buf + len, " %s \n", cfm->t.ssta.s.assocSta.srcNAddrLst.nAddr[idx].u.ipv6NetAddr); + } + len = len + sprintf(buf + len, " \n"); + } + + len = len + sprintf(buf + len, "\n %s \n", PRNT_CM_ADDR_TYPE(cfm->t.ssta.s.assocSta.priNAddr.type)); + + if(cfm->t.ssta.s.assocSta.priNAddr.type == CM_IPV4ADDR_TYPE) + { + ip = ntohl(cfm->t.ssta.s.assocSta.priNAddr.u.ipv4NetAddr); + cmInetNtoa(ip, &asciiAddr); + len = len + sprintf(buf + len, " %s \n",asciiAddr); + } + else + { + len = len + sprintf(buf + len, " %s \n", cfm->t.ssta.s.assocSta.priNAddr.u.ipv6NetAddr); + } + +#ifdef LSB11 + /* TODO - this flag is not enable as of now.. so later on will convert below prints to XML tags */ + len = len + sprintf(buf + len, " The number of unsent datagrams : %d\n", cfm->t.ssta.s.assocSta.nmbUnsentDgms); + len = len + sprintf(buf + len, " The number of unack datagrams : %d\n", cfm->t.ssta.s.assocSta.nmbUnackDgms); + len = len + sprintf(buf + len, " The number of undelivered datagrams : %d\n", cfm->t.ssta.s.assocSta.nmbUndelDgms); + len = len + sprintf(buf + len, " The number of retransmissions count : %d\n", cfm->t.ssta.s.assocSta.rtxCnt); + len = len + sprintf(buf + len, " The receive window size is: %d\n\n", cfm->t.ssta.s.assocSta.SctWinSize); + for(idx =0; idx < LSB_MAX_TMRS ; idx++) + { + len = len + sprintf(buf + len, " %d) Timer state is %d\n", idx, cfm->t.ssta.s.assocSta.tmr[idx].state); + len = len + sprintf(buf + len, " %d) Timer value is %d\n", idx, cfm->t.ssta.s.assocSta.tmr[idx].tmrVal); + len = len + sprintf(buf + len, " %d) No of paths is %d\n", idx, cfm->t.ssta.s.assocSta.tmr[idx].numPaths); + for(idx1 =0; idx1 < cfm->t.ssta.s.assocSta.tmr[idx].numPaths; idx1++) + { + if( cfm->t.ssta.s.assocSta.tmr[idx].path[idx1].localAddr.type == CM_IPV4ADDR_TYPE) + { + len = len + sprintf(buf + len, " %d) the local Addr is %d\n", idx1, + cfm->t.ssta.s.assocSta.tmr[idx].path[idx1].localAddr.u.ipv4NetAddr); + } + else + { + len = len + sprintf(buf + len, " %d) the local Addr is %s\n", idx1, + cfm->t.ssta.s.assocSta.tmr[idx].path[idx1].localAddr.u.ipv6NetAddr); + } + + if( cfm->t.ssta.s.assocSta.tmr[idx].path[idx1].peerAddr.type == CM_IPV4ADDR_TYPE) + { + len = len + sprintf(buf + len, " %d) the peer Addr is %d\n", idx1, + cfm->t.ssta.s.assocSta.tmr[idx].path[idx1].peerAddr.u.ipv4NetAddr); + } + else + { + len = len + sprintf(buf + len, " %d) the peer Addr is %s\n", idx1, + cfm->t.ssta.s.assocSta.tmr[idx].path[idx1].peerAddr.u.ipv6NetAddr); + } + } /* Loop for paths */ + } /* Loop for timers */ +#endif + + return len; +} + +/******************************************************************************/ + /******************************************************************************/ /* For Emacs: * Local Variables: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c index 39e9bba658..9730bc2df2 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c @@ -60,6 +60,7 @@ static int ftmod_nif_dlsap_config(int idx); static int ftmod_sctp_tucl_tsap_bind(int idx); static int ftmod_m2ua_sctp_sctsap_bind(int idx); static int ftmod_open_endpoint(int idx); +static int ftmod_init_sctp_assoc(int peer_id); static int ftmod_nif_m2ua_dlsap_bind(int id); static int ftmod_nif_mtp2_dlsap_bind(int id); static int ftmod_m2ua_enable_debug(void); @@ -76,13 +77,18 @@ ftdm_status_t sng_m2ua_cfg(void); /******************************************************************************/ void ftmod_ss7_m2ua_free() { - ftmod_ss7_m2ua_shutdown(); - ftmod_ss7_sctp_shutdown(); - ftmod_ss7_tucl_shutdown(); - - sng_isup_free_m2ua(); - sng_isup_free_sctp(); - sng_isup_free_tucl(); + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_M2UA_STARTED)) { + ftmod_ss7_m2ua_shutdown(); + sng_isup_free_m2ua(); + } + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_SCTP_STARTED)) { + ftmod_ss7_sctp_shutdown(); + sng_isup_free_sctp(); + } + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_TUCL_STARTED)) { + ftmod_ss7_tucl_shutdown(); + sng_isup_free_tucl(); + } } /******************************************************************************/ static int ftmod_ss7_tucl_shutdown() @@ -186,6 +192,12 @@ ftdm_status_t ftmod_ss7_m2ua_cfg(void) return FTDM_FAIL; } + /* SET STARTED FLAGS */ + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_NIF_STARTED); + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_M2UA_STARTED); + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_SCTP_STARTED); + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_TUCL_STARTED); + return FTDM_SUCCESS; } @@ -1145,8 +1157,10 @@ int ftmod_ss7_m2ua_start(void){ ftmod_tucl_enable_debug(); /***********************************************************************************************************************/ - for (x=1; g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[x].id !=0; x++) { - if (!(g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[x].flags & SNGSS7_CONFIGURED)) { + x = 1; + while(xid; /* M2UA sct sap Id */ + cntrl.t.cntrl.action = AMWENDPOPEN; + cntrl.t.cntrl.s.suId = m2ua->id; /* M2UA sct sap Id */ - return (sng_cntrl_m2ua (&pst, &cntrl)); + return (sng_cntrl_m2ua (&pst, &cntrl)); +} +/***********************************************************************************************************************/ +static int ftmod_init_sctp_assoc(int peer_id) +{ + + Pst pst; + MwMgmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(MwMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTMW; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STMWPEER; /* General */ + cntrl.hdr.transId = 1; /* transaction identifier */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + + cntrl.t.cntrl.action = AMWESTABLISH; + /*cntrl.t.cntrl.s.suId = 1;*/ + + cntrl.t.cntrl.s.peerId = (MwPeerId) peer_id; + + return (sng_cntrl_m2ua (&pst, &cntrl)); } /***********************************************************************************************************************/ @@ -1474,3 +1554,132 @@ static int ftmod_tucl_enable_debug() return (sng_cntrl_tucl (&pst, &cntrl)); } /***********************************************************************************************************************/ + +/***********************************************************************************************************************/ +int ftmod_sctp_ssta_req(int elemt, int id, SbMgmt* cfm) +{ + SbMgmt ssta; + Pst pst; + sng_sctp_link_t *k = &g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[id]; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&ssta, 0, sizeof(SbMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTSB; + + /* prepare header */ + ssta.hdr.msgType = TSSTA; /* message type */ + ssta.hdr.entId.ent = ENTSB; /* entity */ + ssta.hdr.entId.inst = 0; /* instance */ + ssta.hdr.elmId.elmnt = elemt; /* STSBGEN */ /* Others are STSBTSAP, STSBSCTSAP, STSBASSOC, STSBDTA, STSBTMR */ + ssta.hdr.transId = 1; /* transaction identifier */ + + ssta.hdr.response.selector = 0; + ssta.hdr.response.prior = PRIOR0; + ssta.hdr.response.route = RTESPEC; + ssta.hdr.response.mem.region = S_REG; + ssta.hdr.response.mem.pool = S_POOL; + + if((ssta.hdr.elmId.elmnt == STSBSCTSAP) || (ssta.hdr.elmId.elmnt == STSBTSAP)) + { + ssta.t.ssta.sapId = k->id; /* SapId */ + } + if(ssta.hdr.elmId.elmnt == STSBASSOC) + { + ssta.t.ssta.s.assocSta.assocId = 0; /* association id */ + } + return(sng_sta_sctp(&pst,&ssta,cfm)); +} + +#if 0 +int ftmod_m2ua_ssta_req(int elemt) +{ + MwMgmt ssta; + MwMgmt cfm; + Pst pst; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&ssta, 0, sizeof(MwMgmt)); + memset((U8 *)&cfm, 0, sizeof(MwMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + ssta.hdr.msgType = TSSTA; /* message type */ + ssta.hdr.entId.ent = ENTMW; /* entity */ + ssta.hdr.entId.inst = 0; /* instance */ + ssta.hdr.elmId.elmnt = elemt; /*STMWGEN */ /* Others are STMWSCTSAP, STMWCLUSTER, STMWPEER,STMWSID, STMWDLSAP */ + ssta.hdr.transId = 1; /* transaction identifier */ + + ssta.hdr.response.selector = 0; + ssta.hdr.response.prior = PRIOR0; + ssta.hdr.response.route = RTESPEC; + ssta.hdr.response.mem.region = S_REG; + ssta.hdr.response.mem.pool = S_POOL; + + switch(ssta.hdr.elmId.elmnt) + { + case STMWSCTSAP: + { + ssta.t.ssta.id.suId = 0 ; /* lower sap Id */ + break; + } + case STMWDLSAP: + { + ssta.t.ssta.id.lnkNmb = 0 ; /* upper sap Id */ + break; + } + case STMWPEER: + { + ssta.t.ssta.id.peerId = 1 ; /* peer Id */ + break; + } + case STMWCLUSTER: + { + ssta.t.ssta.id.clusterId = 1 ; /* cluster Id */ + break; + } + default: + break; + } + + return(sng_sta_m2ua(&pst,&ssta,&cfm)); +} + +int ftmod_nif_ssta_req(int elemt) +{ + NwMgmt ssta; + NwMgmt cfm; + Pst pst; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&ssta, 0, sizeof(NwMgmt)); + memset((U8 *)&cfm, 0, sizeof(NwMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTNW; + + /* prepare header */ + ssta.hdr.msgType = TSSTA; /* message type */ + ssta.hdr.entId.ent = ENTNW; /* entity */ + ssta.hdr.entId.inst = 0; /* instance */ + + ssta.hdr.response.selector = 0; + ssta.hdr.response.prior = PRIOR0; + ssta.hdr.response.route = RTESPEC; + ssta.hdr.response.mem.region = S_REG; + ssta.hdr.response.mem.pool = S_POOL; + + if(ssta.hdr.elmId.elmnt == STNWDLSAP) + { + ssta.t.ssta.suId = 0; /* Lower sapId */ + } + + return(sng_sta_nif(&pst,&ssta,&cfm)); +} +#endif diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h index a988b9c8db..a14db63189 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h @@ -75,6 +75,7 @@ typedef struct sng_m2ua_peer_cfg{ uint16_t sctpId; /* idx to sctp profile */ uint32_t destAddrList[SCT_MAX_NET_ADDRS+1]; /* Destination adddress list */ uint16_t locOutStrms; /*Number of outgoing streams supported by this association*/ + int init_sctp_assoc; /* flag to tell if we need to initiate SCTP association */ }sng_m2ua_peer_cfg_t; typedef enum{ @@ -103,10 +104,10 @@ typedef struct sng_m2ua_cluster_cfg{ }sng_m2ua_cluster_cfg_t; typedef struct sng_m2ua_gbl_cfg{ - sng_nif_cfg_t nif[MW_MAX_NUM_OF_INTF]; - sng_m2ua_cfg_t m2ua[MW_MAX_NUM_OF_INTF]; - sng_m2ua_peer_cfg_t m2ua_peer[MW_MAX_NUM_OF_PEER]; - sng_m2ua_cluster_cfg_t m2ua_clus[MW_MAX_NUM_OF_CLUSTER]; + sng_nif_cfg_t nif[MW_MAX_NUM_OF_INTF+1]; + sng_m2ua_cfg_t m2ua[MW_MAX_NUM_OF_INTF+1]; + sng_m2ua_peer_cfg_t m2ua_peer[MW_MAX_NUM_OF_PEER+1]; + sng_m2ua_cluster_cfg_t m2ua_clus[MW_MAX_NUM_OF_CLUSTER+1]; }sng_m2ua_gbl_cfg_t; /* m2ua xml parsing APIs */ @@ -122,5 +123,11 @@ void ftmod_ss7_m2ua_free(void); ftdm_status_t ftmod_ss7_m2ua_cfg(void); +int ftmod_sctp_ssta_req(int elemt, int id, SbMgmt* cfm); +#if 0 +int ftmod_m2ua_ssta_req(int elemt); +int ftmod_nif_ssta_req(int elemt); +#endif + #endif /*__FTMOD_SNG_SS7_M2UA_H__*/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c index 9d47a33dbb..a3785cc01d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c @@ -165,6 +165,8 @@ static int ftmod_ss7_fill_in_nif_interface(sng_nif_cfg_t *nif_iface) g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[i].m2uaLnkNmb = nif_iface->m2uaLnkNmb; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[i].mtp2LnkNmb = nif_iface->mtp2LnkNmb; + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_NIF_PRESENT); + return 0; } @@ -300,6 +302,7 @@ static int ftmod_ss7_fill_in_m2ua_interface(sng_m2ua_cfg_t *m2ua_iface) g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].sctpId = m2ua_iface->sctpId; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].peerId = m2ua_iface->peerId; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].clusterId = m2ua_iface->clusterId; + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_M2UA_PRESENT); return 0; } @@ -413,6 +416,19 @@ static int ftmod_ss7_parse_m2ua_peer_interface(ftdm_conf_node_t *m2ua_peer_inter SS7_DEBUG("Found an sng_m2ua_peer loc_out_strms = %d\n", sng_m2ua_peer.locOutStrms); /**********************************************************************/ + } else if (!strcasecmp(parm->var, "init_sctp_assoc")) { + /**********************************************************************/ + if(!strcasecmp(parm->val, "TRUE")){ + sng_m2ua_peer.init_sctp_assoc = 0x01; + } else if(!strcasecmp(parm->val, "FALSE")){ + sng_m2ua_peer.init_sctp_assoc = 0x00; + } else { + SS7_ERROR("Found an invalid init_sctp_assoc Parameter Value[%s]\n", parm->val); + return FTDM_FAIL; + } + + SS7_DEBUG("Found an sng_m2ua_peer init_sctp_assoc = %d\n", sng_m2ua_peer.init_sctp_assoc); + /**********************************************************************/ } else { /**********************************************************************/ SS7_ERROR("Found an invalid parameter %s!\n", parm->var); @@ -447,6 +463,7 @@ static int ftmod_ss7_fill_in_m2ua_peer_interface(sng_m2ua_peer_cfg_t *m2ua_peer_ g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].locOutStrms = m2ua_peer_iface->locOutStrms; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].numDestAddr = m2ua_peer_iface->numDestAddr; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].sctpId = m2ua_peer_iface->sctpId; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].init_sctp_assoc = m2ua_peer_iface->init_sctp_assoc; for (k=0; knumDestAddr; k++) { g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].destAddrList[k] = m2ua_peer_iface->destAddrList[k]; } @@ -687,6 +704,8 @@ static int ftmod_ss7_parse_sctp_link(ftdm_conf_node_t *node) for (i=1; i<=t_link.numSrcAddr; i++) { g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].srcAddrList[i] = t_link.srcAddrList[i]; } + + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_SCTP_PRESENT); return FTDM_SUCCESS; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index fc6a6e61b5..90fb3e5b7f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -758,6 +758,19 @@ typedef enum { SNGSS7_CC_PRESENT = (1 << 12), SNGSS7_CC_STARTED = (1 << 13), + + SNGSS7_TUCL_PRESENT = (1 << 14), + SNGSS7_TUCL_STARTED = (1 << 15), + + SNGSS7_SCTP_PRESENT = (1 << 16), + SNGSS7_SCTP_STARTED = (1 << 17), + + SNGSS7_M2UA_PRESENT = (1 << 18), + SNGSS7_M2UA_STARTED = (1 << 19), + + SNGSS7_NIF_PRESENT = (1 << 20), + SNGSS7_NIF_STARTED = (1 << 21), + } sng_task_flag_t; /******************************************************************************/ From 2b5875a2586e787159bc26733f213d5b7a188bc1 Mon Sep 17 00:00:00 2001 From: kapil Date: Tue, 5 Jun 2012 17:12:16 +0530 Subject: [PATCH 215/822] adding M2UA/NIF CLI commands --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 430 +++++++++++++++++- .../ftmod_sangoma_ss7_m2ua.c | 99 ++-- .../ftmod_sangoma_ss7_m2ua.h | 6 +- 3 files changed, 472 insertions(+), 63 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index cfcfafac7b..f4399d708d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -119,8 +119,12 @@ static ftdm_status_t cli_ss7_show_all_channels_of_span(ftdm_stream_handle_t *str static ftdm_status_t cli_ss7_show_span_by_id(ftdm_stream_handle_t *stream, char *span_id); static ftdm_status_t cli_ss7_show_all_spans_general(ftdm_stream_handle_t *stream); static ftdm_status_t cli_ss7_show_all_spans_detail(ftdm_stream_handle_t *stream); -static ftdm_status_t handle_show_sctp(ftdm_stream_handle_t *stream); -static ftdm_status_t handle_show_m2ua(ftdm_stream_handle_t *stream); +static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream); +static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char* sctp_profile_name); +static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream); +static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char* m2ua_profile_name); +static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream); +static ftdm_status_t handle_show_nif_profile(ftdm_stream_handle_t *stream, char* profile_name); int get_assoc_resp_buf(char* buf,SbMgmt* cfm); /******************************************************************************/ @@ -390,11 +394,30 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha /**********************************************************************/ } else if (!strcasecmp(argv[c], "m2ua")) { /**********************************************************************/ - handle_show_m2ua(stream); + if (check_arg_count(argc, 3)){ + handle_show_m2ua_profiles(stream); + }else{ + c++; + handle_show_m2ua_profile(stream, argv[c]); + } + /**********************************************************************/ + } else if (!strcasecmp(argv[c], "nif")) { + /**********************************************************************/ + if (check_arg_count(argc, 3)){ + handle_show_nif_profiles(stream); + }else{ + c++; + handle_show_nif_profile(stream, argv[c]); + } /**********************************************************************/ } else if (!strcasecmp(argv[c], "sctp")) { /**********************************************************************/ - handle_show_sctp(stream); + if (check_arg_count(argc, 3)){ + handle_show_sctp_profiles(stream); + }else{ + c++; + handle_show_sctp_profile(stream, argv[c]); + } /**********************************************************************/ } else { /**********************************************************************/ @@ -845,9 +868,11 @@ static ftdm_status_t handle_print_usage(ftdm_stream_handle_t *stream) stream->write_function(stream, "ftmod_sangoma_ss7 M2UA status:\n"); stream->write_function(stream, "ftdm ss7 show sctp \n"); - stream->write_function(stream, "ftdm ss7 show sctp \n"); + stream->write_function(stream, "ftdm ss7 show sctp \n"); stream->write_function(stream, "ftdm ss7 show m2ua \n"); - stream->write_function(stream, "ftdm ss7 show m2ua \n"); + stream->write_function(stream, "ftdm ss7 show m2ua \n"); + stream->write_function(stream, "ftdm ss7 show nif \n"); + stream->write_function(stream, "ftdm ss7 show nif \n"); stream->write_function(stream, "\n"); stream->write_function(stream, "\n"); @@ -2969,17 +2994,222 @@ static ftdm_status_t cli_ss7_show_all_spans_general(ftdm_stream_handle_t *stream } /******************************************************************************/ -static ftdm_status_t handle_show_m2ua(ftdm_stream_handle_t *stream) +static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) { - /*char* xmlhdr = "";*/ + char* xmlhdr = (char*)""; + char buf[2048]; + int x = 0x00; + int idx = 0x00; + int len = 0x00; + MwMgmt cfm; + + memset((U8 *)&cfm, 0, sizeof(MwMgmt)); + memset(&buf[0], 0, sizeof(buf)); + + len = len + sprintf(buf + len, "%s\n", xmlhdr); + len = len + sprintf(buf + len, "\n"); + + if(ftmod_m2ua_ssta_req(STMWGEN, 0x00, &cfm)) { + stream->write_function(stream," Request to Trillium M2UA layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memSize); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memAlloc); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbClusters); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbPeers); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbIntf); + len = len + sprintf(buf + len, "\n"); + } /*iterate through all the m2ua links and prints all information */ + x = 1; + while(x\n"); + + if(ftmod_m2ua_ssta_req(STMWDLSAP,x,&cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.dlSapSta.state)); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_LINK_STATE(cfm.t.ssta.s.dlSapSta.lnkState)); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.rpoEnable); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.lpoEnable); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.congLevel); + len = len + sprintf(buf + len, "\n"); + } + + if(ftmod_m2ua_ssta_req(STMWCLUSTER,x,&cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_CLUSTER_STATE(cfm.t.ssta.s.clusterSta.state)); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.clusterSta.nmbPeer); + len = len + sprintf(buf + len, "\n"); + for(idx = 0; idx < cfm.t.ssta.s.clusterSta.nmbPeer; idx++) + { + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.clusterSta.peerSt[idx].peerId); + len = len + sprintf(buf + len, " %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.clusterSta.peerSt[idx].peerState)); + } + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.clusterSta.nmbActPeer); + + len = len + sprintf(buf + len, "\n"); + } + + if(ftmod_m2ua_ssta_req(STMWPEER,x,&cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.retryCount); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.spAssocId); + len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcInProg); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcLevel); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.sctpHBeatEnb); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.locOutStrms); + + len = len + sprintf(buf + len, "\n"); + } + + if(ftmod_m2ua_ssta_req(STMWSCTSAP,x,&cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.sctSapSta.state)); + len = len + sprintf(buf + len," %s \n", (cfm.t.ssta.s.sctSapSta.endpOpen)?"END_POINT_OPENED_SUCCESSFULLY":"END_POINT_NOT_OPEN"); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.spEndpId); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.nmbPrimRetry); + len = len + sprintf(buf + len, "\n"); + } + + len = len + sprintf(buf + len, "\n"); + } + x++; + } + + len = len + sprintf(buf + len, "\n"); + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_FAIL; + +} + +static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char* m2ua_profile_name) +{ + char* xmlhdr = (char*)""; + char buf[2048]; + int x = 0x00; + int idx = 0x00; + int found = 0x00; + int len = 0x00; + MwMgmt cfm; + + memset((U8 *)&cfm, 0, sizeof(MwMgmt)); + memset(&buf[0], 0, sizeof(buf)); + + len = len + sprintf(buf + len, "%s\n", xmlhdr); + + /*iterate through all the m2ua links and get required profile */ + x = 1; + while(xwrite_function(stream,"Requested M2UA profile[%s] not configured\n", m2ua_profile_name); + return FTDM_FAIL; + } + + + len = len + sprintf(buf + len, "\n"); + + if(ftmod_m2ua_ssta_req(STMWDLSAP,x,&cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.dlSapSta.state)); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_LINK_STATE(cfm.t.ssta.s.dlSapSta.lnkState)); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.rpoEnable); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.lpoEnable); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.congLevel); + len = len + sprintf(buf + len, "\n"); + } + + if(ftmod_m2ua_ssta_req(STMWCLUSTER,x,&cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_CLUSTER_STATE(cfm.t.ssta.s.clusterSta.state)); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.clusterSta.nmbPeer); + len = len + sprintf(buf + len, "\n"); + for(idx = 0; idx < cfm.t.ssta.s.clusterSta.nmbPeer; idx++) + { + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.clusterSta.peerSt[idx].peerId); + len = len + sprintf(buf + len, " %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.clusterSta.peerSt[idx].peerState)); + } + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.clusterSta.nmbActPeer); + + len = len + sprintf(buf + len, "\n"); + } + + if(ftmod_m2ua_ssta_req(STMWPEER,x,&cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.retryCount); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.spAssocId); + len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcInProg); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcLevel); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.sctpHBeatEnb); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.locOutStrms); + + len = len + sprintf(buf + len, "\n"); + } + + if(ftmod_m2ua_ssta_req(STMWSCTSAP,x,&cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.sctSapSta.state)); + len = len + sprintf(buf + len," %s \n", (cfm.t.ssta.s.sctSapSta.endpOpen)?"END_POINT_OPENED_SUCCESSFULLY":"END_POINT_NOT_OPEN"); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.spEndpId); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.nmbPrimRetry); + len = len + sprintf(buf + len, "\n"); + } + + len = len + sprintf(buf + len, "\n"); + + stream->write_function(stream,"\n%s\n",buf); return FTDM_FAIL; } /******************************************************************************/ -static ftdm_status_t handle_show_sctp(ftdm_stream_handle_t *stream) +static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream) { char* xmlhdr = (char*)""; char buf[2048]; @@ -3079,7 +3309,7 @@ static ftdm_status_t handle_show_sctp(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); stream->write_function(stream,"\n%s\n",buf); - return FTDM_FAIL; + return FTDM_SUCCESS; } int get_assoc_resp_buf(char* buf,SbMgmt* cfm) @@ -3184,6 +3414,186 @@ int get_assoc_resp_buf(char* buf,SbMgmt* cfm) return len; } + +static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char* sctp_profile_name) +{ + char* xmlhdr = (char*)""; + char buf[2048]; + int x = 0x00; + int len = 0x00; + SbMgmt cfm; + int found = 0x00; + + memset((U8 *)&cfm, 0, sizeof(SbMgmt)); + memset(&buf[0], 0, sizeof(buf)); + + len = len + sprintf(buf + len, "%s\n", xmlhdr); + + /*iterate through all the sctp links and prints all information */ + x = 1; + while(xwrite_function(stream,"Requested SCTP profile[%s] not configured\n", sctp_profile_name); + return FTDM_FAIL; + } + + len = len + sprintf(buf + len, "\n"); + + if(ftmod_sctp_ssta_req(STSBSCTSAP,x,&cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_SCTP_SAP_STATE(cfm.t.ssta.s.sapSta.hlSt)); + len = len + sprintf(buf + len," %s \n", PRNT_SCTP_PROTO_SWITCH(cfm.t.ssta.s.sapSta.swtch)); + len = len + sprintf(buf + len, "\n"); + } + + if(ftmod_sctp_ssta_req(STSBTSAP,x,&cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_SCTP_SAP_STATE(cfm.t.ssta.s.sapSta.hlSt)); + len = len + sprintf(buf + len," %s \n", PRNT_SCTP_PROTO_SWITCH(cfm.t.ssta.s.sapSta.swtch)); + len = len + sprintf(buf + len, "\n"); + } + + if(ftmod_sctp_ssta_req(STSBASSOC,x,&cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + get_assoc_resp_buf(buf + len, &cfm); + len = len + sprintf(buf + len, "\n"); + } + + /* TODO - STSBDTA */ + + len = len + sprintf(buf + len, "\n"); + + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_SUCCESS; +} + +static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream) +{ + char* xmlhdr = (char*)""; + char buf[2048]; + int x = 0x00; + int len = 0x00; + NwMgmt cfm; + + memset((U8 *)&cfm, 0, sizeof(NwMgmt)); + memset(&buf[0], 0, sizeof(buf)); + + len = len + sprintf(buf + len, "%s\n", xmlhdr); + len = len + sprintf(buf + len, "\n"); + + if(ftmod_nif_ssta_req(STNWGEN, 0x00, &cfm)) { + stream->write_function(stream," Request to Trillium NIF layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memSize); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memAlloc); + len = len + sprintf(buf + len, "\n"); + } + + /*iterate through all the NIF links and prints all information */ + x = 1; + while(x\n"); + + if(ftmod_nif_ssta_req(STNWDLSAP,x,&cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.m2uaState)); + len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.mtp2State)); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.nmbRetry); + len = len + sprintf(buf + len, "\n"); + } + + len = len + sprintf(buf + len, "\n"); + } + x++; + } + + len = len + sprintf(buf + len, "\n"); + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_FAIL; +} + +static ftdm_status_t handle_show_nif_profile(ftdm_stream_handle_t *stream, char* nif_profile_name) +{ + char* xmlhdr = (char*)""; + char buf[2048]; + int x = 0x00; + int found = 0x00; + int len = 0x00; + NwMgmt cfm; + + memset((U8 *)&cfm, 0, sizeof(NwMgmt)); + memset(&buf[0], 0, sizeof(buf)); + + len = len + sprintf(buf + len, "%s\n", xmlhdr); + + /*iterate through all the m2ua links and get required profile */ + x = 1; + while(xwrite_function(stream,"Requested NIF profile[%s] not configured\n", nif_profile_name); + return FTDM_FAIL; + } + + + len = len + sprintf(buf + len, "\n"); + + if(ftmod_nif_ssta_req(STNWDLSAP,x,&cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.m2uaState)); + len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.mtp2State)); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.nmbRetry); + len = len + sprintf(buf + len, "\n"); + } + + len = len + sprintf(buf + len, "\n"); + + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_FAIL; +} + /******************************************************************************/ /******************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c index 9730bc2df2..76db4d637e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c @@ -278,8 +278,10 @@ ftdm_status_t sng_m2ua_cfg(void) } /****************************************************************************************************/ /* M2UA SCTP SAP configurations */ - for (x=1; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].id !=0; x++) { - if (!(g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].flags & SNGSS7_CONFIGURED)) { + x = 1; + while(xclusterId]; + sng_m2ua_peer_cfg_t* peer = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[m2ua->peerId]; memset((U8 *)&pst, 0, sizeof(Pst)); memset((U8 *)&ssta, 0, sizeof(MwMgmt)); - memset((U8 *)&cfm, 0, sizeof(MwMgmt)); smPstInit(&pst); @@ -1625,40 +1631,39 @@ int ftmod_m2ua_ssta_req(int elemt) { case STMWSCTSAP: { - ssta.t.ssta.id.suId = 0 ; /* lower sap Id */ + ssta.t.ssta.id.suId = m2ua->id ; /* lower sap Id */ break; } case STMWDLSAP: { - ssta.t.ssta.id.lnkNmb = 0 ; /* upper sap Id */ + ssta.t.ssta.id.lnkNmb = id ; /* upper sap Id */ break; } case STMWPEER: { - ssta.t.ssta.id.peerId = 1 ; /* peer Id */ + ssta.t.ssta.id.peerId = peer->id ; /* peer Id */ break; } case STMWCLUSTER: { - ssta.t.ssta.id.clusterId = 1 ; /* cluster Id */ + ssta.t.ssta.id.clusterId = clust->id ; /* cluster Id */ break; } default: break; } - return(sng_sta_m2ua(&pst,&ssta,&cfm)); + return(sng_sta_m2ua(&pst,&ssta,cfm)); } -int ftmod_nif_ssta_req(int elemt) +int ftmod_nif_ssta_req(int elemt, int id, NwMgmt* cfm) { NwMgmt ssta; - NwMgmt cfm; Pst pst; + sng_nif_cfg_t* nif = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[id]; memset((U8 *)&pst, 0, sizeof(Pst)); memset((U8 *)&ssta, 0, sizeof(NwMgmt)); - memset((U8 *)&cfm, 0, sizeof(NwMgmt)); smPstInit(&pst); @@ -1668,18 +1673,14 @@ int ftmod_nif_ssta_req(int elemt) ssta.hdr.msgType = TSSTA; /* message type */ ssta.hdr.entId.ent = ENTNW; /* entity */ ssta.hdr.entId.inst = 0; /* instance */ + ssta.hdr.elmId.elmnt = elemt; ssta.hdr.response.selector = 0; ssta.hdr.response.prior = PRIOR0; ssta.hdr.response.route = RTESPEC; ssta.hdr.response.mem.region = S_REG; ssta.hdr.response.mem.pool = S_POOL; + ssta.t.ssta.suId = nif->id; /* Lower sapId */ - if(ssta.hdr.elmId.elmnt == STNWDLSAP) - { - ssta.t.ssta.suId = 0; /* Lower sapId */ - } - - return(sng_sta_nif(&pst,&ssta,&cfm)); + return(sng_sta_nif(&pst,&ssta,cfm)); } -#endif diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h index a14db63189..9e13b32e4b 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h @@ -124,10 +124,8 @@ void ftmod_ss7_m2ua_free(void); ftdm_status_t ftmod_ss7_m2ua_cfg(void); int ftmod_sctp_ssta_req(int elemt, int id, SbMgmt* cfm); -#if 0 -int ftmod_m2ua_ssta_req(int elemt); -int ftmod_nif_ssta_req(int elemt); -#endif +int ftmod_m2ua_ssta_req(int elemt, int id, MwMgmt* cfm); +int ftmod_nif_ssta_req(int elemt, int id, NwMgmt* cfm); #endif /*__FTMOD_SNG_SS7_M2UA_H__*/ From e4bd524b7d4a335854600ee6014846240336ae35 Mon Sep 17 00:00:00 2001 From: kapil Date: Tue, 5 Jun 2012 21:33:13 +0530 Subject: [PATCH 216/822] adding peerstatus and logging enable/disable CLI command --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 168 +++++++++++++++++- .../ftmod_sangoma_ss7_m2ua.c | 42 +++-- .../ftmod_sangoma_ss7_m2ua.h | 2 + 3 files changed, 188 insertions(+), 24 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index f4399d708d..bec6e020ac 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -123,6 +123,7 @@ static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream); static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char* sctp_profile_name); static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream); static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char* m2ua_profile_name); +static ftdm_status_t handle_show_m2ua_peer_status(ftdm_stream_handle_t *stream, char* m2ua_profile_name); static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream); static ftdm_status_t handle_show_nif_profile(ftdm_stream_handle_t *stream, char* profile_name); int get_assoc_resp_buf(char* buf,SbMgmt* cfm); @@ -394,12 +395,36 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha /**********************************************************************/ } else if (!strcasecmp(argv[c], "m2ua")) { /**********************************************************************/ - if (check_arg_count(argc, 3)){ - handle_show_m2ua_profiles(stream); - }else{ - c++; - handle_show_m2ua_profile(stream, argv[c]); + switch(argc) + { + case 2: /* show m2ua */ + { + handle_show_m2ua_profiles(stream); + break; + } + case 3: /* show m2ua */ + { + c++; + handle_show_m2ua_profile(stream, argv[c]); + break; + } + case 4: + { + char* profile_name = argv[++c]; + c++; + if(!strcasecmp(argv[c],"peerstatus")){ + handle_show_m2ua_peer_status(stream, profile_name); + } + else{ + stream->write_function(stream, "Unknown \"show m2ua \" command..\n"); + goto handle_cli_error_argc; + } + break; + } + default: + goto handle_cli_error_argc; } + /**********************************************************************/ } else if (!strcasecmp(argv[c], "nif")) { /**********************************************************************/ @@ -786,6 +811,28 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha /**********************************************************************/ } /**************************************************************************/ + } else if (!strcasecmp(argv[c], "m2ua")) { + /**************************************************************************/ + if (check_arg_count(argc, 3)) { + stream->write_function(stream, "Invalid \"m2ua option\", please use \"m2ua logging [enable|disable] \n"); + goto handle_cli_error_argc; + } + c++; + if(!strcasecmp(argv[c],"logging")){ + c++; + if(!strcasecmp(argv[c],"enable")){ + ftmod_ss7_enable_m2ua_sg_logging(); + }else if(!strcasecmp(argv[c],"disable")){ + ftmod_ss7_disable_m2ua_sg_logging(); + } else{ + stream->write_function(stream, "Unknown \"m2ua logging %s option\", supported values enable/disable\n",argv[c]); + goto handle_cli_error_argc; + } + }else{ + stream->write_function(stream, "Unknown \"m2ua %s option\", supported values \"logging\"\n",argv[c]); + goto handle_cli_error_argc; + } + /**************************************************************************/ } else { /**************************************************************************/ goto handle_cli_error; @@ -866,15 +913,20 @@ static ftdm_status_t handle_print_usage(ftdm_stream_handle_t *stream) stream->write_function(stream, "ftdm ss7 show relay\n"); stream->write_function(stream, "\n"); - stream->write_function(stream, "ftmod_sangoma_ss7 M2UA status:\n"); + stream->write_function(stream, "ftmod_sangoma_ss7 M2UA :\n"); stream->write_function(stream, "ftdm ss7 show sctp \n"); stream->write_function(stream, "ftdm ss7 show sctp \n"); stream->write_function(stream, "ftdm ss7 show m2ua \n"); stream->write_function(stream, "ftdm ss7 show m2ua \n"); + stream->write_function(stream, "ftdm ss7 show m2ua peerstatus\n"); stream->write_function(stream, "ftdm ss7 show nif \n"); stream->write_function(stream, "ftdm ss7 show nif \n"); stream->write_function(stream, "\n"); + + stream->write_function(stream, "ftmod_sangoma_ss7 M2UA logging:\n"); + stream->write_function(stream, "ftdm ss7 m2ua logging [enable|disable] \n"); + stream->write_function(stream, "\n"); return FTDM_SUCCESS; @@ -2993,7 +3045,15 @@ static ftdm_status_t cli_ss7_show_all_spans_general(ftdm_stream_handle_t *stream return FTDM_FAIL; } -/******************************************************************************/ + +/****************************************************************************** +* Fun: handle_show_m2ua_profiles() +* Desc: display all m2ua profile information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: Kapil Gupta +*******************************************************************************/ + static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) { char* xmlhdr = (char*)""; @@ -3103,6 +3163,14 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) } +/****************************************************************************** +* Fun: handle_show_m2ua_profile() +* Desc: display requested m2ua profile information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: Kapil Gupta +*******************************************************************************/ + static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char* m2ua_profile_name) { char* xmlhdr = (char*)""; @@ -3208,7 +3276,14 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char return FTDM_FAIL; } -/******************************************************************************/ + +/****************************************************************************** +* Fun: handle_show_sctp_profiles() +* Desc: display all sctp profile information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: Kapil Gupta +*******************************************************************************/ static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream) { char* xmlhdr = (char*)""; @@ -3414,7 +3489,13 @@ int get_assoc_resp_buf(char* buf,SbMgmt* cfm) return len; } - +/****************************************************************************** +* Fun: handle_show_sctp_profile() +* Desc: display requested sctp profile information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: Kapil Gupta +*******************************************************************************/ static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char* sctp_profile_name) { char* xmlhdr = (char*)""; @@ -3486,6 +3567,13 @@ static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char return FTDM_SUCCESS; } +/****************************************************************************** +* Fun: handle_show_nif_profiles() +* Desc: display all nif profile information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: Kapil Gupta +*******************************************************************************/ static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream) { char* xmlhdr = (char*)""; @@ -3540,6 +3628,13 @@ static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream) return FTDM_FAIL; } +/****************************************************************************** +* Fun: handle_show_nif_profile() +* Desc: display requested nif profile information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: Kapil Gupta +*******************************************************************************/ static ftdm_status_t handle_show_nif_profile(ftdm_stream_handle_t *stream, char* nif_profile_name) { char* xmlhdr = (char*)""; @@ -3595,6 +3690,61 @@ static ftdm_status_t handle_show_nif_profile(ftdm_stream_handle_t *stream, char* } /******************************************************************************/ +/****************************************************************************** +* Fun: handle_show_m2ua_peer_status() +* Desc: display requested m2ua profile peer information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: Kapil Gupta +*******************************************************************************/ + +static ftdm_status_t handle_show_m2ua_peer_status(ftdm_stream_handle_t *stream, char* m2ua_profile_name) +{ + char* xmlhdr = (char*)""; + char buf[2048]; + int x = 0x00; + int found = 0x00; + int len = 0x00; + MwMgmt cfm; + + memset((U8 *)&cfm, 0, sizeof(MwMgmt)); + memset(&buf[0], 0, sizeof(buf)); + + len = len + sprintf(buf + len, "%s\n", xmlhdr); + + /*iterate through all the m2ua links and get required profile */ + x = 1; + while(xwrite_function(stream,"Requested M2UA profile[%s] not configured\n", m2ua_profile_name); + return FTDM_FAIL; + } + + if(ftmod_m2ua_ssta_req(STMWPEER,x,&cfm)) { + stream->write_function(stream," Request to Trillium M2UA layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); + len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); + len = len + sprintf(buf + len, "\n"); + } + + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_FAIL; +} /******************************************************************************/ /* For Emacs: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c index 76db4d637e..f0ae00fa5a 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c @@ -63,9 +63,9 @@ static int ftmod_open_endpoint(int idx); static int ftmod_init_sctp_assoc(int peer_id); static int ftmod_nif_m2ua_dlsap_bind(int id); static int ftmod_nif_mtp2_dlsap_bind(int id); -static int ftmod_m2ua_enable_debug(void); -static int ftmod_tucl_enable_debug(void); -static int ftmod_sctp_enable_debug(void); +static int ftmod_m2ua_debug(int action); +static int ftmod_tucl_debug(int action); +static int ftmod_sctp_debug(int action); static int ftmod_ss7_sctp_shutdown(void); static int ftmod_ss7_m2ua_shutdown(void); @@ -1152,15 +1152,26 @@ uint32_t iptoul(const char *ip) return (uint32_t)val; } /***********************************************************************************************************************/ +void ftmod_ss7_enable_m2ua_sg_logging(void){ -int ftmod_ss7_m2ua_start(void){ - int x=0; + /* Enable DEBUGs*/ + ftmod_sctp_debug(AENA); + ftmod_m2ua_debug(AENA); + ftmod_tucl_debug(AENA); +} /***********************************************************************************************************************/ - /* Enable DEBUGs*/ - ftmod_sctp_enable_debug(); - ftmod_m2ua_enable_debug(); - ftmod_tucl_enable_debug(); +void ftmod_ss7_disable_m2ua_sg_logging(void){ + + /* DISABLE DEBUGs*/ + ftmod_sctp_debug(ADISIMM); + ftmod_m2ua_debug(ADISIMM); + ftmod_tucl_debug(ADISIMM); +} + +/***********************************************************************************************************************/ +int ftmod_ss7_m2ua_start(void){ + int x=0; /***********************************************************************************************************************/ x = 1; @@ -1466,7 +1477,7 @@ static int ftmod_nif_mtp2_dlsap_bind(int id) } /***********************************************************************************************************************/ -static int ftmod_sctp_enable_debug() +static int ftmod_sctp_debug(int action) { Pst pst; SbMgmt cntrl; @@ -1490,7 +1501,7 @@ static int ftmod_sctp_enable_debug() cntrl.hdr.response.mem.region = S_REG; cntrl.hdr.response.mem.pool = S_POOL; - cntrl.t.cntrl.action = AENA; + cntrl.t.cntrl.action = action; cntrl.t.cntrl.subAction = SADBG; cntrl.t.cntrl.dbgMask = 0xFFFF; @@ -1498,7 +1509,7 @@ static int ftmod_sctp_enable_debug() } /***********************************************************************************************************************/ -static int ftmod_m2ua_enable_debug() +static int ftmod_m2ua_debug(int action) { Pst pst; MwMgmt cntrl; @@ -1522,14 +1533,14 @@ static int ftmod_m2ua_enable_debug() cntrl.hdr.response.mem.region = S_REG; cntrl.hdr.response.mem.pool = S_POOL; - cntrl.t.cntrl.action = AENA; + cntrl.t.cntrl.action = action; cntrl.t.cntrl.subAction = SADBG; cntrl.t.cntrl.s.dbgMask = 0xFFFF; return (sng_cntrl_m2ua (&pst, &cntrl)); } /***********************************************************************************************************************/ -static int ftmod_tucl_enable_debug() +static int ftmod_tucl_debug(int action) { Pst pst; HiMngmt cntrl; @@ -1553,7 +1564,7 @@ static int ftmod_tucl_enable_debug() cntrl.hdr.response.mem.region = S_REG; cntrl.hdr.response.mem.pool = S_POOL; - cntrl.t.cntrl.action = AENA; + cntrl.t.cntrl.action = action; cntrl.t.cntrl.subAction = SADBG; cntrl.t.cntrl.ctlType.hiDbg.dbgMask = 0xFFFF; @@ -1594,6 +1605,7 @@ int ftmod_sctp_ssta_req(int elemt, int id, SbMgmt* cfm) } if(ssta.hdr.elmId.elmnt == STSBASSOC) { + /*TODO - how to get assoc Id*/ ssta.t.ssta.s.assocSta.assocId = 0; /* association id */ } return(sng_sta_sctp(&pst,&ssta,cfm)); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h index 9e13b32e4b..8f85ac3536 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h @@ -126,6 +126,8 @@ ftdm_status_t ftmod_ss7_m2ua_cfg(void); int ftmod_sctp_ssta_req(int elemt, int id, SbMgmt* cfm); int ftmod_m2ua_ssta_req(int elemt, int id, MwMgmt* cfm); int ftmod_nif_ssta_req(int elemt, int id, NwMgmt* cfm); +void ftmod_ss7_enable_m2ua_sg_logging(void); +void ftmod_ss7_disable_m2ua_sg_logging(void); #endif /*__FTMOD_SNG_SS7_M2UA_H__*/ From d535563abbb166496d34547550f8020bd1c714b7 Mon Sep 17 00:00:00 2001 From: kapil Date: Wed, 6 Jun 2012 14:44:20 +0530 Subject: [PATCH 217/822] modifying XML parsing / configuration code --- src/mod/endpoints/mod_megaco/megaco.c | 115 ++----- src/mod/endpoints/mod_megaco/megaco_stack.c | 341 ++++++++++++-------- src/mod/endpoints/mod_megaco/megaco_stack.h | 15 +- src/mod/endpoints/mod_megaco/megaco_xml.c | 160 +++++++++ src/mod/endpoints/mod_megaco/mod_megaco.c | 19 +- src/mod/endpoints/mod_megaco/mod_megaco.h | 34 +- 6 files changed, 446 insertions(+), 238 deletions(-) diff --git a/src/mod/endpoints/mod_megaco/megaco.c b/src/mod/endpoints/mod_megaco/megaco.c index b73eaefec0..aa8fd8ede1 100644 --- a/src/mod/endpoints/mod_megaco/megaco.c +++ b/src/mod/endpoints/mod_megaco/megaco.c @@ -8,7 +8,7 @@ #include "mod_megaco.h" -megaco_profile_t *megaco_profile_locate(const char *name) +megaco_profile_t *megaco_profile_locate(const char *name) { megaco_profile_t *profile = switch_core_hash_find_rdlock(megaco_globals.profile_hash, name, megaco_globals.profile_rwlock); @@ -22,97 +22,28 @@ megaco_profile_t *megaco_profile_locate(const char *name) return profile; } +mg_peer_profile_t *megaco_peer_profile_locate(const char *name) +{ + mg_peer_profile_t *profile = switch_core_hash_find_rdlock(megaco_globals.peer_profile_hash, name, megaco_globals.peer_profile_rwlock); + + if (profile) { + if (switch_thread_rwlock_tryrdlock(profile->rwlock) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile %s is locked\n", name); + profile = NULL; + } + } + + return profile; +} + void megaco_profile_release(megaco_profile_t *profile) { switch_thread_rwlock_unlock(profile->rwlock); } -static switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) +void megaco_peer_profile_release(mg_peer_profile_t *profile) { - switch_xml_t cfg, xml, mg_interfaces, mg_interface, tpt_interfaces, tpt_interface, peer_interfaces, peer_interface; - switch_status_t status = SWITCH_STATUS_FALSE; - switch_event_t *event = NULL; - const char *file = "megaco.conf"; - const char* mg_profile_tpt_id = NULL; - const char* mg_profile_peer_id = NULL; - - if (!(xml = switch_xml_open_cfg(file, &cfg, NULL))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not open %s\n", file); - goto done; - } - - if (!(mg_interfaces = switch_xml_child(cfg, "sng_mg_interfaces"))) { - goto done; - } - - /* iterate through MG Interface list to build requested MG profile */ - for (mg_interface = switch_xml_child(mg_interfaces, "sng_mg_interface"); mg_interface; mg_interface = mg_interface->next) { - - const char *name = switch_xml_attr_soft(mg_interface, "name"); - if (strcmp(name, profile->name)) { - continue; - } - - /* parse MG profile */ - if(SWITCH_STATUS_FALSE == sng_parse_mg_profile(mg_interface)) { - goto done; - } - - mg_profile_tpt_id = switch_xml_attr_soft(mg_interface, "id"); - - /* Now get required transport profile against mg_profile_tpt_id*/ - if (!(tpt_interfaces = switch_xml_child(cfg, "sng_transport_interfaces"))) { - goto done; - } - - for (tpt_interface = switch_xml_child(tpt_interfaces, "sng_transport_interface"); tpt_interface; tpt_interface = tpt_interface->next) { - const char *id = switch_xml_attr_soft(tpt_interface, "id"); - if (strcmp(id, mg_profile_tpt_id)) { - continue; - } - - /* parse MG transport profile */ - if(SWITCH_STATUS_FALSE == sng_parse_mg_tpt_profile(tpt_interface)) { - goto done; - } - } - - /* as of now supporting only one peer */ - mg_profile_peer_id = switch_xml_attr_soft(mg_interface, "peerId"); - /* Now get required peer profile against mg_profile_peer_id*/ - if (!(peer_interfaces = switch_xml_child(cfg, "sng_mg_peer_interfaces"))) { - goto done; - } - - for (peer_interface = switch_xml_child(peer_interfaces, "sng_mg_peer_interface"); peer_interface; peer_interface = peer_interface->next) { - const char *id = switch_xml_attr_soft(peer_interface, "id"); - if (strcmp(id, mg_profile_peer_id)) { - continue; - } - - /* parse MG Peer profile */ - if(SWITCH_STATUS_FALSE == sng_parse_mg_peer_profile(peer_interface)) { - goto done; - } - } - - - /* configure the MEGACO stack */ - status = sng_mgco_cfg(profile->name); - - /* we should break from here , profile name should be unique */ - break; - } - -done: - if (xml) { - switch_xml_free(xml); - } - - if (event) { - switch_event_destroy(&event); - } - return status; + switch_thread_rwlock_unlock(profile->rwlock); } switch_status_t megaco_profile_start(const char *profilename) @@ -130,14 +61,13 @@ switch_status_t megaco_profile_start(const char *profilename) profile->name = switch_core_strdup(pool, profilename); switch_thread_rwlock_create(&profile->rwlock, pool); - - if (config_profile(profile, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) { + + if (SWITCH_STATUS_SUCCESS != config_profile(profile, SWITCH_FALSE)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error configuring profile %s\n", profile->name); goto fail; } - /* start MEGACP stack */ - if(SWITCH_STATUS_FALSE == sng_mgco_start(profilename)) { + if(SWITCH_STATUS_FALSE == sng_mgco_start(profile)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error starting MEGACO Stack for profile %s\n", profile->name); goto fail; } @@ -161,8 +91,7 @@ switch_status_t megaco_profile_destroy(megaco_profile_t **profile) switch_thread_rwlock_wrlock((*profile)->rwlock); - /* stop MEGACP stack */ - if(SWITCH_STATUS_FALSE == sng_mgco_stop((*profile)->name)) { + if(SWITCH_STATUS_FALSE == sng_mgco_stop((*profile))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error stopping MEGACO Stack for profile %s\n", (*profile)->name); } @@ -171,6 +100,8 @@ switch_status_t megaco_profile_destroy(megaco_profile_t **profile) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Stopped profile: %s\n", (*profile)->name); switch_core_hash_delete_wrlock(megaco_globals.profile_hash, (*profile)->name, megaco_globals.profile_rwlock); + mg_config_cleanup(*profile); + switch_core_destroy_memory_pool(&(*profile)->pool); return SWITCH_STATUS_SUCCESS; diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.c b/src/mod/endpoints/mod_megaco/megaco_stack.c index 74874e75d5..103f8726e7 100644 --- a/src/mod/endpoints/mod_megaco/megaco_stack.c +++ b/src/mod/endpoints/mod_megaco/megaco_stack.c @@ -8,6 +8,7 @@ /* INCLUDES *******************************************************************/ #include "mod_megaco.h" +#include "megaco_stack.h" /******************************************************************************/ /* DEFINES ********************************************************************/ @@ -17,28 +18,32 @@ int mgco_mg_gen_config(void); int mgco_mu_gen_config(void); int mgco_tucl_gen_config(void); int mgco_mu_ssap_config(int idx); -int mgco_mg_tsap_config(int idx); +int mgco_mg_tsap_config(megaco_profile_t* profile); int mgco_mg_enble_debug(void); -int mgco_mg_ssap_config(int idx); -int mgco_mg_peer_config(int idx); -int mgco_mg_tpt_server_config(int idx); +int mgco_mg_ssap_config(megaco_profile_t* profile); +int mgco_mg_peer_config(megaco_profile_t* profile); +int mgco_mg_tpt_server_config(megaco_profile_t* profile); int mgco_tucl_sap_config(int idx); int mgco_mg_tsap_bind_cntrl(int idx); int mgco_mg_tsap_enable_cntrl(int idx); int mgco_mg_ssap_cntrl(int idx); int mgco_mu_ssap_cntrl(int idx); -int mgco_mg_tpt_server(int idx); int sng_mgco_tucl_shutdown(); int sng_mgco_mg_shutdown(); int sng_mgco_mg_ssap_stop(int sapId); -int sng_mgco_mg_tpt_server_stop(int idx); +int sng_mgco_mg_tpt_server_stop(megaco_profile_t* profile); int sng_mgco_mg_app_ssap_stop(int idx); switch_status_t sng_mgco_stack_gen_cfg(); void get_peer_xml_buffer(char* prntBuf, MgPeerSta* cfm); +sng_mg_transport_types_e mg_get_tpt_type(megaco_profile_t* mg_cfg); +sng_mg_transport_types_e mg_get_tpt_type_from_str(char* tpt_type); +sng_mg_encoding_types_e mg_get_enc_type_from_str(char* enc_type); +sng_mg_protocol_types_e mg_get_proto_type_from_str(char* proto_type); + /******************************************************************************/ /* FUNCTIONS ******************************************************************/ @@ -150,20 +155,15 @@ switch_status_t sng_mgco_stack_gen_cfg() /*****************************************************************************************************************/ -switch_status_t sng_mgco_cfg(const char* profilename) +switch_status_t sng_mgco_cfg(megaco_profile_t* profile) { int idx = 0x00; - switch_assert(profilename); + switch_assert(profile); - GET_MG_CFG_IDX(profilename, idx); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," Starting MG configuration for idx[%d] against profilename[%s]\n", profile->idx, profile->name); - if(!idx || (idx == MAX_MG_PROFILES)){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG configuration found against profilename[%s]\n",profilename); - return SWITCH_STATUS_FALSE; - } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," Starting MG configuration for idx[%d] against profilename[%s]\n", idx, profilename); + idx = profile->idx; if(mgco_tucl_sap_config(idx)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," mgco_tucl_sap_config FAILED \n"); @@ -183,7 +183,7 @@ switch_status_t sng_mgco_cfg(const char* profilename) } - if(mgco_mg_tsap_config(idx)) { + if(mgco_mg_tsap_config(profile)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," mgco_mg_tsap_config FAILED \n"); return SWITCH_STATUS_FALSE; } @@ -191,7 +191,7 @@ switch_status_t sng_mgco_cfg(const char* profilename) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," mgco_mg_tsap_config SUCCESS \n"); } - if(mgco_mg_ssap_config(idx)) { + if(mgco_mg_ssap_config(profile)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " mgco_mg_ssap_config FAILED \n"); return SWITCH_STATUS_FALSE; } @@ -199,7 +199,7 @@ switch_status_t sng_mgco_cfg(const char* profilename) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mgco_mg_ssap_config SUCCESS \n"); } - if(mgco_mg_peer_config(idx)) { + if(mgco_mg_peer_config(profile)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " mgco_mg_peer_config FAILED \n"); return SWITCH_STATUS_FALSE; } @@ -207,7 +207,7 @@ switch_status_t sng_mgco_cfg(const char* profilename) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mgco_mg_peer_config SUCCESS \n"); } - if(mgco_mg_tpt_server_config(idx)) { + if(mgco_mg_tpt_server_config(profile)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " mgco_mg_tpt_server_config FAILED \n"); return SWITCH_STATUS_FALSE; } @@ -220,22 +220,11 @@ switch_status_t sng_mgco_cfg(const char* profilename) /*****************************************************************************************************************/ -switch_status_t sng_mgco_start(const char* profilename) +switch_status_t sng_mgco_start(megaco_profile_t* profile ) { - int idx = 0x00; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," Starting MG stack for idx[%d] against profilename[%s]\n", profile->idx, profile->name); - switch_assert(profilename); - - GET_MG_CFG_IDX(profilename, idx); - - if(!idx || (idx == MAX_MG_PROFILES)){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG configuration found against profilename[%s]\n",profilename); - return SWITCH_STATUS_FALSE; - } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," Starting MG stack for idx[%d] against profilename[%s]\n", idx, profilename); - - if(mgco_mu_ssap_cntrl(idx)) { + if(mgco_mu_ssap_cntrl(profile->idx)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " mgco_mu_ssap_cntrl FAILED \n"); return SWITCH_STATUS_FALSE; } @@ -243,7 +232,7 @@ switch_status_t sng_mgco_start(const char* profilename) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mgco_mu_ssap_cntrl SUCCESS \n"); } - if(mgco_mg_tsap_bind_cntrl(idx)) { + if(mgco_mg_tsap_bind_cntrl(profile->idx)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " mgco_mg_tsap_bind_cntrl FAILED \n"); return SWITCH_STATUS_FALSE; } @@ -251,7 +240,7 @@ switch_status_t sng_mgco_start(const char* profilename) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mgco_mg_tsap_bind_cntrl SUCCESS \n"); } - if(mgco_mg_ssap_cntrl(idx)) { + if(mgco_mg_ssap_cntrl(profile->idx)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " mgco_mg_ssap_cntrl FAILED \n"); return SWITCH_STATUS_FALSE; } @@ -259,7 +248,7 @@ switch_status_t sng_mgco_start(const char* profilename) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mgco_mg_ssap_cntrl SUCCESS \n"); } - if(mgco_mg_tsap_enable_cntrl(idx)) { + if(mgco_mg_tsap_enable_cntrl(profile->idx)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " mgco_mg_tsap_enable_cntrl FAILED \n"); return SWITCH_STATUS_FALSE; } @@ -272,28 +261,20 @@ switch_status_t sng_mgco_start(const char* profilename) /*****************************************************************************************************************/ -switch_status_t sng_mgco_stop(const char* profilename) +switch_status_t sng_mgco_stop(megaco_profile_t* profile ) { - int idx = 0x00; - sng_mg_cfg_t* mgCfg = NULL; + int idx = 0x00; - switch_assert(profilename); + switch_assert(profile); - GET_MG_CFG_IDX(profilename, idx); + idx = profile->idx; - if(!idx || (idx == MAX_MG_PROFILES)){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG configuration found against profilename[%s]\n",profilename); - return SWITCH_STATUS_FALSE; - } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," Stopping MG stack for idx[%d] against profilename[%s]\n", idx, profilename); - - mgCfg = &megaco_globals.g_mg_cfg.mgCfg[idx]; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," Stopping MG stack for idx[%d] against profilename[%s]\n", idx, profile->name); /* MG STOP is as good as deleting that perticular mg(virtual mg instance) data from megaco stack */ /* currently we are not supporting enable/disable MG stack */ - if(sng_mgco_mg_ssap_stop(mgCfg->id)) { + if(sng_mgco_mg_ssap_stop(idx)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " sng_mgco_mg_ssap_stop FAILED \n"); return SWITCH_STATUS_FALSE; } @@ -301,7 +282,7 @@ switch_status_t sng_mgco_stop(const char* profilename) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " sng_mgco_mg_ssap_stop SUCCESS \n"); } - if(sng_mgco_mg_tpt_server_stop(idx)) { + if(sng_mgco_mg_tpt_server_stop(profile)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " sng_mgco_mg_tpt_server_stop FAILED \n"); return SWITCH_STATUS_FALSE; } @@ -342,7 +323,7 @@ int sng_mgco_mg_app_ssap_stop(int idx) mgMngmt.hdr.entId.ent = ENTMG; mgMngmt.hdr.entId.inst = S_INST; mgMngmt.hdr.elmId.elmnt = STSSAP; - mgMngmt.hdr.elmId.elmntInst1 = GET_MU_SAP_ID(idx); + mgMngmt.hdr.elmId.elmntInst1 = idx; cntrl->action = ADEL; cntrl->subAction = SAELMNT; @@ -383,14 +364,13 @@ int sng_mgco_mg_ssap_stop(int sapId) } /*****************************************************************************************************************/ -int sng_mgco_mg_tpt_server_stop(int idx) +int sng_mgco_mg_tpt_server_stop(megaco_profile_t* mg_cfg) { MgMngmt mgMngmt; Pst pst; /* Post for layer manager */ MgCntrl *cntrl; MgTptCntrl *tptCntrl = &mgMngmt.t.cntrl.s.tptCntrl; CmInetIpAddr ipAddr = 0; - sng_mg_cfg_t* mgCfg = &megaco_globals.g_mg_cfg.mgCfg[idx]; cntrl = &(mgMngmt.t.cntrl); @@ -402,11 +382,11 @@ int sng_mgco_mg_tpt_server_stop(int idx) /* insert the destination Entity */ pst.dstEnt = ENTMG; - tptCntrl->transportType = GET_TPT_TYPE(idx); + tptCntrl->transportType = mg_get_tpt_type(mg_cfg); tptCntrl->serverAddr.type = CM_INET_IPV4ADDR_TYPE; - tptCntrl->serverAddr.u.ipv4TptAddr.port = mgCfg->port; - if(ROK == cmInetAddr((S8*)mgCfg->my_ipaddr, &ipAddr)) + tptCntrl->serverAddr.u.ipv4TptAddr.port = atoi(mg_cfg->port); + if(ROK == cmInetAddr((S8*)mg_cfg->my_ipaddr, &ipAddr)) { tptCntrl->serverAddr.u.ipv4TptAddr.address = ntohl(ipAddr); } @@ -448,7 +428,7 @@ int mgco_mg_tsap_bind_cntrl(int idx) cntrl->action = ABND_ENA; cntrl->subAction = SAELMNT; - cntrl->spId = GET_TPT_ID(idx); + cntrl->spId = idx; return(sng_cntrl_mg(&pst, &mgMngmt)); } @@ -479,13 +459,14 @@ int mgco_mg_tsap_enable_cntrl(int idx) cntrl->action = AENA; cntrl->subAction = SAELMNT; - cntrl->spId = GET_TPT_ID(idx); + cntrl->spId = idx; return(sng_cntrl_mg(&pst, &mgMngmt)); } /*****************************************************************************************************************/ +#if 0 int mgco_mg_tpt_server(int idx) { MgMngmt mgMngmt; @@ -493,7 +474,7 @@ int mgco_mg_tpt_server(int idx) MgCntrl *cntrl; MgTptCntrl *tptCntrl = &mgMngmt.t.cntrl.s.tptCntrl; CmInetIpAddr ipAddr = 0; - sng_mg_cfg_t* mgCfg = &megaco_globals.g_mg_cfg.mgCfg[idx]; + sng_mg_cfg_t* mg_cfg = &megaco_globals.g_mg_cfg.mg_cfg[idx]; cntrl = &(mgMngmt.t.cntrl); @@ -508,8 +489,8 @@ int mgco_mg_tpt_server(int idx) tptCntrl->transportType = GET_TPT_TYPE(idx); tptCntrl->serverAddr.type = CM_INET_IPV4ADDR_TYPE; - tptCntrl->serverAddr.u.ipv4TptAddr.port = mgCfg->port; - if(ROK == cmInetAddr((S8*)mgCfg->my_ipaddr, &ipAddr)) + tptCntrl->serverAddr.u.ipv4TptAddr.port = mg_cfg->port; + if(ROK == cmInetAddr((S8*)mg_cfg->my_ipaddr, &ipAddr)) { tptCntrl->serverAddr.u.ipv4TptAddr.address = ntohl(ipAddr); } @@ -526,6 +507,7 @@ int mgco_mg_tpt_server(int idx) return(sng_cntrl_mg(&pst, &mgMngmt)); } +#endif /*****************************************************************************************************************/ @@ -550,7 +532,7 @@ int mgco_mu_ssap_cntrl(int idx) mgMngmt.hdr.entId.ent = ENTMG; mgMngmt.hdr.entId.inst = S_INST; mgMngmt.hdr.elmId.elmnt = STSSAP; - mgMngmt.hdr.elmId.elmntInst1 = GET_MU_SAP_ID(idx); + mgMngmt.hdr.elmId.elmntInst1 = idx; cntrl->action = ABND_ENA; cntrl->subAction = SAELMNT; @@ -584,7 +566,7 @@ int mgco_mg_ssap_cntrl(int idx) cntrl->action = AENA; cntrl->subAction = SAELMNT; - cntrl->spId = (SpId)1; + cntrl->spId = (SpId)idx; return(sng_cntrl_mg(&pst, &mgMngmt)); } @@ -698,7 +680,7 @@ int mgco_tucl_sap_config(int idx) pCfg = &cfg.t.cfg.s.hiSap; - pCfg->spId = GET_TPT_ID(idx); + pCfg->spId = idx; pCfg->uiSel = 0x00; /*loosley coupled */ pCfg->flcEnb = TRUE; pCfg->txqCongStrtLim = HI_SAP_TXN_QUEUE_CONG_START_LIMIT; @@ -860,8 +842,8 @@ int mgco_mu_ssap_config(int idx) mgmt.hdr.elmId.elmnt = STSSAP; /* fill lower layer i.e. MG PST */ - cfg->ssapId = GET_MU_SAP_ID(idx); /* SSAP ID */ - cfg->spId = GET_MU_SAP_ID(idx); /* SSAP ID */ + cfg->ssapId = idx; + cfg->spId = idx; cfg->mem.region = S_REG; cfg->mem.pool = S_POOL; @@ -877,14 +859,13 @@ int mgco_mu_ssap_config(int idx) /******************************************************************************/ -int mgco_mg_ssap_config(int idx) +int mgco_mg_ssap_config(megaco_profile_t* profile) { MgMngmt mgMngmt; MgSSAPCfg *pCfg; Pst pst; /* Post for layer manager */ CmInetIpAddr ipAddr; int len = 0x00; - sng_mg_cfg_t* mgCfg = &megaco_globals.g_mg_cfg.mgCfg[idx]; memset(&mgMngmt, 0, sizeof(mgMngmt)); pCfg = &(mgMngmt.t.cfg.c.sSAPCfg); @@ -903,14 +884,14 @@ int mgco_mg_ssap_config(int idx) /* FILL SAP config */ - pCfg->sSAPId = mgCfg->id; /* SSAP ID */ + pCfg->sSAPId = profile->idx; /* SSAP ID */ pCfg->sel = 0x00 ; /* Loosely coupled */ pCfg->memId.region = S_REG; pCfg->memId.pool = S_POOL; pCfg->prior = PRIOR0; pCfg->route = RTESPEC; - pCfg->protocol = mgCfg->protocol_type; + pCfg->protocol = mg_get_proto_type_from_str(profile->protocol_type); pCfg->startTxnNum = 50; pCfg->endTxnNum = 60; @@ -919,7 +900,7 @@ int mgco_mg_ssap_config(int idx) pCfg->mwdTimer = (U16)10; pCfg->minMgcoVersion = LMG_VER_PROF_MGCO_H248_1_0; - switch(mgCfg->protocol_version) + switch(profile->protocol_version) { case 1: pCfg->maxMgcoVersion = LMG_VER_PROF_MGCO_H248_1_0; @@ -931,7 +912,7 @@ int mgco_mg_ssap_config(int idx) pCfg->maxMgcoVersion = LMG_VER_PROF_MGCO_H248_3_0; break; default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Protocol version[%d] \n",mgCfg->protocol_version); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Protocol version[%d] \n",profile->protocol_version); return SWITCH_STATUS_FALSE; } @@ -940,17 +921,17 @@ int mgco_mg_ssap_config(int idx) pCfg->userInfo.mid.pres = PRSNT_NODEF; pCfg->userInfo.dname.namePres.pres = PRSNT_NODEF; - pCfg->userInfo.mid.len = (U8)strlen((char*)mgCfg->mid); - strncpy((char*)pCfg->userInfo.mid.val, (char*)mgCfg->mid, MAX_MID_LEN); + pCfg->userInfo.mid.len = (U8)strlen((char*)profile->mid); + strncpy((char*)pCfg->userInfo.mid.val, (char*)profile->mid, MAX_MID_LEN); - len = (U32)strlen((char*)mgCfg->my_domain); + len = (U32)strlen((char*)profile->my_domain); memcpy( (U8*)(pCfg->userInfo.dname.name), - (CONSTANT U8*)(mgCfg->my_domain), len ); + (CONSTANT U8*)(profile->my_domain), len ); pCfg->userInfo.dname.name[len] = '\0'; pCfg->userInfo.dname.netAddr.type = CM_TPTADDR_IPV4; memset(&ipAddr,'\0',sizeof(ipAddr)); - if(ROK == cmInetAddr((S8*)mgCfg->my_ipaddr,&ipAddr)) + if(ROK == cmInetAddr((S8*)profile->my_ipaddr,&ipAddr)) { pCfg->userInfo.dname.netAddr.u.ipv4NetAddr = ntohl(ipAddr); } @@ -968,13 +949,11 @@ int mgco_mg_ssap_config(int idx) /******************************************************************************/ -int mgco_mg_tsap_config(int idx) +int mgco_mg_tsap_config(megaco_profile_t* profile) { MgMngmt mgMngmt; - /* local variables */ MgTSAPCfg *cfg; - Pst pst; /* Post for layer manager */ - sng_mg_cfg_t* mgCfg = &megaco_globals.g_mg_cfg.mgCfg[idx]; + Pst pst; memset(&mgMngmt, 0, sizeof(mgMngmt)); cfg = &(mgMngmt.t.cfg.c.tSAPCfg); @@ -992,9 +971,9 @@ int mgco_mg_tsap_config(int idx) mgMngmt.hdr.elmId.elmnt = STTSAP; /* FILL TSAP config */ - cfg->tSAPId = mgCfg->id; - cfg->spId = GET_TPT_ID(idx); - cfg->provType = GET_TPT_TYPE(idx); + cfg->tSAPId = profile->idx; + cfg->spId = profile->idx; + cfg->provType = mg_get_tpt_type(profile); /* FILL TUCL Information */ cfg->memId.region = S_REG; @@ -1031,15 +1010,14 @@ int mgco_mg_tsap_config(int idx) /******************************************************************************/ -int mgco_mg_peer_config(int idx) +int mgco_mg_peer_config(megaco_profile_t* mg_cfg) { MgMngmt mgMngmt; MgGcpEntCfg *cfg; Pst pst; /* Post for layer manager */ U32 peerIdx = 0; CmInetIpAddr ipAddr = 0; - sng_mg_cfg_t* mgCfg = &megaco_globals.g_mg_cfg.mgCfg[idx]; - sng_mg_peer_t* mgPeer = &megaco_globals.g_mg_cfg.mgPeer.peers[mgCfg->peer_id]; + mg_peer_profile_t* mg_peer = megaco_peer_profile_locate(mg_cfg->peer_list[0]); memset(&mgMngmt, 0, sizeof(mgMngmt)); cfg = &(mgMngmt.t.cfg.c.mgGcpEntCfg); @@ -1056,10 +1034,10 @@ int mgco_mg_peer_config(int idx) mgMngmt.hdr.entId.inst = S_INST; mgMngmt.hdr.elmId.elmnt = STGCPENT; - cfg->numPeer = megaco_globals.g_mg_cfg.mgPeer.total_peer; - cfg->peerCfg[peerIdx].sSAPId = mgCfg->id; /* SSAP ID */; - cfg->peerCfg[peerIdx].port = mgPeer->port; - cfg->peerCfg[peerIdx].tsapId = GET_TPT_ID(idx); + cfg->numPeer = mg_cfg->total_peers; + cfg->peerCfg[peerIdx].sSAPId = mg_cfg->idx; /* SSAP ID */; + cfg->peerCfg[peerIdx].port = atoi(mg_peer->port); + cfg->peerCfg[peerIdx].tsapId = mg_cfg->idx; cfg->peerCfg[peerIdx].mtuSize = MG_MAX_MTU_SIZE; @@ -1068,7 +1046,7 @@ int mgco_mg_peer_config(int idx) cfg->peerCfg[peerIdx].peerAddrTbl.netAddr[0].type = CM_NETADDR_IPV4; - if(ROK == cmInetAddr((S8*)&mgPeer->ipaddr[0],&ipAddr)) + if(ROK == cmInetAddr((S8*)&mg_peer->ipaddr[0],&ipAddr)) { cfg->peerCfg[peerIdx].peerAddrTbl.netAddr[0].u.ipv4NetAddr = ntohl(ipAddr); } @@ -1079,14 +1057,14 @@ int mgco_mg_peer_config(int idx) } #ifdef GCP_MG - cfg->peerCfg[peerIdx].transportType = GET_TPT_TYPE(idx); - cfg->peerCfg[peerIdx].encodingScheme = GET_ENCODING_TYPE(idx); + cfg->peerCfg[peerIdx].transportType = mg_get_tpt_type_from_str(mg_peer->transport_type); + cfg->peerCfg[peerIdx].encodingScheme = mg_get_enc_type_from_str(mg_peer->encoding_type); cfg->peerCfg[peerIdx].mgcPriority = 0; cfg->peerCfg[peerIdx].useAHScheme = FALSE; cfg->peerCfg[peerIdx].mid.pres = PRSNT_NODEF; - cfg->peerCfg[peerIdx].mid.len = strlen((char*)mgPeer->mid); + cfg->peerCfg[peerIdx].mid.len = strlen((char*)mg_peer->mid); cmMemcpy((U8 *)cfg->peerCfg[peerIdx].mid.val, - (CONSTANT U8*)(char*)mgPeer->mid, + (CONSTANT U8*)(char*)mg_peer->mid, cfg->peerCfg[peerIdx].mid.len); #endif /* GCP_MG */ @@ -1096,14 +1074,14 @@ int mgco_mg_peer_config(int idx) /******************************************************************************/ -int mgco_mg_tpt_server_config(int idx) +int mgco_mg_tpt_server_config(megaco_profile_t* mg_cfg) { MgMngmt mgMngmt; MgTptSrvrCfg *cfg; Pst pst; /* Post for layer manager */ CmInetIpAddr ipAddr = 0; - sng_mg_cfg_t* mgCfg = &megaco_globals.g_mg_cfg.mgCfg[idx]; int srvIdx = 0; + mg_peer_profile_t* mg_peer = megaco_peer_profile_locate(mg_cfg->peer_list[0]); memset(&mgMngmt, 0, sizeof(mgMngmt)); cfg = &(mgMngmt.t.cfg.c.tptSrvrCfg); @@ -1122,18 +1100,18 @@ int mgco_mg_tpt_server_config(int idx) cfg->count = 1; cfg->srvr[srvIdx].isDefault = TRUE; - cfg->srvr[srvIdx].sSAPId = mgCfg->id; - cfg->srvr[srvIdx].tSAPId = GET_TPT_ID(idx); - cfg->srvr[srvIdx].protocol = mgCfg->protocol_type; - cfg->srvr[srvIdx].transportType = GET_TPT_TYPE(idx); - cfg->srvr[srvIdx].encodingScheme = GET_ENCODING_TYPE(idx); + cfg->srvr[srvIdx].sSAPId = mg_cfg->idx; + cfg->srvr[srvIdx].tSAPId = mg_cfg->idx; + cfg->srvr[srvIdx].protocol = mg_get_proto_type_from_str(mg_cfg->protocol_type); + cfg->srvr[srvIdx].transportType = mg_get_tpt_type(mg_cfg); + cfg->srvr[srvIdx].encodingScheme = mg_get_enc_type_from_str(mg_peer->encoding_type); cfg->srvr[srvIdx].tptParam.type = CM_TPTPARAM_SOCK; cfg->srvr[srvIdx].tptParam.u.sockParam.listenQSize = 5; cfg->srvr[srvIdx].tptParam.u.sockParam.numOpts = 0; cfg->srvr[srvIdx].lclTptAddr.type = CM_TPTADDR_IPV4; - cfg->srvr[srvIdx].lclTptAddr.u.ipv4TptAddr.port = mgCfg->port; - if(ROK == cmInetAddr((S8*)mgCfg->my_ipaddr, &ipAddr)) + cfg->srvr[srvIdx].lclTptAddr.u.ipv4TptAddr.port = atoi(mg_cfg->port); + if(ROK == cmInetAddr((S8*)mg_cfg->my_ipaddr, &ipAddr)) { cfg->srvr[srvIdx].lclTptAddr.u.ipv4TptAddr.address = ntohl(ipAddr); } @@ -1677,12 +1655,10 @@ void handle_tucl_alarm(Pst *pst, HiMngmt *sta) } /* handle_sng_tucl_alarm */ /******************************************************************************/ -int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, int mg_cfg_idx) +int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, megaco_profile_t* mg_cfg, mg_peer_profile_t* mg_peer) { Pst pst; MgMngmt cntrl; - sng_mg_cfg_t* mgCfg = &megaco_globals.g_mg_cfg.mgCfg[mg_cfg_idx]; - sng_mg_peer_t* mgPeer = &megaco_globals.g_mg_cfg.mgPeer.peers[mgCfg->peer_id]; CmInetIpAddr ipAddr = 0; memset((U8 *)&pst, 0, sizeof(Pst)); @@ -1709,30 +1685,30 @@ int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, int mg_cfg_idx) case STGCPENT: { cntrl.t.ssta.s.mgPeerSta.peerId.pres = PRSNT_NODEF; - cntrl.t.ssta.s.mgPeerSta.peerId.val = mgCfg->peer_id; + cntrl.t.ssta.s.mgPeerSta.peerId.val = mg_cfg->idx; cntrl.t.ssta.s.mgPeerSta.mid.pres = PRSNT_NODEF; - cntrl.t.ssta.s.mgPeerSta.mid.len = strlen((char*)mgPeer->mid); + cntrl.t.ssta.s.mgPeerSta.mid.len = strlen((char*)mg_peer->mid); cmMemcpy((U8 *)cntrl.t.ssta.s.mgPeerSta.mid.val, - (CONSTANT U8*)(char*)mgPeer->mid, + (CONSTANT U8*)(char*)mg_peer->mid, cntrl.t.ssta.s.mgPeerSta.mid.len); break; } case STSSAP: { - cntrl.t.ssta.s.mgSSAPSta.sapId = mgCfg->id; + cntrl.t.ssta.s.mgSSAPSta.sapId = mg_cfg->idx; break; } case STTSAP: { - cntrl.t.ssta.s.mgTSAPSta.tSapId = GET_TPT_ID(mg_cfg_idx); + cntrl.t.ssta.s.mgTSAPSta.tSapId = mg_cfg->idx; break; } case STSERVER: { cntrl.t.ssta.s.mgTptSrvSta.tptAddr.type = CM_INET_IPV4ADDR_TYPE; cntrl.t.ssta.s.mgTptSrvSta.tptAddr.u.ipv4TptAddr.port = ntohl(ipAddr); - if(ROK == cmInetAddr((S8*)mgCfg->my_ipaddr, &ipAddr)) + if(ROK == cmInetAddr((S8*)mg_cfg->my_ipaddr, &ipAddr)) { cntrl.t.ssta.s.mgTptSrvSta.tptAddr.u.ipv4TptAddr.address = ntohl(ipAddr); } @@ -1753,19 +1729,27 @@ switch_status_t megaco_profile_status(switch_stream_handle_t *stream, const char int len = 0x00; MgMngmt cfm; char prntBuf[1024]; + megaco_profile_t* mg_cfg = NULL; + mg_peer_profile_t* mg_peer = NULL; switch_assert(profilename); memset((U8 *)&cfm, 0, sizeof(cfm)); memset((char *)&prntBuf, 0, sizeof(prntBuf)); - GET_MG_CFG_IDX(profilename, idx); - - if(!idx || (idx == MAX_MG_PROFILES)){ + mg_cfg = megaco_profile_locate(profilename); + if(!mg_cfg){ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG configuration found against profilename[%s]\n",profilename); return SWITCH_STATUS_FALSE; } + mg_peer = megaco_peer_profile_locate(mg_cfg->peer_list[0]); + if(!mg_peer){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG peer configuration found for peername[%s] against profilename[%s]\n",mg_cfg->peer_list[0],profilename); + return SWITCH_STATUS_FALSE; + } + + idx = mg_cfg->idx; /*stream->write_function(stream, "Collecting MG Profile[%s] status... \n",profilename);*/ @@ -1791,15 +1775,15 @@ switch_status_t megaco_profile_status(switch_stream_handle_t *stream, const char #endif /* MG Peer Information */ - sng_mgco_mg_get_status(STGCPENT, &cfm, idx); + sng_mgco_mg_get_status(STGCPENT, &cfm, mg_cfg, mg_peer); smmgPrntPeerSta(&cfm.t.ssta.s.mgPeerSta); /* MG Peer Information */ - sng_mgco_mg_get_status(STSSAP, &cfm, idx); + sng_mgco_mg_get_status(STSSAP, &cfm, mg_cfg, mg_peer); smmgPrntSsapSta(&cfm.t.ssta.s.mgSSAPSta); /* MG Transport SAP Information */ - sng_mgco_mg_get_status(STTSAP, &cfm, idx); + sng_mgco_mg_get_status(STTSAP, &cfm, mg_cfg, mg_peer); len = len + sprintf(prntBuf+len,"***********************************************\n"); len = len + sprintf(prntBuf+len,"**********MG TRANSPORT SAP Information**********\n"); len = len + sprintf(prntBuf+len,"TSAP status:\n"); @@ -1810,7 +1794,7 @@ switch_status_t megaco_profile_status(switch_stream_handle_t *stream, const char switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"%s\n",prntBuf); /* MG Transport Server Information */ - sng_mgco_mg_get_status(STSERVER, &cfm, idx); + sng_mgco_mg_get_status(STSERVER, &cfm, mg_cfg, mg_peer); smmgPrntSrvSta(&cfm.t.ssta.s.mgTptSrvSta); return SWITCH_STATUS_SUCCESS; @@ -1822,33 +1806,37 @@ switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const c int len = 0x00; MgMngmt cfm; char* xmlhdr = ""; - char prntBuf[10024]; - sng_mg_cfg_t* mgCfg = NULL; - sng_mg_peer_t* mgPeer = NULL; + char prntBuf[3048]; int i = 0x00; char *asciiAddr; CmInetIpAddr ip; + megaco_profile_t* mg_cfg = NULL; + mg_peer_profile_t* mg_peer = NULL; switch_assert(profilename); memset((U8 *)&cfm, 0, sizeof(cfm)); memset((char *)&prntBuf, 0, sizeof(prntBuf)); - GET_MG_CFG_IDX(profilename, idx); - - if(!idx || (idx == MAX_MG_PROFILES)){ + mg_cfg = megaco_profile_locate(profilename); + if(!mg_cfg){ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG configuration found against profilename[%s]\n",profilename); return SWITCH_STATUS_FALSE; } + mg_peer = megaco_peer_profile_locate(mg_cfg->peer_list[0]); - mgCfg = &megaco_globals.g_mg_cfg.mgCfg[idx]; - mgPeer = &megaco_globals.g_mg_cfg.mgPeer.peers[mgCfg->peer_id]; + if(!mg_peer){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG peer configuration found for peername[%s] against profilename[%s]\n",mg_cfg->peer_list[0],profilename); + return SWITCH_STATUS_FALSE; + } + idx = mg_cfg->idx; + len = len + sprintf(&prntBuf[0] + len,"%s\n",xmlhdr); len = len + sprintf(&prntBuf[0] + len,"\n"); - len = len + sprintf(&prntBuf[0] + len,"%s\n",mgCfg->name); + len = len + sprintf(&prntBuf[0] + len,"%s\n",mg_cfg->name); len = len + sprintf(&prntBuf[0] + len,"%s\n",profilename); /****************************************************************************************************************/ /* Print Peer Information ***************************************************************************************/ @@ -1856,10 +1844,10 @@ switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const c /* TODO - as of now supporting only one peer .. need to add logic to iterate through all the peers associated with this profile..*/ len = len + sprintf(&prntBuf[0] + len,"\n"); - len = len + sprintf(&prntBuf[0] + len,"\n",mgPeer->name); + len = len + sprintf(&prntBuf[0] + len,"\n",mg_peer->name); /* send request to MEGACO Trillium stack to get peer information*/ - sng_mgco_mg_get_status(STGCPENT, &cfm, idx); + sng_mgco_mg_get_status(STGCPENT, &cfm, mg_cfg, mg_peer); get_peer_xml_buffer(&prntBuf[0] + len, &cfm.t.ssta.s.mgPeerSta); @@ -1873,7 +1861,7 @@ switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const c len = len + sprintf(&prntBuf[0] + len,"\n"); /* MG SAP Information */ - sng_mgco_mg_get_status(STSSAP, &cfm, idx); + sng_mgco_mg_get_status(STSSAP, &cfm, mg_cfg, mg_peer); len = len + sprintf(prntBuf+len, " %s \n", PRNT_SAP_STATE((int)(cfm.t.ssta.s.mgSSAPSta.state))); len = len + sprintf(prntBuf+len, " %u \n", (unsigned int)(cfm.t.ssta.s.mgSSAPSta.numAssocPeer)); @@ -1917,7 +1905,7 @@ switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const c len = len + sprintf(&prntBuf[0] + len,"\n"); /* MG Transport SAP Information */ - sng_mgco_mg_get_status(STTSAP, &cfm, idx); + sng_mgco_mg_get_status(STTSAP, &cfm, mg_cfg, mg_peer); len = len + sprintf(&prntBuf[0] + len," %s \n", PRNT_SAP_STATE(cfm.t.ssta.s.mgTSAPSta.state)); len = len + sprintf(&prntBuf[0] + len," %u \n", (unsigned int)(cfm.t.ssta.s.mgTSAPSta.numServers)); len = len + sprintf(&prntBuf[0] + len,"\n"); @@ -1925,7 +1913,7 @@ switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const c /****************************************************************************************************************/ /* Print MG Transport Server Information ***************************************************************************************/ - if(sng_mgco_mg_get_status(STSERVER, &cfm, idx)){ + if(sng_mgco_mg_get_status(STSERVER, &cfm, mg_cfg, mg_peer)){ len = len + sprintf(&prntBuf[0] + len," no established server found \n"); } else { @@ -2096,3 +2084,84 @@ void get_peer_xml_buffer(char* prntBuf, MgPeerSta* cfm) #endif } +/**********************************************************************************************************************************/ +sng_mg_transport_types_e mg_get_tpt_type(megaco_profile_t* mg_profile) +{ + mg_peer_profile_t* mg_peer_profile = NULL; + + if(NULL == mg_profile){ + return SNG_MG_TPT_NONE; + } + + if(!mg_profile->total_peers){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " No peer configured against profilename[%s]\n",mg_profile->name); + return SNG_MG_TPT_NONE; + } + + if( NULL == (mg_peer_profile = megaco_peer_profile_locate(mg_profile->peer_list[0]))){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " Not able to get peer_profile node based on profilename[%s]\n",mg_profile->peer_list[0]); + return SNG_MG_TPT_NONE; + } + + return mg_get_tpt_type_from_str(mg_peer_profile->transport_type); +} +/**********************************************************************************************************************************/ + +sng_mg_transport_types_e mg_get_tpt_type_from_str(char* tpt_type) +{ + if(!tpt_type) return SNG_MG_TPT_NONE; + + if(!strcasecmp(tpt_type, "UDP")){ + return SNG_MG_TPT_UDP; + }else if(!strcasecmp(tpt_type,"TCP")){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "TCP Transport for H.248 Protocol Not Yet Supported \n"); + return SNG_MG_TPT_TCP; + }else if(!strcasecmp(tpt_type,"STCP")){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "STCP Transport for H.248 Protocol Not Yet Supported \n"); + return SNG_MG_TPT_SCTP; + }else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Protocol Value[%s] \n",tpt_type); + return SNG_MG_TPT_NONE; + } + + return SNG_MG_TPT_NONE; +} +/**********************************************************************************************************************************/ + +sng_mg_encoding_types_e mg_get_enc_type_from_str(char* enc_type) +{ + if(!enc_type) return SNG_MG_ENCODING_NONE; + + if(!strcasecmp(enc_type, "TEXT")){ + return SNG_MG_ENCODING_TEXT; + } else if(!strcasecmp(enc_type, "BINARY")){ + return SNG_MG_ENCODING_BINARY; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Encoding Type[%s] \n", enc_type); + return SNG_MG_ENCODING_NONE; + } + + return SNG_MG_ENCODING_NONE; +} + +/**********************************************************************************************************************************/ + +sng_mg_protocol_types_e mg_get_proto_type_from_str(char* proto_type) +{ + if(!proto_type) return SNG_MG_NONE; + + if(!strcasecmp(proto_type,"MEGACO")) { + return SNG_MG_MEGACO; + }else if(!strcasecmp(proto_type,"MGCP")){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MGCP Protocol Not Yet Supported \n"); + return SNG_MG_MGCP; + }else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Protocol Value[%s] \n",proto_type); + return SNG_MG_NONE; + } + + return SNG_MG_NONE; +} + + +/**********************************************************************************************************************************/ diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.h b/src/mod/endpoints/mod_megaco/megaco_stack.h index 8e1bc12bc1..dabf4a5551 100644 --- a/src/mod/endpoints/mod_megaco/megaco_stack.h +++ b/src/mod/endpoints/mod_megaco/megaco_stack.h @@ -6,7 +6,7 @@ * */ -#include "sng_megaco/sng_ss7.h" +#include "mod_megaco.h" #ifndef _MEGACO_CFG_H_ #define _MEGACO_CFG_H_ @@ -16,6 +16,7 @@ #define MAX_NAME_LEN 25 #define MAX_MG_PROFILES 5 +#if 0 typedef struct sng_mg_peer{ char name[MAX_NAME_LEN]; /* Peer Name as defined in config file */ uint16_t id; /* Peer ID as defined in config file */ @@ -36,6 +37,7 @@ typedef struct sng_mg_transport_profile{ uint16_t transport_type; /* transport type */ }sng_mg_transport_profile_t; +#endif typedef enum{ SNG_MG_TPT_NONE, @@ -68,6 +70,7 @@ typedef enum{ "SNG_MG_ENCODING_NONE") +#if 0 /* each profile is corresponds to each MG Instance */ typedef struct sng_mg_cfg{ char name[MAX_NAME_LEN]; /* MG(Virtual MG) Name as defined in config file */ @@ -94,6 +97,7 @@ typedef struct sng_mg_gbl_cfg{ extern switch_status_t sng_parse_mg_peer_profile(switch_xml_t mg_peer_profile); extern switch_status_t sng_parse_mg_tpt_profile(switch_xml_t mg_tpt_profile); extern switch_status_t sng_parse_mg_profile(switch_xml_t mg_interface); +#endif void handle_sng_log(uint8_t level, char *fmt, ...); @@ -107,17 +111,16 @@ void handle_mg_alarm(Pst *pst, MgMngmt *sta); void handle_tucl_alarm(Pst *pst, HiMngmt *sta); +switch_status_t sng_mgco_cfg(megaco_profile_t* profile); switch_status_t sng_mgco_init(sng_isup_event_interface_t* event); -switch_status_t sng_mgco_cfg(const char* profilename); -switch_status_t sng_mgco_start(const char* profilename); -switch_status_t sng_mgco_stop(const char* profilename); switch_status_t sng_mgco_stack_shutdown(void); -int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, int mg_cfg_idx); +int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, megaco_profile_t* mg_cfg, mg_peer_profile_t* mg_peer); switch_status_t megaco_profile_status(switch_stream_handle_t *stream, const char* profilename); switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const char* profilename); /*****************************************************************************************************/ +#if 0 #define GET_MG_CFG_IDX(_profilename, _idx){\ for(idx=0; idx < MAX_MG_PROFILES; idx++){\ /* id zero is not acceptable */\ @@ -130,12 +133,12 @@ switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const c }\ }\ } - #define GET_TPT_ID(_id) megaco_globals.g_mg_cfg.mgTptProf[megaco_globals.g_mg_cfg.mgCfg[_id].transport_prof_id].id #define GET_MU_SAP_ID(_id) megaco_globals.g_mg_cfg.mgCfg[_id].id #define GET_TPT_TYPE(_id) megaco_globals.g_mg_cfg.mgTptProf[megaco_globals.g_mg_cfg.mgCfg[_id].transport_prof_id].transport_type #define GET_ENCODING_TYPE(_id) megaco_globals.g_mg_cfg.mgPeer.peers[megaco_globals.g_mg_cfg.mgCfg[_id].peer_id].encoding_type +#endif #endif /* _MEGACO_CFG_H_ */ diff --git a/src/mod/endpoints/mod_megaco/megaco_xml.c b/src/mod/endpoints/mod_megaco/megaco_xml.c index 23ff23468d..52b1294cb2 100644 --- a/src/mod/endpoints/mod_megaco/megaco_xml.c +++ b/src/mod/endpoints/mod_megaco/megaco_xml.c @@ -6,8 +6,167 @@ * */ #include "mod_megaco.h" +#include "megaco_stack.h" +/****************************************************************************************************************************/ +static switch_xml_config_item_t *get_instructions(megaco_profile_t *profile) ; +static switch_xml_config_item_t *get_peer_instructions(mg_peer_profile_t *profile) ; +static int mg_sap_id; +/****************************************************************************************************************************/ +switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) +{ + switch_xml_t cfg, xml, param, mg_interfaces, mg_interface, mg_peers, mg_peer, peer_interfaces ; + switch_status_t status = SWITCH_STATUS_FALSE; + switch_event_t *event = NULL; + const char *file = "megaco.conf"; + switch_xml_config_item_t *instructions = (profile ? get_instructions(profile) : NULL); + int count; + int idx; + char *var, *val; + mg_peer_profile_t* peer_profile = NULL; + switch_xml_config_item_t *instructions1 = NULL; + + if (!(xml = switch_xml_open_cfg(file, &cfg, NULL))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not open %s\n", file); + goto done; + } + + if (!(mg_interfaces = switch_xml_child(cfg, "mg_profiles"))) { + goto done; + } + + for (mg_interface = switch_xml_child(mg_interfaces, "mg_profile"); mg_interface; mg_interface = mg_interface->next) { + const char *name = switch_xml_attr_soft(mg_interface, "name"); + if (strcmp(name, profile->name)) { + continue; + } + + count = switch_event_import_xml(switch_xml_child(mg_interface, "param"), "name", "value", &event); + status = switch_xml_config_parse_event(event, count, reload, instructions); + + /* now build peer list */ + if (!(peer_interfaces = switch_xml_child(mg_interface, "peers"))) { + goto done; + } + + for (param = switch_xml_child(peer_interfaces, "param"); param; param = param->next) { + var = (char *) switch_xml_attr_soft(param, "name"); + val = (char *) switch_xml_attr_soft(param, "value"); + profile->peer_list[profile->total_peers] = switch_core_strdup(profile->pool, val); + profile->total_peers++; + } + + profile->idx = ++mg_sap_id; + + /* we should break from here , profile name should be unique */ + break; + } + + /* go through the peer configuration and get the mg profile associated peers only */ + if (!(mg_peers = switch_xml_child(cfg, "mg_peers"))) { + goto done; + } + + count = 0x00; + event = NULL; + for (mg_peer = switch_xml_child(mg_peers, "mg_peer"); mg_peer; mg_peer = mg_peer->next) { + const char *name = switch_xml_attr_soft(mg_peer, "name"); + for(idx=0; idxtotal_peers; idx++){ + if (!strcmp(name, profile->peer_list[idx])) { + /* peer profile */ + peer_profile = switch_core_alloc(profile->pool, sizeof(*peer_profile)); + peer_profile->pool = profile->pool; + peer_profile->name = switch_core_strdup(peer_profile->pool, name); + switch_thread_rwlock_create(&peer_profile->rwlock, peer_profile->pool); + instructions1 = (peer_profile ? get_peer_instructions(peer_profile) : NULL); + + count = switch_event_import_xml(switch_xml_child(mg_peer, "param"), "name", "value", &event); + if(SWITCH_STATUS_FALSE == (status = switch_xml_config_parse_event(event, count, reload, instructions1))){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " Peer XML Parsing failed \n"); + goto done; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"peer_profile name[%s], ipaddr[%s] port[%s], mid[%s] transport_type[%s], encoding_type[%s] \n", + peer_profile->name, peer_profile->ipaddr, peer_profile->port,peer_profile->mid, peer_profile->transport_type, peer_profile->encoding_type); + + switch_core_hash_insert_wrlock(megaco_globals.peer_profile_hash, peer_profile->name, peer_profile, megaco_globals.peer_profile_rwlock); + } + } + } + + /* configure the MEGACO stack */ + status = sng_mgco_cfg(profile); + +done: + if (xml) { + switch_xml_free(xml); + } + + if (event) { + switch_event_destroy(&event); + } + return status; +} + +/****************************************************************************************************************************/ +switch_status_t mg_config_cleanup(megaco_profile_t* profile) +{ + switch_xml_config_item_t *instructions = (profile ? get_instructions(profile) : NULL); + switch_xml_config_cleanup(instructions); + + return SWITCH_STATUS_SUCCESS; +} + +/****************************************************************************************************************************/ +static switch_xml_config_item_t *get_peer_instructions(mg_peer_profile_t *profile) { + switch_xml_config_item_t *dup; + + switch_xml_config_item_t instructions[] = { + /* parameter name type reloadable pointer default value options structure */ + SWITCH_CONFIG_ITEM("ip", SWITCH_CONFIG_STRING, CONFIG_RELOADABLE, &profile->ipaddr, "", &switch_config_string_strdup, "", "Peer IP"), + SWITCH_CONFIG_ITEM("port", SWITCH_CONFIG_STRING, 0, &profile->port, "", &switch_config_string_strdup, "", "peer port"), + SWITCH_CONFIG_ITEM("encoding-scheme", SWITCH_CONFIG_STRING, 0, &profile->encoding_type, "TEXT", &switch_config_string_strdup, "", "peer encoding type"), + SWITCH_CONFIG_ITEM("transport-type", SWITCH_CONFIG_STRING, 0, &profile->transport_type, "", &switch_config_string_strdup, "", "peer transport type "), + SWITCH_CONFIG_ITEM("message-identifier", SWITCH_CONFIG_STRING, 0, &profile->mid, "", &switch_config_string_strdup, "", "peer message identifier "), + SWITCH_CONFIG_ITEM_END() + }; + + dup = malloc(sizeof(instructions)); + memcpy(dup, instructions, sizeof(instructions)); + return dup; +} + +/****************************************************************************************************************************/ + +static switch_xml_config_item_t *get_instructions(megaco_profile_t *profile) { + switch_xml_config_item_t *dup; + static switch_xml_config_int_options_t opt_version = { + SWITCH_TRUE, /* enforce min */ + 1, + SWITCH_TRUE, /* Enforce Max */ + 3 + }; + + switch_xml_config_item_t instructions[] = { + /* parameter name type reloadable pointer default value options structure */ + SWITCH_CONFIG_ITEM("protocol", SWITCH_CONFIG_STRING, CONFIG_RELOADABLE, &profile->protocol_type, "MEGACO", &switch_config_string_strdup, "", "MG Protocol type"), + SWITCH_CONFIG_ITEM("version", SWITCH_CONFIG_INT, CONFIG_RELOADABLE, &profile->protocol_version, 2, &opt_version, "", "MG Protocol version"), + SWITCH_CONFIG_ITEM("local-ip", SWITCH_CONFIG_STRING, CONFIG_RELOADABLE, &profile->my_ipaddr, "127.0.0.1", &switch_config_string_strdup, "", "local ip"), + SWITCH_CONFIG_ITEM("port", SWITCH_CONFIG_STRING, 0, &profile->port, "2944", &switch_config_string_strdup, "", "port"), + SWITCH_CONFIG_ITEM("domain-name", SWITCH_CONFIG_STRING, 0, &profile->my_domain, "", &switch_config_string_strdup, "", "domain name"), + SWITCH_CONFIG_ITEM("message-identifier", SWITCH_CONFIG_STRING, 0, &profile->mid, "", &switch_config_string_strdup, "", "message identifier "), + SWITCH_CONFIG_ITEM_END() + }; + + dup = malloc(sizeof(instructions)); + memcpy(dup, instructions, sizeof(instructions)); + return dup; +} + +/****************************************************************************************************************************/ + +#if 0 switch_status_t sng_parse_mg_profile(switch_xml_t mg_interface) { int i = 0x00; @@ -230,4 +389,5 @@ switch_status_t sng_parse_mg_peer_profile(switch_xml_t mg_peer_profile) megaco_globals.g_mg_cfg.mgPeer.total_peer++; return SWITCH_STATUS_SUCCESS; } +#endif /***********************************************************************************************************/ diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.c b/src/mod/endpoints/mod_megaco/mod_megaco.c index f8fa65a8ee..94a0f64d13 100644 --- a/src/mod/endpoints/mod_megaco/mod_megaco.c +++ b/src/mod/endpoints/mod_megaco/mod_megaco.c @@ -7,6 +7,7 @@ */ #include "mod_megaco.h" +#include "megaco_stack.h" struct megaco_globals megaco_globals; static sng_isup_event_interface_t sng_event; @@ -15,7 +16,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_megaco_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_megaco_shutdown); SWITCH_MODULE_DEFINITION(mod_megaco, mod_megaco_load, mod_megaco_shutdown, NULL); - #define MEGACO_FUNCTION_SYNTAX "profile [name] [start | stop] [status] [xmlstatus]" SWITCH_STANDARD_API(megaco_function) { @@ -34,11 +34,14 @@ SWITCH_STANDARD_API(megaco_function) goto usage; } +/**********************************************************************************/ if (!strcmp(argv[0], "profile")) { if (zstr(argv[1]) || zstr(argv[2])) { goto usage; } +/**********************************************************************************/ if (!strcmp(argv[2], "start")) { +/**********************************************************************************/ megaco_profile_t *profile = megaco_profile_locate(argv[1]); if (profile) { megaco_profile_release(profile); @@ -47,7 +50,9 @@ SWITCH_STANDARD_API(megaco_function) megaco_profile_start(argv[1]); stream->write_function(stream, "+OK\n"); } +/**********************************************************************************/ } else if (!strcmp(argv[2], "stop")) { +/**********************************************************************************/ megaco_profile_t *profile = megaco_profile_locate(argv[1]); if (profile) { megaco_profile_release(profile); @@ -56,22 +61,29 @@ SWITCH_STANDARD_API(megaco_function) } else { stream->write_function(stream, "-ERR No such profile\n"); } +/**********************************************************************************/ }else if(!strcmp(argv[2], "status")) { +/**********************************************************************************/ megaco_profile_t *profile = megaco_profile_locate(argv[1]); if (profile) { megaco_profile_status(stream, profile->name); } else { stream->write_function(stream, "-ERR No such profile\n"); } +/**********************************************************************************/ }else if(!strcmp(argv[2], "xmlstatus")) { +/**********************************************************************************/ megaco_profile_t *profile = megaco_profile_locate(argv[1]); if (profile) { megaco_profile_xmlstatus(stream, profile->name); } else { stream->write_function(stream, "-ERR No such profile\n"); } +/**********************************************************************************/ + }else { +/**********************************************************************************/ + goto usage; } - } goto done; @@ -125,6 +137,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_megaco_load) switch_core_hash_init(&megaco_globals.profile_hash, pool); switch_thread_rwlock_create(&megaco_globals.profile_rwlock, pool); + + switch_core_hash_init(&megaco_globals.peer_profile_hash, pool); + switch_thread_rwlock_create(&megaco_globals.peer_profile_rwlock, pool); SWITCH_ADD_API(api_interface, "megaco", "megaco", megaco_function, MEGACO_FUNCTION_SYNTAX); diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.h b/src/mod/endpoints/mod_megaco/mod_megaco.h index 7c21610639..a277a1f840 100644 --- a/src/mod/endpoints/mod_megaco/mod_megaco.h +++ b/src/mod/endpoints/mod_megaco/mod_megaco.h @@ -10,14 +10,17 @@ #ifndef MOD_MEGACO_H #define MOD_MEGACO_H +#include "sng_megaco/sng_ss7.h" #include -#include "megaco_stack.h" + +#define MG_MAX_PEERS 5 struct megaco_globals { switch_memory_pool_t *pool; switch_hash_t *profile_hash; + switch_hash_t *peer_profile_hash; switch_thread_rwlock_t *profile_rwlock; - sng_mg_gbl_cfg_t g_mg_cfg; + switch_thread_rwlock_t *peer_profile_rwlock; }; extern struct megaco_globals megaco_globals; /* < defined in mod_megaco.c */ @@ -25,19 +28,46 @@ typedef enum { PF_RUNNING = (1 << 0) } megaco_profile_flags_t; +typedef struct mg_peer_profile_s{ + char *name; + switch_memory_pool_t *pool; + switch_thread_rwlock_t *rwlock; /* < Reference counting rwlock */ + megaco_profile_flags_t flags; + char* ipaddr; /* Peer IP */ + char* port; /*Peer Port */ + char* mid; /* Peer H.248 MID */ + char* transport_type; /* UDP/TCP */ + char* encoding_type; /* Encoding TEXT/Binary */ +}mg_peer_profile_t; + + typedef struct megaco_profile_s { char *name; switch_memory_pool_t *pool; switch_thread_rwlock_t *rwlock; /* < Reference counting rwlock */ megaco_profile_flags_t flags; + int idx; /* Trillium MEGACO SAP identification*/ + char* mid; /* MG H.248 MID */ + char* my_domain; /* local domain name */ + char* my_ipaddr; /* local domain name */ + char* port; /* port */ + char* protocol_type; /* MEGACO/MGCP */ + int protocol_version; /* Protocol supported version */ + int total_peers; + char* peer_list[MG_MAX_PEERS]; /* MGC Peer ID LIST */ } megaco_profile_t; megaco_profile_t *megaco_profile_locate(const char *name); +mg_peer_profile_t *megaco_peer_profile_locate(const char *name); void megaco_profile_release(megaco_profile_t *profile); switch_status_t megaco_profile_start(const char *profilename); switch_status_t megaco_profile_destroy(megaco_profile_t **profile); +switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload); +switch_status_t sng_mgco_start(megaco_profile_t* profile); +switch_status_t sng_mgco_stop(megaco_profile_t* profile); +switch_status_t mg_config_cleanup(megaco_profile_t* profile); #endif /* MOD_MEGACO_H */ From 293a65c9c05d4d02ab0746734e979320fabbe1c9 Mon Sep 17 00:00:00 2001 From: kapil Date: Wed, 6 Jun 2012 14:45:39 +0530 Subject: [PATCH 218/822] updating final xml config file --- .../endpoints/mod_megaco/conf/megaco.conf.xml | 65 +++++++------------ 1 file changed, 23 insertions(+), 42 deletions(-) diff --git a/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml b/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml index e21ab3a074..91f8f0cc63 100644 --- a/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml +++ b/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml @@ -1,47 +1,28 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + From ba051e1007d76d7774448ac980e31e3346fa0d12 Mon Sep 17 00:00:00 2001 From: kapil Date: Wed, 6 Jun 2012 15:11:55 +0530 Subject: [PATCH 219/822] reorgnazing code , adding below two files * megaco_cli.c - contains CLI commands APIs * megaco_stack_alarms.c - contains Alarm indication APIs from Trillium MEGACO layer --- src/mod/endpoints/mod_megaco/Makefile | 2 +- src/mod/endpoints/mod_megaco/megaco_cli.c | 465 ++++++++++ src/mod/endpoints/mod_megaco/megaco_stack.c | 840 +----------------- src/mod/endpoints/mod_megaco/megaco_stack.h | 87 +- .../mod_megaco/megaco_stack_alarms.c | 495 +++++++++++ src/mod/endpoints/mod_megaco/megaco_xml.c | 226 ----- src/mod/endpoints/mod_megaco/mod_megaco.c | 77 +- src/mod/endpoints/mod_megaco/mod_megaco.h | 3 + 8 files changed, 969 insertions(+), 1226 deletions(-) create mode 100644 src/mod/endpoints/mod_megaco/megaco_cli.c create mode 100644 src/mod/endpoints/mod_megaco/megaco_stack_alarms.c diff --git a/src/mod/endpoints/mod_megaco/Makefile b/src/mod/endpoints/mod_megaco/Makefile index 4564a420e9..228d3f88e8 100644 --- a/src/mod/endpoints/mod_megaco/Makefile +++ b/src/mod/endpoints/mod_megaco/Makefile @@ -7,6 +7,6 @@ ifeq ($(ARCH),x86_64) endif BASE=../../../.. -LOCAL_OBJS=megaco.o megaco_stack.o megaco_xml.o +LOCAL_OBJS=megaco.o megaco_stack.o megaco_xml.o megaco_cli.o megaco_stack_alarms.o LOCAL_LDFLAGS=-lsng_megaco include $(BASE)/build/modmake.rules diff --git a/src/mod/endpoints/mod_megaco/megaco_cli.c b/src/mod/endpoints/mod_megaco/megaco_cli.c new file mode 100644 index 0000000000..e7d0794c49 --- /dev/null +++ b/src/mod/endpoints/mod_megaco/megaco_cli.c @@ -0,0 +1,465 @@ +/* +* Copyright (c) 2012, Sangoma Technologies +* Kapil Gupta +* All rights reserved. +* +* +*/ + +/* INCLUDES *******************************************************************/ +#include "mod_megaco.h" +#include "megaco_stack.h" +/******************************************************************************/ + +/* FUNCTION PROTOTYPES ********************************************************/ +switch_status_t megaco_profile_status(switch_stream_handle_t *stream, const char* profilename); +switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const char* profilename); +void get_peer_xml_buffer(char* prntBuf, MgPeerSta* cfm); + +/******************************************************************************/ + +/* FUNCTIONS ******************************************************************/ + +switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stream) +{ + int argc; + char *argv[10]; + char *dup = NULL; + + if (zstr(cmd)) { + goto usage; + } + + dup = strdup(cmd); + argc = switch_split(dup, ' ', argv); + + if (argc < 1 || zstr(argv[0])) { + goto usage; + } + + /**********************************************************************************/ + if (!strcmp(argv[0], "profile")) { + if (zstr(argv[1]) || zstr(argv[2])) { + goto usage; + } + /**********************************************************************************/ + if (!strcmp(argv[2], "start")) { + /**********************************************************************************/ + megaco_profile_t *profile = megaco_profile_locate(argv[1]); + if (profile) { + megaco_profile_release(profile); + stream->write_function(stream, "-ERR Profile %s is already started\n", argv[2]); + } else { + megaco_profile_start(argv[1]); + stream->write_function(stream, "+OK\n"); + } + /**********************************************************************************/ + } else if (!strcmp(argv[2], "stop")) { + /**********************************************************************************/ + megaco_profile_t *profile = megaco_profile_locate(argv[1]); + if (profile) { + megaco_profile_release(profile); + megaco_profile_destroy(&profile); + stream->write_function(stream, "+OK\n"); + } else { + stream->write_function(stream, "-ERR No such profile\n"); + } + /**********************************************************************************/ + }else if(!strcmp(argv[2], "status")) { + /**********************************************************************************/ + megaco_profile_t *profile = megaco_profile_locate(argv[1]); + if (profile) { + megaco_profile_status(stream, profile->name); + } else { + stream->write_function(stream, "-ERR No such profile\n"); + } + /**********************************************************************************/ + }else if(!strcmp(argv[2], "xmlstatus")) { + /**********************************************************************************/ + megaco_profile_t *profile = megaco_profile_locate(argv[1]); + if (profile) { + megaco_profile_xmlstatus(stream, profile->name); + } else { + stream->write_function(stream, "-ERR No such profile\n"); + } + /**********************************************************************************/ + }else { + /**********************************************************************************/ + goto usage; + } + } + + goto done; + +usage: + stream->write_function(stream, "-ERR Usage: "MEGACO_FUNCTION_SYNTAX"\n"); + +done: + switch_safe_free(dup); + return SWITCH_STATUS_SUCCESS; +} + +/******************************************************************************/ +switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const char* profilename) +{ + int idx = 0x00; + int len = 0x00; + MgMngmt cfm; + char* xmlhdr = ""; + char prntBuf[3048]; + int i = 0x00; + char *asciiAddr; + CmInetIpAddr ip; + megaco_profile_t* mg_cfg = NULL; + mg_peer_profile_t* mg_peer = NULL; + + switch_assert(profilename); + + memset((U8 *)&cfm, 0, sizeof(cfm)); + memset((char *)&prntBuf, 0, sizeof(prntBuf)); + + mg_cfg = megaco_profile_locate(profilename); + if(!mg_cfg){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG configuration found against profilename[%s]\n",profilename); + return SWITCH_STATUS_FALSE; + } + mg_peer = megaco_peer_profile_locate(mg_cfg->peer_list[0]); + + if(!mg_peer){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG peer configuration found for peername[%s] against profilename[%s]\n",mg_cfg->peer_list[0],profilename); + return SWITCH_STATUS_FALSE; + } + + + idx = mg_cfg->idx; + + len = len + sprintf(&prntBuf[0] + len,"%s\n",xmlhdr); + + len = len + sprintf(&prntBuf[0] + len,"\n"); + len = len + sprintf(&prntBuf[0] + len,"%s\n",mg_cfg->name); + len = len + sprintf(&prntBuf[0] + len,"%s\n",profilename); +/****************************************************************************************************************/ +/* Print Peer Information ***************************************************************************************/ + + /* TODO - as of now supporting only one peer .. need to add logic to iterate through all the peers associated with this profile..*/ + + len = len + sprintf(&prntBuf[0] + len,"\n"); + len = len + sprintf(&prntBuf[0] + len,"\n",mg_peer->name); + + /* send request to MEGACO Trillium stack to get peer information*/ + sng_mgco_mg_get_status(STGCPENT, &cfm, mg_cfg, mg_peer); + + get_peer_xml_buffer(&prntBuf[0] + len, &cfm.t.ssta.s.mgPeerSta); + + len = len + sprintf(&prntBuf[0] + len,"\n"); + len = len + sprintf(&prntBuf[0] + len,"\n"); + + +/****************************************************************************************************************/ +/* Print MG SAP Information ***************************************************************************************/ + + len = len + sprintf(&prntBuf[0] + len,"\n"); + + /* MG SAP Information */ + sng_mgco_mg_get_status(STSSAP, &cfm, mg_cfg, mg_peer); + + len = len + sprintf(prntBuf+len, " %s \n", PRNT_SAP_STATE((int)(cfm.t.ssta.s.mgSSAPSta.state))); + len = len + sprintf(prntBuf+len, " %u \n", (unsigned int)(cfm.t.ssta.s.mgSSAPSta.numAssocPeer)); + len = len + sprintf(prntBuf+len, " %u \n", (unsigned int)(cfm.t.ssta.s.mgSSAPSta.numServers)); + len = len + sprintf(&prntBuf[0] + len,"\n"); + for (i = 0; i < cfm.t.ssta.s.mgSSAPSta.numAssocPeer; i++) + { + len = len + sprintf(&prntBuf[0] + len,"\n"); + if(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].dname.namePres.pres == PRSNT_NODEF) + { + len = len + sprintf(prntBuf+len, " %s \n", (char *)(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].dname.name)); + } + switch(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].dname.netAddr.type) + { + case CM_NETADDR_IPV4: + { + ip = ntohl(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].dname.netAddr.u.ipv4NetAddr); + cmInetNtoa(ip, &asciiAddr); + len = len + sprintf(prntBuf+len, "%s\n",asciiAddr); + break; + } + default: + len = len + sprintf(prntBuf+len, "invalid type \n"); + break; + } + +#ifdef GCP_MGCO + if (PRSNT_NODEF == cfm.t.ssta.s.mgSSAPSta.peerInfo[i].mid.pres) + { + len = len + sprintf(prntBuf+len, " %s \n", (char *)(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].mid.val)); + } +#endif /* GCP_MGCO */ + len = len + sprintf(&prntBuf[0] + len,"\n"); + } + len = len + sprintf(&prntBuf[0] + len,"\n"); + + len = len + sprintf(&prntBuf[0] + len,"\n"); + +/****************************************************************************************************************/ +/* Print MG Transport SAP Information ***************************************************************************************/ + + len = len + sprintf(&prntBuf[0] + len,"\n"); + /* MG Transport SAP Information */ + sng_mgco_mg_get_status(STTSAP, &cfm, mg_cfg, mg_peer); + len = len + sprintf(&prntBuf[0] + len," %s \n", PRNT_SAP_STATE(cfm.t.ssta.s.mgTSAPSta.state)); + len = len + sprintf(&prntBuf[0] + len," %u \n", (unsigned int)(cfm.t.ssta.s.mgTSAPSta.numServers)); + len = len + sprintf(&prntBuf[0] + len,"\n"); + +/****************************************************************************************************************/ +/* Print MG Transport Server Information ***************************************************************************************/ + + if(sng_mgco_mg_get_status(STSERVER, &cfm, mg_cfg, mg_peer)){ + len = len + sprintf(&prntBuf[0] + len," no established server found \n"); + } + else { + len = len + sprintf(&prntBuf[0] + len,"\n"); + len = len + sprintf(&prntBuf[0] + len," %s \n", PRNT_SAP_STATE(cfm.t.ssta.s.mgTptSrvSta.state)); + len = len + sprintf(prntBuf+len, ""); + + switch (cfm.t.ssta.s.mgTptSrvSta.tptAddr.type) + { + case CM_TPTADDR_NOTPRSNT: + { + len = len + sprintf(prntBuf+len, "none"); + break; + } + case CM_TPTADDR_IPV4: + { + ip = ntohl(cfm.t.ssta.s.mgTptSrvSta.tptAddr.u.ipv4TptAddr.address); + cmInetNtoa(ip, &asciiAddr); + len = len + sprintf(prntBuf+len, "IPv4 IP address #%s, port %u",asciiAddr, + (unsigned int)(cfm.t.ssta.s.mgTptSrvSta.tptAddr.u.ipv4TptAddr.port)); + + break; + } + default: + len = len + sprintf(prntBuf+len, "unknown"); + break; + } + len = len + sprintf(prntBuf+len, "\n"); + len = len + sprintf(&prntBuf[0] + len,"\n"); + } + +/****************************************************************************************************************/ + len = len + sprintf(&prntBuf[0] + len,"\n"); + + stream->write_function(stream, "\n%s\n",&prntBuf[0]); + + return SWITCH_STATUS_SUCCESS; +} + +/****************************************************************************************************************/ +switch_status_t megaco_profile_status(switch_stream_handle_t *stream, const char* profilename) +{ + int idx = 0x00; + int len = 0x00; + MgMngmt cfm; + char prntBuf[1024]; + megaco_profile_t* mg_cfg = NULL; + mg_peer_profile_t* mg_peer = NULL; + + switch_assert(profilename); + + memset((U8 *)&cfm, 0, sizeof(cfm)); + memset((char *)&prntBuf, 0, sizeof(prntBuf)); + + mg_cfg = megaco_profile_locate(profilename); + if(!mg_cfg){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG configuration found against profilename[%s]\n",profilename); + return SWITCH_STATUS_FALSE; + } + mg_peer = megaco_peer_profile_locate(mg_cfg->peer_list[0]); + + if(!mg_peer){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG peer configuration found for peername[%s] against profilename[%s]\n",mg_cfg->peer_list[0],profilename); + return SWITCH_STATUS_FALSE; + } + + idx = mg_cfg->idx; + + /*stream->write_function(stream, "Collecting MG Profile[%s] status... \n",profilename);*/ + + /* Fetch data from Trillium MEGACO Stack * + * SystemId - Software version information * + * SSAP - MG SAP Information * + * TSAP - MG Transport SAP Information * + * Peer - MG Peer Information * + * TPT-Server - MG Transport Server information * + */ + +#if 0 + /* get System ID */ + sng_mgco_mg_get_status(STSID, &cfm, idx); + stream->write_function(stream, "***********************************************\n"); + stream->write_function(stream, "**** TRILLIUM MEGACO Software Information *****\n"); + stream->write_function(stream, "Version = %d \n", cfm.t.ssta.s.systemId.mVer); + stream->write_function(stream, "Version Revision = %d \n", cfm.t.ssta.s.systemId.mRev); + stream->write_function(stream, "Branch Version = %d \n", cfm.t.ssta.s.systemId.bVer); + stream->write_function(stream, "Branch Revision = %d \n", cfm.t.ssta.s.systemId.bRev); + stream->write_function(stream, "Part Number = %d \n", cfm.t.ssta.s.systemId.ptNmb); + stream->write_function(stream, "***********************************************\n"); +#endif + + /* MG Peer Information */ + sng_mgco_mg_get_status(STGCPENT, &cfm, mg_cfg, mg_peer); + smmgPrntPeerSta(&cfm.t.ssta.s.mgPeerSta); + + /* MG Peer Information */ + sng_mgco_mg_get_status(STSSAP, &cfm, mg_cfg, mg_peer); + smmgPrntSsapSta(&cfm.t.ssta.s.mgSSAPSta); + + /* MG Transport SAP Information */ + sng_mgco_mg_get_status(STTSAP, &cfm, mg_cfg, mg_peer); + len = len + sprintf(prntBuf+len,"***********************************************\n"); + len = len + sprintf(prntBuf+len,"**********MG TRANSPORT SAP Information**********\n"); + len = len + sprintf(prntBuf+len,"TSAP status:\n"); + len = len + sprintf(prntBuf+len,"state = %d, number of listeners %u\n", + (int)(cfm.t.ssta.s.mgTSAPSta.state), + (unsigned int)(cfm.t.ssta.s.mgTSAPSta.numServers)); + len = len + sprintf(prntBuf+len,"***********************************************\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"%s\n",prntBuf); + + /* MG Transport Server Information */ + sng_mgco_mg_get_status(STSERVER, &cfm, mg_cfg, mg_peer); + smmgPrntSrvSta(&cfm.t.ssta.s.mgTptSrvSta); + + return SWITCH_STATUS_SUCCESS; +} + +/******************************************************************************/ +void get_peer_xml_buffer(char* prntBuf, MgPeerSta* cfm) +{ + int len = 0x00; + int i = 0x00; + char *asciiAddr; + CmInetIpAddr ip; + + if(PRSNT_NODEF == cfm->namePres.pres) + { + len = len + sprintf(prntBuf+len, " %s \n", (char *)(cfm->name)); + } + else + { + len = len + sprintf(prntBuf+len, " Not Present \n"); + } + + /* + * Print all IP addresses in the IP addr table + */ + for(i=0; ipeerAddrTbl.count; i++) + { + switch (cfm->peerAddrTbl.netAddr[i].type) + { + case CM_NETADDR_IPV4: + { + ip = ntohl(cfm->peerAddrTbl.netAddr[i].u.ipv4NetAddr); + cmInetNtoa(ip, &asciiAddr); + len = len + sprintf(prntBuf+len, "%s\n",asciiAddr); + break; + } + case CM_NETADDR_IPV6: + { + char ipv6_buf[128]; + int len1= 0; + int j = 0; + memset(&ipv6_buf[0], 0, sizeof(ipv6_buf)); + len1 = len1 + sprintf(ipv6_buf+len1, "IP V6 address : %2x", (unsigned int) + (cfm->peerAddrTbl.netAddr[i].u.ipv6NetAddr[0])); + + for (j = 1; j < CM_IPV6ADDR_SIZE; j++) + { + len1 = len1 + sprintf(ipv6_buf+len1, ":%2x", (unsigned int) + (cfm->peerAddrTbl.netAddr[i].u.ipv6NetAddr[j])); + } + len1 = len1 + sprintf(ipv6_buf+len1, "\n"); + len = len + sprintf(prntBuf+len, "%s\n", ipv6_buf); + break; + } + default: + { + len = len + sprintf(prntBuf+len, " Invalid address type[%d]\n", cfm->peerAddrTbl.netAddr[i].type); + break; + } + } + } /* End of for */ + + len = len + sprintf(prntBuf+len," %lu \n",(unsigned long)(cfm->numPendOgTxn)); + len = len + sprintf(prntBuf+len," %lu \n",(unsigned long)(cfm->numPendIcTxn)); + len = len + sprintf(prntBuf+len," %lu \n",(unsigned long)(cfm->rttEstimate)); + + switch(cfm->protocol) + { + case LMG_PROTOCOL_MGCP: + len = len + sprintf(prntBuf+len," MGCP \n"); + break; + + case LMG_PROTOCOL_MGCO: + len = len + sprintf(prntBuf+len," MEGACO \n"); + break; + + case LMG_PROTOCOL_NONE: + len = len + sprintf(prntBuf+len," MGCP/MEGACO \n"); + break; + + default: + len = len + sprintf(prntBuf+len," invalid \n"); + break; + } + + switch(cfm->transportType) + { + case LMG_TPT_UDP: + len = len + sprintf(prntBuf+len, "UDP\n"); + break; + + case LMG_TPT_TCP: + len = len + sprintf(prntBuf+len, "TCP\n"); + break; + + case LMG_TPT_NONE: + len = len + sprintf(prntBuf+len, "UDP/TCP\n"); + break; + + default: + len = len + sprintf(prntBuf+len, "invalid\n"); + break; + } +#ifdef GCP_MGCO + switch(cfm->encodingScheme) + { + case LMG_ENCODE_BIN: + len = len + sprintf(prntBuf+len, "BINARY\n"); + break; + + case LMG_ENCODE_TXT: + len = len + sprintf(prntBuf+len, "TEXT\n"); + break; + + case LMG_ENCODE_NONE: + len = len + sprintf(prntBuf+len, "TEXT/BINARY\n"); + break; + + default: + len = len + sprintf(prntBuf+len, "invalid\n"); + break; + } + + if(LMG_VER_PROF_MGCO_H248_1_0 == cfm->version){ + len = len + sprintf(prntBuf+len, "1.0 \n"); + } else if(LMG_VER_PROF_MGCO_H248_2_0 == cfm->version){ + len = len + sprintf(prntBuf+len, "2.0 \n"); + }else if(LMG_VER_PROF_MGCO_H248_3_0 == cfm->version){ + len = len + sprintf(prntBuf+len, "3.0 \n"); + } else{ + len = len + sprintf(prntBuf+len, "invalid \n"); + } +#endif + +} +/******************************************************************************/ + diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.c b/src/mod/endpoints/mod_megaco/megaco_stack.c index 103f8726e7..6038173a8c 100644 --- a/src/mod/endpoints/mod_megaco/megaco_stack.c +++ b/src/mod/endpoints/mod_megaco/megaco_stack.c @@ -37,7 +37,6 @@ int sng_mgco_mg_app_ssap_stop(int idx); switch_status_t sng_mgco_stack_gen_cfg(); -void get_peer_xml_buffer(char* prntBuf, MgPeerSta* cfm); sng_mg_transport_types_e mg_get_tpt_type(megaco_profile_t* mg_cfg); sng_mg_transport_types_e mg_get_tpt_type_from_str(char* tpt_type); @@ -1179,482 +1178,6 @@ int sng_mgco_mg_shutdown() return (sng_cntrl_mg (&pst, &cntrl)); } /******************************************************************************/ -void handle_mg_alarm(Pst *pst, MgMngmt *usta) -{ - U16 ret; - int len = 0x00; - char prBuf[3048]; - - memset(&prBuf[0], 0, sizeof(prBuf)); - - len = len + sprintf(prBuf+len,"MG Status Indication: received with Category = %d, Event = %d, Cause = %d \n", - usta->t.usta.alarm.category, usta->t.usta.alarm.event, - usta->t.usta.alarm.cause); - - len = len + sprintf(prBuf+len, "Category ( "); - - switch (usta->t.usta.alarm.category) - { - case LCM_CATEGORY_PROTOCOL: - { - len = len + sprintf(prBuf+len, "protocol related "); - break; - } - case LCM_CATEGORY_INTERFACE: - { - len = len + sprintf(prBuf+len, "interface related "); - break; - } - case LCM_CATEGORY_INTERNAL: - { - len = len + sprintf(prBuf+len, "internal "); - break; - } - case LCM_CATEGORY_RESOURCE: - { - len = len + sprintf(prBuf+len, "system resources related "); - break; - } - case LCM_CATEGORY_PSF_FTHA: - { - len = len + sprintf(prBuf+len, "fault tolerance / high availability PSF related "); - break; - } - case LCM_CATEGORY_LYR_SPECIFIC: - { - len = len + sprintf(prBuf+len, "MGCP related "); - break; - } - default: - { - len = len + sprintf(prBuf+len, "unknown: %d", (int)(usta->t.usta.alarm.category)); - break; - } - } - len = len + sprintf(prBuf+len, ") "); - - len = len + sprintf(prBuf+len, " Event ( "); - switch (usta->t.usta.alarm.event) - { - case LMG_EVENT_TSAP_RECVRY_SUCCESS: - { - len = len + sprintf(prBuf+len, "TSAP recovery success"); - break; - } - case LMG_EVENT_TSAP_RECVRY_FAILED: - { - len = len + sprintf(prBuf+len, "TSAP recovery failed"); - break; - } - case LCM_EVENT_UI_INV_EVT: - { - len = len + sprintf(prBuf+len, "upper interface invalid event"); - break; - } - case LCM_EVENT_LI_INV_EVT: - { - len = len + sprintf(prBuf+len, "lower interface invalid event"); - break; - } - case LCM_EVENT_PI_INV_EVT: - { - len = len + sprintf(prBuf+len, "peer interface invalid event"); - break; - } - case LCM_EVENT_INV_EVT: - { - len = len + sprintf(prBuf+len, "general invalid event"); - break; - } - case LCM_EVENT_INV_STATE: - { - len = len + sprintf(prBuf+len, "invalid internal state"); - break; - } - case LCM_EVENT_INV_TMR_EVT: - { - len = len + sprintf(prBuf+len, "invalid timer event"); - break; - } - case LCM_EVENT_MI_INV_EVT: - { - len = len + sprintf(prBuf+len, "management interface invalid event"); - break; - } - case LCM_EVENT_BND_FAIL: - { - len = len + sprintf(prBuf+len, "bind failure"); - break; - } - case LCM_EVENT_NAK: - { - len = len + sprintf(prBuf+len, "destination nack"); - break; - } - case LCM_EVENT_TIMEOUT: - { - len = len + sprintf(prBuf+len, "timeout"); - break; - } - case LCM_EVENT_BND_OK: - { - len = len + sprintf(prBuf+len, "bind ok"); - break; - } - case LCM_EVENT_SMEM_ALLOC_FAIL: - { - len = len + sprintf(prBuf+len, "static memory allocation failed"); - break; - } - case LCM_EVENT_DMEM_ALLOC_FAIL: - { - len = len + sprintf(prBuf+len, "dynamic mmemory allocation failed"); - break; - } - case LCM_EVENT_LYR_SPECIFIC: - { - len = len + sprintf(prBuf+len, "MGCP specific"); - break; - } - default: - { - len = len + sprintf(prBuf+len, "unknown event %d", (int)(usta->t.usta.alarm.event)); - break; - } - case LMG_EVENT_HIT_BNDCFM: - { - len = len + sprintf(prBuf+len, "HIT bind confirm"); - break; - } - case LMG_EVENT_HIT_CONCFM: - { - len = len + sprintf(prBuf+len, "HIT connect confirm"); - break; - } - case LMG_EVENT_HIT_DISCIND: - { - len = len + sprintf(prBuf+len, "HIT disconnect indication"); - break; - } - case LMG_EVENT_HIT_UDATIND: - { - len = len + sprintf(prBuf+len, "HIT unit data indication"); - break; - } - case LMG_EVENT_MGT_BNDREQ: - { - len = len + sprintf(prBuf+len, "MGT bind request"); - break; - } - case LMG_EVENT_PEER_CFG_FAIL: - { - len = len + sprintf(prBuf+len, "Peer Configuration Failed"); - break; - } - case LMG_EVENT_MGT_UBNDREQ: - { - len = len + sprintf(prBuf+len, "MGT unbind request"); - break; - } - case LMG_EVENT_MGT_MGCPTXNREQ: - { - len = len + sprintf(prBuf+len, "MGT MGCP transaction request"); - break; - } - case LMG_EVENT_MGT_MGCPTXNIND: - { - len = len + sprintf(prBuf+len, "MGT MGCP transaction indication"); - break; - } - - case LMG_EVENT_PEER_ENABLED: - { - len = len + sprintf(prBuf+len, "gateway enabled"); - break; - } - case LMG_EVENT_PEER_DISCOVERED: - { - len = len + sprintf(prBuf+len, "gateway discovered , notified entity"); - break; - } - case LMG_EVENT_PEER_REMOVED: - { - len = len + sprintf(prBuf+len, "gateway removed"); - break; - } - case LMG_EVENT_RES_CONG_ON: - { - len = len + sprintf(prBuf+len, "resource congestion ON"); - break; - } - case LMG_EVENT_RES_CONG_OFF: - { - len = len + sprintf(prBuf+len, "resource congestion OFF"); - break; - } - case LMG_EVENT_TPTSRV: - { - len = len + sprintf(prBuf+len, "transport service"); - break; - } - case LMG_EVENT_SSAP_ENABLED: - { - len = len + sprintf(prBuf+len, "SSAP enabled"); - break; - } - case LMG_EVENT_NS_NOT_RESPONDING: - { - len = len + sprintf(prBuf+len, "name server not responding"); - break; - } - case LMG_EVENT_TPT_FAILED: - { - len = len + sprintf(prBuf+len, "transport failure"); - break; - } - } - - len = len + sprintf(prBuf+len, " ) "); - - len = len + sprintf(prBuf+len, " cause ( "); - switch (usta->t.usta.alarm.cause) - { - case LCM_CAUSE_UNKNOWN: - { - len = len + sprintf(prBuf+len, "unknown"); - break; - } - case LCM_CAUSE_OUT_OF_RANGE: - { - len = len + sprintf(prBuf+len, "out of range"); - break; - } - case LCM_CAUSE_INV_SAP: - { - len = len + sprintf(prBuf+len, "NULL/unknown sap"); - break; - } - case LCM_CAUSE_INV_SPID: - { - len = len + sprintf(prBuf+len, "invalid service provider"); - break; - } - case LCM_CAUSE_INV_SUID: - { - len = len + sprintf(prBuf+len, "invalid service user"); - break; - } - case LCM_CAUSE_INV_NETWORK_MSG: - { - len = len + sprintf(prBuf+len, "invalid network message"); - break; - } - case LCM_CAUSE_DECODE_ERR: - { - len = len + sprintf(prBuf+len, "message decoding problem"); - break; - } - case LCM_CAUSE_USER_INITIATED: - { - len = len + sprintf(prBuf+len, "user initiated"); - break; - } - case LCM_CAUSE_MGMT_INITIATED: - { - len = len + sprintf(prBuf+len, "management initiated"); - break; - } - case LCM_CAUSE_INV_STATE: /* cause and event! */ - { - len = len + sprintf(prBuf+len, "invalid state"); - break; - } - case LCM_CAUSE_TMR_EXPIRED: /* cause and event! */ - { - len = len + sprintf(prBuf+len, "timer expired"); - break; - } - case LCM_CAUSE_INV_MSG_LENGTH: - { - len = len + sprintf(prBuf+len, "invalid message length"); - break; - } - case LCM_CAUSE_PROT_NOT_ACTIVE: - { - len = len + sprintf(prBuf+len, "protocol layer not active"); - break; - } - case LCM_CAUSE_INV_PAR_VAL: - { - len = len + sprintf(prBuf+len, "invalid parameter value"); - break; - } - case LCM_CAUSE_NEG_CFM: - { - len = len + sprintf(prBuf+len, "negative confirmation"); - break; - } - case LCM_CAUSE_MEM_ALLOC_FAIL: - { - len = len + sprintf(prBuf+len, "memory allocation failure"); - break; - } - case LCM_CAUSE_HASH_FAIL: - { - len = len + sprintf(prBuf+len, "hashing failure"); - break; - } - case LCM_CAUSE_LYR_SPECIFIC: - { - len = len + sprintf(prBuf+len, "MGCP specific"); - break; - } - default: - { - len = len + sprintf(prBuf+len, "unknown %d", (int)(usta->t.usta.alarm.cause)); - break; - } - case LMG_CAUSE_TPT_FAILURE: /* make up your mind - cause or event? */ - { - len = len + sprintf(prBuf+len, "transport failure"); - break; - } - case LMG_CAUSE_NS_NOT_RESPONDING: - { - len = len + sprintf(prBuf+len, "name server not responding"); - break; - } - } - len = len + sprintf(prBuf+len, " ) "); - - len = len + sprintf(prBuf+len, " Alarm parameters ( "); - ret = smmgGetAlarmInfoField(&usta->t.usta); - switch (ret) - { - case SMMG_UNKNOWNFIELD: - { - len = len + sprintf(prBuf+len, "invalid "); - - break; - } - case SMMG_PEERINFO: - { - /* - * Invoke the new function for printing the MgPeerInfo & - * delete all print code here - */ - smmgPrntPeerInfo(&(usta->t.usta.alarmInfo.u.peerInfo)); - break; - } - case SMMG_SAPID: - { - len = len + sprintf(prBuf+len, "SAP ID %d\n", (int)(usta->t.usta.alarmInfo.u.sapId)); - break; - } - case SMMG_MEM: - { - len = len + sprintf(prBuf+len, "memory region %d pool %d\n", - (int)(usta->t.usta.alarmInfo.u.mem.region), - (int)(usta->t.usta.alarmInfo.u.mem.pool)); - - break; - } - case SMMG_SRVSTA: - { - smmgPrntSrvSta(&usta->t.usta.alarmInfo.u.srvSta); - break; - } - case SMMG_PEERSTA: - { - smmgPrntPeerSta(&usta->t.usta.alarmInfo.u.peerSta); - break; - } - case SMMG_SSAPSTA: - { - smmgPrntSsapSta(&usta->t.usta.alarmInfo.u.ssapSta); - break; - } - case SMMG_PARID: - { - len = len + sprintf(prBuf+len, "parameter type: "); - switch (usta->t.usta.alarmInfo.u.parId.parType) - { - case LMG_PAR_TPTADDR: len = len + sprintf(prBuf+len, "transport address"); break; - case LMG_PAR_MBUF: len = len + sprintf(prBuf+len, "message buffer"); break; - case LMG_PAR_CHOICE: len = len + sprintf(prBuf+len, "choice"); break; - case LMG_PAR_SPID: len = len + sprintf(prBuf+len, "spId"); break; - default: len = len + sprintf(prBuf+len, "unknown"); break; - } - - len = len + sprintf(prBuf+len, ", value %d\n", - (int)(usta->t.usta.alarmInfo.u.parId.u.sapId)); - - break; - } - case SMMG_NOT_APPL: - { - len = len + sprintf(prBuf+len, "not applicable\n"); - break; - } - - /*TODO*/ - } - len = len + sprintf(prBuf+len, " ) "); - len = len + sprintf(prBuf+len, " \n "); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s \n", prBuf); -} - -/*****************************************************************************************************************************/ -void handle_tucl_alarm(Pst *pst, HiMngmt *sta) -{ - /* To print the general information */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Recieved a status indication from TUCL layer \n\n"); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " Category = %d , event = %d , cause = %d\n", - sta->t.usta.alarm.category, - sta->t.usta.alarm.event, sta->t.usta.alarm.cause); - - switch(sta->t.usta.alarm.event) - { - case LCM_EVENT_INV_EVT: - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," [HI_USTA]: LCM_EVENT_INV_EVT with type (%d)\n\n", - sta->t.usta.info.type); - break; - } - case LHI_EVENT_BNDREQ: - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," [HI_USTA]: LHI_EVENT_BNDREQ with type (%d) spId (%d)\n\n", - sta->t.usta.info.type, sta->t.usta.info.spId); - break; - } - case LHI_EVENT_SERVOPENREQ: - case LHI_EVENT_DATREQ: - case LHI_EVENT_UDATREQ: - case LHI_EVENT_CONREQ: - case LHI_EVENT_DISCREQ: -#if(defined(HI_TLS) && defined(HI_TCP_TLS)) - case LHI_EVENT_TLS_ESTREQ: -#endif - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," [HI_USTA]: partype (%d) type(%d)\n\n", - sta->t.usta.info.inf.parType, sta->t.usta.info.type); - break; - } - case LCM_EVENT_DMEM_ALLOC_FAIL: - case LCM_EVENT_SMEM_ALLOC_FAIL: - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " [HI_USTA]: MEM_ALLOC_FAIL with region(%d) pool (%d) type(%d)\n\n", - sta->t.usta.info.inf.mem.region, sta->t.usta.info.inf.mem.pool, - sta->t.usta.info.type); - break; - } - default: - break; - } - -} /* handle_sng_tucl_alarm */ -/******************************************************************************/ - int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, megaco_profile_t* mg_cfg, mg_peer_profile_t* mg_peer) { Pst pst; @@ -1722,368 +1245,7 @@ int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, megaco_profile_t* mg_cfg, return (sng_sta_mg (&pst, &cntrl, cfm)); } -/******************************************************************************/ -switch_status_t megaco_profile_status(switch_stream_handle_t *stream, const char* profilename) -{ - int idx = 0x00; - int len = 0x00; - MgMngmt cfm; - char prntBuf[1024]; - megaco_profile_t* mg_cfg = NULL; - mg_peer_profile_t* mg_peer = NULL; - - switch_assert(profilename); - - memset((U8 *)&cfm, 0, sizeof(cfm)); - memset((char *)&prntBuf, 0, sizeof(prntBuf)); - - mg_cfg = megaco_profile_locate(profilename); - if(!mg_cfg){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG configuration found against profilename[%s]\n",profilename); - return SWITCH_STATUS_FALSE; - } - mg_peer = megaco_peer_profile_locate(mg_cfg->peer_list[0]); - - if(!mg_peer){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG peer configuration found for peername[%s] against profilename[%s]\n",mg_cfg->peer_list[0],profilename); - return SWITCH_STATUS_FALSE; - } - - idx = mg_cfg->idx; - - /*stream->write_function(stream, "Collecting MG Profile[%s] status... \n",profilename);*/ - - /* Fetch data from Trillium MEGACO Stack * - * SystemId - Software version information * - * SSAP - MG SAP Information * - * TSAP - MG Transport SAP Information * - * Peer - MG Peer Information * - * TPT-Server - MG Transport Server information * - */ - -#if 0 - /* get System ID */ - sng_mgco_mg_get_status(STSID, &cfm, idx); - stream->write_function(stream, "***********************************************\n"); - stream->write_function(stream, "**** TRILLIUM MEGACO Software Information *****\n"); - stream->write_function(stream, "Version = %d \n", cfm.t.ssta.s.systemId.mVer); - stream->write_function(stream, "Version Revision = %d \n", cfm.t.ssta.s.systemId.mRev); - stream->write_function(stream, "Branch Version = %d \n", cfm.t.ssta.s.systemId.bVer); - stream->write_function(stream, "Branch Revision = %d \n", cfm.t.ssta.s.systemId.bRev); - stream->write_function(stream, "Part Number = %d \n", cfm.t.ssta.s.systemId.ptNmb); - stream->write_function(stream, "***********************************************\n"); -#endif - - /* MG Peer Information */ - sng_mgco_mg_get_status(STGCPENT, &cfm, mg_cfg, mg_peer); - smmgPrntPeerSta(&cfm.t.ssta.s.mgPeerSta); - - /* MG Peer Information */ - sng_mgco_mg_get_status(STSSAP, &cfm, mg_cfg, mg_peer); - smmgPrntSsapSta(&cfm.t.ssta.s.mgSSAPSta); - - /* MG Transport SAP Information */ - sng_mgco_mg_get_status(STTSAP, &cfm, mg_cfg, mg_peer); - len = len + sprintf(prntBuf+len,"***********************************************\n"); - len = len + sprintf(prntBuf+len,"**********MG TRANSPORT SAP Information**********\n"); - len = len + sprintf(prntBuf+len,"TSAP status:\n"); - len = len + sprintf(prntBuf+len,"state = %d, number of listeners %u\n", - (int)(cfm.t.ssta.s.mgTSAPSta.state), - (unsigned int)(cfm.t.ssta.s.mgTSAPSta.numServers)); - len = len + sprintf(prntBuf+len,"***********************************************\n"); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"%s\n",prntBuf); - - /* MG Transport Server Information */ - sng_mgco_mg_get_status(STSERVER, &cfm, mg_cfg, mg_peer); - smmgPrntSrvSta(&cfm.t.ssta.s.mgTptSrvSta); - - return SWITCH_STATUS_SUCCESS; -} -/******************************************************************************/ -switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const char* profilename) -{ - int idx = 0x00; - int len = 0x00; - MgMngmt cfm; - char* xmlhdr = ""; - char prntBuf[3048]; - int i = 0x00; - char *asciiAddr; - CmInetIpAddr ip; - megaco_profile_t* mg_cfg = NULL; - mg_peer_profile_t* mg_peer = NULL; - - switch_assert(profilename); - - memset((U8 *)&cfm, 0, sizeof(cfm)); - memset((char *)&prntBuf, 0, sizeof(prntBuf)); - - mg_cfg = megaco_profile_locate(profilename); - if(!mg_cfg){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG configuration found against profilename[%s]\n",profilename); - return SWITCH_STATUS_FALSE; - } - mg_peer = megaco_peer_profile_locate(mg_cfg->peer_list[0]); - - if(!mg_peer){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG peer configuration found for peername[%s] against profilename[%s]\n",mg_cfg->peer_list[0],profilename); - return SWITCH_STATUS_FALSE; - } - - - idx = mg_cfg->idx; - - len = len + sprintf(&prntBuf[0] + len,"%s\n",xmlhdr); - - len = len + sprintf(&prntBuf[0] + len,"\n"); - len = len + sprintf(&prntBuf[0] + len,"%s\n",mg_cfg->name); - len = len + sprintf(&prntBuf[0] + len,"%s\n",profilename); -/****************************************************************************************************************/ -/* Print Peer Information ***************************************************************************************/ - - /* TODO - as of now supporting only one peer .. need to add logic to iterate through all the peers associated with this profile..*/ - - len = len + sprintf(&prntBuf[0] + len,"\n"); - len = len + sprintf(&prntBuf[0] + len,"\n",mg_peer->name); - - /* send request to MEGACO Trillium stack to get peer information*/ - sng_mgco_mg_get_status(STGCPENT, &cfm, mg_cfg, mg_peer); - - get_peer_xml_buffer(&prntBuf[0] + len, &cfm.t.ssta.s.mgPeerSta); - - len = len + sprintf(&prntBuf[0] + len,"\n"); - len = len + sprintf(&prntBuf[0] + len,"\n"); - - -/****************************************************************************************************************/ -/* Print MG SAP Information ***************************************************************************************/ - - len = len + sprintf(&prntBuf[0] + len,"\n"); - - /* MG SAP Information */ - sng_mgco_mg_get_status(STSSAP, &cfm, mg_cfg, mg_peer); - - len = len + sprintf(prntBuf+len, " %s \n", PRNT_SAP_STATE((int)(cfm.t.ssta.s.mgSSAPSta.state))); - len = len + sprintf(prntBuf+len, " %u \n", (unsigned int)(cfm.t.ssta.s.mgSSAPSta.numAssocPeer)); - len = len + sprintf(prntBuf+len, " %u \n", (unsigned int)(cfm.t.ssta.s.mgSSAPSta.numServers)); - len = len + sprintf(&prntBuf[0] + len,"\n"); - for (i = 0; i < cfm.t.ssta.s.mgSSAPSta.numAssocPeer; i++) - { - len = len + sprintf(&prntBuf[0] + len,"\n"); - if(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].dname.namePres.pres == PRSNT_NODEF) - { - len = len + sprintf(prntBuf+len, " %s \n", (char *)(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].dname.name)); - } - switch(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].dname.netAddr.type) - { - case CM_NETADDR_IPV4: - { - ip = ntohl(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].dname.netAddr.u.ipv4NetAddr); - cmInetNtoa(ip, &asciiAddr); - len = len + sprintf(prntBuf+len, "%s\n",asciiAddr); - break; - } - default: - len = len + sprintf(prntBuf+len, "invalid type \n"); - break; - } - -#ifdef GCP_MGCO - if (PRSNT_NODEF == cfm.t.ssta.s.mgSSAPSta.peerInfo[i].mid.pres) - { - len = len + sprintf(prntBuf+len, " %s \n", (char *)(cfm.t.ssta.s.mgSSAPSta.peerInfo[i].mid.val)); - } -#endif /* GCP_MGCO */ - len = len + sprintf(&prntBuf[0] + len,"\n"); - } - len = len + sprintf(&prntBuf[0] + len,"\n"); - - len = len + sprintf(&prntBuf[0] + len,"\n"); - -/****************************************************************************************************************/ -/* Print MG Transport SAP Information ***************************************************************************************/ - - len = len + sprintf(&prntBuf[0] + len,"\n"); - /* MG Transport SAP Information */ - sng_mgco_mg_get_status(STTSAP, &cfm, mg_cfg, mg_peer); - len = len + sprintf(&prntBuf[0] + len," %s \n", PRNT_SAP_STATE(cfm.t.ssta.s.mgTSAPSta.state)); - len = len + sprintf(&prntBuf[0] + len," %u \n", (unsigned int)(cfm.t.ssta.s.mgTSAPSta.numServers)); - len = len + sprintf(&prntBuf[0] + len,"\n"); - -/****************************************************************************************************************/ -/* Print MG Transport Server Information ***************************************************************************************/ - - if(sng_mgco_mg_get_status(STSERVER, &cfm, mg_cfg, mg_peer)){ - len = len + sprintf(&prntBuf[0] + len," no established server found \n"); - } - else { - len = len + sprintf(&prntBuf[0] + len,"\n"); - len = len + sprintf(&prntBuf[0] + len," %s \n", PRNT_SAP_STATE(cfm.t.ssta.s.mgTptSrvSta.state)); - len = len + sprintf(prntBuf+len, ""); - - switch (cfm.t.ssta.s.mgTptSrvSta.tptAddr.type) - { - case CM_TPTADDR_NOTPRSNT: - { - len = len + sprintf(prntBuf+len, "none"); - break; - } - case CM_TPTADDR_IPV4: - { - ip = ntohl(cfm.t.ssta.s.mgTptSrvSta.tptAddr.u.ipv4TptAddr.address); - cmInetNtoa(ip, &asciiAddr); - len = len + sprintf(prntBuf+len, "IPv4 IP address #%s, port %u",asciiAddr, - (unsigned int)(cfm.t.ssta.s.mgTptSrvSta.tptAddr.u.ipv4TptAddr.port)); - - break; - } - default: - len = len + sprintf(prntBuf+len, "unknown"); - break; - } - len = len + sprintf(prntBuf+len, "\n"); - len = len + sprintf(&prntBuf[0] + len,"\n"); - } - -/****************************************************************************************************************/ - len = len + sprintf(&prntBuf[0] + len,"\n"); - - stream->write_function(stream, "\n%s\n",&prntBuf[0]); - - return SWITCH_STATUS_SUCCESS; -} - -/******************************************************************************/ - -void get_peer_xml_buffer(char* prntBuf, MgPeerSta* cfm) -{ - int len = 0x00; - int i = 0x00; - char *asciiAddr; - CmInetIpAddr ip; - - if(PRSNT_NODEF == cfm->namePres.pres) - { - len = len + sprintf(prntBuf+len, " %s \n", (char *)(cfm->name)); - } - else - { - len = len + sprintf(prntBuf+len, " Not Present \n"); - } - - /* - * Print all IP addresses in the IP addr table - */ - for(i=0; ipeerAddrTbl.count; i++) - { - switch (cfm->peerAddrTbl.netAddr[i].type) - { - case CM_NETADDR_IPV4: - { - ip = ntohl(cfm->peerAddrTbl.netAddr[i].u.ipv4NetAddr); - cmInetNtoa(ip, &asciiAddr); - len = len + sprintf(prntBuf+len, "%s\n",asciiAddr); - break; - } - case CM_NETADDR_IPV6: - { - char ipv6_buf[128]; - int len1= 0; - int j = 0; - memset(&ipv6_buf[0], 0, sizeof(ipv6_buf)); - len1 = len1 + sprintf(ipv6_buf+len1, "IP V6 address : %2x", (unsigned int) - (cfm->peerAddrTbl.netAddr[i].u.ipv6NetAddr[0])); - - for (j = 1; j < CM_IPV6ADDR_SIZE; j++) - { - len1 = len1 + sprintf(ipv6_buf+len1, ":%2x", (unsigned int) - (cfm->peerAddrTbl.netAddr[i].u.ipv6NetAddr[j])); - } - len1 = len1 + sprintf(ipv6_buf+len1, "\n"); - len = len + sprintf(prntBuf+len, "%s\n", ipv6_buf); - break; - } - default: - { - len = len + sprintf(prntBuf+len, " Invalid address type[%d]\n", cfm->peerAddrTbl.netAddr[i].type); - break; - } - } - } /* End of for */ - - len = len + sprintf(prntBuf+len," %lu \n",(unsigned long)(cfm->numPendOgTxn)); - len = len + sprintf(prntBuf+len," %lu \n",(unsigned long)(cfm->numPendIcTxn)); - len = len + sprintf(prntBuf+len," %lu \n",(unsigned long)(cfm->rttEstimate)); - - switch(cfm->protocol) - { - case LMG_PROTOCOL_MGCP: - len = len + sprintf(prntBuf+len," MGCP \n"); - break; - - case LMG_PROTOCOL_MGCO: - len = len + sprintf(prntBuf+len," MEGACO \n"); - break; - - case LMG_PROTOCOL_NONE: - len = len + sprintf(prntBuf+len," MGCP/MEGACO \n"); - break; - - default: - len = len + sprintf(prntBuf+len," invalid \n"); - break; - } - - switch(cfm->transportType) - { - case LMG_TPT_UDP: - len = len + sprintf(prntBuf+len, "UDP\n"); - break; - - case LMG_TPT_TCP: - len = len + sprintf(prntBuf+len, "TCP\n"); - break; - - case LMG_TPT_NONE: - len = len + sprintf(prntBuf+len, "UDP/TCP\n"); - break; - - default: - len = len + sprintf(prntBuf+len, "invalid\n"); - break; - } -#ifdef GCP_MGCO - switch(cfm->encodingScheme) - { - case LMG_ENCODE_BIN: - len = len + sprintf(prntBuf+len, "BINARY\n"); - break; - - case LMG_ENCODE_TXT: - len = len + sprintf(prntBuf+len, "TEXT\n"); - break; - - case LMG_ENCODE_NONE: - len = len + sprintf(prntBuf+len, "TEXT/BINARY\n"); - break; - - default: - len = len + sprintf(prntBuf+len, "invalid\n"); - break; - } - - if(LMG_VER_PROF_MGCO_H248_1_0 == cfm->version){ - len = len + sprintf(prntBuf+len, "1.0 \n"); - } else if(LMG_VER_PROF_MGCO_H248_2_0 == cfm->version){ - len = len + sprintf(prntBuf+len, "2.0 \n"); - }else if(LMG_VER_PROF_MGCO_H248_3_0 == cfm->version){ - len = len + sprintf(prntBuf+len, "3.0 \n"); - } else{ - len = len + sprintf(prntBuf+len, "invalid \n"); - } -#endif - -} + /**********************************************************************************************************************************/ sng_mg_transport_types_e mg_get_tpt_type(megaco_profile_t* mg_profile) { diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.h b/src/mod/endpoints/mod_megaco/megaco_stack.h index dabf4a5551..0e10bc346d 100644 --- a/src/mod/endpoints/mod_megaco/megaco_stack.h +++ b/src/mod/endpoints/mod_megaco/megaco_stack.h @@ -8,36 +8,10 @@ #include "mod_megaco.h" -#ifndef _MEGACO_CFG_H_ -#define _MEGACO_CFG_H_ +#ifndef _MEGACO_STACK_H_ +#define _MEGACO_STACK_H_ #define MAX_MID_LEN 30 -#define MAX_DOMAIN_LEN 30 -#define MAX_NAME_LEN 25 -#define MAX_MG_PROFILES 5 - -#if 0 -typedef struct sng_mg_peer{ - char name[MAX_NAME_LEN]; /* Peer Name as defined in config file */ - uint16_t id; /* Peer ID as defined in config file */ - uint8_t ipaddr[MAX_DOMAIN_LEN]; /* Peer IP */ - uint16_t port; /*Peer Port */ - uint8_t mid[MAX_MID_LEN]; /* Peer H.248 MID */ - uint16_t encoding_type; /* Encoding TEXT/Binary */ -}sng_mg_peer_t; - -typedef struct sng_mg_peers{ - uint16_t total_peer; /* Total number of MGC Peer */ - sng_mg_peer_t peers[MG_MAX_PEERS+1]; -}sng_mg_peers_t; - -typedef struct sng_mg_transport_profile{ - char name[MAX_NAME_LEN]; /* Peer Name as defined in config file */ - uint32_t id; /* map to tsap id */ - uint16_t transport_type; /* transport type */ -}sng_mg_transport_profile_t; - -#endif typedef enum{ SNG_MG_TPT_NONE, @@ -70,36 +44,6 @@ typedef enum{ "SNG_MG_ENCODING_NONE") -#if 0 -/* each profile is corresponds to each MG Instance */ -typedef struct sng_mg_cfg{ - char name[MAX_NAME_LEN]; /* MG(Virtual MG) Name as defined in config file */ - uint32_t id; /* Id - map to MG SAP ID */ - uint8_t mid[MAX_MID_LEN]; /* MG H.248 MID */ - uint8_t my_domain[MAX_DOMAIN_LEN]; /* local domain name */ - uint8_t my_ipaddr[MAX_DOMAIN_LEN]; /* local domain name */ - uint32_t port; /* port */ - uint16_t protocol_version; /* Protocol supported version */ - uint16_t peer_id; /* MGC Peer ID */ - uint16_t transport_prof_id; /* Transport profile id ..this also will be the spId for MG SAP*/ - uint16_t protocol_type; /* MEGACO/MGCP */ -}sng_mg_cfg_t; - - -typedef struct sng_mg_gbl_cfg{ - int num_of_mg_profiles; - sng_mg_cfg_t mgCfg[MAX_MG_PROFILES + 1]; - sng_mg_transport_profile_t mgTptProf[MG_MAX_PEERS+1]; /* transport profile */ - sng_mg_peers_t mgPeer; -}sng_mg_gbl_cfg_t; - - -extern switch_status_t sng_parse_mg_peer_profile(switch_xml_t mg_peer_profile); -extern switch_status_t sng_parse_mg_tpt_profile(switch_xml_t mg_tpt_profile); -extern switch_status_t sng_parse_mg_profile(switch_xml_t mg_interface); -#endif - - void handle_sng_log(uint8_t level, char *fmt, ...); void handle_mgco_sta_ind(Pst *pst, SuId suId, MgMgtSta* msg); void handle_mgco_txn_sta_ind(Pst *pst, SuId suId, MgMgcoInd* msg); @@ -115,30 +59,5 @@ switch_status_t sng_mgco_cfg(megaco_profile_t* profile); switch_status_t sng_mgco_init(sng_isup_event_interface_t* event); switch_status_t sng_mgco_stack_shutdown(void); int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, megaco_profile_t* mg_cfg, mg_peer_profile_t* mg_peer); -switch_status_t megaco_profile_status(switch_stream_handle_t *stream, const char* profilename); -switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const char* profilename); -/*****************************************************************************************************/ - -#if 0 -#define GET_MG_CFG_IDX(_profilename, _idx){\ - for(idx=0; idx < MAX_MG_PROFILES; idx++){\ - /* id zero is not acceptable */\ - if(megaco_globals.g_mg_cfg.mgCfg[idx].id){\ - if (strcmp(megaco_globals.g_mg_cfg.mgCfg[idx].name, profilename)) {\ - continue;\ - } else{\ - break;\ - }\ - }\ - }\ -} -#define GET_TPT_ID(_id) megaco_globals.g_mg_cfg.mgTptProf[megaco_globals.g_mg_cfg.mgCfg[_id].transport_prof_id].id -#define GET_MU_SAP_ID(_id) megaco_globals.g_mg_cfg.mgCfg[_id].id - -#define GET_TPT_TYPE(_id) megaco_globals.g_mg_cfg.mgTptProf[megaco_globals.g_mg_cfg.mgCfg[_id].transport_prof_id].transport_type - -#define GET_ENCODING_TYPE(_id) megaco_globals.g_mg_cfg.mgPeer.peers[megaco_globals.g_mg_cfg.mgCfg[_id].peer_id].encoding_type -#endif - -#endif /* _MEGACO_CFG_H_ */ +#endif /* _MEGACO_STACK_H_ */ diff --git a/src/mod/endpoints/mod_megaco/megaco_stack_alarms.c b/src/mod/endpoints/mod_megaco/megaco_stack_alarms.c new file mode 100644 index 0000000000..dd114a3850 --- /dev/null +++ b/src/mod/endpoints/mod_megaco/megaco_stack_alarms.c @@ -0,0 +1,495 @@ +/* +* Copyright (c) 2012, Sangoma Technologies +* Kapil Gupta +* All rights reserved. +* +* +*/ + +/* INCLUDES *******************************************************************/ +#include "mod_megaco.h" +#include "megaco_stack.h" +/******************************************************************************/ + +/* FUNCTION PROTOTYPES ********************************************************/ + +/******************************************************************************/ + +/* FUNCTIONS ******************************************************************/ + +void handle_mg_alarm(Pst *pst, MgMngmt *usta) +{ + U16 ret; + int len = 0x00; + char prBuf[3048]; + + memset(&prBuf[0], 0, sizeof(prBuf)); + + len = len + sprintf(prBuf+len,"MG Status Indication: received with Category = %d, Event = %d, Cause = %d \n", + usta->t.usta.alarm.category, usta->t.usta.alarm.event, + usta->t.usta.alarm.cause); + + len = len + sprintf(prBuf+len, "Category ( "); + + switch (usta->t.usta.alarm.category) + { + case LCM_CATEGORY_PROTOCOL: + { + len = len + sprintf(prBuf+len, "protocol related "); + break; + } + case LCM_CATEGORY_INTERFACE: + { + len = len + sprintf(prBuf+len, "interface related "); + break; + } + case LCM_CATEGORY_INTERNAL: + { + len = len + sprintf(prBuf+len, "internal "); + break; + } + case LCM_CATEGORY_RESOURCE: + { + len = len + sprintf(prBuf+len, "system resources related "); + break; + } + case LCM_CATEGORY_PSF_FTHA: + { + len = len + sprintf(prBuf+len, "fault tolerance / high availability PSF related "); + break; + } + case LCM_CATEGORY_LYR_SPECIFIC: + { + len = len + sprintf(prBuf+len, "MGCP related "); + break; + } + default: + { + len = len + sprintf(prBuf+len, "unknown: %d", (int)(usta->t.usta.alarm.category)); + break; + } + } + len = len + sprintf(prBuf+len, ") "); + + len = len + sprintf(prBuf+len, " Event ( "); + switch (usta->t.usta.alarm.event) + { + case LMG_EVENT_TSAP_RECVRY_SUCCESS: + { + len = len + sprintf(prBuf+len, "TSAP recovery success"); + break; + } + case LMG_EVENT_TSAP_RECVRY_FAILED: + { + len = len + sprintf(prBuf+len, "TSAP recovery failed"); + break; + } + case LCM_EVENT_UI_INV_EVT: + { + len = len + sprintf(prBuf+len, "upper interface invalid event"); + break; + } + case LCM_EVENT_LI_INV_EVT: + { + len = len + sprintf(prBuf+len, "lower interface invalid event"); + break; + } + case LCM_EVENT_PI_INV_EVT: + { + len = len + sprintf(prBuf+len, "peer interface invalid event"); + break; + } + case LCM_EVENT_INV_EVT: + { + len = len + sprintf(prBuf+len, "general invalid event"); + break; + } + case LCM_EVENT_INV_STATE: + { + len = len + sprintf(prBuf+len, "invalid internal state"); + break; + } + case LCM_EVENT_INV_TMR_EVT: + { + len = len + sprintf(prBuf+len, "invalid timer event"); + break; + } + case LCM_EVENT_MI_INV_EVT: + { + len = len + sprintf(prBuf+len, "management interface invalid event"); + break; + } + case LCM_EVENT_BND_FAIL: + { + len = len + sprintf(prBuf+len, "bind failure"); + break; + } + case LCM_EVENT_NAK: + { + len = len + sprintf(prBuf+len, "destination nack"); + break; + } + case LCM_EVENT_TIMEOUT: + { + len = len + sprintf(prBuf+len, "timeout"); + break; + } + case LCM_EVENT_BND_OK: + { + len = len + sprintf(prBuf+len, "bind ok"); + break; + } + case LCM_EVENT_SMEM_ALLOC_FAIL: + { + len = len + sprintf(prBuf+len, "static memory allocation failed"); + break; + } + case LCM_EVENT_DMEM_ALLOC_FAIL: + { + len = len + sprintf(prBuf+len, "dynamic mmemory allocation failed"); + break; + } + case LCM_EVENT_LYR_SPECIFIC: + { + len = len + sprintf(prBuf+len, "MGCP specific"); + break; + } + default: + { + len = len + sprintf(prBuf+len, "unknown event %d", (int)(usta->t.usta.alarm.event)); + break; + } + case LMG_EVENT_HIT_BNDCFM: + { + len = len + sprintf(prBuf+len, "HIT bind confirm"); + break; + } + case LMG_EVENT_HIT_CONCFM: + { + len = len + sprintf(prBuf+len, "HIT connect confirm"); + break; + } + case LMG_EVENT_HIT_DISCIND: + { + len = len + sprintf(prBuf+len, "HIT disconnect indication"); + break; + } + case LMG_EVENT_HIT_UDATIND: + { + len = len + sprintf(prBuf+len, "HIT unit data indication"); + break; + } + case LMG_EVENT_MGT_BNDREQ: + { + len = len + sprintf(prBuf+len, "MGT bind request"); + break; + } + case LMG_EVENT_PEER_CFG_FAIL: + { + len = len + sprintf(prBuf+len, "Peer Configuration Failed"); + break; + } + case LMG_EVENT_MGT_UBNDREQ: + { + len = len + sprintf(prBuf+len, "MGT unbind request"); + break; + } + case LMG_EVENT_MGT_MGCPTXNREQ: + { + len = len + sprintf(prBuf+len, "MGT MGCP transaction request"); + break; + } + case LMG_EVENT_MGT_MGCPTXNIND: + { + len = len + sprintf(prBuf+len, "MGT MGCP transaction indication"); + break; + } + + case LMG_EVENT_PEER_ENABLED: + { + len = len + sprintf(prBuf+len, "gateway enabled"); + break; + } + case LMG_EVENT_PEER_DISCOVERED: + { + len = len + sprintf(prBuf+len, "gateway discovered , notified entity"); + break; + } + case LMG_EVENT_PEER_REMOVED: + { + len = len + sprintf(prBuf+len, "gateway removed"); + break; + } + case LMG_EVENT_RES_CONG_ON: + { + len = len + sprintf(prBuf+len, "resource congestion ON"); + break; + } + case LMG_EVENT_RES_CONG_OFF: + { + len = len + sprintf(prBuf+len, "resource congestion OFF"); + break; + } + case LMG_EVENT_TPTSRV: + { + len = len + sprintf(prBuf+len, "transport service"); + break; + } + case LMG_EVENT_SSAP_ENABLED: + { + len = len + sprintf(prBuf+len, "SSAP enabled"); + break; + } + case LMG_EVENT_NS_NOT_RESPONDING: + { + len = len + sprintf(prBuf+len, "name server not responding"); + break; + } + case LMG_EVENT_TPT_FAILED: + { + len = len + sprintf(prBuf+len, "transport failure"); + break; + } + } + + len = len + sprintf(prBuf+len, " ) "); + + len = len + sprintf(prBuf+len, " cause ( "); + switch (usta->t.usta.alarm.cause) + { + case LCM_CAUSE_UNKNOWN: + { + len = len + sprintf(prBuf+len, "unknown"); + break; + } + case LCM_CAUSE_OUT_OF_RANGE: + { + len = len + sprintf(prBuf+len, "out of range"); + break; + } + case LCM_CAUSE_INV_SAP: + { + len = len + sprintf(prBuf+len, "NULL/unknown sap"); + break; + } + case LCM_CAUSE_INV_SPID: + { + len = len + sprintf(prBuf+len, "invalid service provider"); + break; + } + case LCM_CAUSE_INV_SUID: + { + len = len + sprintf(prBuf+len, "invalid service user"); + break; + } + case LCM_CAUSE_INV_NETWORK_MSG: + { + len = len + sprintf(prBuf+len, "invalid network message"); + break; + } + case LCM_CAUSE_DECODE_ERR: + { + len = len + sprintf(prBuf+len, "message decoding problem"); + break; + } + case LCM_CAUSE_USER_INITIATED: + { + len = len + sprintf(prBuf+len, "user initiated"); + break; + } + case LCM_CAUSE_MGMT_INITIATED: + { + len = len + sprintf(prBuf+len, "management initiated"); + break; + } + case LCM_CAUSE_INV_STATE: /* cause and event! */ + { + len = len + sprintf(prBuf+len, "invalid state"); + break; + } + case LCM_CAUSE_TMR_EXPIRED: /* cause and event! */ + { + len = len + sprintf(prBuf+len, "timer expired"); + break; + } + case LCM_CAUSE_INV_MSG_LENGTH: + { + len = len + sprintf(prBuf+len, "invalid message length"); + break; + } + case LCM_CAUSE_PROT_NOT_ACTIVE: + { + len = len + sprintf(prBuf+len, "protocol layer not active"); + break; + } + case LCM_CAUSE_INV_PAR_VAL: + { + len = len + sprintf(prBuf+len, "invalid parameter value"); + break; + } + case LCM_CAUSE_NEG_CFM: + { + len = len + sprintf(prBuf+len, "negative confirmation"); + break; + } + case LCM_CAUSE_MEM_ALLOC_FAIL: + { + len = len + sprintf(prBuf+len, "memory allocation failure"); + break; + } + case LCM_CAUSE_HASH_FAIL: + { + len = len + sprintf(prBuf+len, "hashing failure"); + break; + } + case LCM_CAUSE_LYR_SPECIFIC: + { + len = len + sprintf(prBuf+len, "MGCP specific"); + break; + } + default: + { + len = len + sprintf(prBuf+len, "unknown %d", (int)(usta->t.usta.alarm.cause)); + break; + } + case LMG_CAUSE_TPT_FAILURE: /* make up your mind - cause or event? */ + { + len = len + sprintf(prBuf+len, "transport failure"); + break; + } + case LMG_CAUSE_NS_NOT_RESPONDING: + { + len = len + sprintf(prBuf+len, "name server not responding"); + break; + } + } + len = len + sprintf(prBuf+len, " ) "); + + len = len + sprintf(prBuf+len, " Alarm parameters ( "); + ret = smmgGetAlarmInfoField(&usta->t.usta); + switch (ret) + { + case SMMG_UNKNOWNFIELD: + { + len = len + sprintf(prBuf+len, "invalid "); + + break; + } + case SMMG_PEERINFO: + { + /* + * Invoke the new function for printing the MgPeerInfo & + * delete all print code here + */ + smmgPrntPeerInfo(&(usta->t.usta.alarmInfo.u.peerInfo)); + break; + } + case SMMG_SAPID: + { + len = len + sprintf(prBuf+len, "SAP ID %d\n", (int)(usta->t.usta.alarmInfo.u.sapId)); + break; + } + case SMMG_MEM: + { + len = len + sprintf(prBuf+len, "memory region %d pool %d\n", + (int)(usta->t.usta.alarmInfo.u.mem.region), + (int)(usta->t.usta.alarmInfo.u.mem.pool)); + + break; + } + case SMMG_SRVSTA: + { + smmgPrntSrvSta(&usta->t.usta.alarmInfo.u.srvSta); + break; + } + case SMMG_PEERSTA: + { + smmgPrntPeerSta(&usta->t.usta.alarmInfo.u.peerSta); + break; + } + case SMMG_SSAPSTA: + { + smmgPrntSsapSta(&usta->t.usta.alarmInfo.u.ssapSta); + break; + } + case SMMG_PARID: + { + len = len + sprintf(prBuf+len, "parameter type: "); + switch (usta->t.usta.alarmInfo.u.parId.parType) + { + case LMG_PAR_TPTADDR: len = len + sprintf(prBuf+len, "transport address"); break; + case LMG_PAR_MBUF: len = len + sprintf(prBuf+len, "message buffer"); break; + case LMG_PAR_CHOICE: len = len + sprintf(prBuf+len, "choice"); break; + case LMG_PAR_SPID: len = len + sprintf(prBuf+len, "spId"); break; + default: len = len + sprintf(prBuf+len, "unknown"); break; + } + + len = len + sprintf(prBuf+len, ", value %d\n", + (int)(usta->t.usta.alarmInfo.u.parId.u.sapId)); + + break; + } + case SMMG_NOT_APPL: + { + len = len + sprintf(prBuf+len, "not applicable\n"); + break; + } + + /*TODO*/ + } + len = len + sprintf(prBuf+len, " ) "); + len = len + sprintf(prBuf+len, " \n "); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s \n", prBuf); +} + +/*****************************************************************************************************************************/ +void handle_tucl_alarm(Pst *pst, HiMngmt *sta) +{ + /* To print the general information */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Recieved a status indication from TUCL layer \n\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " Category = %d , event = %d , cause = %d\n", + sta->t.usta.alarm.category, + sta->t.usta.alarm.event, sta->t.usta.alarm.cause); + + switch(sta->t.usta.alarm.event) + { + case LCM_EVENT_INV_EVT: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," [HI_USTA]: LCM_EVENT_INV_EVT with type (%d)\n\n", + sta->t.usta.info.type); + break; + } + case LHI_EVENT_BNDREQ: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," [HI_USTA]: LHI_EVENT_BNDREQ with type (%d) spId (%d)\n\n", + sta->t.usta.info.type, sta->t.usta.info.spId); + break; + } + case LHI_EVENT_SERVOPENREQ: + case LHI_EVENT_DATREQ: + case LHI_EVENT_UDATREQ: + case LHI_EVENT_CONREQ: + case LHI_EVENT_DISCREQ: +#if(defined(HI_TLS) && defined(HI_TCP_TLS)) + case LHI_EVENT_TLS_ESTREQ: +#endif + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," [HI_USTA]: partype (%d) type(%d)\n\n", + sta->t.usta.info.inf.parType, sta->t.usta.info.type); + break; + } + case LCM_EVENT_DMEM_ALLOC_FAIL: + case LCM_EVENT_SMEM_ALLOC_FAIL: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " [HI_USTA]: MEM_ALLOC_FAIL with region(%d) pool (%d) type(%d)\n\n", + sta->t.usta.info.inf.mem.region, sta->t.usta.info.inf.mem.pool, + sta->t.usta.info.type); + break; + } + default: + break; + } + +} /* handle_sng_tucl_alarm */ +/******************************************************************************/ + diff --git a/src/mod/endpoints/mod_megaco/megaco_xml.c b/src/mod/endpoints/mod_megaco/megaco_xml.c index 52b1294cb2..236fb68cfd 100644 --- a/src/mod/endpoints/mod_megaco/megaco_xml.c +++ b/src/mod/endpoints/mod_megaco/megaco_xml.c @@ -165,229 +165,3 @@ static switch_xml_config_item_t *get_instructions(megaco_profile_t *profile) { } /****************************************************************************************************************************/ - -#if 0 -switch_status_t sng_parse_mg_profile(switch_xml_t mg_interface) -{ - int i = 0x00; - const char *prof_name = NULL; - switch_xml_t param; - - /*************************************************************************/ - prof_name = switch_xml_attr_soft(mg_interface, "name"); - - /*************************************************************************/ - for (param = switch_xml_child(mg_interface, "param"); param; param = param->next) { - char *var = (char *) switch_xml_attr_soft(param, "name"); - char *val = (char *) switch_xml_attr_soft(param, "value"); - if (!var || !val) { - continue; - } - - /******************************************************************************************/ - if(!strcasecmp(var, "id")){ - i = atoi(val); - megaco_globals.g_mg_cfg.mgCfg[i].id = i; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mg_interface Id[%d] \n", i); - /*******************************************************************************************/ - }else if(!strcasecmp(var, "protocol")){ - /********************************************************************************************/ - if(!strcasecmp(val,"MEGACO")) { - megaco_globals.g_mg_cfg.mgCfg[i].protocol_type = SNG_MG_MEGACO; - }else if(!strcasecmp(val,"MGCP")){ - megaco_globals.g_mg_cfg.mgCfg[i].protocol_type = SNG_MG_MGCP; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MGCP Protocol Not Yet Supported \n"); - return SWITCH_STATUS_FALSE; - }else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Protocol Value[%s] \n",val); - return SWITCH_STATUS_FALSE; - } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mg_interface protocol[%d] \n", - megaco_globals.g_mg_cfg.mgCfg[i].protocol_type); - /********************************************************************************************/ - }else if(!strcasecmp(var, "version")){ - /********************************************************************************************/ - megaco_globals.g_mg_cfg.mgCfg[i].protocol_version = atoi(val); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mg_interface protocol version[%s] \n",val); - if((megaco_globals.g_mg_cfg.mgCfg[i].protocol_version < 1) - || (megaco_globals.g_mg_cfg.mgCfg[i].protocol_version > 3)) - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Protocol version[%s] , Supported values are [1/2/3] \n",val); - return SWITCH_STATUS_FALSE; - } - /********************************************************************************************/ - }else if(!strcasecmp(var, "transportProfileId")){ - /********************************************************************************************/ - megaco_globals.g_mg_cfg.mgCfg[i].transport_prof_id = atoi(val); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mg_interface transport_prof_id[%d] \n", - megaco_globals.g_mg_cfg.mgCfg[i].transport_prof_id); - /********************************************************************************************/ - }else if(!strcasecmp(var, "localIp")){ - /***********************************************************************i*********************/ - strcpy((char*)&megaco_globals.g_mg_cfg.mgCfg[i].my_ipaddr[0],val); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mg_interface my_ipaddr[%s] \n", - megaco_globals.g_mg_cfg.mgCfg[i].my_ipaddr); - /********************************************************************************************/ - }else if(!strcasecmp(var, "port")){ - /********************************************************************************************/ - megaco_globals.g_mg_cfg.mgCfg[i].port = atoi(val); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, - " mg_interface my_port[%d] \n", megaco_globals.g_mg_cfg.mgCfg[i].port); - /********************************************************************************************/ - }else if(!strcasecmp(var, "myDomainName")){ - /********************************************************************************************/ - strcpy((char*)&megaco_globals.g_mg_cfg.mgCfg[i].my_domain[0],val); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, - " mg_interface myDomainName[%s] \n", megaco_globals.g_mg_cfg.mgCfg[i].my_domain); - /********************************************************************************************/ - }else if(!strcasecmp(var, "mid")){ - /********************************************************************************************/ - strcpy((char*)&megaco_globals.g_mg_cfg.mgCfg[i].mid[0],val); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, - " mg_interface mid[%s] \n", megaco_globals.g_mg_cfg.mgCfg[i].mid); - /********************************************************************************************/ - }else if(!strcasecmp(var, "peerId")){ - /********************************************************************************************/ - megaco_globals.g_mg_cfg.mgCfg[i].peer_id = atoi(val); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, - " mg_interface peerId[%d] \n", megaco_globals.g_mg_cfg.mgCfg[i].peer_id); - /********************************************************************************************/ - }else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " Invalid var[%s] in mg_interface \n", var); - return SWITCH_STATUS_FALSE; - } - } - - strcpy((char*)&megaco_globals.g_mg_cfg.mgCfg[i].name[0], prof_name); - - return SWITCH_STATUS_SUCCESS; -} - -/***********************************************************************************************************/ - -switch_status_t sng_parse_mg_tpt_profile(switch_xml_t mg_tpt_profile) -{ - int i = 0x00; - switch_xml_t param; - const char *prof_name = NULL; - - /*************************************************************************/ - prof_name = switch_xml_attr_soft(mg_tpt_profile, "name"); - - /*************************************************************************/ - for (param = switch_xml_child(mg_tpt_profile, "param"); param; param = param->next) { - char *var = (char *) switch_xml_attr_soft(param, "name"); - char *val = (char *) switch_xml_attr_soft(param, "value"); - if (!var || !val) { - continue; - } - - /******************************************************************************************/ - if(!strcasecmp(var, "id")){ - /*******************************************************************************************/ - i = atoi(val); - megaco_globals.g_mg_cfg.mgTptProf[i].id = i; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mg_tpt_profile Id[%d] \n", i); - /*******************************************************************************************/ - }else if(!strcasecmp(var, "transportType")){ - /*******************************************************************************************/ - if(!strcasecmp(val,"UDP")) { - megaco_globals.g_mg_cfg.mgTptProf[i].transport_type = SNG_MG_TPT_UDP; - }else if(!strcasecmp(val,"TCP")){ - megaco_globals.g_mg_cfg.mgTptProf[i].transport_type = SNG_MG_TPT_TCP; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "TCP Transport for H.248 Protocol Not Yet Supported \n"); - return SWITCH_STATUS_FALSE; - }else if(!strcasecmp(val,"STCP")){ - megaco_globals.g_mg_cfg.mgTptProf[i].transport_type = SNG_MG_TPT_SCTP; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "STCP Transport for H.248 Protocol Not Yet Supported \n"); - return SWITCH_STATUS_FALSE; - }else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Protocol Value[%s] \n",val); - return SWITCH_STATUS_FALSE; - } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mg_tpt_profile transport_type[%d] \n", - megaco_globals.g_mg_cfg.mgTptProf[i].transport_type); - /********************************************************************************************/ - }else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " Invalid var[%s] in mg_transport \n", var); - return SWITCH_STATUS_FALSE; - } - } - - strcpy((char*)&megaco_globals.g_mg_cfg.mgTptProf[i].name[0], prof_name); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, - " mg_tpt_profile Name[%s] \n", &megaco_globals.g_mg_cfg.mgTptProf[i].name[0]); - - return SWITCH_STATUS_SUCCESS; -} -/***********************************************************************************************************/ - -switch_status_t sng_parse_mg_peer_profile(switch_xml_t mg_peer_profile) -{ - int i = 0x00; - switch_xml_t param; - const char *prof_name = NULL; - - /*************************************************************************/ - prof_name = switch_xml_attr_soft(mg_peer_profile, "name"); - - for (param = switch_xml_child(mg_peer_profile, "param"); param; param = param->next) { - /***********************************************************************************************************/ - char *var = (char *) switch_xml_attr_soft(param, "name"); - char *val = (char *) switch_xml_attr_soft(param, "value"); - if (!var || !val) { - continue; - } - - /***********************************************************************************************************/ - if(!strcasecmp(var, "id")){ - /***********************************************************************************************************/ - i = atoi(val); - megaco_globals.g_mg_cfg.mgPeer.peers[i].id = i; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mg_peer_profile Id[%d] \n", i); - /***********************************************************************************************************/ - }else if(!strcasecmp(var, "port")){ - /***********************************************************************************************************/ - megaco_globals.g_mg_cfg.mgPeer.peers[i].port = atoi(val); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, - " mg_peer_profile port[%d] \n", megaco_globals.g_mg_cfg.mgPeer.peers[i].port); - /***********************************************************************************************************/ - }else if(!strcasecmp(var, "encodingScheme")){ - /***********************************************************************************************************/ - if(!strcasecmp(val, "TEXT")){ - megaco_globals.g_mg_cfg.mgPeer.peers[i].encoding_type = SNG_MG_ENCODING_TEXT; - } else if(!strcasecmp(val, "BINARY")){ - megaco_globals.g_mg_cfg.mgPeer.peers[i].encoding_type = SNG_MG_ENCODING_BINARY; - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Encoding Type[%s] \n",val); - return SWITCH_STATUS_FALSE; - } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, - " mg_peer_profile encodingScheme[%d] \n", megaco_globals.g_mg_cfg.mgPeer.peers[i].encoding_type); - /***********************************************************************************************************/ - }else if(!strcasecmp(var, "mid")){ - /***********************************************************************************************************/ - strcpy((char*)&megaco_globals.g_mg_cfg.mgPeer.peers[i].mid[0],val); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, - " mg_peer_profile mid[%s] \n", megaco_globals.g_mg_cfg.mgPeer.peers[i].mid); - /***********************************************************************************************************/ - }else if(!strcasecmp(var, "ip")){ - /***********************************************************************************************************/ - strcpy((char*)&megaco_globals.g_mg_cfg.mgPeer.peers[i].ipaddr[0],val); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, - " mg_peer_profile ip[%s] \n", megaco_globals.g_mg_cfg.mgPeer.peers[i].ipaddr); - /***********************************************************************************************************/ - }else{ - /***********************************************************************************************************/ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " Invalid var[%s] in mg_peer \n", var); - return SWITCH_STATUS_FALSE; - } - } - - strcpy((char*)&megaco_globals.g_mg_cfg.mgPeer.peers[i].name[0], prof_name); - - megaco_globals.g_mg_cfg.mgPeer.total_peer++; - return SWITCH_STATUS_SUCCESS; -} -#endif -/***********************************************************************************************************/ diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.c b/src/mod/endpoints/mod_megaco/mod_megaco.c index 94a0f64d13..e966c76095 100644 --- a/src/mod/endpoints/mod_megaco/mod_megaco.c +++ b/src/mod/endpoints/mod_megaco/mod_megaco.c @@ -16,84 +16,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_megaco_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_megaco_shutdown); SWITCH_MODULE_DEFINITION(mod_megaco, mod_megaco_load, mod_megaco_shutdown, NULL); -#define MEGACO_FUNCTION_SYNTAX "profile [name] [start | stop] [status] [xmlstatus]" SWITCH_STANDARD_API(megaco_function) { - int argc; - char *argv[10]; - char *dup = NULL; - - if (zstr(cmd)) { - goto usage; - } - - dup = strdup(cmd); - argc = switch_split(dup, ' ', argv); - - if (argc < 1 || zstr(argv[0])) { - goto usage; - } - -/**********************************************************************************/ - if (!strcmp(argv[0], "profile")) { - if (zstr(argv[1]) || zstr(argv[2])) { - goto usage; - } -/**********************************************************************************/ - if (!strcmp(argv[2], "start")) { -/**********************************************************************************/ - megaco_profile_t *profile = megaco_profile_locate(argv[1]); - if (profile) { - megaco_profile_release(profile); - stream->write_function(stream, "-ERR Profile %s is already started\n", argv[2]); - } else { - megaco_profile_start(argv[1]); - stream->write_function(stream, "+OK\n"); - } -/**********************************************************************************/ - } else if (!strcmp(argv[2], "stop")) { -/**********************************************************************************/ - megaco_profile_t *profile = megaco_profile_locate(argv[1]); - if (profile) { - megaco_profile_release(profile); - megaco_profile_destroy(&profile); - stream->write_function(stream, "+OK\n"); - } else { - stream->write_function(stream, "-ERR No such profile\n"); - } -/**********************************************************************************/ - }else if(!strcmp(argv[2], "status")) { -/**********************************************************************************/ - megaco_profile_t *profile = megaco_profile_locate(argv[1]); - if (profile) { - megaco_profile_status(stream, profile->name); - } else { - stream->write_function(stream, "-ERR No such profile\n"); - } -/**********************************************************************************/ - }else if(!strcmp(argv[2], "xmlstatus")) { -/**********************************************************************************/ - megaco_profile_t *profile = megaco_profile_locate(argv[1]); - if (profile) { - megaco_profile_xmlstatus(stream, profile->name); - } else { - stream->write_function(stream, "-ERR No such profile\n"); - } -/**********************************************************************************/ - }else { -/**********************************************************************************/ - goto usage; - } - } - - goto done; - - usage: - stream->write_function(stream, "-ERR Usage: "MEGACO_FUNCTION_SYNTAX"\n"); - - done: - switch_safe_free(dup); - return SWITCH_STATUS_SUCCESS; + return mg_process_cli_cmd(cmd, stream); } static switch_status_t console_complete_hashtable(switch_hash_t *hash, const char *line, const char *cursor, switch_console_callback_match_t **matches) diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.h b/src/mod/endpoints/mod_megaco/mod_megaco.h index a277a1f840..444639677c 100644 --- a/src/mod/endpoints/mod_megaco/mod_megaco.h +++ b/src/mod/endpoints/mod_megaco/mod_megaco.h @@ -15,6 +15,8 @@ #define MG_MAX_PEERS 5 +#define MEGACO_FUNCTION_SYNTAX "profile [name] [start | stop] [status] [xmlstatus]" + struct megaco_globals { switch_memory_pool_t *pool; switch_hash_t *profile_hash; @@ -68,6 +70,7 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload); switch_status_t sng_mgco_start(megaco_profile_t* profile); switch_status_t sng_mgco_stop(megaco_profile_t* profile); switch_status_t mg_config_cleanup(megaco_profile_t* profile); +switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stream); #endif /* MOD_MEGACO_H */ From 0fc6ccff7a19a4c009f446e6d44c84bc67f88e30 Mon Sep 17 00:00:00 2001 From: kapil Date: Wed, 6 Jun 2012 18:03:07 +0530 Subject: [PATCH 220/822] adding "peerxmlstatus" CLI command to show the peer status for requested profile --- src/mod/endpoints/mod_megaco/megaco_cli.c | 133 +++++++++++++++------- src/mod/endpoints/mod_megaco/mod_megaco.c | 1 + src/mod/endpoints/mod_megaco/mod_megaco.h | 2 +- 3 files changed, 94 insertions(+), 42 deletions(-) diff --git a/src/mod/endpoints/mod_megaco/megaco_cli.c b/src/mod/endpoints/mod_megaco/megaco_cli.c index e7d0794c49..0bdb334754 100644 --- a/src/mod/endpoints/mod_megaco/megaco_cli.c +++ b/src/mod/endpoints/mod_megaco/megaco_cli.c @@ -12,8 +12,9 @@ /******************************************************************************/ /* FUNCTION PROTOTYPES ********************************************************/ -switch_status_t megaco_profile_status(switch_stream_handle_t *stream, const char* profilename); -switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const char* profilename); +switch_status_t megaco_profile_status(switch_stream_handle_t *stream, megaco_profile_t* mg_cfg); +switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, megaco_profile_t* mg_cfg); +switch_status_t megaco_profile_peer_xmlstatus(switch_stream_handle_t *stream, megaco_profile_t* mg_cfg); void get_peer_xml_buffer(char* prntBuf, MgPeerSta* cfm); /******************************************************************************/ @@ -22,9 +23,10 @@ void get_peer_xml_buffer(char* prntBuf, MgPeerSta* cfm); switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stream) { - int argc; - char *argv[10]; - char *dup = NULL; + int argc; + char* argv[10]; + char* dup = NULL; + megaco_profile_t* profile = NULL; if (zstr(cmd)) { goto usage; @@ -37,15 +39,17 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre goto usage; } - /**********************************************************************************/ +/**********************************************************************************/ if (!strcmp(argv[0], "profile")) { if (zstr(argv[1]) || zstr(argv[2])) { goto usage; } - /**********************************************************************************/ +/**********************************************************************************/ + profile = megaco_profile_locate(argv[1]); + +/**********************************************************************************/ if (!strcmp(argv[2], "start")) { - /**********************************************************************************/ - megaco_profile_t *profile = megaco_profile_locate(argv[1]); +/**********************************************************************************/ if (profile) { megaco_profile_release(profile); stream->write_function(stream, "-ERR Profile %s is already started\n", argv[2]); @@ -53,10 +57,9 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre megaco_profile_start(argv[1]); stream->write_function(stream, "+OK\n"); } - /**********************************************************************************/ +/**********************************************************************************/ } else if (!strcmp(argv[2], "stop")) { - /**********************************************************************************/ - megaco_profile_t *profile = megaco_profile_locate(argv[1]); +/**********************************************************************************/ if (profile) { megaco_profile_release(profile); megaco_profile_destroy(&profile); @@ -64,27 +67,36 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre } else { stream->write_function(stream, "-ERR No such profile\n"); } - /**********************************************************************************/ +/**********************************************************************************/ }else if(!strcmp(argv[2], "status")) { - /**********************************************************************************/ - megaco_profile_t *profile = megaco_profile_locate(argv[1]); +/**********************************************************************************/ if (profile) { - megaco_profile_status(stream, profile->name); + megaco_profile_release(profile); + megaco_profile_status(stream, profile); } else { stream->write_function(stream, "-ERR No such profile\n"); } - /**********************************************************************************/ +/**********************************************************************************/ }else if(!strcmp(argv[2], "xmlstatus")) { - /**********************************************************************************/ - megaco_profile_t *profile = megaco_profile_locate(argv[1]); +/**********************************************************************************/ if (profile) { - megaco_profile_xmlstatus(stream, profile->name); + megaco_profile_release(profile); + megaco_profile_xmlstatus(stream, profile); } else { stream->write_function(stream, "-ERR No such profile\n"); } - /**********************************************************************************/ +/**********************************************************************************/ + }else if(!strcmp(argv[2], "peerxmlstatus")) { +/**********************************************************************************/ + if (profile) { + megaco_profile_release(profile); + megaco_profile_peer_xmlstatus(stream, profile); + } else { + stream->write_function(stream, "-ERR No such profile\n"); + } +/**********************************************************************************/ }else { - /**********************************************************************************/ +/**********************************************************************************/ goto usage; } } @@ -100,7 +112,7 @@ done: } /******************************************************************************/ -switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const char* profilename) +switch_status_t megaco_profile_peer_xmlstatus(switch_stream_handle_t *stream, megaco_profile_t* mg_cfg) { int idx = 0x00; int len = 0x00; @@ -110,23 +122,69 @@ switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const c int i = 0x00; char *asciiAddr; CmInetIpAddr ip; - megaco_profile_t* mg_cfg = NULL; mg_peer_profile_t* mg_peer = NULL; - switch_assert(profilename); + switch_assert(mg_cfg); memset((U8 *)&cfm, 0, sizeof(cfm)); memset((char *)&prntBuf, 0, sizeof(prntBuf)); - mg_cfg = megaco_profile_locate(profilename); - if(!mg_cfg){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG configuration found against profilename[%s]\n",profilename); - return SWITCH_STATUS_FALSE; - } mg_peer = megaco_peer_profile_locate(mg_cfg->peer_list[0]); if(!mg_peer){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG peer configuration found for peername[%s] against profilename[%s]\n",mg_cfg->peer_list[0],profilename); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG peer configuration found for peername[%s] against profilename[%s]\n",mg_cfg->peer_list[0],mg_cfg->name); + return SWITCH_STATUS_FALSE; + } + + + idx = mg_cfg->idx; + + len = len + sprintf(&prntBuf[0] + len,"%s\n",xmlhdr); + + len = len + sprintf(&prntBuf[0] + len,"\n"); + len = len + sprintf(&prntBuf[0] + len,"%s\n",mg_cfg->peer_list[0]); + + /* TODO - as of now supporting only one peer .. need to add logic to iterate through all the peers associated with this profile..*/ + + /* send request to MEGACO Trillium stack to get peer information*/ + sng_mgco_mg_get_status(STGCPENT, &cfm, mg_cfg, mg_peer); + + ip = ntohl(cfm.t.ssta.s.mgPeerSta.peerAddrTbl.netAddr[i].u.ipv4NetAddr); + cmInetNtoa(ip, &asciiAddr); + len = len + sprintf(prntBuf+len, "%s\n",asciiAddr); + + len = len + sprintf(prntBuf+len, "%s\n",PRNT_MG_PEER_STATE(cfm.t.ssta.s.mgPeerSta.peerState)); + + len = len + sprintf(&prntBuf[0] + len,"\n"); + + stream->write_function(stream, "\n%s\n",&prntBuf[0]); + + return SWITCH_STATUS_SUCCESS; +} + +/******************************************************************************/ + +switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, megaco_profile_t* mg_cfg) +{ + int idx = 0x00; + int len = 0x00; + MgMngmt cfm; + char* xmlhdr = ""; + char prntBuf[3048]; + int i = 0x00; + char *asciiAddr; + CmInetIpAddr ip; + mg_peer_profile_t* mg_peer = NULL; + + switch_assert(mg_cfg); + + memset((U8 *)&cfm, 0, sizeof(cfm)); + memset((char *)&prntBuf, 0, sizeof(prntBuf)); + + mg_peer = megaco_peer_profile_locate(mg_cfg->peer_list[0]); + + if(!mg_peer){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG peer configuration found for peername[%s] against profilename[%s]\n",mg_cfg->peer_list[0],mg_cfg->name); return SWITCH_STATUS_FALSE; } @@ -137,7 +195,6 @@ switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const c len = len + sprintf(&prntBuf[0] + len,"\n"); len = len + sprintf(&prntBuf[0] + len,"%s\n",mg_cfg->name); - len = len + sprintf(&prntBuf[0] + len,"%s\n",profilename); /****************************************************************************************************************/ /* Print Peer Information ***************************************************************************************/ @@ -254,29 +311,23 @@ switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, const c } /****************************************************************************************************************/ -switch_status_t megaco_profile_status(switch_stream_handle_t *stream, const char* profilename) +switch_status_t megaco_profile_status(switch_stream_handle_t *stream, megaco_profile_t* mg_cfg) { int idx = 0x00; int len = 0x00; MgMngmt cfm; char prntBuf[1024]; - megaco_profile_t* mg_cfg = NULL; mg_peer_profile_t* mg_peer = NULL; - switch_assert(profilename); + switch_assert(mg_cfg); memset((U8 *)&cfm, 0, sizeof(cfm)); memset((char *)&prntBuf, 0, sizeof(prntBuf)); - mg_cfg = megaco_profile_locate(profilename); - if(!mg_cfg){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG configuration found against profilename[%s]\n",profilename); - return SWITCH_STATUS_FALSE; - } mg_peer = megaco_peer_profile_locate(mg_cfg->peer_list[0]); if(!mg_peer){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG peer configuration found for peername[%s] against profilename[%s]\n",mg_cfg->peer_list[0],profilename); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG peer configuration found for peername[%s] against profilename[%s]\n",mg_cfg->peer_list[0],mg_cfg->name); return SWITCH_STATUS_FALSE; } diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.c b/src/mod/endpoints/mod_megaco/mod_megaco.c index e966c76095..722e023ec6 100644 --- a/src/mod/endpoints/mod_megaco/mod_megaco.c +++ b/src/mod/endpoints/mod_megaco/mod_megaco.c @@ -72,6 +72,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_megaco_load) switch_console_set_complete("add megaco profile ::megaco::list_profiles stop"); switch_console_set_complete("add megaco profile ::megaco::list_profiles status"); switch_console_set_complete("add megaco profile ::megaco::list_profiles xmlstatus"); + switch_console_set_complete("add megaco profile ::megaco::list_profiles peerxmlstatus"); switch_console_add_complete_func("::megaco::list_profiles", list_profiles); diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.h b/src/mod/endpoints/mod_megaco/mod_megaco.h index 444639677c..9a30bc01df 100644 --- a/src/mod/endpoints/mod_megaco/mod_megaco.h +++ b/src/mod/endpoints/mod_megaco/mod_megaco.h @@ -15,7 +15,7 @@ #define MG_MAX_PEERS 5 -#define MEGACO_FUNCTION_SYNTAX "profile [name] [start | stop] [status] [xmlstatus]" +#define MEGACO_FUNCTION_SYNTAX "profile [name] [start | stop] [status] [xmlstatus] [peerxmlstatus]" struct megaco_globals { switch_memory_pool_t *pool; From f49fb271daa6d1c26892a12c221f8287fb03f7b3 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 6 Jun 2012 16:21:22 -0400 Subject: [PATCH 221/822] Renamed files from megaco* media_gateway* --- src/mod/endpoints/mod_megaco/{megaco.c => media_gateway.c} | 0 .../endpoints/mod_megaco/{megaco_cli.c => media_gateway_cli.c} | 0 .../mod_megaco/{megaco_stack.c => media_gateway_stack.c} | 0 .../mod_megaco/{megaco_stack.h => media_gateway_stack.h} | 0 .../{megaco_stack_alarms.c => media_gateway_stack_alarms.c} | 0 .../endpoints/mod_megaco/{megaco_xml.c => media_gateway_xml.c} | 0 .../endpoints/mod_megaco/{mod_megaco.c => mod_media_gateway.c} | 0 .../endpoints/mod_megaco/{mod_megaco.h => mod_media_gateway.h} | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename src/mod/endpoints/mod_megaco/{megaco.c => media_gateway.c} (100%) rename src/mod/endpoints/mod_megaco/{megaco_cli.c => media_gateway_cli.c} (100%) rename src/mod/endpoints/mod_megaco/{megaco_stack.c => media_gateway_stack.c} (100%) rename src/mod/endpoints/mod_megaco/{megaco_stack.h => media_gateway_stack.h} (100%) rename src/mod/endpoints/mod_megaco/{megaco_stack_alarms.c => media_gateway_stack_alarms.c} (100%) rename src/mod/endpoints/mod_megaco/{megaco_xml.c => media_gateway_xml.c} (100%) rename src/mod/endpoints/mod_megaco/{mod_megaco.c => mod_media_gateway.c} (100%) rename src/mod/endpoints/mod_megaco/{mod_megaco.h => mod_media_gateway.h} (100%) diff --git a/src/mod/endpoints/mod_megaco/megaco.c b/src/mod/endpoints/mod_megaco/media_gateway.c similarity index 100% rename from src/mod/endpoints/mod_megaco/megaco.c rename to src/mod/endpoints/mod_megaco/media_gateway.c diff --git a/src/mod/endpoints/mod_megaco/megaco_cli.c b/src/mod/endpoints/mod_megaco/media_gateway_cli.c similarity index 100% rename from src/mod/endpoints/mod_megaco/megaco_cli.c rename to src/mod/endpoints/mod_megaco/media_gateway_cli.c diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.c b/src/mod/endpoints/mod_megaco/media_gateway_stack.c similarity index 100% rename from src/mod/endpoints/mod_megaco/megaco_stack.c rename to src/mod/endpoints/mod_megaco/media_gateway_stack.c diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.h b/src/mod/endpoints/mod_megaco/media_gateway_stack.h similarity index 100% rename from src/mod/endpoints/mod_megaco/megaco_stack.h rename to src/mod/endpoints/mod_megaco/media_gateway_stack.h diff --git a/src/mod/endpoints/mod_megaco/megaco_stack_alarms.c b/src/mod/endpoints/mod_megaco/media_gateway_stack_alarms.c similarity index 100% rename from src/mod/endpoints/mod_megaco/megaco_stack_alarms.c rename to src/mod/endpoints/mod_megaco/media_gateway_stack_alarms.c diff --git a/src/mod/endpoints/mod_megaco/megaco_xml.c b/src/mod/endpoints/mod_megaco/media_gateway_xml.c similarity index 100% rename from src/mod/endpoints/mod_megaco/megaco_xml.c rename to src/mod/endpoints/mod_megaco/media_gateway_xml.c diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.c b/src/mod/endpoints/mod_megaco/mod_media_gateway.c similarity index 100% rename from src/mod/endpoints/mod_megaco/mod_megaco.c rename to src/mod/endpoints/mod_megaco/mod_media_gateway.c diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.h b/src/mod/endpoints/mod_megaco/mod_media_gateway.h similarity index 100% rename from src/mod/endpoints/mod_megaco/mod_megaco.h rename to src/mod/endpoints/mod_megaco/mod_media_gateway.h From abc1e1e42bafad6c2c428d48db44acb1b81be379 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 6 Jun 2012 16:24:36 -0400 Subject: [PATCH 222/822] Revert "Renamed files from megaco* media_gateway*" This reverts commit f49fb271daa6d1c26892a12c221f8287fb03f7b3. --- src/mod/endpoints/mod_megaco/{media_gateway.c => megaco.c} | 0 .../endpoints/mod_megaco/{media_gateway_cli.c => megaco_cli.c} | 0 .../mod_megaco/{media_gateway_stack.c => megaco_stack.c} | 0 .../mod_megaco/{media_gateway_stack.h => megaco_stack.h} | 0 .../{media_gateway_stack_alarms.c => megaco_stack_alarms.c} | 0 .../endpoints/mod_megaco/{media_gateway_xml.c => megaco_xml.c} | 0 .../endpoints/mod_megaco/{mod_media_gateway.c => mod_megaco.c} | 0 .../endpoints/mod_megaco/{mod_media_gateway.h => mod_megaco.h} | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename src/mod/endpoints/mod_megaco/{media_gateway.c => megaco.c} (100%) rename src/mod/endpoints/mod_megaco/{media_gateway_cli.c => megaco_cli.c} (100%) rename src/mod/endpoints/mod_megaco/{media_gateway_stack.c => megaco_stack.c} (100%) rename src/mod/endpoints/mod_megaco/{media_gateway_stack.h => megaco_stack.h} (100%) rename src/mod/endpoints/mod_megaco/{media_gateway_stack_alarms.c => megaco_stack_alarms.c} (100%) rename src/mod/endpoints/mod_megaco/{media_gateway_xml.c => megaco_xml.c} (100%) rename src/mod/endpoints/mod_megaco/{mod_media_gateway.c => mod_megaco.c} (100%) rename src/mod/endpoints/mod_megaco/{mod_media_gateway.h => mod_megaco.h} (100%) diff --git a/src/mod/endpoints/mod_megaco/media_gateway.c b/src/mod/endpoints/mod_megaco/megaco.c similarity index 100% rename from src/mod/endpoints/mod_megaco/media_gateway.c rename to src/mod/endpoints/mod_megaco/megaco.c diff --git a/src/mod/endpoints/mod_megaco/media_gateway_cli.c b/src/mod/endpoints/mod_megaco/megaco_cli.c similarity index 100% rename from src/mod/endpoints/mod_megaco/media_gateway_cli.c rename to src/mod/endpoints/mod_megaco/megaco_cli.c diff --git a/src/mod/endpoints/mod_megaco/media_gateway_stack.c b/src/mod/endpoints/mod_megaco/megaco_stack.c similarity index 100% rename from src/mod/endpoints/mod_megaco/media_gateway_stack.c rename to src/mod/endpoints/mod_megaco/megaco_stack.c diff --git a/src/mod/endpoints/mod_megaco/media_gateway_stack.h b/src/mod/endpoints/mod_megaco/megaco_stack.h similarity index 100% rename from src/mod/endpoints/mod_megaco/media_gateway_stack.h rename to src/mod/endpoints/mod_megaco/megaco_stack.h diff --git a/src/mod/endpoints/mod_megaco/media_gateway_stack_alarms.c b/src/mod/endpoints/mod_megaco/megaco_stack_alarms.c similarity index 100% rename from src/mod/endpoints/mod_megaco/media_gateway_stack_alarms.c rename to src/mod/endpoints/mod_megaco/megaco_stack_alarms.c diff --git a/src/mod/endpoints/mod_megaco/media_gateway_xml.c b/src/mod/endpoints/mod_megaco/megaco_xml.c similarity index 100% rename from src/mod/endpoints/mod_megaco/media_gateway_xml.c rename to src/mod/endpoints/mod_megaco/megaco_xml.c diff --git a/src/mod/endpoints/mod_megaco/mod_media_gateway.c b/src/mod/endpoints/mod_megaco/mod_megaco.c similarity index 100% rename from src/mod/endpoints/mod_megaco/mod_media_gateway.c rename to src/mod/endpoints/mod_megaco/mod_megaco.c diff --git a/src/mod/endpoints/mod_megaco/mod_media_gateway.h b/src/mod/endpoints/mod_megaco/mod_megaco.h similarity index 100% rename from src/mod/endpoints/mod_megaco/mod_media_gateway.h rename to src/mod/endpoints/mod_megaco/mod_megaco.h From 8b017f6c01670d231a3d735f0a301070b2361606 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 6 Jun 2012 16:36:22 -0400 Subject: [PATCH 223/822] Renamed mod_megaco to mod_media_gateway --- .../Makefile | 4 +-- .../conf/megaco.conf.xml | 0 .../media_gateway.c} | 2 +- .../media_gateway_cli.c} | 4 +-- .../media_gateway_stack.c} | 30 +++++++++---------- .../media_gateway_stack.h} | 4 +-- .../media_gateway_stack_alarms.c} | 4 +-- .../media_gateway_xml.c} | 4 +-- .../mod_media_gateway.c} | 6 ++-- .../mod_media_gateway.h} | 2 +- 10 files changed, 30 insertions(+), 30 deletions(-) rename src/mod/endpoints/{mod_megaco => mod_media_gateway}/Makefile (55%) rename src/mod/endpoints/{mod_megaco => mod_media_gateway}/conf/megaco.conf.xml (100%) rename src/mod/endpoints/{mod_megaco/megaco.c => mod_media_gateway/media_gateway.c} (99%) rename src/mod/endpoints/{mod_megaco/megaco_cli.c => mod_media_gateway/media_gateway_cli.c} (99%) rename src/mod/endpoints/{mod_megaco/megaco_stack.c => mod_media_gateway/media_gateway_stack.c} (98%) rename src/mod/endpoints/{mod_megaco/megaco_stack.h => mod_media_gateway/media_gateway_stack.h} (94%) rename src/mod/endpoints/{mod_megaco/megaco_stack_alarms.c => mod_media_gateway/media_gateway_stack_alarms.c} (99%) rename src/mod/endpoints/{mod_megaco/megaco_xml.c => mod_media_gateway/media_gateway_xml.c} (99%) rename src/mod/endpoints/{mod_megaco/mod_megaco.c => mod_media_gateway/mod_media_gateway.c} (98%) rename src/mod/endpoints/{mod_megaco/mod_megaco.h => mod_media_gateway/mod_media_gateway.h} (98%) diff --git a/src/mod/endpoints/mod_megaco/Makefile b/src/mod/endpoints/mod_media_gateway/Makefile similarity index 55% rename from src/mod/endpoints/mod_megaco/Makefile rename to src/mod/endpoints/mod_media_gateway/Makefile index 228d3f88e8..2a8f5e7ac8 100644 --- a/src/mod/endpoints/mod_megaco/Makefile +++ b/src/mod/endpoints/mod_media_gateway/Makefile @@ -7,6 +7,6 @@ ifeq ($(ARCH),x86_64) endif BASE=../../../.. -LOCAL_OBJS=megaco.o megaco_stack.o megaco_xml.o megaco_cli.o megaco_stack_alarms.o -LOCAL_LDFLAGS=-lsng_megaco +LOCAL_OBJS=media_gateway.o media_gateway_stack.o media_gateway_xml.o media_gateway_cli.o media_gateway_stack_alarms.o +LOCAL_LDFLAGS=-lsng_mg include $(BASE)/build/modmake.rules diff --git a/src/mod/endpoints/mod_megaco/conf/megaco.conf.xml b/src/mod/endpoints/mod_media_gateway/conf/megaco.conf.xml similarity index 100% rename from src/mod/endpoints/mod_megaco/conf/megaco.conf.xml rename to src/mod/endpoints/mod_media_gateway/conf/megaco.conf.xml diff --git a/src/mod/endpoints/mod_megaco/megaco.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c similarity index 99% rename from src/mod/endpoints/mod_megaco/megaco.c rename to src/mod/endpoints/mod_media_gateway/media_gateway.c index aa8fd8ede1..98d433179e 100644 --- a/src/mod/endpoints/mod_megaco/megaco.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -6,7 +6,7 @@ * */ -#include "mod_megaco.h" +#include "mod_media_gateway.h" megaco_profile_t *megaco_profile_locate(const char *name) { diff --git a/src/mod/endpoints/mod_megaco/megaco_cli.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c similarity index 99% rename from src/mod/endpoints/mod_megaco/megaco_cli.c rename to src/mod/endpoints/mod_media_gateway/media_gateway_cli.c index 0bdb334754..db50feaa57 100644 --- a/src/mod/endpoints/mod_megaco/megaco_cli.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c @@ -7,8 +7,8 @@ */ /* INCLUDES *******************************************************************/ -#include "mod_megaco.h" -#include "megaco_stack.h" +#include "mod_media_gateway.h" +#include "media_gateway_stack.h" /******************************************************************************/ /* FUNCTION PROTOTYPES ********************************************************/ diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.c b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c similarity index 98% rename from src/mod/endpoints/mod_megaco/megaco_stack.c rename to src/mod/endpoints/mod_media_gateway/media_gateway_stack.c index 6038173a8c..abe46a5837 100644 --- a/src/mod/endpoints/mod_megaco/megaco_stack.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c @@ -7,8 +7,8 @@ */ /* INCLUDES *******************************************************************/ -#include "mod_megaco.h" -#include "megaco_stack.h" +#include "mod_media_gateway.h" +#include "media_gateway_stack.h" /******************************************************************************/ /* DEFINES ********************************************************************/ @@ -47,42 +47,42 @@ sng_mg_protocol_types_e mg_get_proto_type_from_str(char* proto_type); /* FUNCTIONS ******************************************************************/ -switch_status_t sng_mgco_init(sng_isup_event_interface_t* event) +switch_status_t sng_mgco_init(sng_mg_event_interface_t* event) { uint32_t major, minor, build; switch_assert(event); /* initalize sng_mg library */ - sng_isup_init_gen(event); + sng_mg_init_gen(event); /* print the version of the library being used */ - sng_isup_version(&major, &minor, &build); + sng_mg_version(&major, &minor, &build); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"Loaded LibSng-MEGACO %d.%d.%d\n", major, minor, build); /* start up the stack manager */ - if (sng_isup_init_sm()) { + if (sng_mg_init_sm()) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"Failed to start Stack Manager\n"); return SWITCH_STATUS_FALSE; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"Started Stack Manager!\n"); } - if (sng_isup_init_tucl()) { + if (sng_mg_init_tucl()) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,"Failed to start TUCL\n"); return SWITCH_STATUS_FALSE; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"Started TUCL!\n"); } - if (sng_isup_init_mg()) { + if (sng_mg_init_mg()) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,"Failed to start MG\n"); return SWITCH_STATUS_FALSE; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"Started MG!\n"); } - if (sng_isup_init_mu()) { + if (sng_mg_init_mu()) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,"Failed to start MU\n"); return SWITCH_STATUS_FALSE; } else { @@ -104,19 +104,19 @@ switch_status_t sng_mgco_stack_shutdown() sng_mgco_tucl_shutdown(); /* free MEGACO Application */ - sng_isup_free_mu(); + sng_mg_free_mu(); /* free MEGACO */ - sng_isup_free_mg(); + sng_mg_free_mg(); /* free TUCL */ - sng_isup_free_tucl(); + sng_mg_free_tucl(); /* free SM */ - sng_isup_free_sm(); + sng_mg_free_sm(); /* free gen */ - sng_isup_free_gen(); + sng_mg_free_gen(); return SWITCH_STATUS_SUCCESS; } @@ -638,7 +638,7 @@ int mgco_tucl_gen_config(void) cfg.t.cfg.s.hiGen.poolDropThr = HI_MEM_POOL_DROP_THRESHOLD; cfg.t.cfg.s.hiGen.poolStopThr = HI_MEM_POOL_STOP_THRESHOLD; - cfg.t.cfg.s.hiGen.timeRes = SI_PERIOD; /* time resolution */ + cfg.t.cfg.s.hiGen.timeRes = HI_PERIOD; /* time resolution */ #ifdef HI_SPECIFY_GENSOCK_ADDR cfg.t.cfg.s.hiGen.ipv4GenSockAddr.address = CM_INET_INADDR_ANY; diff --git a/src/mod/endpoints/mod_megaco/megaco_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h similarity index 94% rename from src/mod/endpoints/mod_megaco/megaco_stack.h rename to src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index 0e10bc346d..ac5b911f9b 100644 --- a/src/mod/endpoints/mod_megaco/megaco_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -6,7 +6,7 @@ * */ -#include "mod_megaco.h" +#include "mod_media_gateway.h" #ifndef _MEGACO_STACK_H_ #define _MEGACO_STACK_H_ @@ -56,7 +56,7 @@ void handle_tucl_alarm(Pst *pst, HiMngmt *sta); switch_status_t sng_mgco_cfg(megaco_profile_t* profile); -switch_status_t sng_mgco_init(sng_isup_event_interface_t* event); +switch_status_t sng_mgco_init(sng_mg_event_interface_t* event); switch_status_t sng_mgco_stack_shutdown(void); int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, megaco_profile_t* mg_cfg, mg_peer_profile_t* mg_peer); diff --git a/src/mod/endpoints/mod_megaco/megaco_stack_alarms.c b/src/mod/endpoints/mod_media_gateway/media_gateway_stack_alarms.c similarity index 99% rename from src/mod/endpoints/mod_megaco/megaco_stack_alarms.c rename to src/mod/endpoints/mod_media_gateway/media_gateway_stack_alarms.c index dd114a3850..fc09a6bea4 100644 --- a/src/mod/endpoints/mod_megaco/megaco_stack_alarms.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack_alarms.c @@ -7,8 +7,8 @@ */ /* INCLUDES *******************************************************************/ -#include "mod_megaco.h" -#include "megaco_stack.h" +#include "mod_media_gateway.h" +#include "media_gateway_stack.h" /******************************************************************************/ /* FUNCTION PROTOTYPES ********************************************************/ diff --git a/src/mod/endpoints/mod_megaco/megaco_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c similarity index 99% rename from src/mod/endpoints/mod_megaco/megaco_xml.c rename to src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index 236fb68cfd..710cc7e6c4 100644 --- a/src/mod/endpoints/mod_megaco/megaco_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -5,8 +5,8 @@ * * */ -#include "mod_megaco.h" -#include "megaco_stack.h" +#include "mod_media_gateway.h" +#include "media_gateway_stack.h" /****************************************************************************************************************************/ static switch_xml_config_item_t *get_instructions(megaco_profile_t *profile) ; diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c similarity index 98% rename from src/mod/endpoints/mod_megaco/mod_megaco.c rename to src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 722e023ec6..ebad0b30b7 100644 --- a/src/mod/endpoints/mod_megaco/mod_megaco.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -6,11 +6,11 @@ * */ -#include "mod_megaco.h" -#include "megaco_stack.h" +#include "mod_media_gateway.h" +#include "media_gateway_stack.h" struct megaco_globals megaco_globals; -static sng_isup_event_interface_t sng_event; +static sng_mg_event_interface_t sng_event; SWITCH_MODULE_LOAD_FUNCTION(mod_megaco_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_megaco_shutdown); diff --git a/src/mod/endpoints/mod_megaco/mod_megaco.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h similarity index 98% rename from src/mod/endpoints/mod_megaco/mod_megaco.h rename to src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index 9a30bc01df..c55bb6744f 100644 --- a/src/mod/endpoints/mod_megaco/mod_megaco.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -10,7 +10,7 @@ #ifndef MOD_MEGACO_H #define MOD_MEGACO_H -#include "sng_megaco/sng_ss7.h" +#include "sng_mg/sng_mg.h" #include #define MG_MAX_PEERS 5 From 07a1093cf442a8ebc97474278de0ae0d0eeb2a06 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 6 Jun 2012 20:41:48 -0400 Subject: [PATCH 224/822] Fix for NFAS when one of the d-channels are down --- libs/freetdm/mod_freetdm/mod_freetdm.c | 4 +- .../ftmod_sangoma_isdn/ftmod_sangoma_isdn.c | 140 +++++--- .../ftmod_sangoma_isdn/ftmod_sangoma_isdn.h | 71 ++-- .../ftmod_sangoma_isdn_cfg.c | 188 +++++++++-- .../ftmod_sangoma_isdn_cntrl.c | 4 +- .../ftmod_sangoma_isdn_stack_cfg.c | 172 ++++++---- .../ftmod_sangoma_isdn_stack_cntrl.c | 53 +-- .../ftmod_sangoma_isdn_stack_hndl.c | 46 ++- .../ftmod_sangoma_isdn_stack_out.c | 67 ++-- .../ftmod_sangoma_isdn_stack_rcv.c | 302 +++++++++++------- .../ftmod_sangoma_isdn_support.c | 37 ++- 11 files changed, 757 insertions(+), 327 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 8b0acc3aef..a2dacafd43 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1884,10 +1884,8 @@ static FIO_SIGNAL_CB_FUNCTION(on_common_signal) return FTDM_FAIL; } if (sigmsg->event_id == FTDM_SIGEVENT_ALARM_CLEAR) { - ftdm_log(FTDM_LOG_NOTICE, "Alarm cleared on channel %d:%d\n", spanid, chanid); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-clear"); } else { - ftdm_log(FTDM_LOG_NOTICE, "Alarm raised on channel %d:%d\n", spanid, chanid); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-trap"); } } @@ -2489,7 +2487,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal) break; case FTDM_SIGEVENT_SIGSTATUS_CHANGED: { - ftdm_signaling_status_t sigstatus = sigmsg->ev_data.sigstatus.status; + ftdm_signaling_status_t sigstatus = sigmsg->ev_data.sigstatus.status; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%d:%d signalling changed to :%s\n", spanid, chanid, ftdm_signaling_status2str(sigstatus)); } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c index e3af9d9b98..0f9a63fde2 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c @@ -281,8 +281,8 @@ ftdm_state_map_t sangoma_isdn_state_map = { static void ftdm_sangoma_isdn_process_phy_events(ftdm_span_t *span, ftdm_oob_event_t event) { sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data; - sngisdn_snd_event(signal_data->dchan, event); - + sngisdn_snd_event(signal_data, event); + switch (event) { /* Check if the span woke up from power-saving mode */ case FTDM_OOB_ALARM_CLEAR: @@ -354,7 +354,6 @@ static void *ftdm_sangoma_isdn_io_run(ftdm_thread_t *me, void *obj) short *poll_events = ftdm_malloc(sizeof(short) * span->chan_count); /* Initialize the d-channel */ - ftdm_assert(((sngisdn_span_data_t*)span->signal_data)->dchan, "Span does not have a dchannel"); chaniter = ftdm_span_get_chan_iterator(span, NULL); if (!chaniter) { ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name); @@ -1039,21 +1038,11 @@ static ftdm_status_t ftdm_sangoma_isdn_dtmf(ftdm_channel_t *ftdmchan, const char return FTDM_SUCCESS; } -static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span) +static ftdm_status_t ftdm_sangoma_isdn_perform_start(ftdm_span_t *span) { sngisdn_span_data_t *signal_data = span->signal_data; - ftdm_log(FTDM_LOG_INFO,"Starting span %s:%u.\n",span->name,span->span_id); - - ftdm_channel_set_feature(((sngisdn_span_data_t*)span->signal_data)->dchan, FTDM_CHANNEL_FEATURE_IO_STATS); - ftdm_channel_open_chan(((sngisdn_span_data_t*)span->signal_data)->dchan); - ftdm_sangoma_isdn_dchan_set_queue_size(((sngisdn_span_data_t*)span->signal_data)->dchan); - - if (sngisdn_stack_start(span) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_CRIT, "Failed to start span %s\n", span->name); - return FTDM_FAIL; - } - + ftdm_log(FTDM_LOG_DEBUG, "Actually starting span:%s\n", span->name); /* clear the monitor thread stop flag */ ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD); ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD); @@ -1085,12 +1074,64 @@ static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span) if (signal_data->restart_timeout) { ftdm_log(FTDM_LOG_DEBUG, "%s:Scheduling Restart timeout\n", signal_data->ftdm_span->name); ftdm_sched_timer(signal_data->sched, "restart_timeout", signal_data->restart_timeout, - sngisdn_restart_timeout, (void*) signal_data, &signal_data->timers[SNGISDN_SPAN_TIMER_RESTART]); + sngisdn_restart_timeout, (void*) signal_data, &signal_data->timers[SNGISDN_SPAN_TIMER_RESTART]); } + ftdm_log(FTDM_LOG_DEBUG,"Finished starting span %s\n", span->name); return FTDM_SUCCESS; } + +static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span) +{ + sngisdn_span_data_t *signal_data = span->signal_data; + + ftdm_log(FTDM_LOG_INFO,"Starting span %s:%u.\n",span->name,span->span_id); + + if (signal_data->dchan) { + ftdm_channel_set_feature(signal_data->dchan, FTDM_CHANNEL_FEATURE_IO_STATS); + ftdm_channel_open_chan(signal_data->dchan); + ftdm_sangoma_isdn_dchan_set_queue_size(signal_data->dchan); + } + + if (signal_data->nfas.trunk) { + if (signal_data->nfas.trunk->num_spans == signal_data->nfas.trunk->num_spans_configured) { + int i; + ftdm_log(FTDM_LOG_DEBUG, "Starting span for all spans within trunkgroup:%s\n", signal_data->nfas.trunk->name); + + sngisdn_stack_start(signal_data->nfas.trunk->dchan->ftdm_span); + ftdm_sangoma_isdn_perform_start(signal_data->nfas.trunk->dchan->ftdm_span); + + if (signal_data->nfas.trunk->backup) { + sngisdn_stack_start(signal_data->nfas.trunk->backup->ftdm_span); + ftdm_sangoma_isdn_perform_start(signal_data->nfas.trunk->backup->ftdm_span); + } + + for (i = 0; i < signal_data->nfas.trunk->num_spans; i++) { + if (signal_data->nfas.trunk->spans[i] && + signal_data->nfas.trunk->spans[i]->nfas.sigchan == SNGISDN_NFAS_DCHAN_NONE) { + sngisdn_stack_start(signal_data->nfas.trunk->spans[i]->ftdm_span); + ftdm_sangoma_isdn_perform_start(signal_data->nfas.trunk->spans[i]->ftdm_span); + } + } + + return FTDM_SUCCESS; + } else { + ftdm_log(FTDM_LOG_DEBUG, "Delaying span start until all spans within trunkgroup are started: %s\n", signal_data->nfas.trunk->name); + return FTDM_SUCCESS; + } + } + + if (sngisdn_stack_start(span) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_CRIT, "Failed to start span %s\n", span->name); + return FTDM_FAIL; + } + + ftdm_sangoma_isdn_perform_start(span); + + return FTDM_SUCCESS; +} + static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span) { ftdm_iterator_t *chaniter = NULL; @@ -1138,13 +1179,13 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config) ftdm_iterator_t *chaniter = NULL; ftdm_iterator_t *curr = NULL; - sngisdn_span_data_t *span_data; + sngisdn_span_data_t *signal_data; ftdm_log(FTDM_LOG_INFO, "Configuring ftmod_sangoma_isdn span = %s\n", span->name); - span_data = ftdm_calloc(1, sizeof(sngisdn_span_data_t)); - span_data->ftdm_span = span; - span->signal_data = span_data; + signal_data = ftdm_calloc(1, sizeof(sngisdn_span_data_t)); + signal_data->ftdm_span = span; + span->signal_data = signal_data; chaniter = ftdm_span_get_chan_iterator(span, NULL); for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { @@ -1160,79 +1201,98 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config) return FTDM_FAIL; } - if (sngisdn_stack_cfg(span) != FTDM_SUCCESS) { + if (signal_data->nfas.trunk) { + if (signal_data->nfas.trunk->num_spans == ++signal_data->nfas.trunk->num_spans_configured) { + int i; + ftdm_log(FTDM_LOG_DEBUG, "Starting stack configuration for all spans within trunkgroup:%s\n", signal_data->nfas.trunk->name); + + sngisdn_stack_cfg(signal_data->nfas.trunk->dchan->ftdm_span); + if (signal_data->nfas.trunk->backup) { + sngisdn_stack_cfg(signal_data->nfas.trunk->backup->ftdm_span); + } + + for (i = 0; i < signal_data->nfas.trunk->num_spans; i++) { + if (signal_data->nfas.trunk->spans[i] && + signal_data->nfas.trunk->spans[i]->nfas.sigchan == SNGISDN_NFAS_DCHAN_NONE) { + sngisdn_stack_cfg(signal_data->nfas.trunk->spans[i]->ftdm_span); + } + } + } else { + ftdm_log(FTDM_LOG_DEBUG, "Delaying span stack configuration until all spans within trunkgroup are started:%s\n", signal_data->nfas.trunk->name); + } + } else if (sngisdn_stack_cfg(span) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_CRIT, "Sangoma ISDN Stack configuration failed\n"); return FTDM_FAIL; } - if (span_data->cid_name_method == SNGISDN_CID_NAME_AUTO) { - switch (span_data->switchtype) { + if (signal_data->cid_name_method == SNGISDN_CID_NAME_AUTO) { + switch (signal_data->switchtype) { case SNGISDN_SWITCH_EUROISDN: if (FTDM_SPAN_IS_BRI(span)) { - span_data->cid_name_method = SNGISDN_CID_NAME_USR_USR_IE; + signal_data->cid_name_method = SNGISDN_CID_NAME_USR_USR_IE; } else { - span_data->cid_name_method = SNGISDN_CID_NAME_DISPLAY_IE; + signal_data->cid_name_method = SNGISDN_CID_NAME_DISPLAY_IE; } break; case SNGISDN_SWITCH_DMS100: - span_data->cid_name_method = SNGISDN_CID_NAME_DISPLAY_IE; + signal_data->cid_name_method = SNGISDN_CID_NAME_DISPLAY_IE; break; case SNGISDN_SWITCH_NI2: case SNGISDN_SWITCH_5ESS: case SNGISDN_SWITCH_4ESS: - span_data->cid_name_method = SNGISDN_CID_NAME_FACILITY_IE; + signal_data->cid_name_method = SNGISDN_CID_NAME_FACILITY_IE; break; default: break; } } - if (span_data->send_cid_name == SNGISDN_OPT_DEFAULT) { - switch (span_data->switchtype) { + if (signal_data->send_cid_name == SNGISDN_OPT_DEFAULT) { + switch (signal_data->switchtype) { case SNGISDN_SWITCH_EUROISDN: #ifdef SNGISDN_SUPPORT_CALLING_NAME_IN_FACILITY case SNGISDN_SWITCH_NI2: case SNGISDN_SWITCH_5ESS: case SNGISDN_SWITCH_4ESS: #endif - if (span_data->signalling == SNGISDN_SIGNALING_NET) { - span_data->send_cid_name = SNGISDN_OPT_TRUE; + if (signal_data->signalling == SNGISDN_SIGNALING_NET) { + signal_data->send_cid_name = SNGISDN_OPT_TRUE; } else { - span_data->send_cid_name = SNGISDN_OPT_FALSE; + signal_data->send_cid_name = SNGISDN_OPT_FALSE; } break; case SNGISDN_SWITCH_DMS100: - span_data->send_cid_name = SNGISDN_OPT_TRUE; + signal_data->send_cid_name = SNGISDN_OPT_TRUE; break; #ifndef SNGISDN_SUPPORT_CALLING_NAME_IN_FACILITY case SNGISDN_SWITCH_NI2: case SNGISDN_SWITCH_5ESS: case SNGISDN_SWITCH_4ESS: - span_data->send_cid_name = SNGISDN_OPT_FALSE; + signal_data->send_cid_name = SNGISDN_OPT_FALSE; break; #endif default: - span_data->send_cid_name = SNGISDN_OPT_FALSE; + signal_data->send_cid_name = SNGISDN_OPT_FALSE; break; } - } else if (span_data->send_cid_name == SNGISDN_OPT_TRUE) { - switch (span_data->switchtype) { + } else if (signal_data->send_cid_name == SNGISDN_OPT_TRUE) { + switch (signal_data->switchtype) { case SNGISDN_SWITCH_NI2: case SNGISDN_SWITCH_5ESS: case SNGISDN_SWITCH_4ESS: #ifndef SNGISDN_SUPPORT_CALLING_NAME_IN_FACILITY ftdm_log(FTDM_LOG_WARNING, "Sending Calling Name in Facility IE not supported, please update your libsng_isdn library\n"); - span_data->send_cid_name = SNGISDN_OPT_FALSE; + signal_data->send_cid_name = SNGISDN_OPT_FALSE; #endif break; case SNGISDN_SWITCH_INSNET: /* Don't know how to transmit caller ID name on INSNET */ case SNGISDN_SWITCH_QSIG: /* It seems like QSIG does not support Caller ID */ - span_data->send_cid_name = SNGISDN_OPT_FALSE; + signal_data->send_cid_name = SNGISDN_OPT_FALSE; break; case SNGISDN_SWITCH_EUROISDN: break; default: - span_data->send_cid_name = SNGISDN_OPT_FALSE; + signal_data->send_cid_name = SNGISDN_OPT_FALSE; break; } } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h index 92054b8869..0034add153 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h @@ -58,7 +58,8 @@ /* Theoretical limit for MAX_SPANS_PER_NFAS_LINK is 31, but set to 8 for now to save some memory */ -#define MAX_SPANS_PER_NFAS_LINK 8 +#define MAX_SPANS_PER_NFAS_LINK 16 +#define MAX_NFAS_GROUPS 16 #define NUM_E1_CHANNELS_PER_SPAN 32 #define NUM_T1_CHANNELS_PER_SPAN 24 #define NUM_BRI_CHANNELS_PER_SPAN 2 @@ -66,6 +67,9 @@ #define SNGISDN_EVENT_POLL_RATE 100 #define SNGISDN_NUM_LOCAL_NUMBERS 8 #define SNGISDN_DCHAN_QUEUE_LEN 200 +#define MAX_NFAS_GROUP_NAME 50 + +#define NSG #ifndef MI_NOTIFY #define MI_NOTIFY 0x14 @@ -242,16 +246,25 @@ typedef struct sngisdn_chan_data { ftdm_size_t raw_data_len; } sngisdn_chan_data_t; +struct sngisdn_nfas_data; +typedef struct sngisdn_nfas_data sngisdn_nfas_data_t; + +typedef enum { + SNGISDN_NFAS_DCHAN_NONE, + SNGISDN_NFAS_DCHAN_PRIMARY, + SNGISDN_NFAS_DCHAN_BACKUP, +} sngisdn_nfas_sigchan_t; + /* Span specific data */ typedef struct sngisdn_span_data { ftdm_span_t *ftdm_span; ftdm_channel_t *dchan; uint8_t link_id; uint8_t switchtype; - uint8_t signalling; /* SNGISDN_SIGNALING_CPE or SNGISDN_SIGNALING_NET */ + uint8_t signalling; /* SNGISDN_SIGNALING_CPE or SNGISDN_SIGNALING_NET */ uint8_t cc_id; - uint8_t dchan_id; - uint8_t span_id; + ftdm_signaling_status_t sigstatus; + uint8_t tei; uint8_t min_digits; uint8_t trace_flags; /* TODO change to bit map of sngisdn_tracetype_t */ @@ -274,7 +287,7 @@ typedef struct sngisdn_span_data { uint8_t restart_timeout; uint8_t force_sending_complete; uint8_t cid_name_method; - uint8_t send_cid_name; + uint8_t send_cid_name; int32_t timer_t301; int32_t timer_t302; @@ -292,11 +305,20 @@ typedef struct sngisdn_span_data { int32_t timer_t318; int32_t timer_t319; int32_t timer_t322; - + char* local_numbers[SNGISDN_NUM_LOCAL_NUMBERS]; ftdm_timer_id_t timers[SNGISDN_NUM_SPAN_TIMERS]; ftdm_sched_t *sched; ftdm_queue_t *event_queue; + + struct nfas_info { + sngisdn_nfas_data_t *trunk; + sngisdn_nfas_sigchan_t sigchan; + uint8_t interface_id; + } nfas; + + uint32_t num_chans; + sngisdn_chan_data_t *channels[NUM_E1_CHANNELS_PER_SPAN]; } sngisdn_span_data_t; typedef struct sngisdn_event_data { @@ -331,19 +353,18 @@ typedef struct sngisdn_event_data { } sngisdn_event_data_t; -/* dchan_data can have more than 1 span when running NFAS */ -typedef struct sngisdn_dchan_data { - uint8_t num_spans; - sngisdn_span_data_t *spans[MAX_L1_LINKS+1]; - uint16_t num_chans; - /* worst case for number of channel is when using NFAS, and NFAS is only used on T1, - so we can use MAX_SPANS_PER_NFAS_LINK*NUM_T1_CHANNELS_PER_SPAN instead of - MAX_SPANS_PER_NFAS_LINK*NUM_E1_CHANNELS_PER_SPAN - */ - /* Never seen NFAS on E1 yet, so use NUM_T1_CHANNELS_PER_SPAN */ - /* b-channels are arranged by physical id's not logical */ - sngisdn_chan_data_t *channels[MAX_SPANS_PER_NFAS_LINK*NUM_T1_CHANNELS_PER_SPAN]; -}sngisdn_dchan_data_t; +struct sngisdn_nfas_data { + char name[MAX_NFAS_GROUP_NAME]; + + char dchan_span_name[20]; + sngisdn_span_data_t *dchan; /* Span that contains primary d-channel */ + + char backup_span_name[20]; + sngisdn_span_data_t *backup; /* Span that contains backup d-channel */ + uint8_t num_spans; /* Number of spans within this NFAS */ + uint8_t num_spans_configured; + sngisdn_span_data_t *spans[MAX_SPANS_PER_NFAS_LINK+1]; //indexed by logical span id +}; typedef struct sngisdn_cc { /* TODO: use flags instead of config_done and activation_done */ @@ -360,10 +381,10 @@ typedef struct sngisdn_cc { /* Global sngisdn data */ typedef struct ftdm_sngisdn_data { uint8_t gen_config_done; - uint8_t num_cc; /* 1 ent per switchtype */ - struct sngisdn_cc ccs[MAX_VARIANTS+1]; - uint8_t num_dchan; - sngisdn_dchan_data_t dchans[MAX_L1_LINKS+1]; + uint8_t num_cc; /* 1 ent per switchtype */ + struct sngisdn_cc ccs[MAX_VARIANTS+1]; + uint8_t num_nfas; + sngisdn_nfas_data_t nfass[MAX_NFAS_GROUPS+1]; sngisdn_span_data_t *spans[MAX_L1_LINKS+1]; /* spans are indexed by link_id */ #ifdef SANGOMA_ISDN_CHAN_ID_INVERT_BIT @@ -424,7 +445,7 @@ void sngisdn_snd_info_req(ftdm_channel_t *ftdmchan); void sngisdn_snd_status_enq(ftdm_channel_t *ftdmchan); void sngisdn_snd_restart(ftdm_channel_t *ftdmchan); void sngisdn_snd_data(ftdm_channel_t *dchan, uint8_t *data, ftdm_size_t len); -void sngisdn_snd_event(ftdm_channel_t *dchan, ftdm_oob_event_t event); +void sngisdn_snd_event(sngisdn_span_data_t *signal_data, ftdm_oob_event_t event); /* Inbound Call Control functions */ void sngisdn_rcv_con_ind(int16_t suId, uint32_t suInstId, uint32_t spInstId, ConEvnt *conEvnt, int16_t dChan, uint8_t ces); @@ -553,6 +574,7 @@ static __inline__ void sngisdn_set_flag(sngisdn_chan_data_t *sngisdn_info, sngis void handle_sng_log(uint8_t level, char *fmt,...); void sngisdn_delayed_setup(void* p_sngisdn_info); void sngisdn_delayed_release(void* p_sngisdn_info); +void sngisdn_delayed_release_nfas(void *p_sngisdn_info); void sngisdn_delayed_connect(void* p_sngisdn_info); void sngisdn_delayed_disconnect(void* p_sngisdn_info); void sngisdn_facility_timeout(void* p_sngisdn_info); @@ -564,6 +586,7 @@ ftdm_status_t sngisdn_stack_cfg(ftdm_span_t *span); ftdm_status_t sngisdn_stack_start(ftdm_span_t *span); ftdm_status_t sngisdn_stack_stop(ftdm_span_t *span); ftdm_status_t sngisdn_wake_up_phy(ftdm_span_t *span); +sngisdn_span_data_t *sngisdn_dchan(sngisdn_span_data_t *signal_data); ftdm_status_t sngisdn_show_l1_stats(ftdm_stream_handle_t *stream, ftdm_span_t *span); ftdm_status_t sngisdn_show_spans(ftdm_stream_handle_t *stream); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c index ba05d9b4a4..45c6c9cc17 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c @@ -37,6 +37,7 @@ static ftdm_status_t parse_timer(const char* val, int32_t *target); static ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span); static ftdm_status_t parse_signalling(const char* signalling, ftdm_span_t *span); +static ftdm_status_t parse_trunkgroup(const char *_trunkgroup); static ftdm_status_t add_local_number(const char* val, ftdm_span_t *span); static ftdm_status_t parse_yesno(const char* var, const char* val, uint8_t *target); static ftdm_status_t set_switchtype_defaults(ftdm_span_t *span); @@ -81,7 +82,7 @@ static ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span unsigned i; ftdm_iterator_t *chaniter = NULL; ftdm_iterator_t *curr = NULL; - sngisdn_dchan_data_t *dchan_data; + //sngisdn_dchan_data_t *dchan_data; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data; switch(span->trunk_type) { @@ -133,13 +134,15 @@ static ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported trunktype:%s\n", span->name, switch_name, ftdm_trunk_type2str(span->trunk_type)); return FTDM_FAIL; } + /* see if we have profile with this switch_type already */ - for (i=1; i <= g_sngisdn_data.num_cc; i++) { + for (i = 1; i <= g_sngisdn_data.num_cc; i++) { if (g_sngisdn_data.ccs[i].switchtype == signal_data->switchtype && g_sngisdn_data.ccs[i].trunktype == span->trunk_type) { break; } } + /* need to create a new switch_type */ if (i > g_sngisdn_data.num_cc) { g_sngisdn_data.num_cc++; @@ -151,20 +154,9 @@ static ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span /* add this span to its ent_cc */ signal_data->cc_id = i; - /* create a new dchan */ /* for NFAS - no-dchan on b-channels-only links */ - g_sngisdn_data.num_dchan++; - signal_data->dchan_id = g_sngisdn_data.num_dchan; - - dchan_data = &g_sngisdn_data.dchans[signal_data->dchan_id]; - dchan_data->num_spans++; - - signal_data->span_id = dchan_data->num_spans; - dchan_data->spans[signal_data->span_id] = signal_data; - g_sngisdn_data.spans[signal_data->link_id] = signal_data; - ftdm_log(FTDM_LOG_DEBUG, "%s: cc_id:%d dchan_id:%d span_id:%d link_id:%d\n", span->name, signal_data->cc_id, signal_data->dchan_id, signal_data->span_id, signal_data->link_id); - + ftdm_log(FTDM_LOG_DEBUG, "%s: cc_id:%d link_id:%d\n", span->name, signal_data->cc_id, signal_data->link_id); chaniter = ftdm_span_get_chan_iterator(span, NULL); for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { @@ -175,17 +167,16 @@ static ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span signal_data->dchan = ftdmchan; } else { /* Add the channels to the span */ - /* NFAS is not supported on E1, so span_id will always be 1 for E1 so this will work for E1 as well */ - chan_id = ((signal_data->span_id-1)*NUM_T1_CHANNELS_PER_SPAN)+ftdmchan->physical_chan_id; - dchan_data->channels[chan_id] = (sngisdn_chan_data_t*)ftdmchan->call_data; - dchan_data->num_chans++; + chan_id = ftdmchan->physical_chan_id; + signal_data->channels[chan_id] = (sngisdn_chan_data_t*)ftdmchan->call_data; + signal_data->num_chans++; } } ftdm_iterator_free(chaniter); return FTDM_SUCCESS; } -static ftdm_status_t parse_signalling(const char* signalling, ftdm_span_t *span) +static ftdm_status_t parse_signalling(const char *signalling, ftdm_span_t *span) { sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data; if (!strcasecmp(signalling, "net") || @@ -205,6 +196,146 @@ static ftdm_status_t parse_signalling(const char* signalling, ftdm_span_t *span) return FTDM_SUCCESS; } +static ftdm_status_t parse_spanmap(const char *_spanmap, ftdm_span_t *span) +{ + int i; + char *p, *name, *spanmap; + uint8_t logical_span_id = 0; + ftdm_status_t ret = FTDM_SUCCESS; + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data; + + spanmap = ftdm_strdup(_spanmap); + + p = name = NULL; + + i = 0; + for (p = strtok(spanmap, ","); p; p = strtok(NULL, ",")) { + while (*p == ' ') { + p++; + } + switch(i++) { + case 0: + name = ftdm_strdup(p); + break; + case 1: + logical_span_id = atoi(p); + break; + } + } + + if (!name || logical_span_id < 0) { + ftdm_log(FTDM_LOG_ERROR, "Invalid spanmap syntax %s\n", _spanmap); + ret = FTDM_FAIL; + goto done; + } + + for (i = 0; i < g_sngisdn_data.num_nfas; i++) { + if (!ftdm_strlen_zero(g_sngisdn_data.nfass[i].name) && + !strcasecmp(g_sngisdn_data.nfass[i].name, name)) { + + signal_data->nfas.trunk = &g_sngisdn_data.nfass[i]; + break; + } + } + + if (!signal_data->nfas.trunk) { + ftdm_log(FTDM_LOG_ERROR, "Could not find trunkgroup with name %s\n", name); + ret = FTDM_FAIL; + goto done; + } + + if (signal_data->nfas.trunk->spans[logical_span_id]) { + ftdm_log(FTDM_LOG_ERROR, "trunkgroup:%s already had a span with logical span id:%d\n", name, logical_span_id); + } else { + signal_data->nfas.trunk->spans[logical_span_id] = signal_data; + signal_data->nfas.interface_id = logical_span_id; + } + + if (!strcasecmp(signal_data->ftdm_span->name, signal_data->nfas.trunk->dchan_span_name)) { + + signal_data->nfas.sigchan = SNGISDN_NFAS_DCHAN_PRIMARY; + signal_data->nfas.trunk->dchan = signal_data; + } + + if (!strcasecmp(signal_data->ftdm_span->name, signal_data->nfas.trunk->backup_span_name)) { + + signal_data->nfas.sigchan = SNGISDN_NFAS_DCHAN_BACKUP; + signal_data->nfas.trunk->backup = signal_data; + } + +done: + ftdm_safe_free(spanmap); + ftdm_safe_free(name); + return ret; +} + +static ftdm_status_t parse_trunkgroup(const char *_trunkgroup) +{ + int i; + char *p, *name, *dchan_span, *backup_span, *trunkgroup; + uint8_t num_spans; + ftdm_status_t ret = FTDM_SUCCESS; + + trunkgroup = ftdm_strdup(_trunkgroup); + + p = name = dchan_span = backup_span = NULL; + + /* format: name, num_chans, dchan_span, [backup_span] */ + + i = 0; + for (p = strtok(trunkgroup, ","); p; p = strtok(NULL, ",")) { + while (*p == ' ') { + p++; + } + switch(i++) { + case 0: + name = ftdm_strdup(p); + break; + case 1: + num_spans = atoi(p); + break; + case 2: + dchan_span = ftdm_strdup(p); + break; + case 3: + backup_span = ftdm_strdup(p); + } + } + + if (!name || !dchan_span || num_spans <= 0) { + ftdm_log(FTDM_LOG_ERROR, "Invalid parameters for trunkgroup:%s\n", _trunkgroup); + ret = FTDM_FAIL; + goto done; + } + + for (i = 0; i < g_sngisdn_data.num_nfas; i++) { + if (!ftdm_strlen_zero(g_sngisdn_data.nfass[i].name) && + !strcasecmp(g_sngisdn_data.nfass[i].name, name)) { + + /* We already configured this trunkgroup */ + goto done; + } + } + + /* Trunk group was not found, need to configure it */ + strncpy(g_sngisdn_data.nfass[i].name, name, sizeof(g_sngisdn_data.nfass[i].name)); + g_sngisdn_data.nfass[i].num_spans = num_spans; + strncpy(g_sngisdn_data.nfass[i].dchan_span_name, dchan_span, sizeof(g_sngisdn_data.nfass[i].dchan_span_name)); + + if (backup_span) { + strncpy(g_sngisdn_data.nfass[i].backup_span_name, backup_span, sizeof(g_sngisdn_data.nfass[i].backup_span_name)); + } + + + g_sngisdn_data.num_nfas++; +done: + ftdm_safe_free(trunkgroup); + ftdm_safe_free(name); + ftdm_safe_free(dchan_span); + ftdm_safe_free(backup_span); + return FTDM_SUCCESS; +} + static ftdm_status_t parse_early_media(const char* opt, ftdm_span_t *span) { sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data; @@ -314,6 +445,19 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_ /* Cannot set default bearer_layer1 yet, as we do not know the switchtype */ span->default_caller_data.bearer_layer1 = FTDM_INVALID_INT_PARM; + /* Find out if NFAS is enabled first */ + for (paramindex = 0; ftdm_parameters[paramindex].var; paramindex++) { + ftdm_log(FTDM_LOG_DEBUG, "Sangoma ISDN key=value, %s=%s\n", ftdm_parameters[paramindex].var, ftdm_parameters[paramindex].val); + var = ftdm_parameters[paramindex].var; + val = ftdm_parameters[paramindex].val; + + if (!strcasecmp(var, "trunkgroup")) { + if (parse_trunkgroup(val) != FTDM_SUCCESS) { + return FTDM_FAIL; + } + } + } + for (paramindex = 0; ftdm_parameters[paramindex].var; paramindex++) { ftdm_log(FTDM_LOG_DEBUG, "Sangoma ISDN key=value, %s=%s\n", ftdm_parameters[paramindex].var, ftdm_parameters[paramindex].val); var = ftdm_parameters[paramindex].var; @@ -331,6 +475,10 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_ if (parse_signalling(val, span) != FTDM_SUCCESS) { return FTDM_FAIL; } + } else if (!strcasecmp(var, "spanmap")) { + if (parse_spanmap(val, span) != FTDM_SUCCESS) { + return FTDM_FAIL; + } } else if (!strcasecmp(var, "tei")) { uint8_t tei = atoi(val); if (tei > 127) { @@ -465,6 +613,8 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_ parse_timer(val, &signal_data->timer_t319); } else if (!strcasecmp(var, "timer-t322")) { parse_timer(val, &signal_data->timer_t322); + } else if (!strcasecmp(var, "trunkgroup")) { + /* Do nothing, we already parsed this parameter */ } else { ftdm_log(FTDM_LOG_WARNING, "Ignoring unknown parameter %s\n", ftdm_parameters[paramindex].var); } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c index 15def40218..754aff1187 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c @@ -40,6 +40,8 @@ void sngisdn_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status void sngisdn_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status) { ftdm_sigmsg_t sig; + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)ftdmchan->span->signal_data; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Signalling link status changed to %s\n", ftdm_signaling_status2str(status)); memset(&sig, 0, sizeof(sig)); @@ -52,7 +54,6 @@ void sngisdn_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status if (FTDM_SPAN_IS_BRI(ftdmchan->span)) { sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data; - sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)ftdmchan->span->signal_data; if (ftdm_test_flag(sngisdn_info, FLAG_ACTIVATING)) { ftdm_clear_flag(sngisdn_info, FLAG_ACTIVATING); @@ -67,6 +68,7 @@ void sngisdn_set_span_sig_status(ftdm_span_t *span, ftdm_signaling_status_t stat ftdm_iterator_t *chaniter = NULL; ftdm_iterator_t *curr = NULL; + ((sngisdn_span_data_t*)span->signal_data)->sigstatus = status; chaniter = ftdm_span_get_chan_iterator(span, NULL); for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c index 55a156c562..b96a801243 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c @@ -62,6 +62,8 @@ ftdm_status_t sngisdn_stack_cfg(ftdm_span_t *span) { sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data; + ftdm_log(FTDM_LOG_DEBUG, "Starting stack configuration for span:%s\n", span->name); + if (!g_sngisdn_data.gen_config_done) { g_sngisdn_data.gen_config_done = 1; ftdm_log(FTDM_LOG_DEBUG, "Starting general stack configuration\n"); @@ -91,33 +93,33 @@ ftdm_status_t sngisdn_stack_cfg(ftdm_span_t *span) ftdm_log(FTDM_LOG_INFO, "General stack configuration done\n"); } - /* TODO: for NFAS, should only call these function for spans with d-chans */ - if (sngisdn_stack_cfg_phy_psap(span) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "%s:phy_psap configuration failed\n", span->name); - return FTDM_FAIL; - } - ftdm_log(FTDM_LOG_DEBUG, "%s:phy_psap configuration done\n", span->name); - - if (sngisdn_stack_cfg_q921_msap(span) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "%s:q921_msap configuration failed\n", span->name); - return FTDM_FAIL; - } - ftdm_log(FTDM_LOG_DEBUG, "%s:q921_msap configuration done\n", span->name); - - if (sngisdn_stack_cfg_q921_dlsap(span, 0) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "%s:q921_dlsap configuration failed\n", span->name); - return FTDM_FAIL; - } - ftdm_log(FTDM_LOG_DEBUG, "%s:q921_dlsap configuration done\n", span->name); - - if (span->trunk_type == FTDM_TRUNK_BRI_PTMP) { - if (sngisdn_stack_cfg_q921_dlsap(span, 1) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "%s:q921_dlsap management configuration failed\n", span->name); + if (signal_data->dchan) { + if (sngisdn_stack_cfg_phy_psap(span) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "%s:phy_psap configuration failed\n", span->name); return FTDM_FAIL; } - ftdm_log(FTDM_LOG_DEBUG, "%s:q921_dlsap management configuration done\n", span->name); + ftdm_log(FTDM_LOG_DEBUG, "%s:phy_psap configuration done\n", span->name); + + if (sngisdn_stack_cfg_q921_msap(span) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "%s:q921_msap configuration failed\n", span->name); + return FTDM_FAIL; + } + ftdm_log(FTDM_LOG_DEBUG, "%s:q921_msap configuration done\n", span->name); + + if (sngisdn_stack_cfg_q921_dlsap(span, 0) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "%s:q921_dlsap configuration failed\n", span->name); + return FTDM_FAIL; + } + ftdm_log(FTDM_LOG_DEBUG, "%s:q921_dlsap configuration done\n", span->name); + + if (span->trunk_type == FTDM_TRUNK_BRI_PTMP) { + if (sngisdn_stack_cfg_q921_dlsap(span, 1) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "%s:q921_dlsap management configuration failed\n", span->name); + return FTDM_FAIL; + } + ftdm_log(FTDM_LOG_DEBUG, "%s:q921_dlsap management configuration done\n", span->name); + } } - if (sngisdn_stack_cfg_q931_dlsap(span) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_ERROR, "%s:q931_dlsap configuration failed\n", span->name); @@ -125,11 +127,13 @@ ftdm_status_t sngisdn_stack_cfg(ftdm_span_t *span) } ftdm_log(FTDM_LOG_DEBUG, "%s:q931_dlsap configuration done\n", span->name); - if (sngisdn_stack_cfg_q931_lce(span) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "%s:q931_lce configuration failed\n", span->name); - return FTDM_FAIL; + if (signal_data->dchan) { + if (sngisdn_stack_cfg_q931_lce(span) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "%s:q931_lce configuration failed\n", span->name); + return FTDM_FAIL; + } + ftdm_log(FTDM_LOG_DEBUG, "%s:q931_lce configuration done\n", span->name); } - ftdm_log(FTDM_LOG_DEBUG, "%s:q931_lce configuration done\n", span->name); if (!g_sngisdn_data.ccs[signal_data->cc_id].config_done) { g_sngisdn_data.ccs[signal_data->cc_id].config_done = 1; @@ -216,7 +220,7 @@ ftdm_status_t sngisdn_stack_cfg_phy_psap(ftdm_span_t *span) cfg.hdr.entId.inst = S_INST; cfg.hdr.elmId.elmnt = STPSAP; - cfg.hdr.elmId.elmntInst1 = signal_data->dchan_id; + cfg.hdr.elmId.elmntInst1 = signal_data->link_id; if (!signal_data->dchan) { ftdm_log(FTDM_LOG_ERROR, "%s:No d-channels specified\n", span->name); @@ -242,7 +246,7 @@ ftdm_status_t sngisdn_stack_cfg_phy_psap(ftdm_span_t *span) return FTDM_FAIL; } - cfg.t.cfg.s.l1PSAP.spId = signal_data->dchan_id; + cfg.t.cfg.s.l1PSAP.spId = signal_data->link_id; if (sng_isdn_phy_config(&pst, &cfg)) { return FTDM_FAIL; @@ -316,7 +320,7 @@ ftdm_status_t sngisdn_stack_cfg_q921_msap(ftdm_span_t *span) cfg.hdr.entId.inst = S_INST; cfg.hdr.elmId.elmnt = STMSAP; - cfg.t.cfg.s.bdMSAP.lnkNmb = signal_data->dchan_id; + cfg.t.cfg.s.bdMSAP.lnkNmb = signal_data->link_id; cfg.t.cfg.s.bdMSAP.maxOutsFrms = 24; /* MAC window */ cfg.t.cfg.s.bdMSAP.tQUpperTrs = 32; /* Tx Queue Upper Threshold */ @@ -409,7 +413,7 @@ ftdm_status_t sngisdn_stack_cfg_q921_dlsap(ftdm_span_t *span, uint8_t management cfg.hdr.entId.inst = S_INST; cfg.hdr.elmId.elmnt = STDLSAP; - cfg.t.cfg.s.bdDLSAP.lnkNmb = signal_data->dchan_id; + cfg.t.cfg.s.bdDLSAP.lnkNmb = signal_data->link_id; cfg.t.cfg.s.bdDLSAP.n201 = 1028; /* n201 */ if (span->trunk_type == FTDM_TRUNK_BRI_PTMP || @@ -614,8 +618,8 @@ ftdm_status_t sngisdn_stack_cfg_q931_dlsap(ftdm_span_t *span) cfg.hdr.response.selector=0; - cfg.t.cfg.s.inDLSAP.sapId = signal_data->dchan_id; - cfg.t.cfg.s.inDLSAP.spId = signal_data->dchan_id; + cfg.t.cfg.s.inDLSAP.sapId = signal_data->link_id; + cfg.t.cfg.s.inDLSAP.spId = signal_data->link_id; cfg.t.cfg.s.inDLSAP.swtch = sng_isdn_stack_switchtype(signal_data->switchtype); @@ -630,11 +634,9 @@ ftdm_status_t sngisdn_stack_cfg_q931_dlsap(ftdm_span_t *span) } else { cfg.t.cfg.s.inDLSAP.facilityHandling = 0; } - - /* TODO : NFAS configuration */ - cfg.t.cfg.s.inDLSAP.nfasInt = FALSE; /* pass this later */ - - if (!cfg.t.cfg.s.inDLSAP.nfasInt) { + + if (!signal_data->nfas.trunk) { + cfg.t.cfg.s.inDLSAP.nfasInt = FALSE; cfg.t.cfg.s.inDLSAP.intId = 0; cfg.t.cfg.s.inDLSAP.sigInt = 0; cfg.t.cfg.s.inDLSAP.bupInt = 0; @@ -645,19 +647,55 @@ ftdm_status_t sngisdn_stack_cfg_q931_dlsap(ftdm_span_t *span) cfg.t.cfg.s.inDLSAP.ctldInt[i] = IN_INT_NOT_CFGD; } else { - /* Need to get these parameters from NFAS */ - cfg.t.cfg.s.inDLSAP.intId = 0; - cfg.t.cfg.s.inDLSAP.sigInt = 0; - cfg.t.cfg.s.inDLSAP.bupInt = 1; - cfg.t.cfg.s.inDLSAP.nmbNfasInt = 2; - cfg.t.cfg.s.inDLSAP.buIntPr = 1; + cfg.t.cfg.s.inDLSAP.nfasInt = TRUE; + cfg.t.cfg.s.inDLSAP.intId = signal_data->nfas.interface_id; for (i = 0; i < IN_MAX_NMB_INTRFS; i++) cfg.t.cfg.s.inDLSAP.ctldInt[i] = IN_INT_NOT_CFGD; - /* For primary and backup interfaces, need to initialize this array */ - cfg.t.cfg.s.inDLSAP.ctldInt[0] = 0; /* This is primary if for NFAS */ - cfg.t.cfg.s.inDLSAP.ctldInt[1] = 1; + switch (signal_data->nfas.sigchan) { + case SNGISDN_NFAS_DCHAN_PRIMARY: + cfg.t.cfg.s.inDLSAP.sigInt = signal_data->nfas.trunk->dchan->link_id; + cfg.t.cfg.s.inDLSAP.nmbNfasInt = signal_data->nfas.trunk->num_spans; + + if (signal_data->nfas.trunk->backup) { + cfg.t.cfg.s.inDLSAP.buIntPr = TRUE; + cfg.t.cfg.s.inDLSAP.bupInt = signal_data->nfas.trunk->backup->link_id; + } else { + cfg.t.cfg.s.inDLSAP.buIntPr = FALSE; + } + + for (i = 0; i < MAX_SPANS_PER_NFAS_LINK; i++) { + if (signal_data->nfas.trunk->spans[i]) { + cfg.t.cfg.s.inDLSAP.ctldInt[i] = signal_data->nfas.trunk->spans[i]->link_id; + } + } + + break; + case SNGISDN_NFAS_DCHAN_BACKUP: + cfg.t.cfg.s.inDLSAP.sigInt = signal_data->nfas.trunk->dchan->link_id; + cfg.t.cfg.s.inDLSAP.nmbNfasInt = signal_data->nfas.trunk->num_spans; + + if (signal_data->nfas.trunk->backup) { + cfg.t.cfg.s.inDLSAP.buIntPr = TRUE; + cfg.t.cfg.s.inDLSAP.bupInt = signal_data->nfas.trunk->backup->link_id; + } else { + cfg.t.cfg.s.inDLSAP.buIntPr = FALSE; + } + + for (i = 0; i < MAX_SPANS_PER_NFAS_LINK; i++) { + if (signal_data->nfas.trunk->spans[i]) { + cfg.t.cfg.s.inDLSAP.ctldInt[i] = signal_data->nfas.trunk->spans[i]->link_id; + } + } + + break; + case SNGISDN_NFAS_DCHAN_NONE: + cfg.t.cfg.s.inDLSAP.sigInt = signal_data->nfas.trunk->dchan->link_id; + cfg.t.cfg.s.inDLSAP.nmbNfasInt = 0; + + break; + } } cfg.t.cfg.s.inDLSAP.numRstInd = 255; @@ -903,13 +941,27 @@ ftdm_status_t sngisdn_stack_cfg_q931_dlsap(ftdm_span_t *span) break; case FTDM_TRUNK_T1: case FTDM_TRUNK_J1: - /* if NFAS, could be 0 if no signalling */ - cfg.t.cfg.s.inDLSAP.dChannelNum = 24; - cfg.t.cfg.s.inDLSAP.nmbBearChan = NUM_T1_CHANNELS_PER_SPAN; - cfg.t.cfg.s.inDLSAP.firstBChanNum = 1; + /* if NFAS, could be 0 if no signalling */ cfg.t.cfg.s.inDLSAP.callRefLen = 2; cfg.t.cfg.s.inDLSAP.teiAlloc = IN_STATIC; cfg.t.cfg.s.inDLSAP.intCfg = IN_INTCFG_PTPT; + cfg.t.cfg.s.inDLSAP.firstBChanNum = 1; + + if (signal_data->nfas.trunk) { + if (signal_data->nfas.sigchan == SNGISDN_NFAS_DCHAN_PRIMARY || + signal_data->nfas.sigchan == SNGISDN_NFAS_DCHAN_BACKUP) { + + cfg.t.cfg.s.inDLSAP.dChannelNum = 24; + cfg.t.cfg.s.inDLSAP.nmbBearChan = NUM_T1_CHANNELS_PER_SPAN - 1; + } else { + cfg.t.cfg.s.inDLSAP.dChannelNum = 0; + cfg.t.cfg.s.inDLSAP.nmbBearChan = NUM_T1_CHANNELS_PER_SPAN; + } + } else { + cfg.t.cfg.s.inDLSAP.dChannelNum = 24; + cfg.t.cfg.s.inDLSAP.nmbBearChan = NUM_T1_CHANNELS_PER_SPAN; + cfg.t.cfg.s.inDLSAP.firstBChanNum = 1; + } break; case FTDM_TRUNK_BRI: cfg.t.cfg.s.inDLSAP.dChannelNum = 0; /* Unused for BRI */ @@ -969,7 +1021,7 @@ ftdm_status_t sngisdn_stack_cfg_q931_lce(ftdm_span_t *span) cfg.hdr.response.selector=0; - cfg.t.cfg.s.inLCe.sapId = signal_data->dchan_id; + cfg.t.cfg.s.inLCe.sapId = signal_data->link_id; cfg.t.cfg.s.inLCe.lnkUpDwnInd = TRUE; @@ -990,13 +1042,13 @@ ftdm_status_t sngisdn_stack_cfg_q931_lce(ftdm_span_t *span) cfg.t.cfg.s.inLCe.t314.enb = FALSE; /* if segmentation enabled, set to TRUE */ cfg.t.cfg.s.inLCe.t314.val = 35; - cfg.t.cfg.s.inLCe.t332i.enb = FALSE; /* set to TRUE for NFAS */ - -#ifdef NFAS - cfg.t.cfg.s.inLCe.t332i.val = 35; -#else - cfg.t.cfg.s.inLCe.t332i.val = 0; -#endif + if (signal_data->nfas.trunk) { + cfg.t.cfg.s.inLCe.t332i.enb = TRUE; + cfg.t.cfg.s.inLCe.t332i.val = 35; + } else { + cfg.t.cfg.s.inLCe.t332i.enb = FALSE; + cfg.t.cfg.s.inLCe.t332i.val = 35; + } #if (ISDN_NI1 || ISDN_NT || ISDN_ATT) cfg.t.cfg.s.inLCe.tSpid.enb = TRUE; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c index 2023f4c54c..1cc23ddb8d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c @@ -55,10 +55,12 @@ ftdm_status_t sngisdn_stack_start(ftdm_span_t *span) { sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data; - - if (sngisdn_cntrl_q921(span, ABND_ENA, NOTUSED) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_CRIT, "%s:Failed to activate stack q921\n", span->name); - return FTDM_FAIL; + if (signal_data->dchan) { + if (sngisdn_cntrl_q921(span, ABND_ENA, NOTUSED) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_CRIT, "%s:Failed to activate stack q921\n", span->name); + return FTDM_FAIL; + } + ftdm_log(FTDM_LOG_DEBUG, "%s:Stack q921 activated\n", span->name); } /* Try to find an alternative for this */ @@ -67,8 +69,7 @@ ftdm_status_t sngisdn_stack_start(ftdm_span_t *span) LdUiDatConReq when activated, and this requires the Mac SAP to be already bound first */ ftdm_sleep(500); - - ftdm_log(FTDM_LOG_DEBUG, "%s:Stack q921 activated\n", span->name); + if (!g_sngisdn_data.ccs[signal_data->cc_id].activation_done) { g_sngisdn_data.ccs[signal_data->cc_id].activation_done = 1; if (sngisdn_activate_cc(span) != FTDM_SUCCESS) { @@ -78,7 +79,6 @@ ftdm_status_t sngisdn_stack_start(ftdm_span_t *span) ftdm_log(FTDM_LOG_DEBUG, "%s:Stack CC activated\n", span->name); } - if (sngisdn_cntrl_q931(span, ABND_ENA, SAELMNT) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_CRIT, "%s:Failed to activate stack q931\n", span->name); return FTDM_FAIL; @@ -91,7 +91,11 @@ ftdm_status_t sngisdn_stack_start(ftdm_span_t *span) ftdm_status_t sngisdn_stack_stop(ftdm_span_t *span) { + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data; /* Stop L1 first, so we do not receive any more frames */ + if (!signal_data->dchan) { + return FTDM_SUCCESS; + } if (sngisdn_deactivate_phy(span) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_CRIT, "%s:Failed to deactivate stack phy\n", span->name); return FTDM_FAIL; @@ -147,7 +151,7 @@ ftdm_status_t sngisdn_deactivate_phy(ftdm_span_t *span) cntrl.t.cntrl.action = AUBND_DIS; cntrl.t.cntrl.subAction = SAELMNT; - cntrl.t.cntrl.sapId = signal_data->dchan_id; + cntrl.t.cntrl.sapId = signal_data->link_id; if (sng_isdn_phy_cntrl(&pst, &cntrl)) { return FTDM_FAIL; @@ -182,7 +186,7 @@ ftdm_status_t sngisdn_wake_up_phy(ftdm_span_t *span) cntrl.t.cntrl.action = AENA; cntrl.t.cntrl.subAction = SAELMNT; - cntrl.t.cntrl.sapId = signal_data->dchan_id; + cntrl.t.cntrl.sapId = signal_data->link_id; if (sng_isdn_phy_cntrl(&pst, &cntrl)) { return FTDM_FAIL; @@ -226,33 +230,34 @@ ftdm_status_t sngisdn_activate_cc(ftdm_span_t *span) ftdm_status_t sngisdn_activate_trace(ftdm_span_t *span, sngisdn_tracetype_t trace_opt) { - sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data; + sngisdn_span_data_t *signal_data = sngisdn_dchan((sngisdn_span_data_t*)span->signal_data); + switch (trace_opt) { case SNGISDN_TRACE_DISABLE: if (sngisdn_test_trace_flag(signal_data, SNGISDN_TRACE_Q921)) { - ftdm_log(FTDM_LOG_INFO, "s%d Disabling q921 trace\n", signal_data->link_id); + ftdm_log(FTDM_LOG_INFO, "%s:Disabling q921 trace\n", signal_data->ftdm_span->name); sngisdn_clear_trace_flag(signal_data, SNGISDN_TRACE_Q921); - if (sngisdn_cntrl_q921(span, ADISIMM, SATRC) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "s%d Failed to disable q921 trace\n"); + if (sngisdn_cntrl_q921(signal_data->ftdm_span, ADISIMM, SATRC) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_INFO, "%s:Failed to disable q921 trace\n", signal_data->ftdm_span->name); } } if (sngisdn_test_trace_flag(signal_data, SNGISDN_TRACE_Q931)) { - ftdm_log(FTDM_LOG_INFO, "s%d Disabling q931 trace\n", signal_data->link_id); + ftdm_log(FTDM_LOG_INFO, "%s:Disabling q921 trace\n", signal_data->ftdm_span->name); sngisdn_clear_trace_flag(signal_data, SNGISDN_TRACE_Q931); - if (sngisdn_cntrl_q931(span, ADISIMM, SATRC) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "s%d Failed to disable q931 trace\n"); + if (sngisdn_cntrl_q931(signal_data->ftdm_span, ADISIMM, SATRC) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_INFO, "%s:Failed to disable q921 trace\n", signal_data->ftdm_span->name); } } break; case SNGISDN_TRACE_Q921: if (!sngisdn_test_trace_flag(signal_data, SNGISDN_TRACE_Q921)) { - ftdm_log(FTDM_LOG_INFO, "s%d Enabling q921 trace\n", signal_data->link_id); + ftdm_log(FTDM_LOG_INFO, "%s:Enabling q921 trace\n", signal_data->ftdm_span->name); sngisdn_set_trace_flag(signal_data, SNGISDN_TRACE_Q921); - if (sngisdn_cntrl_q921(span, AENA, SATRC) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "s%d Failed to enable q921 trace\n"); + if (sngisdn_cntrl_q921(signal_data->ftdm_span, AENA, SATRC) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_INFO, "%s:Failed to enable q921 trace\n", signal_data->ftdm_span->name); } } break; @@ -261,8 +266,8 @@ ftdm_status_t sngisdn_activate_trace(ftdm_span_t *span, sngisdn_tracetype_t trac ftdm_log(FTDM_LOG_INFO, "s%d Enabling q931 trace\n", signal_data->link_id); sngisdn_set_trace_flag(signal_data, SNGISDN_TRACE_Q931); - if (sngisdn_cntrl_q931(span, AENA, SATRC) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "s%d Failed to enable q931 trace\n"); + if (sngisdn_cntrl_q931(signal_data->ftdm_span, AENA, SATRC) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_INFO, "%s:Failed to enable q931 trace\n", signal_data->ftdm_span->name); } } break; @@ -301,7 +306,7 @@ ftdm_status_t sngisdn_cntrl_q931(ftdm_span_t *span, uint8_t action, uint8_t suba cntrl.t.cntrl.trcLen = -1; /* Trace the entire message buffer */ } - cntrl.t.cntrl.sapId = signal_data->dchan_id; + cntrl.t.cntrl.sapId = signal_data->link_id; cntrl.t.cntrl.ces = 0; if(sng_isdn_q931_cntrl(&pst, &cntrl)) { @@ -342,11 +347,11 @@ ftdm_status_t sngisdn_cntrl_q921(ftdm_span_t *span, uint8_t action, uint8_t suba cntrl.t.cntrl.subAction = subaction; #if (SMBD_LMINT3 || BD_LMINT3) - cntrl.t.cntrl.lnkNmb = signal_data->dchan_id; + cntrl.t.cntrl.lnkNmb = signal_data->link_id; cntrl.t.cntrl.sapi = NOTUSED; cntrl.t.cntrl.tei = NOTUSED; #else /* _LMINT3 */ - cntrl.hdr.elmId.elmntInst1 = signal_data->dchan_id; + cntrl.hdr.elmId.elmntInst1 = signal_data->link_id; cntrl.hdr.elmId.elmntInst2 = NOTUSED; cntrl.hdr.elmId.elmntInst3 = NOTUSED; #endif /* _LMINT3 */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c index 0a34068359..15bff0390e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c @@ -58,6 +58,19 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_DOWN: /* Proper state to receive a SETUP */ + if (signal_data->nfas.trunk) { + ftdm_alarm_flag_t alarmflag = 0; + + ftdm_channel_get_alarms(ftdmchan, &alarmflag); + if (alarmflag) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Received SETUP but channel has physical layer alarm - rejecting\n"); + + ftdmchan->caller_data.hangup_cause = 0x2C; /* Channel requested not available */ + ftdm_sched_timer(signal_data->sched, "delayed_release", 1, sngisdn_delayed_release, (void*) sngisdn_info, NULL); + break; + } + } + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE) || ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) { @@ -1177,13 +1190,13 @@ void sngisdn_process_rst_cfm (sngisdn_event_data_t *sngisdn_event) uint8_t chan_no = 0; Rst *rstEvnt = &sngisdn_event->event.rstEvnt; - sngisdn_span_data_t *signal_data = g_sngisdn_data.dchans[dChan].spans[1]; + sngisdn_span_data_t *signal_data = g_sngisdn_data.spans[dChan]; if (!signal_data) { ftdm_log(FTDM_LOG_CRIT, "Received RESTART CFM on unconfigured span (suId:%d)\n", suId); return; } - - if (rstEvnt->rstInd.eh.pres == PRSNT_NODEF && rstEvnt->rstInd.rstClass.pres == PRSNT_NODEF) { + + if (rstEvnt->rstInd.eh.pres == PRSNT_NODEF && rstEvnt->rstInd.rstClass.pres == PRSNT_NODEF) { switch(rstEvnt->rstInd.rstClass.val) { case IN_CL_INDCHAN: /* Indicated b-channel */ if (rstEvnt->chanId.eh.pres) { @@ -1196,6 +1209,16 @@ void sngisdn_process_rst_cfm (sngisdn_event_data_t *sngisdn_event) chan_no = rstEvnt->chanId.chanNmbSlotMap.val[0]; } } + + if (signal_data->nfas.trunk) { + if (!rstEvnt->chanId.intIdent.pres) { + ftdm_log(FTDM_LOG_CRIT, "Failed to determine interface from RESTART\n"); + return; + } else if (signal_data->nfas.interface_id != rstEvnt->chanId.intIdent.val) { + /* This RESTART is for another interface */ + return; + } + } } if (!chan_no) { ftdm_log(FTDM_LOG_CRIT, "Failed to determine channel from RESTART\n"); @@ -1258,10 +1281,7 @@ void sngisdn_process_rst_ind (sngisdn_event_data_t *sngisdn_event) rstEvnt = &sngisdn_event->event.rstEvnt; - /* TODO: readjust this when NFAS is implemented as signal_data will not always be the first - * span for that d-channel */ - - signal_data = g_sngisdn_data.dchans[dChan].spans[1]; + signal_data = g_sngisdn_data.spans[dChan]; if (!signal_data) { ftdm_log(FTDM_LOG_CRIT, "Received RESTART IND on unconfigured span (suId:%d)\n", suId); @@ -1292,6 +1312,16 @@ void sngisdn_process_rst_ind (sngisdn_event_data_t *sngisdn_event) chan_no = rstEvnt->chanId.chanNmbSlotMap.val[0]; } } + + if (signal_data->nfas.trunk) { + if (!rstEvnt->chanId.intIdent.pres) { + ftdm_log(FTDM_LOG_CRIT, "Failed to determine interface from RESTART\n"); + return; + } else if (signal_data->nfas.interface_id != rstEvnt->chanId.intIdent.val) { + /* This RESTART is for another interface */ + return; + } + } } if (!chan_no) { ftdm_log(FTDM_LOG_CRIT, "Failed to determine channel from RESTART\n"); @@ -1300,7 +1330,7 @@ void sngisdn_process_rst_ind (sngisdn_event_data_t *sngisdn_event) break; case IN_CL_SNGINT: /* Single interface */ case IN_CL_ALLINT: /* All interfaces */ - /* In case restart class indicates all interfaces, we will duplicate + /* In case restart class indicates all interfaces, we will duplicated this event on each span associated to this d-channel in sngisdn_rcv_rst_cfm, so treat it as a single interface anyway */ chan_no = 0; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c index f528333634..20b0c86ca9 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c @@ -36,10 +36,10 @@ void sngisdn_snd_setup(ftdm_channel_t *ftdmchan) { - ConEvnt conEvnt; + ConEvnt conEvnt; sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; - ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_INVALID}; + ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_INVALID}; ftdm_assert((!sngisdn_info->suInstId && !sngisdn_info->spInstId), "Trying to call out, but call data was not cleared\n"); @@ -75,9 +75,9 @@ void sngisdn_snd_setup(ftdm_channel_t *ftdmchan) set_facility_ie(ftdmchan, &conEvnt.facilityStr); set_prog_ind_ie(ftdmchan, &conEvnt.progInd, prog_ind); - ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending SETUP (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); + ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending SETUP (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces); - if (sng_isdn_con_request(signal_data->cc_id, sngisdn_info->suInstId, &conEvnt, signal_data->dchan_id, sngisdn_info->ces)) { + if (sng_isdn_con_request(signal_data->cc_id, sngisdn_info->suInstId, &conEvnt, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused SETUP request\n"); } @@ -103,9 +103,9 @@ void sngisdn_snd_setup_ack(ftdm_channel_t *ftdmchan) - ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending SETUP ACK (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); + ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending SETUP ACK (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces); - if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, MI_SETUPACK, signal_data->dchan_id, sngisdn_info->ces)) { + if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, MI_SETUPACK, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused SETUP ACK request\n"); } return; @@ -135,9 +135,9 @@ void sngisdn_snd_con_complete(ftdm_channel_t *ftdmchan) set_chan_id_ie(ftdmchan, &cnStEvnt.chanId); } - ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending CONNECT COMPL (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); + ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending CONNECT COMPL (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces); - if(sng_isdn_con_comp(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, signal_data->dchan_id, sngisdn_info->ces)) { + if(sng_isdn_con_comp(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused CONNECT ACK request\n"); } return; @@ -171,9 +171,9 @@ void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_i set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind); set_facility_ie(ftdmchan, &cnStEvnt.facilityStr); - ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending PROCEED (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); + ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending PROCEED (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces); - if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, MI_CALLPROC, signal_data->dchan_id, sngisdn_info->ces)) { + if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, MI_CALLPROC, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused PROCEED request\n"); } return; @@ -203,8 +203,8 @@ void sngisdn_snd_progress(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind); set_facility_ie(ftdmchan, &cnStEvnt.facilityStr); - ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending PROGRESS (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); - if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId,&cnStEvnt, MI_PROGRESS, signal_data->dchan_id, sngisdn_info->ces)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending PROGRESS (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces); + if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId,&cnStEvnt, MI_PROGRESS, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused PROGRESS request\n"); } return; @@ -229,9 +229,9 @@ void sngisdn_snd_alert(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind); set_facility_ie(ftdmchan, &cnStEvnt.facilityStr); - ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending ALERT (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); + ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending ALERT (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces); - if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId,&cnStEvnt, MI_ALERTING, signal_data->dchan_id, sngisdn_info->ces)) { + if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId,&cnStEvnt, MI_ALERTING, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused ALERT request\n"); } return; @@ -265,8 +265,8 @@ void sngisdn_snd_connect(ftdm_channel_t *ftdmchan) set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind); set_facility_ie(ftdmchan, &cnStEvnt.facilityStr); - ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending CONNECT (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); - if (sng_isdn_con_response(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, signal_data->dchan_id, sngisdn_info->ces)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending CONNECT (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces); + if (sng_isdn_con_response(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused CONNECT request\n"); } return; @@ -297,9 +297,9 @@ void sngisdn_snd_fac_req(ftdm_channel_t *ftdmchan) facEvnt.facElmt.facStr.val[1] = (uint8_t)facEvnt.facElmt.facStr.len; facEvnt.facElmt.facStr.len +=2; /* Need to include the size of identifier + len */ - ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending FACILITY (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); + ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending FACILITY (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces); - if (sng_isdn_facility_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &facEvnt, MI_FACIL, signal_data->dchan_id, sngisdn_info->ces)) { + if (sng_isdn_facility_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &facEvnt, MI_FACIL, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused FACILITY request\n"); } return; @@ -322,9 +322,9 @@ void sngisdn_snd_info_req(ftdm_channel_t *ftdmchan) memset(&cnStEvnt, 0, sizeof(cnStEvnt)); - ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending INFO REQ (suId:%d dchan:%d ces:%d)\n", signal_data->cc_id, signal_data->dchan_id, sngisdn_info->ces); + ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending INFO REQ (suId:%d dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces); - if (sng_isdn_con_status(signal_data->cc_id, 0, 0, &cnStEvnt, MI_INFO, signal_data->dchan_id, sngisdn_info->ces)) { + if (sng_isdn_con_status(signal_data->cc_id, 0, 0, &cnStEvnt, MI_INFO, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused INFO request\n"); } return; @@ -348,9 +348,9 @@ void sngisdn_snd_notify_req(ftdm_channel_t *ftdmchan) set_not_ind_ie(ftdmchan, &cnStEvnt.notInd); - ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending NOTIFY (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); + ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending NOTIFY (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces); - if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId,&cnStEvnt, MI_NOTIFY, signal_data->dchan_id, sngisdn_info->ces)) { + if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId,&cnStEvnt, MI_NOTIFY, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused NOTIFY request\n"); } return; @@ -368,7 +368,7 @@ void sngisdn_snd_status_enq(ftdm_channel_t *ftdmchan) memset(&staEvnt, 0, sizeof(StaEvnt)); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending Status ENQ on suId:%d suInstId:%u spInstId:%d dchan:%d ces:%d\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending Status ENQ on suId:%d suInstId:%u spInstId:%d dchan:%d ces:%d\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces); if (sng_isdn_status_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &staEvnt, MI_STATENQ)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused Status ENQ request\n"); } @@ -468,9 +468,9 @@ void sngisdn_snd_restart(ftdm_channel_t *ftdmchan) set_chan_id_ie(ftdmchan, &rstEvnt.chanId); set_restart_ind_ie(ftdmchan, &rstEvnt.rstInd); - ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending RESTART (suId:%d dchan:%d ces:%d)\n", signal_data->cc_id, signal_data->dchan_id, CES_MNGMNT); + ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending RESTART (suId:%d dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_dchan(signal_data)->link_id, CES_MNGMNT); - if (sng_isdn_restart_request(signal_data->cc_id, &rstEvnt, signal_data->dchan_id, CES_MNGMNT, IN_SND_RST)) { + if (sng_isdn_restart_request(signal_data->cc_id, &rstEvnt, sngisdn_dchan(signal_data)->link_id, CES_MNGMNT, IN_SND_RST)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused RESTART request\n"); } return; @@ -535,25 +535,26 @@ void sngisdn_snd_data(ftdm_channel_t *dchan, uint8_t *data, ftdm_size_t len) ftdm_log_chan(dchan, FTDM_LOG_CRIT, "\nL1 RX [%s] flags:%x\n", string, l1_frame.flags); } #endif - sng_isdn_data_ind(signal_data->dchan_id, &l1_frame); + sng_isdn_data_ind(signal_data->link_id, &l1_frame); } -void sngisdn_snd_event(ftdm_channel_t *dchan, ftdm_oob_event_t event) +void sngisdn_snd_event(sngisdn_span_data_t *signal_data, ftdm_oob_event_t event) { sng_l1_event_t l1_event; - sngisdn_span_data_t *signal_data = NULL; + + if (!signal_data->dchan) { + return; + } memset(&l1_event, 0, sizeof(l1_event)); - - - signal_data = (sngisdn_span_data_t*) dchan->span->signal_data; + switch(event) { case FTDM_OOB_ALARM_CLEAR: l1_event.type = SNG_L1EVENT_ALARM_OFF; - sng_isdn_event_ind(signal_data->dchan_id, &l1_event); + sng_isdn_event_ind(signal_data->link_id, &l1_event); break; case FTDM_OOB_ALARM_TRAP: l1_event.type = SNG_L1EVENT_ALARM_ON; - sng_isdn_event_ind(signal_data->dchan_id, &l1_event); + sng_isdn_event_ind(signal_data->link_id, &l1_event); break; default: /* We do not care about the other OOB events for now */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c index c45bbf0874..17e8d54084 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c @@ -33,17 +33,19 @@ */ #include "ftmod_sangoma_isdn.h" +//static void sngisdn_rcv_q931_ind_span(sngisdn_span_data_t *signal_data, InMngmt *status); void sngisdn_rcv_con_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, ConEvnt *conEvnt, int16_t dChan, uint8_t ces) { uint8_t bchan_no = 0; + int8_t interface_id = -1; /* Specifies which interface for NFAS */ sngisdn_chan_data_t *sngisdn_info = NULL; sngisdn_event_data_t *sngisdn_event = NULL; ISDN_FUNC_TRACE_ENTER(__FUNCTION__); ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Con Ind on unconfigured cc\n"); - ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Con Ind on unconfigured dchan\n"); + ftdm_assert(g_sngisdn_data.spans[dChan], "Con Ind on unconfigured dchan\n"); if (conEvnt->chanId.eh.pres != PRSNT_NODEF) { /* TODO: Implement me */ @@ -58,19 +60,38 @@ void sngisdn_rcv_con_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, Co bchan_no = conEvnt->chanId.infoChanSel.val; } + if (conEvnt->chanId.intIdent.pres) { + interface_id = conEvnt->chanId.intIdent.val; + } + if (!bchan_no) { ftdm_log(FTDM_LOG_ERROR, "Failed to obtain b-channel number from SETUP message\n"); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); return; } - if (g_sngisdn_data.dchans[dChan].channels[bchan_no] == NULL) { - ftdm_log(FTDM_LOG_ERROR, "Incoming call on unconfigured b-channel:%d\n", bchan_no); - ISDN_FUNC_TRACE_EXIT(__FUNCTION__); - return; + if (g_sngisdn_data.spans[dChan]->nfas.trunk) { + if (interface_id < 0) { + ftdm_log(FTDM_LOG_ERROR, "Interface ID not present on NFAS interface\n"); + ISDN_FUNC_TRACE_EXIT(__FUNCTION__); + return; + } else if (!g_sngisdn_data.spans[dChan]->nfas.trunk->spans[interface_id]) { + ftdm_log(FTDM_LOG_ERROR, "NFAS group:%s does not have logical interface %d\n", g_sngisdn_data.spans[dChan]->nfas.trunk->name, interface_id); + ISDN_FUNC_TRACE_EXIT(__FUNCTION__); + return; + } else { + sngisdn_info = g_sngisdn_data.spans[dChan]->nfas.trunk->spans[interface_id]->channels[bchan_no]; + } + } else { + if (g_sngisdn_data.spans[dChan]->channels[bchan_no] == NULL) { + ftdm_log(FTDM_LOG_ERROR, "Incoming call on unconfigured b-channel:%d\n", bchan_no); + ISDN_FUNC_TRACE_EXIT(__FUNCTION__); + return; + } + + sngisdn_info = g_sngisdn_data.spans[dChan]->channels[bchan_no]; } - - sngisdn_info = g_sngisdn_data.dchans[dChan].channels[bchan_no]; + ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received SETUP (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); @@ -103,7 +124,7 @@ void sngisdn_rcv_con_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, Cn ISDN_FUNC_TRACE_ENTER(__FUNCTION__); ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Con Cfm on unconfigured cc\n"); - ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Con Cfm on unconfigured dchan\n"); + ftdm_assert(g_sngisdn_data.spans[dChan] != 0, "Con Cfm on unconfigured dchan\n"); if (get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_CRIT, "Could not find matching call suId:%u suInstId:%u spInstId:%u\n", suId, suInstId, spInstId); @@ -147,7 +168,7 @@ void sngisdn_rcv_cnst_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, C ISDN_FUNC_TRACE_ENTER(__FUNCTION__); ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Cnst Ind on unconfigured cc\n"); - ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Cnst Ind on unconfigured dchan\n"); + ftdm_assert(g_sngisdn_data.spans[dChan] != 0, "Cnst Ind on unconfigured dchan\n"); if (get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_CRIT, "Could not find matching call suId:%u suInstId:%u spInstId:%u\n", suId, suInstId, spInstId); @@ -537,37 +558,41 @@ void sngisdn_rcv_sta_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, St void sngisdn_rcv_srv_ind (int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces) { - unsigned i; + sngisdn_span_data_t *signal_data; sngisdn_event_data_t *sngisdn_event = NULL; ISDN_FUNC_TRACE_ENTER(__FUNCTION__); ftdm_log(FTDM_LOG_INFO, "Received SERVICE IND (dChan:%d ces:%u)\n", dChan, ces); - - /* Enqueue the event to each span within the dChan */ - for(i=1; i<=g_sngisdn_data.dchans[dChan].num_spans; i++) { - signal_data = g_sngisdn_data.dchans[dChan].spans[i]; - sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); - memset(sngisdn_event, 0, sizeof(*sngisdn_event)); - sngisdn_event->event_id = SNGISDN_EVENT_SRV_IND; - sngisdn_event->suId = suId; - sngisdn_event->dChan = dChan; - sngisdn_event->ces = ces; - sngisdn_event->signal_data = signal_data; - - memcpy(&sngisdn_event->event.srvEvnt, srvEvnt, sizeof(*srvEvnt)); - ftdm_queue_enqueue((signal_data)->event_queue, sngisdn_event); + signal_data = g_sngisdn_data.spans[dChan]; + + if (signal_data->nfas.trunk) { + unsigned i; + for (i = 0; i < signal_data->nfas.trunk->num_spans; i++) { + sngisdn_span_data_t *my_signal_data = signal_data->nfas.trunk->spans[i]; + + sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); + memset(sngisdn_event, 0, sizeof(*sngisdn_event)); + sngisdn_event->event_id = SNGISDN_EVENT_SRV_IND; + sngisdn_event->suId = suId; + sngisdn_event->dChan = dChan; + sngisdn_event->ces = ces; + sngisdn_event->signal_data = my_signal_data; + memcpy(&sngisdn_event->event.srvEvnt, srvEvnt, sizeof(*srvEvnt)); + ftdm_queue_enqueue(my_signal_data->event_queue, sngisdn_event); + } + } else { + ftdm_queue_enqueue(signal_data->event_queue, sngisdn_event); } ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } void sngisdn_rcv_srv_cfm (int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces) -{ - unsigned i; +{ sngisdn_span_data_t *signal_data = NULL; sngisdn_event_data_t *sngisdn_event = NULL; @@ -575,59 +600,65 @@ void sngisdn_rcv_srv_cfm (int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces ftdm_log(FTDM_LOG_INFO, "Received SERVICE CFM (dChan:%d ces:%u)\n", dChan, ces); - /* Enqueue the event to each span within the dChan */ - for(i=1; i<=g_sngisdn_data.dchans[dChan].num_spans; i++) { - signal_data = g_sngisdn_data.dchans[dChan].spans[i]; - sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); - memset(sngisdn_event, 0, sizeof(*sngisdn_event)); + signal_data = g_sngisdn_data.spans[dChan]; - sngisdn_event->event_id = SNGISDN_EVENT_SRV_CFM; - sngisdn_event->suId = suId; - sngisdn_event->dChan = dChan; - sngisdn_event->ces = ces; - sngisdn_event->signal_data = signal_data; + if (signal_data->nfas.trunk) { + unsigned i; + for (i = 0; i < signal_data->nfas.trunk->num_spans; i++) { + sngisdn_span_data_t *my_signal_data = signal_data->nfas.trunk->spans[i]; - memcpy(&sngisdn_event->event.srvEvnt, srvEvnt, sizeof(*srvEvnt)); - ftdm_queue_enqueue((signal_data)->event_queue, sngisdn_event); + sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); + memset(sngisdn_event, 0, sizeof(*sngisdn_event)); + sngisdn_event->event_id = SNGISDN_EVENT_SRV_CFM; + sngisdn_event->suId = suId; + sngisdn_event->dChan = dChan; + sngisdn_event->ces = ces; + sngisdn_event->signal_data = my_signal_data; + memcpy(&sngisdn_event->event.srvEvnt, srvEvnt, sizeof(*srvEvnt)); + ftdm_queue_enqueue(my_signal_data->event_queue, sngisdn_event); + } + } else { + ftdm_queue_enqueue(signal_data->event_queue, sngisdn_event); } ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } void sngisdn_rcv_rst_ind (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces, uint8_t evntType) -{ - unsigned i; +{ sngisdn_span_data_t *signal_data = NULL; sngisdn_event_data_t *sngisdn_event = NULL; ISDN_FUNC_TRACE_ENTER(__FUNCTION__); ftdm_log(FTDM_LOG_INFO, "Received RESTART IND (dChan:%d ces:%u type:%u)\n", dChan, ces, evntType); - - /* Enqueue the event to each span within the dChan */ - for(i=1; i<=g_sngisdn_data.dchans[dChan].num_spans; i++) { - signal_data = g_sngisdn_data.dchans[dChan].spans[i]; - sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); - memset(sngisdn_event, 0, sizeof(*sngisdn_event)); + signal_data = g_sngisdn_data.spans[dChan]; - sngisdn_event->event_id = SNGISDN_EVENT_RST_IND; - sngisdn_event->suId = suId; - sngisdn_event->dChan = dChan; - sngisdn_event->ces = ces; - sngisdn_event->evntType = evntType; - sngisdn_event->signal_data = signal_data; + if (signal_data->nfas.trunk) { + unsigned i; + for (i = 0; i < signal_data->nfas.trunk->num_spans; i++) { + sngisdn_span_data_t *my_signal_data = signal_data->nfas.trunk->spans[i]; - memcpy(&sngisdn_event->event.rstEvnt, rstEvnt, sizeof(*rstEvnt)); + sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); + memset(sngisdn_event, 0, sizeof(*sngisdn_event)); + sngisdn_event->event_id = SNGISDN_EVENT_RST_IND; + sngisdn_event->suId = suId; + sngisdn_event->dChan = dChan; + sngisdn_event->ces = ces; + sngisdn_event->signal_data = my_signal_data; + memcpy(&sngisdn_event->event.rstEvnt, rstEvnt, sizeof(*rstEvnt)); + ftdm_queue_enqueue(my_signal_data->event_queue, sngisdn_event); + } + } else { ftdm_queue_enqueue(signal_data->event_queue, sngisdn_event); } ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } void sngisdn_rcv_rst_cfm (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces, uint8_t evntType) -{ - unsigned i; +{ sngisdn_span_data_t *signal_data; sngisdn_event_data_t *sngisdn_event = NULL; @@ -636,22 +667,26 @@ void sngisdn_rcv_rst_cfm (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces ftdm_log(FTDM_LOG_INFO, "Received RESTART CFM (dChan:%d ces:%u type:%u)\n", dChan, ces, evntType); - /* Enqueue the event to each span within the dChan */ - for(i=1; i<=g_sngisdn_data.dchans[dChan].num_spans; i++) { - signal_data = g_sngisdn_data.dchans[dChan].spans[i]; - sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); - memset(sngisdn_event, 0, sizeof(*sngisdn_event)); + signal_data = g_sngisdn_data.spans[dChan]; - sngisdn_event->event_id = SNGISDN_EVENT_RST_CFM; - sngisdn_event->suId = suId; - sngisdn_event->dChan = dChan; - sngisdn_event->ces = ces; - sngisdn_event->evntType = evntType; - sngisdn_event->signal_data = signal_data; + if (signal_data->nfas.trunk) { + unsigned i; + for (i = 0; i < signal_data->nfas.trunk->num_spans; i++) { + sngisdn_span_data_t *my_signal_data = signal_data->nfas.trunk->spans[i]; - memcpy(&sngisdn_event->event.rstEvnt, rstEvnt, sizeof(*rstEvnt)); - ftdm_queue_enqueue((signal_data)->event_queue, sngisdn_event); + sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); + memset(sngisdn_event, 0, sizeof(*sngisdn_event)); + sngisdn_event->event_id = SNGISDN_EVENT_RST_CFM; + sngisdn_event->suId = suId; + sngisdn_event->dChan = dChan; + sngisdn_event->ces = ces; + sngisdn_event->signal_data = my_signal_data; + memcpy(&sngisdn_event->event.rstEvnt, rstEvnt, sizeof(*rstEvnt)); + ftdm_queue_enqueue(my_signal_data->event_queue, sngisdn_event); + } + } else { + ftdm_queue_enqueue(signal_data->event_queue, sngisdn_event); } ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } @@ -660,7 +695,7 @@ void sngisdn_rcv_rst_cfm (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces void sngisdn_rcv_phy_ind(SuId suId, Reason reason) { if (reason != LL1_REASON_CON_REQ_FAIL) { - ftdm_log(FTDM_LOG_INFO, "[SNGISDN PHY] D-chan %d : %s\n", suId, DECODE_LL1_REASON(reason)); + ftdm_log(FTDM_LOG_DEBUG, "[SNGISDN PHY] D-chan %d : %s\n", suId, DECODE_LL1_REASON(reason)); } return; } @@ -669,7 +704,7 @@ void sngisdn_rcv_q921_ind(BdMngmt *status) { ftdm_span_t *ftdmspan; - sngisdn_span_data_t *signal_data = g_sngisdn_data.dchans[status->t.usta.lnkNmb].spans[1]; + sngisdn_span_data_t *signal_data = g_sngisdn_data.spans[status->t.usta.lnkNmb]; if (!signal_data) { ftdm_log(FTDM_LOG_INFO, "Received q921 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.lnkNmb); @@ -722,8 +757,43 @@ void sngisdn_rcv_q921_ind(BdMngmt *status) } return; } + +#if 0 +static void sngisdn_rcv_q931_ind_span(sngisdn_span_data_t *signal_data, InMngmt *status) +{ + ftdm_span_t *ftdmspan = signal_data->ftdm_span; + uint32_t chan_no = status->t.usta.evntParm[2]; + + if (!signal_data) { + ftdm_log(FTDM_LOG_INFO, "Received q931 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.suId); + return; + } + + ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q931] s%d: %s: %s(%d): %s(%d)\n", + status->t.usta.suId, + DECODE_LCM_CATEGORY(status->t.usta.alarm.category), + DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event, + DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause); + + if (chan_no) { + ftdm_channel_t *ftdmchan = ftdm_span_get_channel(ftdmspan, chan_no); + if (ftdmchan) { + sngisdn_set_chan_sig_status(ftdmchan, (status->t.usta.alarm.event == LCM_EVENT_UP) ? FTDM_SIG_STATE_UP : FTDM_SIG_STATE_DOWN); + sngisdn_set_chan_avail_rate(ftdmchan, (status->t.usta.alarm.event == LCM_EVENT_UP) ? SNGISDN_AVAIL_UP: SNGISDN_AVAIL_PWR_SAVING); + } else { + ftdm_log(FTDM_LOG_CRIT, "stack alarm event on invalid channel :%d\n", chan_no); + } + } else { + sngisdn_set_span_sig_status(ftdmspan, (status->t.usta.alarm.event == LCM_EVENT_UP) ? FTDM_SIG_STATE_UP : FTDM_SIG_STATE_DOWN); + sngisdn_set_span_avail_rate(ftdmspan, (status->t.usta.alarm.event == LCM_EVENT_UP) ? SNGISDN_AVAIL_UP: SNGISDN_AVAIL_PWR_SAVING); + } +} +#endif + void sngisdn_rcv_q931_ind(InMngmt *status) -{ +{ + sngisdn_span_data_t *signal_data = NULL; + ftdm_span_t *ftdmspan = NULL; #ifndef WIN32 if (status->t.usta.alarm.cause == 287) { sngisdn_get_memory_info(); @@ -731,47 +801,53 @@ void sngisdn_rcv_q931_ind(InMngmt *status) } #endif + signal_data = g_sngisdn_data.spans[status->t.usta.suId]; + if (!signal_data) { + ftdm_log(FTDM_LOG_INFO, "Received q931 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.suId); + return; + } + + ftdmspan = signal_data->ftdm_span; + switch (status->t.usta.alarm.event) { case LCM_EVENT_UP: case LCM_EVENT_DOWN: { - ftdm_span_t *ftdmspan; - sngisdn_span_data_t *signal_data = g_sngisdn_data.dchans[status->t.usta.suId].spans[1]; - if (!signal_data) { - ftdm_log(FTDM_LOG_INFO, "Received q931 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.suId); - return; - } - ftdmspan = signal_data->ftdm_span; - - if (status->t.usta.alarm.event == LCM_EVENT_UP) { - uint32_t chan_no = status->t.usta.evntParm[2]; - ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q931] s%d: %s: %s(%d): %s(%d)\n", - status->t.usta.suId, - DECODE_LCM_CATEGORY(status->t.usta.alarm.category), - DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event, - DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause); + int i; + sngisdn_nfas_data_t *nfas_data = NULL; + ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q931] s%d: %s: %s(%d): %s(%d)\n", + status->t.usta.suId, + DECODE_LCM_CATEGORY(status->t.usta.alarm.category), + DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event, + DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause); - if (chan_no) { - ftdm_channel_t *ftdmchan = ftdm_span_get_channel(ftdmspan, chan_no); - if (ftdmchan) { - sngisdn_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_UP); - sngisdn_set_chan_avail_rate(ftdmchan, SNGISDN_AVAIL_UP); - } else { - ftdm_log(FTDM_LOG_CRIT, "stack alarm event on invalid channel :%d\n", chan_no); + nfas_data = signal_data->nfas.trunk; + + if (nfas_data && status->t.usta.alarm.event == LCM_EVENT_UP) { + for (i = 0; i < ftdm_array_len(nfas_data->spans); i++) { + if (nfas_data->spans[i] && nfas_data->spans[i]->nfas.sigchan == SNGISDN_NFAS_DCHAN_NONE) { + + sngisdn_set_span_sig_status(nfas_data->spans[i]->ftdm_span, FTDM_SIG_STATE_UP); + sngisdn_set_span_avail_rate(nfas_data->spans[i]->ftdm_span, SNGISDN_AVAIL_UP); + } + } + } + + sngisdn_set_span_sig_status(ftdmspan, (status->t.usta.alarm.event == LCM_EVENT_UP) ? FTDM_SIG_STATE_UP : FTDM_SIG_STATE_DOWN); + sngisdn_set_span_avail_rate(ftdmspan, (status->t.usta.alarm.event == LCM_EVENT_UP) ? SNGISDN_AVAIL_UP: SNGISDN_AVAIL_PWR_SAVING); + + if (nfas_data && status->t.usta.alarm.event == LCM_EVENT_DOWN) { + if (nfas_data->dchan->sigstatus == FTDM_SIG_STATE_DOWN && + (nfas_data->backup && nfas_data->backup->sigstatus == FTDM_SIG_STATE_DOWN)) { + + for (i = 0; i < ftdm_array_len(nfas_data->spans); i++) { + if (nfas_data->spans[i] && nfas_data->spans[i]->nfas.sigchan == SNGISDN_NFAS_DCHAN_NONE) { + + sngisdn_set_span_sig_status(nfas_data->spans[i]->ftdm_span, FTDM_SIG_STATE_DOWN); + sngisdn_set_span_avail_rate(nfas_data->spans[i]->ftdm_span, SNGISDN_AVAIL_PWR_SAVING); + } } - } else { - sngisdn_set_span_sig_status(ftdmspan, FTDM_SIG_STATE_UP); - sngisdn_set_span_avail_rate(ftdmspan, SNGISDN_AVAIL_UP); } - } else { - ftdm_log(FTDM_LOG_WARNING, "[SNGISDN Q931] s%d: %s: %s(%d): %s(%d)\n", - status->t.usta.suId, - DECODE_LCM_CATEGORY(status->t.usta.alarm.category), - DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event, - DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause); - - sngisdn_set_span_sig_status(ftdmspan, FTDM_SIG_STATE_DOWN); - sngisdn_set_span_avail_rate(ftdmspan, SNGISDN_AVAIL_PWR_SAVING); } } break; @@ -805,7 +881,7 @@ void sngisdn_rcv_q931_trace(InMngmt *trc, Buffer *mBuf) ftdm_trace_dir_t dir; uint8_t tdata[1000]; - sngisdn_span_data_t *signal_data = g_sngisdn_data.dchans[trc->t.trc.suId].spans[1]; + sngisdn_span_data_t *signal_data = g_sngisdn_data.spans[trc->t.trc.suId]; ftdm_assert(mBuf != NULLP, "Received a Q931 trace with no buffer"); mlen = ((SsMsgInfo*)(mBuf->b_rptr))->len; @@ -851,7 +927,7 @@ void sngisdn_rcv_q921_trace(BdMngmt *trc, Buffer *mBuf) ftdm_trace_dir_t dir; uint8_t tdata[1000]; - sngisdn_span_data_t *signal_data = g_sngisdn_data.dchans[trc->t.trc.lnkNmb].spans[1]; + sngisdn_span_data_t *signal_data = g_sngisdn_data.spans[trc->t.trc.lnkNmb]; if (trc->t.trc.evnt == TL2TMR) { return; @@ -900,7 +976,7 @@ int16_t sngisdn_rcv_l1_data_req(uint16_t spId, sng_l1_frame_t *l1_frame) { ftdm_status_t status; ftdm_wait_flag_t flags = FTDM_WRITE; - sngisdn_span_data_t *signal_data = g_sngisdn_data.dchans[spId].spans[1]; + sngisdn_span_data_t *signal_data = g_sngisdn_data.spans[spId]; ftdm_size_t length = l1_frame->len; ftdm_assert(signal_data, "Received Data request on unconfigured span\n"); @@ -952,7 +1028,7 @@ int16_t sngisdn_rcv_l1_data_req(uint16_t spId, sng_l1_frame_t *l1_frame) int16_t sngisdn_rcv_l1_cmd_req(uint16_t spId, sng_l1_cmd_t *l1_cmd) { - sngisdn_span_data_t *signal_data = g_sngisdn_data.dchans[spId].spans[1]; + sngisdn_span_data_t *signal_data = g_sngisdn_data.spans[spId]; ftdm_assert(signal_data, "Received Data request on unconfigured span\n"); switch(l1_cmd->type) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c index 254b3abbfb..737805c0cd 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c @@ -1061,11 +1061,12 @@ ftdm_status_t set_cause_ie(ftdm_channel_t *ftdmchan, CauseDgn *causeDgn) ftdm_status_t set_chan_id_ie(ftdm_channel_t *ftdmchan, ChanId *chanId) { + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*)ftdmchan->call_data; if (!ftdmchan) { return FTDM_SUCCESS; } - + ftdm_set_flag(sngisdn_info, FLAG_SENT_CHAN_ID); chanId->eh.pres = PRSNT_NODEF; @@ -1084,6 +1085,12 @@ ftdm_status_t set_chan_id_ie(ftdm_channel_t *ftdmchan, ChanId *chanId) chanId->infoChanSel.pres = PRSNT_NODEF; chanId->infoChanSel.val = ftdmchan->physical_chan_id; } else { + if (signal_data->nfas.trunk) { + chanId->intIdentPres.val = IN_IIP_EXPLICIT; + chanId->intIdent.pres = PRSNT_NODEF; + chanId->intIdent.val = signal_data->nfas.interface_id; + } + chanId->intType.pres = PRSNT_NODEF; chanId->intType.val = IN_IT_OTHER; chanId->infoChanSel.pres = PRSNT_NODEF; @@ -1098,6 +1105,7 @@ ftdm_status_t set_chan_id_ie(ftdm_channel_t *ftdmchan, ChanId *chanId) chanId->chanNmbSlotMap.len = 1; chanId->chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id; } + return FTDM_SUCCESS; } @@ -1217,6 +1225,23 @@ void sngisdn_delayed_setup(void *p_sngisdn_info) return; } +void sngisdn_delayed_release_nfas(void *p_sngisdn_info) +{ + sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*)p_sngisdn_info; + ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; + + ftdm_mutex_lock(ftdmchan->mutex); + + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending delayed RELEASE (suId:%d suInstId:%u spInstId:%u)\n", + signal_data->cc_id, sngisdn_info->spInstId, sngisdn_info->suInstId); + + sngisdn_snd_release(ftdmchan, 0); + + ftdm_mutex_unlock(ftdmchan->mutex); + return; +} + void sngisdn_delayed_release(void *p_sngisdn_info) { sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*)p_sngisdn_info; @@ -1413,7 +1438,7 @@ ftdm_status_t sngisdn_show_l1_stats(ftdm_stream_handle_t *stream, ftdm_span_t *s sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data; memset(&sts, 0, sizeof(sts)); - sng_isdn_phy_stats(signal_data->link_id , &sts); + sng_isdn_phy_stats(sngisdn_dchan(signal_data)->link_id , &sts); stream->write_function(stream, "\n---------------------------------------------------------------------\n"); stream->write_function(stream, " Span:%s", span->name); @@ -1548,6 +1573,14 @@ void sngisdn_send_signal(sngisdn_chan_data_t *sngisdn_info, ftdm_signal_event_t ftdm_span_send_signal(ftdmchan->span, &sigev); } +sngisdn_span_data_t *sngisdn_dchan(sngisdn_span_data_t *signal_data) +{ + if (!signal_data->nfas.trunk) { + return signal_data; + } + return signal_data->nfas.trunk->dchan; +} + /* For Emacs: * Local Variables: From 69bada70259ba3506f1e1565944186875c9eb532 Mon Sep 17 00:00:00 2001 From: kapil Date: Mon, 11 Jun 2012 12:43:08 +0530 Subject: [PATCH 225/822] removign sctp/peer id from config xml block --- .../ftmod_sangoma_ss7_m2ua.c | 61 +++++++++++++------ .../ftmod_sangoma_ss7_m2ua.h | 2 - .../ftmod_sangoma_ss7_m2ua_xml.c | 13 ---- 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c index f0ae00fa5a..57ab67c0ca 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c @@ -51,8 +51,9 @@ static int ftmod_sctp_config(int id); static ftdm_status_t ftmod_sctp_sap_config(int id); static ftdm_status_t ftmod_sctp_tsap_config(int id); static int ftmod_m2ua_gen_config(void); -static int ftmod_m2ua_sctsap_config(int id); +static int ftmod_m2ua_sctsap_config(int m2ua_inf_id, int sctp_id); static int ftmod_m2ua_peer_config(int id); +static int ftmod_m2ua_peer_config1(int m2ua_inf_id, int peer_id); static int ftmod_m2ua_cluster_config(int idx); static int ftmod_m2ua_dlsap_config(int idx); static int ftmod_nif_gen_config(void); @@ -283,13 +284,6 @@ ftdm_status_t sng_m2ua_cfg(void) if((g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].id !=0) && (!(g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].flags & SNGSS7_CONFIGURED))) { - if(ftmod_m2ua_sctsap_config(x)) { - ftdm_log (FTDM_LOG_ERROR ,"M2UA SCTSAP[%d] configuration: NOT OK\n", x); - return FTDM_FAIL; - }else { - ftdm_log (FTDM_LOG_INFO ,"M2UA SCTSAP[%d] configuration: OK\n", x); - } - /****************************************************************************************************/ /* M2UA PEER configurations */ @@ -780,13 +774,44 @@ static int ftmod_m2ua_gen_config(void) } /**********************************************************************************************/ -static int ftmod_m2ua_sctsap_config(int id) +static int ftmod_m2ua_peer_config(int id) +{ + int x = 0; + int peer_id = 0; + sng_m2ua_cfg_t* m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; + sng_m2ua_cluster_cfg_t* clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[m2ua->clusterId]; + sng_m2ua_peer_cfg_t* peer = NULL; + + /* loop through peer list from cluster to configure SCTSAP */ + + for(x = 0; x < clust->numOfPeers;x++){ + peer_id = clust->peerIdLst[x]; + peer = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[peer_id]; + if(ftmod_m2ua_sctsap_config(id, peer->sctpId)){ + ftdm_log (FTDM_LOG_ERROR, " ftmod_m2ua_sctsap_config: M2UA SCTSAP for M2UA Intf Id[%d] config FAILED \n", id); + return 0x01; + }else{ + ftdm_log (FTDM_LOG_ERROR, " ftmod_m2ua_sctsap_config: M2UA SCTSAP for M2UA Intf Id[%d] config SUCCESS \n", id); + } + if(ftmod_m2ua_peer_config1(id, peer_id)){ + ftdm_log (FTDM_LOG_ERROR, " ftmod_m2ua_peer_config1: M2UA Peer configuration for M2UA Intf Id[%d] config FAILED \n", id); + return 0x01; + }else{ + ftdm_log (FTDM_LOG_ERROR, " ftmod_m2ua_peer_config1: M2UA Peer configuration for M2UA Intf Id[%d] config SUCCESS \n", id); + } + + + } + + return 0x0;; +} + +static int ftmod_m2ua_sctsap_config(int m2ua_inf_id, int sctp_id) { int i; Pst pst; MwMgmt cfg; - sng_m2ua_cfg_t* m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; - sng_sctp_link_t *sctp = &g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[m2ua->sctpId]; + sng_sctp_link_t *sctp = &g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[sctp_id]; memset((U8 *)&cfg, 0, sizeof(MwMgmt)); memset((U8 *)&pst, 0, sizeof(Pst)); @@ -802,7 +827,7 @@ static int ftmod_m2ua_sctsap_config(int id) cfg.hdr.elmId.elmnt = STMWSCTSAP; /* SCTSAP */ cfg.hdr.transId = 0; /* transaction identifier */ - cfg.hdr.response.selector = 0; + cfg.hdr.response.selector = 0; cfg.hdr.response.prior = PRIOR0; cfg.hdr.response.route = RTESPEC; cfg.hdr.response.mem.region = S_REG; @@ -811,9 +836,9 @@ static int ftmod_m2ua_sctsap_config(int id) cfg.t.cfg.s.sctSapCfg.reConfig.selector = 0; /* service user SAP ID */ - cfg.t.cfg.s.sctSapCfg.suId = m2ua->id; + cfg.t.cfg.s.sctSapCfg.suId = m2ua_inf_id; /* service provider ID */ - cfg.t.cfg.s.sctSapCfg.spId = m2ua->sctpId; + cfg.t.cfg.s.sctSapCfg.spId = sctp_id; /* source port number */ cfg.t.cfg.s.sctSapCfg.srcPort = 2904; /* interface address */ @@ -858,13 +883,12 @@ static int ftmod_m2ua_sctsap_config(int id) /****************************************************************************************************/ /* M2UA - Peer configuration */ -static int ftmod_m2ua_peer_config(int id) +static int ftmod_m2ua_peer_config1(int m2ua_inf_id, int peer_id) { int i; Pst pst; MwMgmt cfg; - sng_m2ua_cfg_t* m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; - sng_m2ua_peer_cfg_t* peer = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[m2ua->peerId]; + sng_m2ua_peer_cfg_t* peer = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[peer_id]; sng_sctp_link_t *sctp = &g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[peer->sctpId]; memset((U8 *)&cfg, 0, sizeof(MwMgmt)); @@ -1615,9 +1639,10 @@ int ftmod_m2ua_ssta_req(int elemt, int id, MwMgmt* cfm) { MwMgmt ssta; Pst pst; + int peerId = 0x01; sng_m2ua_cfg_t* m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; sng_m2ua_cluster_cfg_t* clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[m2ua->clusterId]; - sng_m2ua_peer_cfg_t* peer = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[m2ua->peerId]; + sng_m2ua_peer_cfg_t* peer = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[peerId]; /*TODO - KAPIL - need to add proper peerId*/ memset((U8 *)&pst, 0, sizeof(Pst)); memset((U8 *)&ssta, 0, sizeof(MwMgmt)); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h index 8f85ac3536..8c2a12e1c8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h @@ -60,8 +60,6 @@ typedef struct sng_m2ua_cfg{ uint32_t flags; uint32_t id; /* ID */ uint8_t nodeType; /*Node Type SG/ASP */ - uint16_t sctpId; /* idx to sctp profile */ - uint16_t peerId; /* idx to m2ua_peer profile */ uint16_t clusterId; /* idx to m2ua_cluster profile */ }sng_m2ua_cfg_t; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c index a3785cc01d..a0ed2b3d7f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c @@ -252,17 +252,6 @@ static int ftmod_ss7_parse_m2ua_interface(ftdm_conf_node_t *m2ua_interface) } SS7_DEBUG("Found an nif node_type = %d\n", sng_m2ua.nodeType); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "sctp_id")) { - /**********************************************************************/ - sng_m2ua.sctpId=atoi(parm->val); - - SS7_DEBUG("Found an m2ua sctp_id = %d\n", sng_m2ua.sctpId); - /**********************************************************************/ - } else if (!strcasecmp(parm->var, "peerd_id")) { - /**********************************************************************/ - sng_m2ua.peerId=atoi(parm->val); - - SS7_DEBUG("Found an m2ua peerd_id = %d\n", sng_m2ua.peerId); /**********************************************************************/ } else if (!strcasecmp(parm->var, "cluster_id")) { /**********************************************************************/ @@ -299,8 +288,6 @@ static int ftmod_ss7_fill_in_m2ua_interface(sng_m2ua_cfg_t *m2ua_iface) g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].id = m2ua_iface->id; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].nodeType = m2ua_iface->nodeType; - g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].sctpId = m2ua_iface->sctpId; - g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].peerId = m2ua_iface->peerId; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].clusterId = m2ua_iface->clusterId; sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_M2UA_PRESENT); From 8102c1603cd6455361d68809b9ee61647d52363b Mon Sep 17 00:00:00 2001 From: kapil Date: Mon, 11 Jun 2012 18:45:56 +0530 Subject: [PATCH 226/822] adding src/peer port into xml config --- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c | 4 ++-- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h | 1 + .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c | 12 +++++++++++- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c index 57ab67c0ca..c1566d7758 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c @@ -840,7 +840,7 @@ static int ftmod_m2ua_sctsap_config(int m2ua_inf_id, int sctp_id) /* service provider ID */ cfg.t.cfg.s.sctSapCfg.spId = sctp_id; /* source port number */ - cfg.t.cfg.s.sctSapCfg.srcPort = 2904; + cfg.t.cfg.s.sctSapCfg.srcPort = sctp->port; /* interface address */ /*For multiple IP address support */ #ifdef SCT_ENDP_MULTI_IPADDR @@ -925,7 +925,7 @@ static int ftmod_m2ua_peer_config1(int m2ua_inf_id, int peer_id) cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[i].u.ipv4NetAddr = peer->destAddrList[i]; } #ifdef MW_CFG_DSTPORT - cfg.t.cfg.s.peerCfg.assocCfg.dstPort = /* TODO */ 2904; /* Port on which M2UA runs */ + cfg.t.cfg.s.peerCfg.assocCfg.dstPort = peer->port; /* Port on which M2UA runs */ #endif cfg.t.cfg.s.peerCfg.assocCfg.srcAddrLst.nmb = sctp->numSrcAddr; /* source address list */ for (i=0; i <= (sctp->numSrcAddr-1); i++) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h index 8c2a12e1c8..d87b9d6c04 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h @@ -71,6 +71,7 @@ typedef struct sng_m2ua_peer_cfg{ uint16_t selfAspId; /* Self ASP ID. ASP identifier for this ASP node if the aspIdFlag is TRUE. */ uint32_t numDestAddr; /* Number of destination address defined */ uint16_t sctpId; /* idx to sctp profile */ + uint16_t port; /* port */ uint32_t destAddrList[SCT_MAX_NET_ADDRS+1]; /* Destination adddress list */ uint16_t locOutStrms; /*Number of outgoing streams supported by this association*/ int init_sctp_assoc; /* flag to tell if we need to initiate SCTP association */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c index a0ed2b3d7f..be8cbe4a85 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c @@ -387,6 +387,12 @@ static int ftmod_ss7_parse_m2ua_peer_interface(ftdm_conf_node_t *m2ua_peer_inter SS7_DEBUG("Found an sng_m2ua_peer sctp_id = %d\n", sng_m2ua_peer.sctpId); /**********************************************************************/ + } else if (!strcasecmp(parm->var, "dest_port")) { + /**********************************************************************/ + sng_m2ua_peer.port = atoi(parm->val); + + SS7_DEBUG("Found an sng_m2ua_peer port = %d\n", sng_m2ua_peer.port); + /**********************************************************************/ } else if (!strcasecmp(parm->var, "dest_addr")) { /**********************************************************************/ if (sng_m2ua_peer.numDestAddr < SCT_MAX_NET_ADDRS) { @@ -450,6 +456,7 @@ static int ftmod_ss7_fill_in_m2ua_peer_interface(sng_m2ua_peer_cfg_t *m2ua_peer_ g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].locOutStrms = m2ua_peer_iface->locOutStrms; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].numDestAddr = m2ua_peer_iface->numDestAddr; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].sctpId = m2ua_peer_iface->sctpId; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].port = m2ua_peer_iface->port; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].init_sctp_assoc = m2ua_peer_iface->init_sctp_assoc; for (k=0; knumDestAddr; k++) { g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].destAddrList[k] = m2ua_peer_iface->destAddrList[k]; @@ -677,6 +684,9 @@ static int ftmod_ss7_parse_sctp_link(ftdm_conf_node_t *node) } else { SS7_ERROR("SCTP - too many source address configured. dropping %s \n", param->val); } + } else if (!strcasecmp(param->var, "src_port")) { + t_link.port = atoi(param->val); + SS7_DEBUG("SCTP - Parsing with port = %s\n", param->val); } else { SS7_ERROR("SCTP - Found an unknown parameter <%s>. Skipping it.\n", param->var); @@ -684,7 +694,7 @@ static int ftmod_ss7_parse_sctp_link(ftdm_conf_node_t *node) } g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].id = t_link.id; - g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].tuclId = t_link.id; + g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].port = t_link.port; strncpy((char*)g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].name, t_link.name, strlen(t_link.name) ); g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].flags = 0; g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].numSrcAddr = t_link.numSrcAddr; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 90fb3e5b7f..63e146c029 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -462,7 +462,7 @@ typedef struct sng_sctp_link { char name[MAX_NAME_LEN]; uint32_t flags; uint32_t id; - uint32_t tuclId; + uint32_t port; uint32_t numSrcAddr; uint32_t srcAddrList[SCT_MAX_NET_ADDRS+1]; } sng_sctp_link_t; From 91f9374a9f7d1b1ae23347b9ef2cd5104c4b49e5 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Mon, 11 Jun 2012 13:23:37 -0400 Subject: [PATCH 227/822] Added code to treat sngss7_config section (same as sng_isup) --- libs/freetdm/mod_freetdm/mod_freetdm.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 2e4f7e1e5f..9896e932aa 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -2894,8 +2894,11 @@ static ftdm_conf_node_t *_get_ss7_config_node(switch_xml_t cfg, const char *conf return NULL; } - /* search the isup config */ - for (isup = switch_xml_child(ss7configs, "sng_isup"); isup; isup = isup->next) { + /* sng_isup and ss7config xml childs are treated the same way. sng_isup was used initially, but does not make sense + * for configurations that do not have an ISUP layer, sng_isup is kept for backward compatibility */ + + /* search the ss7config */ + for (isup = switch_xml_child(ss7configs, "sngss7_config"); isup; isup = isup->next) { char *name = (char *) switch_xml_attr(isup, "name"); if (!name) { continue; @@ -2904,10 +2907,23 @@ static ftdm_conf_node_t *_get_ss7_config_node(switch_xml_t cfg, const char *conf break; } } - + if (!isup) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "not found '%s' sng_isup XML config section\n", confname); - return NULL; + /* search the isup config */ + for (isup = switch_xml_child(ss7configs, "sng_isup"); isup; isup = isup->next) { + char *name = (char *) switch_xml_attr(isup, "name"); + if (!name) { + continue; + } + if (!strcasecmp(name, confname)) { + break; + } + } + + if (!isup) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "not found '%s' ss7config or sng_isup XML config section\n", confname); + return NULL; + } } /* found our XML chunk, create the root node */ From 58dc659fbbaa734b37149840ce3e2f55a8585105 Mon Sep 17 00:00:00 2001 From: kapil Date: Tue, 12 Jun 2012 18:43:01 +0530 Subject: [PATCH 228/822] adding code based on modified xml and cli code changes (rename the m2ua cli command to "xmlshow" and adding cli code to show sctp state also in m2ua peerstatus command) --- libs/freetdm/mod_freetdm/mod_freetdm.c | 102 ++++++-- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 222 ++++++++++++------ .../ftmod_sangoma_ss7_logger.c | 5 + .../ftmod_sangoma_ss7_m2ua.c | 14 +- .../ftmod_sangoma_ss7_m2ua.h | 4 +- .../ftmod_sangoma_ss7_m2ua_xml.c | 62 ++--- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 13 +- 7 files changed, 273 insertions(+), 149 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 9896e932aa..6751175cb5 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -2867,6 +2867,77 @@ static int add_config_list_nodes(switch_xml_t swnode, ftdm_conf_node_t *rootnode return 0; } +/* create ftdm_conf_node_t tree based on a fixed pattern XML configuration list + * last arg is to specify if we have any sublist for e.g. + * + * + * + * + * + * + * + * + * */ +static int add_config_nodes(switch_xml_t swnode, ftdm_conf_node_t *rootnode, + const char *list_name, const char *list_element_name, const char *sub_list_name) +{ + char *var, *val; + switch_xml_t list; + switch_xml_t sub_list; + switch_xml_t element; + switch_xml_t param; + + ftdm_conf_node_t *n_list; + ftdm_conf_node_t *n_element; + + list = switch_xml_child(swnode, list_name); + if (!list) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "no list %s found\n", list_name); + return -1; + } + + if ((FTDM_SUCCESS != ftdm_conf_node_create(list_name, &n_list, rootnode))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to create %s node\n", list_name); + return -1; + } + + for (element = switch_xml_child(list, list_element_name); element; element = element->next) { + char *element_name = (char *) switch_xml_attr(element, "name"); + + if (!element_name) { + continue; + } + + if ((FTDM_SUCCESS != ftdm_conf_node_create(list_element_name, &n_element, n_list))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to create %s node for %s\n", list_element_name, element_name); + return -1; + } + ftdm_conf_node_add_param(n_element, "name", element_name); + + for (param = switch_xml_child(element, "param"); param; param = param->next) { + var = (char *) switch_xml_attr_soft(param, "name"); + val = (char *) switch_xml_attr_soft(param, "value"); + ftdm_conf_node_add_param(n_element, var, val); + } + + /*If we have single node list */ + if (sub_list_name ) { + sub_list = switch_xml_child(element, sub_list_name); + if (!sub_list) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "no sub_list %s found\n", sub_list_name); + return -1; + } + for (param = switch_xml_child(sub_list, "param"); param; param = param->next) { + var = (char *) switch_xml_attr_soft(param, "name"); + val = (char *) switch_xml_attr_soft(param, "value"); + ftdm_conf_node_add_param(n_element, var, val); + } + } + } + + return 0; +} + static ftdm_conf_node_t *_get_ss7_config_node(switch_xml_t cfg, const char *confname, const char *operatingMode) { switch_xml_t signode, ss7configs, isup, gen, param; @@ -2998,23 +3069,21 @@ static ftdm_conf_node_t *_get_ss7_config_node(switch_xml_t cfg, const char *conf ftdm_conf_node_destroy(rootnode); return NULL; } - } - /* add mtp linksets */ - if (add_config_list_nodes(isup, rootnode, "mtp_linksets", "mtp_linkset", NULL, NULL)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process mtp_linksets for sng_isup config %s\n", confname); - ftdm_conf_node_destroy(rootnode); - return NULL; - } + /* add mtp linksets */ + if (add_config_list_nodes(isup, rootnode, "mtp_linksets", "mtp_linkset", NULL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process mtp_linksets for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } - /* add mtp routes */ - if (add_config_list_nodes(isup, rootnode, "mtp_routes", "mtp_route", "linksets", "linkset")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process mtp_routes for sng_isup config %s\n", confname); - ftdm_conf_node_destroy(rootnode); - return NULL; - } + /* add mtp routes */ + if (add_config_list_nodes(isup, rootnode, "mtp_routes", "mtp_route", "linksets", "linkset")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process mtp_routes for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } - if(is_isup) { /* add isup interfaces */ if (add_config_list_nodes(isup, rootnode, "isup_interfaces", "isup_interface", NULL, NULL)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process isup_interfaces for sng_isup config %s\n", confname); @@ -3049,13 +3118,14 @@ static ftdm_conf_node_t *_get_ss7_config_node(switch_xml_t cfg, const char *conf return NULL; } - if (add_config_list_nodes(isup, rootnode, "sng_m2ua_peer_interfaces", "sng_m2ua_peer_interface", NULL, NULL)) { + if (add_config_nodes(isup, rootnode, "sng_m2ua_peer_interfaces", "sng_m2ua_peer_interface", "sng_destination_addresses")) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process sng_m2ua_peer_interfaces for sng_isup config %s\n", confname); ftdm_conf_node_destroy(rootnode); return NULL; } - if (add_config_list_nodes(isup, rootnode, "sng_m2ua_cluster_interfaces", "sng_m2ua_cluster_interface", NULL, NULL)) { + + if (add_config_nodes(isup, rootnode, "sng_m2ua_cluster_interfaces", "sng_m2ua_cluster_interface", "sng_m2ua_peers")) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process sng_m2ua_cluster_interfaces for sng_isup config %s\n", confname); ftdm_conf_node_destroy(rootnode); return NULL; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index bec6e020ac..6fece294cc 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -393,64 +393,78 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha handle_show_procId(stream); /**********************************************************************/ - } else if (!strcasecmp(argv[c], "m2ua")) { - /**********************************************************************/ + } else{ + /**********************************************************************/ + stream->write_function(stream, "Unknown \"show\" command\n"); + goto handle_cli_error; + } + /**************************************************************************/ + } else if (!strcasecmp(argv[c], "xmlshow")) { + /**************************************************************************/ + + if (check_arg_count(argc, 2)) { + cli_ss7_show_general(stream); + return FTDM_SUCCESS; + } + c++; + /**************************************************************************/ + if (!strcasecmp(argv[c], "m2ua")) { + /**************************************************************************/ switch(argc) { case 2: /* show m2ua */ - { - handle_show_m2ua_profiles(stream); - break; - } + { + handle_show_m2ua_profiles(stream); + break; + } case 3: /* show m2ua */ - { - c++; - handle_show_m2ua_profile(stream, argv[c]); - break; - } + { + c++; + handle_show_m2ua_profile(stream, argv[c]); + break; + } case 4: - { - char* profile_name = argv[++c]; - c++; - if(!strcasecmp(argv[c],"peerstatus")){ - handle_show_m2ua_peer_status(stream, profile_name); + { + char* profile_name = argv[++c]; + c++; + if(!strcasecmp(argv[c],"peerstatus")){ + handle_show_m2ua_peer_status(stream, profile_name); + } + else{ + stream->write_function(stream, "Unknown \"show m2ua \" command..\n"); + goto handle_cli_error_argc; + } + break; } - else{ - stream->write_function(stream, "Unknown \"show m2ua \" command..\n"); - goto handle_cli_error_argc; - } - break; - } default: - goto handle_cli_error_argc; + goto handle_cli_error_argc; } - /**********************************************************************/ + /**********************************************************************/ } else if (!strcasecmp(argv[c], "nif")) { - /**********************************************************************/ + /**********************************************************************/ if (check_arg_count(argc, 3)){ handle_show_nif_profiles(stream); }else{ c++; handle_show_nif_profile(stream, argv[c]); } - /**********************************************************************/ + /**********************************************************************/ } else if (!strcasecmp(argv[c], "sctp")) { - /**********************************************************************/ + /**********************************************************************/ if (check_arg_count(argc, 3)){ handle_show_sctp_profiles(stream); }else{ c++; handle_show_sctp_profile(stream, argv[c]); } - /**********************************************************************/ + /**********************************************************************/ } else { - /**********************************************************************/ - stream->write_function(stream, "Unknown \"show\" command\n"); + /**********************************************************************/ + stream->write_function(stream, "Unknown \"xmlshow\" command\n"); goto handle_cli_error; - /**********************************************************************/ } - /**************************************************************************/ + /**********************************************************************/ } else if (!strcasecmp(argv[c], "set")) { /**************************************************************************/ if (check_arg_count(argc, 4)) goto handle_cli_error_argc; @@ -914,13 +928,13 @@ static ftdm_status_t handle_print_usage(ftdm_stream_handle_t *stream) stream->write_function(stream, "\n"); stream->write_function(stream, "ftmod_sangoma_ss7 M2UA :\n"); - stream->write_function(stream, "ftdm ss7 show sctp \n"); - stream->write_function(stream, "ftdm ss7 show sctp \n"); - stream->write_function(stream, "ftdm ss7 show m2ua \n"); - stream->write_function(stream, "ftdm ss7 show m2ua \n"); - stream->write_function(stream, "ftdm ss7 show m2ua peerstatus\n"); - stream->write_function(stream, "ftdm ss7 show nif \n"); - stream->write_function(stream, "ftdm ss7 show nif \n"); + stream->write_function(stream, "ftdm ss7 xmlshow sctp \n"); + stream->write_function(stream, "ftdm ss7 xmlshow sctp \n"); + stream->write_function(stream, "ftdm ss7 xmlshow m2ua \n"); + stream->write_function(stream, "ftdm ss7 xmlshow m2ua \n"); + stream->write_function(stream, "ftdm ss7 xmlshow m2ua peerstatus\n"); + stream->write_function(stream, "ftdm ss7 xmlshow nif \n"); + stream->write_function(stream, "ftdm ss7 xmlshow nif \n"); stream->write_function(stream, "\n"); @@ -3062,8 +3076,10 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) int idx = 0x00; int len = 0x00; MwMgmt cfm; + MwMgmt rsp; memset((U8 *)&cfm, 0, sizeof(MwMgmt)); + memset((U8 *)&rsp, 0, sizeof(MwMgmt)); memset(&buf[0], 0, sizeof(buf)); len = len + sprintf(buf + len, "%s\n", xmlhdr); @@ -3103,7 +3119,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); } - if(ftmod_m2ua_ssta_req(STMWCLUSTER,x,&cfm)) { + if(ftmod_m2ua_ssta_req(STMWCLUSTER,g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].clusterId,&cfm)) { stream->write_function(stream," Request to Trillium SCTP layer failed \n"); return FTDM_FAIL; } else { @@ -3122,21 +3138,30 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); } - if(ftmod_m2ua_ssta_req(STMWPEER,x,&cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); - return FTDM_FAIL; - } else { - len = len + sprintf(buf + len, "\n"); - len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.retryCount); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.spAssocId); - len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcInProg); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcLevel); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.sctpHBeatEnb); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.locOutStrms); + memcpy((U8 *)&rsp, &cfm, sizeof(MwMgmt)); - len = len + sprintf(buf + len, "\n"); + /* loop through configured peers */ + for(idx = 0; idx < rsp.t.ssta.s.clusterSta.nmbPeer; idx++) + { + memset((U8 *)&cfm, 0, sizeof(MwMgmt)); + + if(ftmod_m2ua_ssta_req(STMWPEER, rsp.t.ssta.s.clusterSta.peerSt[idx].peerId, &cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %s \n",g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[rsp.t.ssta.s.clusterSta.peerSt[idx].peerId].name); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.retryCount); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.spAssocId); + len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcInProg); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcLevel); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.sctpHBeatEnb); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.locOutStrms); + + len = len + sprintf(buf + len, "\n"); + } } if(ftmod_m2ua_ssta_req(STMWSCTSAP,x,&cfm)) { @@ -3180,8 +3205,10 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char int found = 0x00; int len = 0x00; MwMgmt cfm; + MwMgmt rsp; memset((U8 *)&cfm, 0, sizeof(MwMgmt)); + memset((U8 *)&rsp, 0, sizeof(MwMgmt)); memset(&buf[0], 0, sizeof(buf)); len = len + sprintf(buf + len, "%s\n", xmlhdr); @@ -3240,21 +3267,30 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char len = len + sprintf(buf + len, "\n"); } - if(ftmod_m2ua_ssta_req(STMWPEER,x,&cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); - return FTDM_FAIL; - } else { - len = len + sprintf(buf + len, "\n"); - len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.retryCount); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.spAssocId); - len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcInProg); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcLevel); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.sctpHBeatEnb); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.locOutStrms); + memcpy((U8 *)&rsp, &cfm, sizeof(MwMgmt)); - len = len + sprintf(buf + len, "\n"); + /* loop through configured peers */ + for(idx = 0; idx < rsp.t.ssta.s.clusterSta.nmbPeer; idx++) + { + memset((U8 *)&cfm, 0, sizeof(MwMgmt)); + + if(ftmod_m2ua_ssta_req(STMWPEER, rsp.t.ssta.s.clusterSta.peerSt[idx].peerId, &cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %s \n",g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[rsp.t.ssta.s.clusterSta.peerSt[idx].peerId].name); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.retryCount); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.spAssocId); + len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcInProg); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcLevel); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.sctpHBeatEnb); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.locOutStrms); + + len = len + sprintf(buf + len, "\n"); + } } if(ftmod_m2ua_ssta_req(STMWSCTSAP,x,&cfm)) { @@ -3706,8 +3742,15 @@ static ftdm_status_t handle_show_m2ua_peer_status(ftdm_stream_handle_t *stream, int found = 0x00; int len = 0x00; MwMgmt cfm; + SbMgmt sctp_cfm; + sng_m2ua_cluster_cfg_t* clust = NULL; + sng_m2ua_cfg_t* m2ua = NULL; + sng_m2ua_peer_cfg_t* peer = NULL; + int peer_id = 0; + int sctp_id = 0; memset((U8 *)&cfm, 0, sizeof(MwMgmt)); + memset((U8 *)&sctp_cfm, 0, sizeof(SbMgmt)); memset(&buf[0], 0, sizeof(buf)); len = len + sprintf(buf + len, "%s\n", xmlhdr); @@ -3731,14 +3774,41 @@ static ftdm_status_t handle_show_m2ua_peer_status(ftdm_stream_handle_t *stream, return FTDM_FAIL; } - if(ftmod_m2ua_ssta_req(STMWPEER,x,&cfm)) { - stream->write_function(stream," Request to Trillium M2UA layer failed \n"); - return FTDM_FAIL; - } else { - len = len + sprintf(buf + len, "\n"); - len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); - len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); - len = len + sprintf(buf + len, "\n"); + m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x]; + clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[m2ua->clusterId]; + + for(x = 0; x < clust->numOfPeers;x++){ + peer_id = clust->peerIdLst[x]; + peer = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[peer_id]; + + if(ftmod_m2ua_ssta_req(STMWPEER, peer_id, &cfm)) { + stream->write_function(stream," Request to Trillium M2UA layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %s \n",peer->name); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); + /*len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED");*/ + len = len + sprintf(buf + len, "\n"); + } + + sctp_id = peer->sctpId; + + if(ftmod_sctp_ssta_req(STSBASSOC, sctp_id, &sctp_cfm)) { + if(LMW_PEER_DOWN == cfm.t.ssta.s.peerSta.state){ + /* If there is no association established so far, it will return fail..*/ + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " SCT_ASSOC_STATE_CLOSED \n"); + len = len + sprintf(buf + len, "\n"); + }else{ + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %s \n", PRNT_SCTP_ASSOC_STATE(sctp_cfm.t.ssta.s.assocSta.assocState)); + len = len + sprintf(buf + len, "\n"); + } } stream->write_function(stream,"\n%s\n",buf); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c index 922200629f..e9b370a151 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c @@ -870,6 +870,11 @@ void handle_sng_m2ua_alarm(Pst *pst, MwMgmt *sta) /* To print the event specific information */ switch(sta->t.usta.alarm.event) { + case LMW_EVENT_TERM_OK: + { + ftdm_log(FTDM_LOG_INFO," M2UA : LMW_EVENT_TERM_OK: Association Terminated with PeerId[%d] \n",sta->t.usta.s.peerId); + break; + } case LMW_EVENT_ENDPOPEN_OK: { ftdm_log(FTDM_LOG_INFO," M2UA : LMW_EVENT_ENDPOPEN_OK: \n"); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c index c1566d7758..0639165e97 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c @@ -791,13 +791,13 @@ static int ftmod_m2ua_peer_config(int id) ftdm_log (FTDM_LOG_ERROR, " ftmod_m2ua_sctsap_config: M2UA SCTSAP for M2UA Intf Id[%d] config FAILED \n", id); return 0x01; }else{ - ftdm_log (FTDM_LOG_ERROR, " ftmod_m2ua_sctsap_config: M2UA SCTSAP for M2UA Intf Id[%d] config SUCCESS \n", id); + ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_sctsap_config: M2UA SCTSAP for M2UA Intf Id[%d] config SUCCESS \n", id); } if(ftmod_m2ua_peer_config1(id, peer_id)){ ftdm_log (FTDM_LOG_ERROR, " ftmod_m2ua_peer_config1: M2UA Peer configuration for M2UA Intf Id[%d] config FAILED \n", id); return 0x01; }else{ - ftdm_log (FTDM_LOG_ERROR, " ftmod_m2ua_peer_config1: M2UA Peer configuration for M2UA Intf Id[%d] config SUCCESS \n", id); + ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_peer_config1: M2UA Peer configuration for M2UA Intf Id[%d] config SUCCESS \n", id); } @@ -1639,10 +1639,9 @@ int ftmod_m2ua_ssta_req(int elemt, int id, MwMgmt* cfm) { MwMgmt ssta; Pst pst; - int peerId = 0x01; - sng_m2ua_cfg_t* m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; - sng_m2ua_cluster_cfg_t* clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[m2ua->clusterId]; - sng_m2ua_peer_cfg_t* peer = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[peerId]; /*TODO - KAPIL - need to add proper peerId*/ + sng_m2ua_cfg_t* m2ua = NULL; + sng_m2ua_cluster_cfg_t* clust = NULL; + sng_m2ua_peer_cfg_t* peer = NULL; memset((U8 *)&pst, 0, sizeof(Pst)); memset((U8 *)&ssta, 0, sizeof(MwMgmt)); @@ -1668,6 +1667,7 @@ int ftmod_m2ua_ssta_req(int elemt, int id, MwMgmt* cfm) { case STMWSCTSAP: { + m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; ssta.t.ssta.id.suId = m2ua->id ; /* lower sap Id */ break; } @@ -1678,11 +1678,13 @@ int ftmod_m2ua_ssta_req(int elemt, int id, MwMgmt* cfm) } case STMWPEER: { + peer = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[id]; ssta.t.ssta.id.peerId = peer->id ; /* peer Id */ break; } case STMWCLUSTER: { + clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[id]; ssta.t.ssta.id.clusterId = clust->id ; /* cluster Id */ break; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h index d87b9d6c04..2b44426102 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h @@ -71,8 +71,8 @@ typedef struct sng_m2ua_peer_cfg{ uint16_t selfAspId; /* Self ASP ID. ASP identifier for this ASP node if the aspIdFlag is TRUE. */ uint32_t numDestAddr; /* Number of destination address defined */ uint16_t sctpId; /* idx to sctp profile */ - uint16_t port; /* port */ - uint32_t destAddrList[SCT_MAX_NET_ADDRS+1]; /* Destination adddress list */ + uint16_t port; + uint32_t destAddrList[SCT_MAX_NET_ADDRS+1]; /* Destination adddress list */ uint16_t locOutStrms; /*Number of outgoing streams supported by this association*/ int init_sctp_assoc; /* flag to tell if we need to initiate SCTP association */ }sng_m2ua_peer_cfg_t; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c index be8cbe4a85..46f7fd7d19 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c @@ -38,6 +38,7 @@ /* INCLUDE ********************************************************************/ #include "ftmod_sangoma_ss7_main.h" +#include "switch_utils.h" /******************************************************************************/ /* DEFINES ********************************************************************/ @@ -123,16 +124,16 @@ static int ftmod_ss7_parse_nif_interface(ftdm_conf_node_t *nif_interface) sng_nif.id = atoi(parm->val); SS7_DEBUG("Found an nif id = %d\n", sng_nif.id); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "m2ua_link_nmb")) { + } else if (!strcasecmp(parm->var, "m2ua-interface-id")) { /**********************************************************************/ sng_nif.m2uaLnkNmb = atoi(parm->val); - SS7_DEBUG("Found an nif m2ua_link_nmb = %d\n", sng_nif.m2uaLnkNmb); + SS7_DEBUG("Found an nif m2ua-interface-id = %d\n", sng_nif.m2uaLnkNmb); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "mtp2_link_nmb")) { + } else if (!strcasecmp(parm->var, "mtp2-interface-id")) { /**********************************************************************/ sng_nif.mtp2LnkNmb=atoi(parm->val); - SS7_DEBUG("Found an nif mtp2_link_nmb = %d\n", sng_nif.mtp2LnkNmb); + SS7_DEBUG("Found an nif mtp2-interface-id = %d\n", sng_nif.mtp2LnkNmb); /**********************************************************************/ } else { /**********************************************************************/ @@ -239,21 +240,7 @@ static int ftmod_ss7_parse_m2ua_interface(ftdm_conf_node_t *m2ua_interface) sng_m2ua.id = atoi(parm->val); SS7_DEBUG("Found an m2ua id = %d\n", sng_m2ua.id); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "node_type")) { - /**********************************************************************/ - if(!strcasecmp(parm->val, "SGP")){ - sng_m2ua.nodeType = SNG_M2UA_NODE_TYPE_SGP; - } else if(!strcasecmp(parm->val, "ASP")){ - SS7_ERROR(" NodeType = ASP Not Supported Yet \n"); - return FTDM_FAIL; - } else { - SS7_ERROR("Found an invalid NodeType Parameter Value[%s]\n", parm->val); - return FTDM_FAIL; - } - SS7_DEBUG("Found an nif node_type = %d\n", sng_m2ua.nodeType); - /**********************************************************************/ - /**********************************************************************/ - } else if (!strcasecmp(parm->var, "cluster_id")) { + } else if (!strcasecmp(parm->var, "m2ua-cluster-interface-id")) { /**********************************************************************/ sng_m2ua.clusterId=atoi(parm->val); @@ -271,6 +258,8 @@ static int ftmod_ss7_parse_m2ua_interface(ftdm_conf_node_t *m2ua_interface) /**************************************************************************/ } /* for (i = 0; i < num_parms; i++) */ + sng_m2ua.nodeType = SNG_M2UA_NODE_TYPE_SGP; + /* default the interface to paused state */ sngss7_set_flag(&sng_m2ua, SNGSS7_PAUSED); @@ -348,7 +337,6 @@ static int ftmod_ss7_parse_m2ua_peer_interface(ftdm_conf_node_t *m2ua_peer_inter SS7_DEBUG("Parsing \"m2ua_peer_interface\"...\n"); } - for (i = 0; i < num_parms; i++) { /**************************************************************************/ @@ -363,7 +351,7 @@ static int ftmod_ss7_parse_m2ua_peer_interface(ftdm_conf_node_t *m2ua_peer_inter sng_m2ua_peer.id = atoi(parm->val); SS7_DEBUG("Found an sng_m2ua_peer id = %d\n", sng_m2ua_peer.id); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "asp_id_flag")) { + } else if (!strcasecmp(parm->var, "include-asp-identifier")) { /**********************************************************************/ if(!strcasecmp(parm->val, "TRUE")){ sng_m2ua_peer.aspIdFlag = 0x01; @@ -375,41 +363,41 @@ static int ftmod_ss7_parse_m2ua_peer_interface(ftdm_conf_node_t *m2ua_peer_inter } SS7_DEBUG("Found an sng_m2ua_peer aspIdFlag = %d\n", sng_m2ua_peer.aspIdFlag); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "self_asp_id")) { + } else if (!strcasecmp(parm->var, "asp-identifier")) { /**********************************************************************/ sng_m2ua_peer.selfAspId=atoi(parm->val); SS7_DEBUG("Found an sng_m2ua_peer self_asp_id = %d\n", sng_m2ua_peer.selfAspId); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "sctp_id")) { + } else if (!strcasecmp(parm->var, "sctp-interface-id")) { /**********************************************************************/ sng_m2ua_peer.sctpId = atoi(parm->val); SS7_DEBUG("Found an sng_m2ua_peer sctp_id = %d\n", sng_m2ua_peer.sctpId); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "dest_port")) { + } else if (!strcasecmp(parm->var, "destination-port")) { /**********************************************************************/ sng_m2ua_peer.port = atoi(parm->val); SS7_DEBUG("Found an sng_m2ua_peer port = %d\n", sng_m2ua_peer.port); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "dest_addr")) { + } else if (!strcasecmp(parm->var, "address")) { /**********************************************************************/ if (sng_m2ua_peer.numDestAddr < SCT_MAX_NET_ADDRS) { sng_m2ua_peer.destAddrList[sng_m2ua_peer.numDestAddr] = iptoul (parm->val); sng_m2ua_peer.numDestAddr++; - SS7_DEBUG("sng_m2ua_peer - Parsing with dest IP Address = %s\n", parm->val); + SS7_DEBUG("sng_m2ua_peer - Parsing with dest IP Address = %s \n", parm->val); } else { SS7_ERROR("sng_m2ua_peer - too many dest address configured. dropping %s \n", parm->val); } /**********************************************************************/ - } else if (!strcasecmp(parm->var, "loc_out_strms")) { + } else if (!strcasecmp(parm->var, "number-of-outgoing-streams")) { /**********************************************************************/ sng_m2ua_peer.locOutStrms=atoi(parm->val); - SS7_DEBUG("Found an sng_m2ua_peer loc_out_strms = %d\n", sng_m2ua_peer.locOutStrms); + SS7_DEBUG("Found an sng_m2ua_peer number-of-outgoing-streams = %d\n", sng_m2ua_peer.locOutStrms); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "init_sctp_assoc")) { + } else if (!strcasecmp(parm->var, "init-sctp-association")) { /**********************************************************************/ if(!strcasecmp(parm->val, "TRUE")){ sng_m2ua_peer.init_sctp_assoc = 0x01; @@ -535,7 +523,7 @@ static int ftmod_ss7_parse_m2ua_clust_interface(ftdm_conf_node_t *m2ua_cluster_i sng_m2ua_cluster.id = atoi(parm->val); SS7_DEBUG("Found an sng_m2ua_cluster id = %d\n", sng_m2ua_cluster.id); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "trf_mode")) { + } else if (!strcasecmp(parm->var, "traffic-mode")) { /**********************************************************************/ if(!strcasecmp(parm->val, "loadshare")){ sng_m2ua_cluster.trfMode = SNG_M2UA_TRF_MODE_LOADSHARE; @@ -549,7 +537,7 @@ static int ftmod_ss7_parse_m2ua_clust_interface(ftdm_conf_node_t *m2ua_cluster_i } SS7_DEBUG("Found an sng_m2ua_cluster.trfMode = %d\n", sng_m2ua_cluster.trfMode); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "load_share_algo")) { + } else if (!strcasecmp(parm->var, "load-share-algorithm")) { /**********************************************************************/ if(!strcasecmp(parm->val, "roundrobin")){ sng_m2ua_cluster.loadShareAlgo = SNG_M2UA_LOAD_SHARE_ALGO_RR; @@ -564,14 +552,14 @@ static int ftmod_ss7_parse_m2ua_clust_interface(ftdm_conf_node_t *m2ua_cluster_i SS7_DEBUG("Found an sng_m2ua_cluster.loadShareAlgo = %d\n", sng_m2ua_cluster.loadShareAlgo); /**********************************************************************/ - } else if (!strcasecmp(parm->var, "peer_id")) { + } else if (!strcasecmp(parm->var, "m2ua-peer-interface-id")) { /**********************************************************************/ if(sng_m2ua_cluster.numOfPeers < MW_MAX_NUM_OF_PEER) { sng_m2ua_cluster.peerIdLst[sng_m2ua_cluster.numOfPeers] = atoi(parm->val); - sng_m2ua_cluster.numOfPeers++; SS7_DEBUG("Found an sng_m2ua_cluster peerId[%d], Total numOfPeers[%d] \n", sng_m2ua_cluster.peerIdLst[sng_m2ua_cluster.numOfPeers], - sng_m2ua_cluster.numOfPeers); + sng_m2ua_cluster.numOfPeers+1); + sng_m2ua_cluster.numOfPeers++; }else{ SS7_ERROR("Peer List excedding max[%d] limit \n", MW_MAX_NUM_OF_PEER); return FTDM_FAIL; @@ -603,7 +591,7 @@ static int ftmod_ss7_fill_in_m2ua_clust_interface(sng_m2ua_cluster_cfg_t *m2ua_c int k = 0x00; int i = m2ua_cluster_iface->id; - strncpy((char *)g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].name, (char *)m2ua_cluster_iface->name, MAX_NAME_LEN-1); + strncpy((char *)g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[i].name, (char *)m2ua_cluster_iface->name, MAX_NAME_LEN-1); g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[i].id = m2ua_cluster_iface->id; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[i].trfMode = m2ua_cluster_iface->trfMode; @@ -676,7 +664,7 @@ static int ftmod_ss7_parse_sctp_link(ftdm_conf_node_t *node) t_link.id = atoi(param->val); SS7_DEBUG("SCTP - Parsing with id = %s\n", param->val); } - else if (!strcasecmp(param->var, "src_addr")) { + else if (!strcasecmp(param->var, "src-addr")) { if (t_link.numSrcAddr < SCT_MAX_NET_ADDRS) { t_link.srcAddrList[t_link.numSrcAddr+1] = iptoul (param->val); t_link.numSrcAddr++; @@ -684,7 +672,7 @@ static int ftmod_ss7_parse_sctp_link(ftdm_conf_node_t *node) } else { SS7_ERROR("SCTP - too many source address configured. dropping %s \n", param->val); } - } else if (!strcasecmp(param->var, "src_port")) { + } else if (!strcasecmp(param->var, "src-port")) { t_link.port = atoi(param->val); SS7_DEBUG("SCTP - Parsing with port = %s\n", param->val); } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 4b51bfc0e7..4136423257 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -223,7 +223,6 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa var = ftdm_parameters[i].var; val = ftdm_parameters[i].val; - printf("var[%s], val[%s]\n",var,val); /* confirm that the first parameter is the "operatingMode" */ if(!strcasecmp(var, "operatingMode")){ /**********************************************************************/ @@ -275,7 +274,7 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa /**********************************************************************/ /* don't care for now */ /**********************************************************************/ - } else if (!strcasecmp(var, "ccSpanId")) { + } else if (!strcasecmp(var, "span-id")) { /**********************************************************************/ sngSpan.ccSpanId = atoi(val); SS7_DEBUG("Found an ccSpanId = %d\n",sngSpan.ccSpanId); @@ -543,16 +542,6 @@ static int ftmod_ss7_parse_sng_isup(ftdm_conf_node_t *sng_isup) } case SNG_SS7_OPR_MODE_M2UA_SG: { - if (ftmod_ss7_parse_mtp_linksets(mtp_linksets)) { - SS7_ERROR("Failed to parse \"mtp_linksets\"!\n"); - return FTDM_FAIL; - } - - if (ftmod_ss7_parse_mtp_routes(mtp_routes)) { - SS7_ERROR("Failed to parse \"mtp_routes\"!\n"); - return FTDM_FAIL; - } - if (ftmod_ss7_parse_sctp_links(sctp_ifaces) != FTDM_SUCCESS) { SS7_ERROR("Failed to parse !\n"); return FTDM_FAIL; From b22a4b566a329f522613f1b9c69329f828ffe3ab Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 12 Jun 2012 18:07:42 -0400 Subject: [PATCH 229/822] Fix for some compile warnings --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 6fece294cc..246aeb232b 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -3070,13 +3070,13 @@ static ftdm_status_t cli_ss7_show_all_spans_general(ftdm_stream_handle_t *stream static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) { - char* xmlhdr = (char*)""; + MwMgmt cfm; + MwMgmt rsp; char buf[2048]; + char* xmlhdr = (char*)""; int x = 0x00; int idx = 0x00; int len = 0x00; - MwMgmt cfm; - MwMgmt rsp; memset((U8 *)&cfm, 0, sizeof(MwMgmt)); memset((U8 *)&rsp, 0, sizeof(MwMgmt)); From bdaead271d78879b73cc16db56904da5659b5959 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 12 Jun 2012 18:18:14 -0400 Subject: [PATCH 230/822] Fix for compile warnings --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 246aeb232b..f1403c5c84 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -3090,11 +3090,11 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memSize); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memAlloc); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbClusters); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbPeers); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbIntf); + len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.memSize); + len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.memAlloc); + len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.nmbClusters); + len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.nmbPeers); + len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.nmbIntf); len = len + sprintf(buf + len, "\n"); } @@ -3153,7 +3153,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, " %s \n",g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[rsp.t.ssta.s.clusterSta.peerSt[idx].peerId].name); len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.retryCount); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.spAssocId); + len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.peerSta.assocSta.spAssocId); len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcInProg); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcLevel); @@ -3282,7 +3282,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char len = len + sprintf(buf + len, " %s \n",g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[rsp.t.ssta.s.clusterSta.peerSt[idx].peerId].name); len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.retryCount); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.spAssocId); + len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.peerSta.assocSta.spAssocId); len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcInProg); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcLevel); @@ -3300,7 +3300,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char len = len + sprintf(buf + len, "\n"); len = len + sprintf(buf + len," %s \n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.sctSapSta.state)); len = len + sprintf(buf + len," %s \n", (cfm.t.ssta.s.sctSapSta.endpOpen)?"END_POINT_OPENED_SUCCESSFULLY":"END_POINT_NOT_OPEN"); - len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.spEndpId); + len = len + sprintf(buf + len," %ld \n", cfm.t.ssta.s.sctSapSta.spEndpId); len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.nmbPrimRetry); len = len + sprintf(buf + len, "\n"); } @@ -3630,7 +3630,7 @@ static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream) } else { len = len + sprintf(buf + len, "\n"); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memSize); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memAlloc); + len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.genSta.memAlloc); len = len + sprintf(buf + len, "\n"); } @@ -3649,7 +3649,7 @@ static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.m2uaState)); len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.mtp2State)); - len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.nmbRetry); + len = len + sprintf(buf + len," %ld \n", cfm.t.ssta.s.dlSapSta.nmbRetry); len = len + sprintf(buf + len, "\n"); } @@ -3714,7 +3714,7 @@ static ftdm_status_t handle_show_nif_profile(ftdm_stream_handle_t *stream, char* len = len + sprintf(buf + len, "\n"); len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.m2uaState)); len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.mtp2State)); - len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.nmbRetry); + len = len + sprintf(buf + len," %ld \n", cfm.t.ssta.s.dlSapSta.nmbRetry); len = len + sprintf(buf + len, "\n"); } From ba17ae3f1071823f87a459fed7e874f4c2b005e6 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 12 Jun 2012 18:32:58 -0400 Subject: [PATCH 231/822] Fix for compile warnings --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index f1403c5c84..6496da388b 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -3092,9 +3092,9 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.memSize); len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.memAlloc); - len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.nmbClusters); - len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.nmbPeers); - len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.nmbIntf); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.nmbClusters); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.nmbPeers); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.nmbIntf); len = len + sprintf(buf + len, "\n"); } @@ -3171,7 +3171,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); len = len + sprintf(buf + len," %s \n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.sctSapSta.state)); len = len + sprintf(buf + len," %s \n", (cfm.t.ssta.s.sctSapSta.endpOpen)?"END_POINT_OPENED_SUCCESSFULLY":"END_POINT_NOT_OPEN"); - len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.spEndpId); + len = len + sprintf(buf + len," %ld \n", cfm.t.ssta.s.sctSapSta.spEndpId); len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.nmbPrimRetry); len = len + sprintf(buf + len, "\n"); } @@ -3339,8 +3339,8 @@ static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream) return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memSize); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memAlloc); + len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.genSta.memSize); + len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.genSta.memAlloc); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbAssoc); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbEndp); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbLocalAddr); @@ -3430,7 +3430,7 @@ int get_assoc_resp_buf(char* buf,SbMgmt* cfm) char *asciiAddr; CmInetIpAddr ip; - len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.assocId); + len = len + sprintf(buf + len, " %ld \n", cfm->t.ssta.s.assocSta.assocId); len = len + sprintf(buf + len, " %s \n", PRNT_SCTP_ASSOC_STATE(cfm->t.ssta.s.assocSta.assocState)); len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.dstPort); len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.srcPort); @@ -3629,7 +3629,7 @@ static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream) return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memSize); + len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.genSta.memSize); len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.genSta.memAlloc); len = len + sprintf(buf + len, "\n"); } From 88807931745c406f280d0fed578c1066f55f4611 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 12 Jun 2012 18:47:53 -0400 Subject: [PATCH 232/822] Removed include for switch_utils.h --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c index 46f7fd7d19..57bca70e61 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c @@ -38,7 +38,6 @@ /* INCLUDE ********************************************************************/ #include "ftmod_sangoma_ss7_main.h" -#include "switch_utils.h" /******************************************************************************/ /* DEFINES ********************************************************************/ From 055dc8bc4beea90ed88d0604823d6e7d54827863 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 12 Jun 2012 19:15:14 -0400 Subject: [PATCH 233/822] re-adjusted parameter names --- libs/freetdm/mod_freetdm/mod_freetdm.c | 22 +++++++++---------- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 11 +++++----- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 6751175cb5..35690b1e24 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -2938,7 +2938,7 @@ static int add_config_nodes(switch_xml_t swnode, ftdm_conf_node_t *rootnode, return 0; } -static ftdm_conf_node_t *_get_ss7_config_node(switch_xml_t cfg, const char *confname, const char *operatingMode) +static ftdm_conf_node_t *_get_ss7_config_node(switch_xml_t cfg, const char *confname, const char *operating_mode) { switch_xml_t signode, ss7configs, isup, gen, param; ftdm_conf_node_t *rootnode, *list; @@ -3004,19 +3004,19 @@ static ftdm_conf_node_t *_get_ss7_config_node(switch_xml_t cfg, const char *conf } /* operating mode , M2UA or ISUP */ - if(operatingMode && ('\0' != operatingMode[0])) { - if(!strcasecmp(operatingMode, "ISUP")) { + if(operating_mode && ('\0' != operating_mode[0])) { + if(!strcasecmp(operating_mode, "ISUP")) { is_isup = 0x01; } - else if(!strcasecmp(operatingMode, "M2UA_SG")) { + else if(!strcasecmp(operating_mode, "M2UA_SG")) { is_isup = 0x00; } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid operating Mode[%s] \n", operatingMode); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid operating Mode[%s] \n", operating_mode); ftdm_conf_node_destroy(rootnode); return NULL; } } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Operating mode not specified, default to ISUP \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Operating mode not specified, default to ISUP \n"); is_isup = 0x01; } @@ -3367,7 +3367,7 @@ static switch_status_t load_config(void) char *id = (char *) switch_xml_attr(myspan, "id"); char *name = (char *) switch_xml_attr(myspan, "name"); char *configname = (char *) switch_xml_attr(myspan, "cfgprofile"); - char *operatingMode = (char *) switch_xml_attr(myspan, "operating_mode"); + char *operating_mode = (char *) switch_xml_attr(myspan, "operating_mode"); ftdm_span_t *span = NULL; uint32_t span_id = 0; unsigned paramindex = 0; @@ -3401,7 +3401,7 @@ static switch_status_t load_config(void) span_id = ftdm_span_get_id(span); } - ss7confnode = _get_ss7_config_node(cfg, configname, operatingMode); + ss7confnode = _get_ss7_config_node(cfg, configname, operating_mode); if (!ss7confnode) { CONFIG_ERROR("Error finding ss7config '%s' for FreeTDM span id: %s\n", configname, switch_str_nil(id)); continue; @@ -3409,9 +3409,9 @@ static switch_status_t load_config(void) memset(spanparameters, 0, sizeof(spanparameters)); paramindex = 0; - if(operatingMode){ - spanparameters[paramindex].var = "operatingMode"; - spanparameters[paramindex].val = operatingMode; + if(operating_mode){ + spanparameters[paramindex].var = "operating-mode"; + spanparameters[paramindex].val = operating_mode; paramindex++; } spanparameters[paramindex].var = "confnode"; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 4136423257..ebbdc69cae 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -206,13 +206,12 @@ static void ftmod_ss7_set_glare_resolution (const char *method); int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *span) { + sng_route_t self_route; + sng_span_t sngSpan; int i = 0; const char *var = NULL; const char *val = NULL; ftdm_conf_node_t *ptr = NULL; - sng_route_t self_route; - sng_span_t sngSpan; - /* clean out the isup ckt */ memset(&sngSpan, 0x0, sizeof(sngSpan)); @@ -223,8 +222,8 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa var = ftdm_parameters[i].var; val = ftdm_parameters[i].val; - /* confirm that the first parameter is the "operatingMode" */ - if(!strcasecmp(var, "operatingMode")){ + /* confirm that the first parameter is the "operating-mode" */ + if(!strcasecmp(var, "operating-mode")){ /**********************************************************************/ if(!strcasecmp(val, "ISUP")) { g_ftdm_operating_mode = SNG_SS7_OPR_MODE_ISUP; @@ -274,7 +273,7 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa /**********************************************************************/ /* don't care for now */ /**********************************************************************/ - } else if (!strcasecmp(var, "span-id")) { + } else if (!strcasecmp(var, "span-id") || !strcasecmp(var, "ccSpanId")) { /**********************************************************************/ sngSpan.ccSpanId = atoi(val); SS7_DEBUG("Found an ccSpanId = %d\n",sngSpan.ccSpanId); From feaadd2f43751af626ec526efff956531032da33 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 12 Jun 2012 19:29:07 -0400 Subject: [PATCH 234/822] re-adjusted parameter names --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index ebbdc69cae..0d37dffb12 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -260,27 +260,18 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa i++; while (ftdm_parameters[i].var != NULL) { - /**************************************************************************/ - var = ftdm_parameters[i].var; val = ftdm_parameters[i].val; if (!strcasecmp(var, "dialplan")) { - /**********************************************************************/ /* don't care for now */ - /**********************************************************************/ } else if (!strcasecmp(var, "context")) { - /**********************************************************************/ /* don't care for now */ - /**********************************************************************/ } else if (!strcasecmp(var, "span-id") || !strcasecmp(var, "ccSpanId")) { - /**********************************************************************/ sngSpan.ccSpanId = atoi(val); SS7_DEBUG("Found an ccSpanId = %d\n",sngSpan.ccSpanId); - /**********************************************************************/ } else { SS7_ERROR("Unknown parameter found =\"%s\"...ignoring it!\n", var); - /**********************************************************************/ } i++; From 143fb61bdb66ef946d4245665f29f62039c91aa0 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 12 Jun 2012 20:12:27 -0400 Subject: [PATCH 235/822] re-adjusted parameter names --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 0d37dffb12..182ca0745e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -224,20 +224,19 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa /* confirm that the first parameter is the "operating-mode" */ if(!strcasecmp(var, "operating-mode")){ - /**********************************************************************/ if(!strcasecmp(val, "ISUP")) { g_ftdm_operating_mode = SNG_SS7_OPR_MODE_ISUP; } else if(!strcasecmp(val, "M2UA_SG")) { g_ftdm_operating_mode = SNG_SS7_OPR_MODE_M2UA_SG; } else { - SS7_ERROR("Invalid operating Mode[%s] \n", val); - return FTDM_FAIL; + SS7_DEBUG("Operating mode not specified, defaulting to ISUP\n"); + g_ftdm_operating_mode = SNG_SS7_OPR_MODE_ISUP; } - /**********************************************************************/ + i++; } - i++; + var = ftdm_parameters[i].var; val = ftdm_parameters[i].val; From 2112375e07a5e59a4766e15459a423b27c8860df Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 12 Jun 2012 20:19:37 -0400 Subject: [PATCH 236/822] re-adjusted parameter names --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 182ca0745e..c028bb709d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -222,6 +222,8 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa var = ftdm_parameters[i].var; val = ftdm_parameters[i].val; + g_ftdm_operating_mode = SNG_SS7_OPR_MODE_ISUP; + /* confirm that the first parameter is the "operating-mode" */ if(!strcasecmp(var, "operating-mode")){ if(!strcasecmp(val, "ISUP")) { @@ -231,7 +233,6 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa g_ftdm_operating_mode = SNG_SS7_OPR_MODE_M2UA_SG; } else { SS7_DEBUG("Operating mode not specified, defaulting to ISUP\n"); - g_ftdm_operating_mode = SNG_SS7_OPR_MODE_ISUP; } i++; } From 088a564c02d1d5bcf4d6b42743ac69d694c8d775 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 12 Jun 2012 20:26:15 -0400 Subject: [PATCH 237/822] changed mod_megaco to mod_media_gateway --- build/modules.conf.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/modules.conf.in b/build/modules.conf.in index cc99d528f0..783eddf41f 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -7,7 +7,7 @@ applications/mod_hash applications/mod_spandsp dialplans/mod_dialplan_xml endpoints/mod_sofia -endpoints/mod_megaco +endpoints/mod_media_gateway ../../libs/freetdm/mod_freetdm xml_int/mod_xml_cdr event_handlers/mod_event_socket From bb075a6f10fba52d57498b81321223d52175ab09 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 13 Jun 2012 14:02:56 -0400 Subject: [PATCH 238/822] Added radius --- build/modules.conf.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/modules.conf.in b/build/modules.conf.in index 783eddf41f..daaa6084c7 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -5,6 +5,7 @@ applications/mod_dptools applications/mod_commands applications/mod_hash applications/mod_spandsp +applications/mod_rad_auth dialplans/mod_dialplan_xml endpoints/mod_sofia endpoints/mod_media_gateway @@ -12,3 +13,5 @@ endpoints/mod_media_gateway xml_int/mod_xml_cdr event_handlers/mod_event_socket codecs/mod_sangoma_codec +event_handlers/mod_radius_cdr + From 69197b1d0cec61c3580854a9960169b8f2c914df Mon Sep 17 00:00:00 2001 From: kapil Date: Thu, 14 Jun 2012 15:40:57 +0530 Subject: [PATCH 239/822] fixing cli issues --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 65 ++++++++++++------- .../ftmod_sangoma_ss7_m2ua.c | 52 ++++++++++++--- .../ftmod_sangoma_ss7_m2ua.h | 1 + .../ftmod_sangoma_ss7_main.h | 5 +- 4 files changed, 88 insertions(+), 35 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 6fece294cc..8c76bb6f12 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -403,8 +403,8 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha /**************************************************************************/ if (check_arg_count(argc, 2)) { - cli_ss7_show_general(stream); - return FTDM_SUCCESS; + stream->write_function(stream, "Unknown \"xmlshow\" command\n"); + goto handle_cli_error; } c++; /**************************************************************************/ @@ -3071,7 +3071,7 @@ static ftdm_status_t cli_ss7_show_all_spans_general(ftdm_stream_handle_t *stream static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) { char* xmlhdr = (char*)""; - char buf[2048]; + char buf[6144]; int x = 0x00; int idx = 0x00; int len = 0x00; @@ -3105,6 +3105,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) (!(g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].flags & SNGSS7_CONFIGURED))) { len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %s \n", g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].name); if(ftmod_m2ua_ssta_req(STMWDLSAP,x,&cfm)) { stream->write_function(stream," Request to Trillium SCTP layer failed \n"); @@ -3164,17 +3165,17 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) } } - if(ftmod_m2ua_ssta_req(STMWSCTSAP,x,&cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); - return FTDM_FAIL; - } else { - len = len + sprintf(buf + len, "\n"); - len = len + sprintf(buf + len," %s \n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.sctSapSta.state)); - len = len + sprintf(buf + len," %s \n", (cfm.t.ssta.s.sctSapSta.endpOpen)?"END_POINT_OPENED_SUCCESSFULLY":"END_POINT_NOT_OPEN"); - len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.spEndpId); - len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.nmbPrimRetry); - len = len + sprintf(buf + len, "\n"); - } + if(ftmod_m2ua_ssta_req(STMWSCTSAP,x,&cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.sctSapSta.state)); + len = len + sprintf(buf + len," %s \n", (cfm.t.ssta.s.sctSapSta.endpOpen)?"END_POINT_OPENED_SUCCESSFULLY":"END_POINT_NOT_OPEN"); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.spEndpId); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.nmbPrimRetry); + len = len + sprintf(buf + len, "\n"); + } len = len + sprintf(buf + len, "\n"); } @@ -3199,7 +3200,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char* m2ua_profile_name) { char* xmlhdr = (char*)""; - char buf[2048]; + char buf[4096]; int x = 0x00; int idx = 0x00; int found = 0x00; @@ -3234,6 +3235,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %s \n", m2ua_profile_name); if(ftmod_m2ua_ssta_req(STMWDLSAP,x,&cfm)) { stream->write_function(stream," Request to Trillium SCTP layer failed \n"); @@ -3248,7 +3250,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char len = len + sprintf(buf + len, "\n"); } - if(ftmod_m2ua_ssta_req(STMWCLUSTER,x,&cfm)) { + if(ftmod_m2ua_ssta_req(STMWCLUSTER, g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].clusterId, &cfm)) { stream->write_function(stream," Request to Trillium SCTP layer failed \n"); return FTDM_FAIL; } else { @@ -3323,7 +3325,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream) { char* xmlhdr = (char*)""; - char buf[2048]; + char buf[4096]; int x = 0x00; int len = 0x00; SbMgmt cfm; @@ -3402,8 +3404,14 @@ static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream) } if(ftmod_sctp_ssta_req(STSBASSOC,x,&cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); - return FTDM_FAIL; + if(LCM_REASON_INVALID_PAR_VAL == cfm.cfm.reason){ + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " SCT_ASSOC_STATE_CLOSED \n"); + len = len + sprintf(buf + len, "\n"); + }else{ + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } } else { len = len + sprintf(buf + len, "\n"); len = len + get_assoc_resp_buf(buf + len, &cfm); @@ -3535,7 +3543,7 @@ int get_assoc_resp_buf(char* buf,SbMgmt* cfm) static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char* sctp_profile_name) { char* xmlhdr = (char*)""; - char buf[2048]; + char buf[4096]; int x = 0x00; int len = 0x00; SbMgmt cfm; @@ -3586,8 +3594,15 @@ static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char } if(ftmod_sctp_ssta_req(STSBASSOC,x,&cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); - return FTDM_FAIL; + /* it means assoc id not yet allocated */ + if(LCM_REASON_INVALID_PAR_VAL == cfm.cfm.reason){ + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " SCT_ASSOC_STATE_CLOSED \n"); + len = len + sprintf(buf + len, "\n"); + }else{ + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } } else { len = len + sprintf(buf + len, "\n"); len = len + get_assoc_resp_buf(buf + len, &cfm); @@ -3613,7 +3628,7 @@ static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream) { char* xmlhdr = (char*)""; - char buf[2048]; + char buf[4096]; int x = 0x00; int len = 0x00; NwMgmt cfm; @@ -3674,7 +3689,7 @@ static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream) static ftdm_status_t handle_show_nif_profile(ftdm_stream_handle_t *stream, char* nif_profile_name) { char* xmlhdr = (char*)""; - char buf[2048]; + char buf[4096]; int x = 0x00; int found = 0x00; int len = 0x00; @@ -3737,7 +3752,7 @@ static ftdm_status_t handle_show_nif_profile(ftdm_stream_handle_t *stream, char* static ftdm_status_t handle_show_m2ua_peer_status(ftdm_stream_handle_t *stream, char* m2ua_profile_name) { char* xmlhdr = (char*)""; - char buf[2048]; + char buf[4096]; int x = 0x00; int found = 0x00; int len = 0x00; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c index 0639165e97..a5ff80a636 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c @@ -51,7 +51,7 @@ static int ftmod_sctp_config(int id); static ftdm_status_t ftmod_sctp_sap_config(int id); static ftdm_status_t ftmod_sctp_tsap_config(int id); static int ftmod_m2ua_gen_config(void); -static int ftmod_m2ua_sctsap_config(int m2ua_inf_id, int sctp_id); +static int ftmod_m2ua_sctsap_config(int sct_sap_id, int sctp_id); static int ftmod_m2ua_peer_config(int id); static int ftmod_m2ua_peer_config1(int m2ua_inf_id, int peer_id); static int ftmod_m2ua_cluster_config(int idx); @@ -782,6 +782,14 @@ static int ftmod_m2ua_peer_config(int id) sng_m2ua_cluster_cfg_t* clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[m2ua->clusterId]; sng_m2ua_peer_cfg_t* peer = NULL; + if((clust->flags & SNGSS7_CONFIGURED)){ + ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_peer_config: Cluster [%s] is already configured \n", clust->name); + return 0x00; + } + + /*NOTE : SCTSAP is based on per source address , so if we have same Cluster / peer shared across many then + * we dont have do configuration for each time */ + /* loop through peer list from cluster to configure SCTSAP */ for(x = 0; x < clust->numOfPeers;x++){ @@ -800,13 +808,18 @@ static int ftmod_m2ua_peer_config(int id) ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_peer_config1: M2UA Peer configuration for M2UA Intf Id[%d] config SUCCESS \n", id); } + clust->sct_sap_id = id; + /* set configured flag for cluster and peer */ + clust->flags |= SNGSS7_CONFIGURED; + peer->flags |= SNGSS7_CONFIGURED; } return 0x0;; } -static int ftmod_m2ua_sctsap_config(int m2ua_inf_id, int sctp_id) + +static int ftmod_m2ua_sctsap_config(int sct_sap_id, int sctp_id) { int i; Pst pst; @@ -836,7 +849,7 @@ static int ftmod_m2ua_sctsap_config(int m2ua_inf_id, int sctp_id) cfg.t.cfg.s.sctSapCfg.reConfig.selector = 0; /* service user SAP ID */ - cfg.t.cfg.s.sctSapCfg.suId = m2ua_inf_id; + cfg.t.cfg.s.sctSapCfg.suId = sct_sap_id; /* service provider ID */ cfg.t.cfg.s.sctSapCfg.spId = sctp_id; /* source port number */ @@ -1275,7 +1288,7 @@ int ftmod_ss7_m2ua_start(void){ x = 1; while (x < (MW_MAX_NUM_OF_PEER)) { if ((g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[x].id !=0) && - (!(g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[x].flags & SNGSS7_CONFIGURED)) && + ((g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[x].flags & SNGSS7_CONFIGURED)) && (g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[x].init_sctp_assoc)) { if(ftmod_init_sctp_assoc(x)) { ftdm_log (FTDM_LOG_ERROR ,"ftmod_init_sctp_assoc FAIL for peerId[%d] \n", x); @@ -1296,9 +1309,16 @@ int ftmod_ss7_m2ua_start(void){ static int ftmod_open_endpoint(int id) { + int ret = 0x00; Pst pst; MwMgmt cntrl; sng_m2ua_cfg_t* m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; + sng_m2ua_cluster_cfg_t* clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[m2ua->clusterId]; + + if(clust->flags & SNGSS7_M2UA_EP_OPENED) { + ftdm_log (FTDM_LOG_INFO ," END-POINT already opened\n"); + return ret; + } memset((U8 *)&pst, 0, sizeof(Pst)); memset((U8 *)&cntrl, 0, sizeof(MwMgmt)); @@ -1324,7 +1344,12 @@ static int ftmod_open_endpoint(int id) cntrl.t.cntrl.action = AMWENDPOPEN; cntrl.t.cntrl.s.suId = m2ua->id; /* M2UA sct sap Id */ - return (sng_cntrl_m2ua (&pst, &cntrl)); + + if(0 == (ret = sng_cntrl_m2ua (&pst, &cntrl))){ + clust->flags |= SNGSS7_M2UA_EP_OPENED; + } + return ret; + } /***********************************************************************************************************************/ @@ -1400,9 +1425,17 @@ static int ftmod_sctp_tucl_tsap_bind(int id) static int ftmod_m2ua_sctp_sctsap_bind(int id) { + int ret = 0x00; Pst pst; MwMgmt cntrl; sng_m2ua_cfg_t* m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; + sng_m2ua_cluster_cfg_t* clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[m2ua->clusterId]; + + if(clust->flags & SNGSS7_ACTIVE) { + ftdm_log (FTDM_LOG_INFO ," SCT-SAP is already enabled\n"); + return ret; + } + memset((U8 *)&pst, 0, sizeof(Pst)); memset((U8 *)&cntrl, 0, sizeof(MwMgmt)); @@ -1427,8 +1460,10 @@ static int ftmod_m2ua_sctp_sctsap_bind(int id) cntrl.t.cntrl.action = ABND; cntrl.t.cntrl.s.suId = m2ua->id; - return (sng_cntrl_m2ua (&pst, &cntrl)); - + if(0 == (ret = sng_cntrl_m2ua (&pst, &cntrl))){ + clust->flags |= SNGSS7_ACTIVE; + } + return ret; } /***********************************************************************************************************************/ static int ftmod_nif_m2ua_dlsap_bind(int id) @@ -1668,7 +1703,8 @@ int ftmod_m2ua_ssta_req(int elemt, int id, MwMgmt* cfm) case STMWSCTSAP: { m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; - ssta.t.ssta.id.suId = m2ua->id ; /* lower sap Id */ + clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[m2ua->clusterId]; + ssta.t.ssta.id.suId = clust->sct_sap_id ; /* lower sap Id */ break; } case STMWDLSAP: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h index 2b44426102..8e22e47b97 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h @@ -96,6 +96,7 @@ typedef struct sng_m2ua_cluster_cfg{ char name[MAX_NAME_LEN]; uint32_t flags; uint32_t id; /* ID */ + uint32_t sct_sap_id; /* Internal - sct_sap_id */ uint8_t trfMode; /* Traffic mode. This parameter defines the mode in which this m2ua cluster is supposed to work */ uint8_t loadShareAlgo; /* This parameter defines the M2UA load share algorithm which is used to distribute the traffic */ uint16_t numOfPeers; /* idx to m2ua_peer profile */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 63e146c029..0e52f88710 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -767,9 +767,10 @@ typedef enum { SNGSS7_M2UA_PRESENT = (1 << 18), SNGSS7_M2UA_STARTED = (1 << 19), + SNGSS7_M2UA_EP_OPENED = (1 << 20), - SNGSS7_NIF_PRESENT = (1 << 20), - SNGSS7_NIF_STARTED = (1 << 21), + SNGSS7_NIF_PRESENT = (1 << 21), + SNGSS7_NIF_STARTED = (1 << 22), } sng_task_flag_t; /******************************************************************************/ From 6502e96f50edc60e7d23f08b05570e2ff73f04dc Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Thu, 14 Jun 2012 18:23:12 -0400 Subject: [PATCH 240/822] Fix for hard link for freeradius-client --- src/mod/applications/mod_rad_auth/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/mod/applications/mod_rad_auth/Makefile b/src/mod/applications/mod_rad_auth/Makefile index c00bce2cc2..88d1f0b585 100644 --- a/src/mod/applications/mod_rad_auth/Makefile +++ b/src/mod/applications/mod_rad_auth/Makefile @@ -1,6 +1,12 @@ switch_srcdir=../../../.. +ifdef FREERADIUSDIR +FREERADIUSLA=$(FREERADIUSDIR)/libfreeradius-client.so +else FREERADIUSLA=/usr/local/lib/libfreeradius-client.so +endif + + LOCAL_LIBADD=$(FREERADIUSLA) include $(switch_srcdir)/build/modmake.rules From 2f5ac6243332fb75add1e13159966b2a8d49ffc8 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 15 Jun 2012 15:46:53 -0400 Subject: [PATCH 241/822] added mod_distributor --- build/modules.conf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/build/modules.conf.in b/build/modules.conf.in index 1d27aaad1b..1284bb8bc1 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -5,6 +5,7 @@ applications/mod_dptools applications/mod_commands applications/mod_hash applications/mod_spandsp +applications/mod_distributor dialplans/mod_dialplan_xml endpoints/mod_sofia ../../libs/freetdm/mod_freetdm From 92b55af0715a2a8c41b78ba01ec75763697cf3e5 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 15 Jun 2012 16:08:18 -0400 Subject: [PATCH 242/822] missing functions rename --- src/mod/endpoints/mod_media_gateway/mod_media_gateway.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index ebad0b30b7..6383bb0750 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -14,7 +14,7 @@ static sng_mg_event_interface_t sng_event; SWITCH_MODULE_LOAD_FUNCTION(mod_megaco_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_megaco_shutdown); -SWITCH_MODULE_DEFINITION(mod_megaco, mod_megaco_load, mod_megaco_shutdown, NULL); +SWITCH_MODULE_DEFINITION(mod_media_gateway, mod_media_gateway_load, mod_media_gateway_shutdown, NULL); SWITCH_STANDARD_API(megaco_function) { @@ -51,7 +51,7 @@ static switch_status_t list_profiles(const char *line, const char *cursor, switc return status; } -SWITCH_MODULE_LOAD_FUNCTION(mod_megaco_load) +SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load) { switch_api_interface_t *api_interface; @@ -93,7 +93,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_megaco_load) return sng_mgco_init(&sng_event); } -SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_megaco_shutdown) +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_media_gateway_shutdown) { sng_mgco_stack_shutdown(); From af39d4c9d2a5ac277035ccbb5b984c06ee4cb155 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 15 Jun 2012 16:16:11 -0400 Subject: [PATCH 243/822] missed one --- src/mod/endpoints/mod_media_gateway/mod_media_gateway.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 6383bb0750..58a8794fad 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -12,8 +12,8 @@ struct megaco_globals megaco_globals; static sng_mg_event_interface_t sng_event; -SWITCH_MODULE_LOAD_FUNCTION(mod_megaco_load); -SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_megaco_shutdown); +SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load); +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_media_gateway_shutdown); SWITCH_MODULE_DEFINITION(mod_media_gateway, mod_media_gateway_load, mod_media_gateway_shutdown, NULL); SWITCH_STANDARD_API(megaco_function) From 07b260d18baab081e51d39c6dd4aef2d201e3772 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 15 Jun 2012 16:17:01 -0400 Subject: [PATCH 244/822] Trying to re-use same Makefile as mod_rad_cdr --- src/mod/applications/mod_rad_auth/Makefile | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/mod/applications/mod_rad_auth/Makefile b/src/mod/applications/mod_rad_auth/Makefile index 88d1f0b585..d2e91c24b3 100644 --- a/src/mod/applications/mod_rad_auth/Makefile +++ b/src/mod/applications/mod_rad_auth/Makefile @@ -1,13 +1,14 @@ switch_srcdir=../../../.. -ifdef FREERADIUSDIR -FREERADIUSLA=$(FREERADIUSDIR)/libfreeradius-client.so -else -FREERADIUSLA=/usr/local/lib/libfreeradius-client.so -endif +RADCLIENT_VERSION=1.1.6 +RADCLIENT=freeradius-client-$(RADCLIENT_VERSION) +RADCLIENT_DIR=$(switch_srcdir)/libs/$(RADCLIENT) +RADCLIENT_BUILDDIR=$(switch_builddir)/libs/$(RADCLIENT) +RADCLIENT_LIBDIR=$(RADCLIENT_BUILDDIR)/lib +RADCLIENT_LA=${RADCLIENT_LIBDIR}/libfreeradius-client.la - -LOCAL_LIBADD=$(FREERADIUSLA) +LOCAL_CFLAGS=-I$(RADCLIENT_DIR)/include +LOCAL_LIBADD=$(RADCLIENT_LA) include $(switch_srcdir)/build/modmake.rules From 74de83c6eb8742887a3be75801088bb03c4a0e8b Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 15 Jun 2012 16:48:53 -0400 Subject: [PATCH 245/822] Trying without rad_auth --- build/modules.conf.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/modules.conf.in b/build/modules.conf.in index daaa6084c7..2bdedc6237 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -5,7 +5,7 @@ applications/mod_dptools applications/mod_commands applications/mod_hash applications/mod_spandsp -applications/mod_rad_auth +#applications/mod_rad_auth dialplans/mod_dialplan_xml endpoints/mod_sofia endpoints/mod_media_gateway From 3b4c725b1c339233452a2832a05e9b8325bb8822 Mon Sep 17 00:00:00 2001 From: kapil Date: Mon, 18 Jun 2012 17:41:05 +0530 Subject: [PATCH 246/822] fixing cli issues --- libs/freetdm/configure.ac | 2 +- libs/freetdm/mod_freetdm/mod_freetdm.c | 8 +- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c | 7 + .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 96 ++++---- .../ftmod_sangoma_ss7_m2ua.c | 216 +++++++++--------- .../ftmod_sangoma_ss7_m2ua.h | 2 + .../ftmod_sangoma_ss7_m2ua_xml.c | 17 +- .../ftmod_sangoma_ss7_main.h | 5 +- 8 files changed, 178 insertions(+), 175 deletions(-) diff --git a/libs/freetdm/configure.ac b/libs/freetdm/configure.ac index 80f0c73070..292c1e7cfa 100644 --- a/libs/freetdm/configure.ac +++ b/libs/freetdm/configure.ac @@ -316,7 +316,7 @@ if test "${HAVE_SNG_SS7}" = "yes"; then case "${host}" in x86_64-*) # X86_64 machines need additional flags when compiling against libsng_isdn - CFLAGS="$CFLAGS -DBIT_64 -DALIGN_64BIT -DDEBUGP" + CFLAGS="$CFLAGS -DBIT_64 -DALIGN_64BIT" ;; esac fi diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 35690b1e24..89524f0eca 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -3061,7 +3061,6 @@ static ftdm_conf_node_t *_get_ss7_config_node(switch_xml_t cfg, const char *conf return NULL; } - /* If ISUP is operating mode then only include mtp3_links/isup links */ if(is_isup) { /* add mtp3 links */ if (add_config_list_nodes(isup, rootnode, "mtp3_links", "mtp3_link", NULL, NULL)) { @@ -3097,10 +3096,9 @@ static ftdm_conf_node_t *_get_ss7_config_node(switch_xml_t cfg, const char *conf ftdm_conf_node_destroy(rootnode); return NULL; } - } - else { + } else { /* add sctp links */ - if (add_config_list_nodes(isup, rootnode, "sng_sctp_interfaces", "sng_sctp_interface", NULL, NULL)) { + if (add_config_nodes(isup, rootnode, "sng_sctp_interfaces", "sng_sctp_interface", "sng_source_addresses")) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process sng_sctp_interface for sng_isup config %s\n", confname); ftdm_conf_node_destroy(rootnode); return NULL; @@ -3124,13 +3122,11 @@ static ftdm_conf_node_t *_get_ss7_config_node(switch_xml_t cfg, const char *conf return NULL; } - if (add_config_nodes(isup, rootnode, "sng_m2ua_cluster_interfaces", "sng_m2ua_cluster_interface", "sng_m2ua_peers")) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process sng_m2ua_cluster_interfaces for sng_isup config %s\n", confname); ftdm_conf_node_destroy(rootnode); return NULL; } - } switch_core_hash_insert(globals.ss7_configs, confname, rootnode); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c index 170f03f8f3..1600e71016 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c @@ -209,6 +209,13 @@ int ft_to_sngss7_cfg_all(void) } } /* if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP2)) */ + if(SNG_SS7_OPR_MODE_M2UA_SG == g_ftdm_operating_mode){ + if(FTDM_SUCCESS != ftmod_ss7_m2ua_init()){ + ftdm_log (FTDM_LOG_ERROR, "ftmod_ss7_m2ua_init FAILED \n"); + return FTDM_FAIL; + } + } + g_ftdm_sngss7_data.gen_config = SNG_GEN_CFG_STATUS_DONE; } /* if (!(g_ftdm_sngss7_data.gen_config)) */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 89cfec14a7..6906b80290 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -3090,8 +3090,8 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); - len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.memSize); - len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.memAlloc); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.memSize); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.memAlloc); len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.nmbClusters); len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.nmbPeers); len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.nmbIntf); @@ -3102,7 +3102,9 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) x = 1; while(x\n"); len = len + sprintf(buf + len, " %s \n", g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].name); @@ -3120,6 +3122,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); } + memset((U8 *)&cfm, 0, sizeof(MwMgmt)); if(ftmod_m2ua_ssta_req(STMWCLUSTER,g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].clusterId,&cfm)) { stream->write_function(stream," Request to Trillium SCTP layer failed \n"); return FTDM_FAIL; @@ -3137,34 +3140,47 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.clusterSta.nmbActPeer); len = len + sprintf(buf + len, "\n"); - } - memcpy((U8 *)&rsp, &cfm, sizeof(MwMgmt)); + memset((U8 *)&rsp, 0, sizeof(MwMgmt)); + memcpy(&rsp, &cfm, sizeof(MwMgmt)); - /* loop through configured peers */ - for(idx = 0; idx < rsp.t.ssta.s.clusterSta.nmbPeer; idx++) - { - memset((U8 *)&cfm, 0, sizeof(MwMgmt)); - if(ftmod_m2ua_ssta_req(STMWPEER, rsp.t.ssta.s.clusterSta.peerSt[idx].peerId, &cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); - return FTDM_FAIL; - } else { - len = len + sprintf(buf + len, "\n"); - len = len + sprintf(buf + len, " %s \n",g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[rsp.t.ssta.s.clusterSta.peerSt[idx].peerId].name); - len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.retryCount); - len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.peerSta.assocSta.spAssocId); - len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcInProg); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcLevel); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.sctpHBeatEnb); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.locOutStrms); + /* loop through configured peers */ + for(idx = 0; idx < rsp.t.ssta.s.clusterSta.nmbPeer; idx++) + { + int peer_id = rsp.t.ssta.s.clusterSta.peerSt[idx].peerId; + + memset(&cfm, 0, sizeof(MwMgmt)); - len = len + sprintf(buf + len, "\n"); + if(LMW_PEER_DOWN != rsp.t.ssta.s.clusterSta.peerSt[idx].peerState){ + + if(ftmod_m2ua_ssta_req(STMWPEER, peer_id, &cfm)) { + stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %s \n",g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[peer_id].name); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.retryCount); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.spAssocId); + len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcInProg); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcLevel); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.sctpHBeatEnb); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.locOutStrms); + + len = len + sprintf(buf + len, "\n"); + } + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %s \n",g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[peer_id].name); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(rsp.t.ssta.s.clusterSta.peerSt[idx].peerState)); + len = len + sprintf(buf + len, "\n"); + } } } + memset((U8 *)&cfm, 0, sizeof(MwMgmt)); if(ftmod_m2ua_ssta_req(STMWSCTSAP,x,&cfm)) { stream->write_function(stream," Request to Trillium SCTP layer failed \n"); return FTDM_FAIL; @@ -3172,7 +3188,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); len = len + sprintf(buf + len," %s \n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.sctSapSta.state)); len = len + sprintf(buf + len," %s \n", (cfm.t.ssta.s.sctSapSta.endpOpen)?"END_POINT_OPENED_SUCCESSFULLY":"END_POINT_NOT_OPEN"); - len = len + sprintf(buf + len," %ld \n", cfm.t.ssta.s.sctSapSta.spEndpId); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.spEndpId); len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.nmbPrimRetry); len = len + sprintf(buf + len, "\n"); } @@ -3218,7 +3234,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char x = 1; while(x %s \n",g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[rsp.t.ssta.s.clusterSta.peerSt[idx].peerId].name); len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.retryCount); - len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.peerSta.assocSta.spAssocId); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.spAssocId); len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcInProg); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcLevel); @@ -3302,7 +3318,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char len = len + sprintf(buf + len, "\n"); len = len + sprintf(buf + len," %s \n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.sctSapSta.state)); len = len + sprintf(buf + len," %s \n", (cfm.t.ssta.s.sctSapSta.endpOpen)?"END_POINT_OPENED_SUCCESSFULLY":"END_POINT_NOT_OPEN"); - len = len + sprintf(buf + len," %ld \n", cfm.t.ssta.s.sctSapSta.spEndpId); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.spEndpId); len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.nmbPrimRetry); len = len + sprintf(buf + len, "\n"); } @@ -3341,8 +3357,8 @@ static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream) return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); - len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.genSta.memSize); - len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.genSta.memAlloc); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memSize); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memAlloc); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbAssoc); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbEndp); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbLocalAddr); @@ -3379,7 +3395,7 @@ static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream) x = 1; while(x\n"); @@ -3438,7 +3454,7 @@ int get_assoc_resp_buf(char* buf,SbMgmt* cfm) char *asciiAddr; CmInetIpAddr ip; - len = len + sprintf(buf + len, " %ld \n", cfm->t.ssta.s.assocSta.assocId); + len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.assocId); len = len + sprintf(buf + len, " %s \n", PRNT_SCTP_ASSOC_STATE(cfm->t.ssta.s.assocSta.assocState)); len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.dstPort); len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.srcPort); @@ -3558,7 +3574,7 @@ static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char x = 1; while(x\n"); - len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.genSta.memSize); - len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.genSta.memAlloc); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memSize); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memAlloc); len = len + sprintf(buf + len, "\n"); } @@ -3653,7 +3669,7 @@ static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream) x = 1; while(x\n"); @@ -3664,7 +3680,7 @@ static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.m2uaState)); len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.mtp2State)); - len = len + sprintf(buf + len," %ld \n", cfm.t.ssta.s.dlSapSta.nmbRetry); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.nmbRetry); len = len + sprintf(buf + len, "\n"); } @@ -3704,7 +3720,7 @@ static ftdm_status_t handle_show_nif_profile(ftdm_stream_handle_t *stream, char* x = 1; while(x\n"); len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.m2uaState)); len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.mtp2State)); - len = len + sprintf(buf + len," %ld \n", cfm.t.ssta.s.dlSapSta.nmbRetry); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.nmbRetry); len = len + sprintf(buf + len, "\n"); } @@ -3774,7 +3790,7 @@ static ftdm_status_t handle_show_m2ua_peer_status(ftdm_stream_handle_t *stream, x = 1; while(xid ; /* peer Id */ + ssta.t.ssta.id.peerId = id ; /* peer Id */ break; } case STMWCLUSTER: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h index 8e22e47b97..c7ce2e74eb 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h @@ -60,6 +60,7 @@ typedef struct sng_m2ua_cfg{ uint32_t flags; uint32_t id; /* ID */ uint8_t nodeType; /*Node Type SG/ASP */ + uint8_t end_point_opened; /* flag to check is end-point already opened */ uint16_t clusterId; /* idx to m2ua_cluster profile */ }sng_m2ua_cfg_t; @@ -122,6 +123,7 @@ int ftmod_ss7_m2ua_start(void); void ftmod_ss7_m2ua_free(void); ftdm_status_t ftmod_ss7_m2ua_cfg(void); +ftdm_status_t ftmod_ss7_m2ua_init(void); int ftmod_sctp_ssta_req(int elemt, int id, SbMgmt* cfm); int ftmod_m2ua_ssta_req(int elemt, int id, MwMgmt* cfm); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c index 57bca70e61..b9ae986402 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c @@ -146,9 +146,6 @@ static int ftmod_ss7_parse_nif_interface(ftdm_conf_node_t *nif_interface) /**************************************************************************/ } /* for (i = 0; i < num_parms; i++) */ - /* default the interface to paused state */ - sngss7_set_flag(&sng_nif, SNGSS7_PAUSED); - /* fill in the nif interface */ ftmod_ss7_fill_in_nif_interface(&sng_nif); @@ -259,9 +256,6 @@ static int ftmod_ss7_parse_m2ua_interface(ftdm_conf_node_t *m2ua_interface) sng_m2ua.nodeType = SNG_M2UA_NODE_TYPE_SGP; - /* default the interface to paused state */ - sngss7_set_flag(&sng_m2ua, SNGSS7_PAUSED); - /* fill in the nif interface */ ftmod_ss7_fill_in_m2ua_interface(&sng_m2ua); @@ -421,9 +415,6 @@ static int ftmod_ss7_parse_m2ua_peer_interface(ftdm_conf_node_t *m2ua_peer_inter /**************************************************************************/ } /* for (i = 0; i < num_parms; i++) */ - /* default the interface to paused state */ - sngss7_set_flag(&sng_m2ua_peer, SNGSS7_PAUSED); - /* fill in the sng_m2ua_peer interface */ ftmod_ss7_fill_in_m2ua_peer_interface(&sng_m2ua_peer); @@ -576,9 +567,6 @@ static int ftmod_ss7_parse_m2ua_clust_interface(ftdm_conf_node_t *m2ua_cluster_i /**************************************************************************/ } /* for (i = 0; i < num_parms; i++) */ - /* default the interface to paused state */ - sngss7_set_flag(&sng_m2ua_cluster, SNGSS7_PAUSED); - /* fill in the sng_m2ua_peer interface */ ftmod_ss7_fill_in_m2ua_clust_interface(&sng_m2ua_cluster); @@ -663,7 +651,7 @@ static int ftmod_ss7_parse_sctp_link(ftdm_conf_node_t *node) t_link.id = atoi(param->val); SS7_DEBUG("SCTP - Parsing with id = %s\n", param->val); } - else if (!strcasecmp(param->var, "src-addr")) { + else if (!strcasecmp(param->var, "address")) { if (t_link.numSrcAddr < SCT_MAX_NET_ADDRS) { t_link.srcAddrList[t_link.numSrcAddr+1] = iptoul (param->val); t_link.numSrcAddr++; @@ -671,7 +659,7 @@ static int ftmod_ss7_parse_sctp_link(ftdm_conf_node_t *node) } else { SS7_ERROR("SCTP - too many source address configured. dropping %s \n", param->val); } - } else if (!strcasecmp(param->var, "src-port")) { + } else if (!strcasecmp(param->var, "source-port")) { t_link.port = atoi(param->val); SS7_DEBUG("SCTP - Parsing with port = %s\n", param->val); } @@ -683,7 +671,6 @@ static int ftmod_ss7_parse_sctp_link(ftdm_conf_node_t *node) g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].id = t_link.id; g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].port = t_link.port; strncpy((char*)g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].name, t_link.name, strlen(t_link.name) ); - g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].flags = 0; g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].numSrcAddr = t_link.numSrcAddr; for (i=1; i<=t_link.numSrcAddr; i++) { g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].srcAddrList[i] = t_link.srcAddrList[i]; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 0e52f88710..9a5a8cbe95 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -768,9 +768,10 @@ typedef enum { SNGSS7_M2UA_PRESENT = (1 << 18), SNGSS7_M2UA_STARTED = (1 << 19), SNGSS7_M2UA_EP_OPENED = (1 << 20), + SNGSS7_M2UA_INIT_ASSOC_DONE = (1 << 21), - SNGSS7_NIF_PRESENT = (1 << 21), - SNGSS7_NIF_STARTED = (1 << 22), + SNGSS7_NIF_PRESENT = (1 << 22), + SNGSS7_NIF_STARTED = (1 << 23), } sng_task_flag_t; /******************************************************************************/ From 32106afc433b6e96f00742a3e55b9565f4e4f8a9 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Mon, 18 Jun 2012 12:51:38 -0400 Subject: [PATCH 247/822] Fixed compile issues again on 32-bit --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 6906b80290..620e4f3ece 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -3090,9 +3090,15 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); +#ifdef BIT_64 len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.memSize); - len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.memAlloc); + len = len + sprintf(buf + len, " %d \n", (int64_t) cfm.t.ssta.s.genSta.memAlloc); len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.nmbClusters); +#else + len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.memSize); + len = len + sprintf(buf + len, " %ld \n", (int64_t) cfm.t.ssta.s.genSta.memAlloc); + len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.nmbClusters); +#endif len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.nmbPeers); len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.nmbIntf); len = len + sprintf(buf + len, "\n"); @@ -3162,7 +3168,11 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, " %s \n",g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[peer_id].name); len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.retryCount); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.spAssocId); +#ifdef BIT_64 + len = len + sprintf(buf + len, " %d \n", (int64_t) cfm.t.ssta.s.peerSta.assocSta.spAssocId); +#else + len = len + sprintf(buf + len, " %ld \n", (int64_t) cfm.t.ssta.s.peerSta.assocSta.spAssocId); +#endif len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcInProg); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcLevel); @@ -3188,7 +3198,11 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); len = len + sprintf(buf + len," %s \n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.sctSapSta.state)); len = len + sprintf(buf + len," %s \n", (cfm.t.ssta.s.sctSapSta.endpOpen)?"END_POINT_OPENED_SUCCESSFULLY":"END_POINT_NOT_OPEN"); - len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.spEndpId); +#ifdef BIT_64 + len = len + sprintf(buf + len," %d \n", (int64_t) cfm.t.ssta.s.sctSapSta.spEndpId); +#else + len = len + sprintf(buf + len," %ld \n", (int64_t) cfm.t.ssta.s.sctSapSta.spEndpId); +#endif len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.nmbPrimRetry); len = len + sprintf(buf + len, "\n"); } @@ -3300,7 +3314,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char len = len + sprintf(buf + len, " %s \n",g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[rsp.t.ssta.s.clusterSta.peerSt[idx].peerId].name); len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.retryCount); - len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.spAssocId); + len = len + sprintf(buf + len, " %ld \n", (int64_t) cfm.t.ssta.s.peerSta.assocSta.spAssocId); len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcInProg); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcLevel); @@ -3318,7 +3332,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char len = len + sprintf(buf + len, "\n"); len = len + sprintf(buf + len," %s \n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.sctSapSta.state)); len = len + sprintf(buf + len," %s \n", (cfm.t.ssta.s.sctSapSta.endpOpen)?"END_POINT_OPENED_SUCCESSFULLY":"END_POINT_NOT_OPEN"); - len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.spEndpId); + len = len + sprintf(buf + len," %ld \n", (int64_t) cfm.t.ssta.s.sctSapSta.spEndpId); len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.nmbPrimRetry); len = len + sprintf(buf + len, "\n"); } @@ -3357,8 +3371,13 @@ static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream) return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); +#ifdef BIT_64 len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memSize); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memAlloc); +#else + len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.genSta.memSize); + len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.genSta.memAlloc); +#endif len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbAssoc); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbEndp); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbLocalAddr); @@ -3454,7 +3473,11 @@ int get_assoc_resp_buf(char* buf,SbMgmt* cfm) char *asciiAddr; CmInetIpAddr ip; +#ifdef BIT_64 len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.assocId); +#else + len = len + sprintf(buf + len, " %ld \n", cfm->t.ssta.s.assocSta.assocId); +#endif len = len + sprintf(buf + len, " %s \n", PRNT_SCTP_ASSOC_STATE(cfm->t.ssta.s.assocSta.assocState)); len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.dstPort); len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.srcPort); @@ -3660,8 +3683,13 @@ static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream) return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); +#ifdef BIT_64 len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memSize); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memAlloc); +#else + len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.genSta.memSize); + len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.genSta.memAlloc); +#endif len = len + sprintf(buf + len, "\n"); } From 56c8534827f980b773f20035d1385ed9f54160c7 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Mon, 18 Jun 2012 14:34:12 -0400 Subject: [PATCH 248/822] Fixed compile issues again on 32-bit --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 620e4f3ece..80aad15ee8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -3092,11 +3092,11 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); #ifdef BIT_64 len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.memSize); - len = len + sprintf(buf + len, " %d \n", (int64_t) cfm.t.ssta.s.genSta.memAlloc); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.memAlloc); len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.nmbClusters); #else len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.memSize); - len = len + sprintf(buf + len, " %ld \n", (int64_t) cfm.t.ssta.s.genSta.memAlloc); + len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.memAlloc); len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.nmbClusters); #endif len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.nmbPeers); @@ -3314,7 +3314,11 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char len = len + sprintf(buf + len, " %s \n",g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[rsp.t.ssta.s.clusterSta.peerSt[idx].peerId].name); len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.retryCount); - len = len + sprintf(buf + len, " %ld \n", (int64_t) cfm.t.ssta.s.peerSta.assocSta.spAssocId); +#ifdef BIT_64 + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.peerSta.assocSta.spAssocId); +#else + len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.peerSta.assocSta.spAssocId); +#endif len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcInProg); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcLevel); @@ -3332,7 +3336,11 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char len = len + sprintf(buf + len, "\n"); len = len + sprintf(buf + len," %s \n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.sctSapSta.state)); len = len + sprintf(buf + len," %s \n", (cfm.t.ssta.s.sctSapSta.endpOpen)?"END_POINT_OPENED_SUCCESSFULLY":"END_POINT_NOT_OPEN"); - len = len + sprintf(buf + len," %ld \n", (int64_t) cfm.t.ssta.s.sctSapSta.spEndpId); +#ifdef BIT_64 + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.spEndpId); +#else + len = len + sprintf(buf + len," %ld \n", cfm.t.ssta.s.sctSapSta.spEndpId); +#endif len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.nmbPrimRetry); len = len + sprintf(buf + len, "\n"); } @@ -3708,7 +3716,11 @@ static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.m2uaState)); len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.mtp2State)); +#ifdef BIT_64 len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.nmbRetry); +#else + len = len + sprintf(buf + len," %ld \n", cfm.t.ssta.s.dlSapSta.nmbRetry); +#endif len = len + sprintf(buf + len, "\n"); } From 0cefb8d63337d3365a0c9a3ce9e27e06d6319db0 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Mon, 18 Jun 2012 15:01:08 -0400 Subject: [PATCH 249/822] Fixed compile issues again on 32-bit --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 80aad15ee8..951d0a3e49 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -3093,12 +3093,11 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) #ifdef BIT_64 len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.memSize); len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.memAlloc); - len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.nmbClusters); #else len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.memSize); len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.memAlloc); - len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.nmbClusters); #endif + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.nmbClusters); len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.nmbPeers); len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.nmbIntf); len = len + sprintf(buf + len, "\n"); @@ -3171,7 +3170,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) #ifdef BIT_64 len = len + sprintf(buf + len, " %d \n", (int64_t) cfm.t.ssta.s.peerSta.assocSta.spAssocId); #else - len = len + sprintf(buf + len, " %ld \n", (int64_t) cfm.t.ssta.s.peerSta.assocSta.spAssocId); + len = len + sprintf(buf + len, " %lld \n", (int64_t) cfm.t.ssta.s.peerSta.assocSta.spAssocId); #endif len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcInProg); @@ -3201,7 +3200,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) #ifdef BIT_64 len = len + sprintf(buf + len," %d \n", (int64_t) cfm.t.ssta.s.sctSapSta.spEndpId); #else - len = len + sprintf(buf + len," %ld \n", (int64_t) cfm.t.ssta.s.sctSapSta.spEndpId); + len = len + sprintf(buf + len," %lld \n", (int64_t) cfm.t.ssta.s.sctSapSta.spEndpId); #endif len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.nmbPrimRetry); len = len + sprintf(buf + len, "\n"); From 0a9f34aa09cbe60ae9bd8c8ceb855b8a261cc44e Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Mon, 18 Jun 2012 15:27:45 -0400 Subject: [PATCH 250/822] Fixed compile issues again on 32-bit --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 951d0a3e49..b8cc34480f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -3784,7 +3784,11 @@ static ftdm_status_t handle_show_nif_profile(ftdm_stream_handle_t *stream, char* len = len + sprintf(buf + len, "\n"); len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.m2uaState)); len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.mtp2State)); +#ifdef BIT_64 len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.nmbRetry); +#else + len = len + sprintf(buf + len," %ld \n", cfm.t.ssta.s.dlSapSta.nmbRetry); +#endif len = len + sprintf(buf + len, "\n"); } From 743e91569e5ef10abc92198ed473d9ac561abb5f Mon Sep 17 00:00:00 2001 From: kapil Date: Tue, 19 Jun 2012 17:00:39 +0530 Subject: [PATCH 251/822] adding enable/disable MEGACO stack looging CLI command --- .../mod_media_gateway/media_gateway_cli.c | 25 +++++++++++++++- .../mod_media_gateway/media_gateway_stack.c | 30 +++++++++++++++++-- .../mod_media_gateway/media_gateway_stack.h | 2 ++ .../mod_media_gateway/mod_media_gateway.c | 2 ++ .../mod_media_gateway/mod_media_gateway.h | 2 ++ 5 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c index db50feaa57..720032673c 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c @@ -99,12 +99,35 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre /**********************************************************************************/ goto usage; } +/**********************************************************************************/ + }else if (!strcmp(argv[0], "logging")) { +/**********************************************************************************/ + if (zstr(argv[1])) { + goto usage; + } + /******************************************************************/ + if(!strcasecmp(argv[1], "enable")){ + mg_enable_logging(); + /******************************************************************/ + }else if(!strcasecmp(argv[1], "disable")){ + /******************************************************************/ + mg_disable_logging(); + /******************************************************************/ + } else { + /******************************************************************/ + goto usage; + } +/**********************************************************************************/ + }else { +/**********************************************************************************/ + goto usage; } +/**********************************************************************************/ goto done; usage: - stream->write_function(stream, "-ERR Usage: "MEGACO_FUNCTION_SYNTAX"\n"); + stream->write_function(stream, "-ERR Usage: \n""\t"MEGACO_CLI_SYNTAX" \n \t"MEGACO_FUNCTION_SYNTAX"\n \t" MEGACO_LOGGING_CLI_SYNTAX "\n"); done: switch_safe_free(dup); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c index abe46a5837..d4717501ce 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c @@ -19,7 +19,6 @@ int mgco_mu_gen_config(void); int mgco_tucl_gen_config(void); int mgco_mu_ssap_config(int idx); int mgco_mg_tsap_config(megaco_profile_t* profile); -int mgco_mg_enble_debug(void); int mgco_mg_ssap_config(megaco_profile_t* profile); int mgco_mg_peer_config(megaco_profile_t* profile); int mgco_mg_tpt_server_config(megaco_profile_t* profile); @@ -571,7 +570,7 @@ int mgco_mg_ssap_cntrl(int idx) } /******************************************************************************/ -int mgco_mg_enble_debug() +int mg_enable_logging() { MgMngmt mgMngmt; Pst pst; /* Post for layer manager */ @@ -597,6 +596,33 @@ int mgco_mg_enble_debug() return(sng_cntrl_mg(&pst, &mgMngmt)); } +/******************************************************************************/ +int mg_disable_logging() +{ + MgMngmt mgMngmt; + Pst pst; /* Post for layer manager */ + MgCntrl* cntrl; + + memset(&mgMngmt, 0, sizeof(mgMngmt)); + cntrl = &mgMngmt.t.cntrl; + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTMG; + mgMngmt.hdr.msgType = TCFG; + mgMngmt.hdr.entId.ent = ENTHI; + mgMngmt.hdr.entId.inst = S_INST; + mgMngmt.hdr.elmId.elmnt = STGEN; + + cntrl->action = ADISIMM; + cntrl->subAction = SADBG; + cntrl->s.dbg.genDbgMask = 0xfffffdff; + + return(sng_cntrl_mg(&pst, &mgMngmt)); +} + /******************************************************************************/ int mgco_tucl_gen_config(void) { diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index ac5b911f9b..9bbe90b7df 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -53,6 +53,8 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg); void handle_mgco_audit_cfm(Pst *pst, SuId suId, MgMgtAudit* audit, Reason reason); void handle_mg_alarm(Pst *pst, MgMngmt *sta); void handle_tucl_alarm(Pst *pst, HiMngmt *sta); +int mg_enable_logging(void); +int mg_disable_logging(void); switch_status_t sng_mgco_cfg(megaco_profile_t* profile); diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 58a8794fad..322dbd4221 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -73,6 +73,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load) switch_console_set_complete("add megaco profile ::megaco::list_profiles status"); switch_console_set_complete("add megaco profile ::megaco::list_profiles xmlstatus"); switch_console_set_complete("add megaco profile ::megaco::list_profiles peerxmlstatus"); + switch_console_set_complete("add megaco logging ::megaco::list_profiles enable"); + switch_console_set_complete("add megaco logging ::megaco::list_profiles disable"); switch_console_add_complete_func("::megaco::list_profiles", list_profiles); diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index c55bb6744f..2e0db8cb62 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -15,6 +15,8 @@ #define MG_MAX_PEERS 5 +#define MEGACO_CLI_SYNTAX "profile|logging" +#define MEGACO_LOGGING_CLI_SYNTAX "logging [enable|disable]" #define MEGACO_FUNCTION_SYNTAX "profile [name] [start | stop] [status] [xmlstatus] [peerxmlstatus]" struct megaco_globals { From 8846e1fea1029ac8599762c4e219e9984b1cd70b Mon Sep 17 00:00:00 2001 From: kapil Date: Tue, 19 Jun 2012 23:36:38 +0530 Subject: [PATCH 252/822] issue fix --- src/mod/endpoints/mod_media_gateway/media_gateway_stack.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c index d4717501ce..591bb5f13d 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c @@ -96,6 +96,9 @@ switch_status_t sng_mgco_init(sng_mg_event_interface_t* event) /*****************************************************************************************************************/ switch_status_t sng_mgco_stack_shutdown() { + /* disable MG logging */ + mg_disable_logging(); + /* shutdown MG */ sng_mgco_mg_shutdown(); @@ -1256,7 +1259,7 @@ int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, megaco_profile_t* mg_cfg, case STSERVER: { cntrl.t.ssta.s.mgTptSrvSta.tptAddr.type = CM_INET_IPV4ADDR_TYPE; - cntrl.t.ssta.s.mgTptSrvSta.tptAddr.u.ipv4TptAddr.port = ntohl(ipAddr); + cntrl.t.ssta.s.mgTptSrvSta.tptAddr.u.ipv4TptAddr.port = atoi(mg_cfg->port); if(ROK == cmInetAddr((S8*)mg_cfg->my_ipaddr, &ipAddr)) { cntrl.t.ssta.s.mgTptSrvSta.tptAddr.u.ipv4TptAddr.address = ntohl(ipAddr); From cb73fdf2f6e2e1189bc7d93615079a17dc855a5f Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 19 Jun 2012 17:30:03 -0400 Subject: [PATCH 253/822] Added parsing for additional parameters for UI team to test their code --- .../mod_media_gateway/media_gateway_xml.c | 29 +++++++++++++-- .../mod_media_gateway/mod_media_gateway.h | 36 ++++++++++++------- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index 710cc7e6c4..2d584ed0ed 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -19,7 +19,7 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) switch_xml_t cfg, xml, param, mg_interfaces, mg_interface, mg_peers, mg_peer, peer_interfaces ; switch_status_t status = SWITCH_STATUS_FALSE; switch_event_t *event = NULL; - const char *file = "megaco.conf"; + const char *file = "media_gateway.conf"; switch_xml_config_item_t *instructions = (profile ? get_instructions(profile) : NULL); int count; int idx; @@ -63,6 +63,11 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) break; } + if (!mg_interface) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error profile %s not found\n", profile->name); + return SWITCH_STATUS_FALSE; + } + /* go through the peer configuration and get the mg profile associated peers only */ if (!(mg_peers = switch_xml_child(cfg, "mg_peers"))) { goto done; @@ -144,10 +149,25 @@ static switch_xml_config_item_t *get_instructions(megaco_profile_t *profile) { static switch_xml_config_int_options_t opt_version = { SWITCH_TRUE, /* enforce min */ 1, - SWITCH_TRUE, /* Enforce Max */ + SWITCH_TRUE, /* enforce Max */ 3 }; + static switch_xml_config_int_options_t opt_termination_id_len = { + SWITCH_TRUE, /* enforce min */ + 1, + SWITCH_TRUE, /* enforce Max */ + 9 + }; + + static switch_xml_config_enum_item_t opt_default_codec_enum[] = { + { "PCMA", MEGACO_CODEC_PCMA}, + { "PCMU", MEGACO_CODEC_PCMU}, + { "G.729", MEGACO_CODEC_G729}, + { "G.723.1", MEGACO_CODEC_G723_1}, + { "ILBC", MEGACO_CODEC_ILBC }, + }; + switch_xml_config_item_t instructions[] = { /* parameter name type reloadable pointer default value options structure */ SWITCH_CONFIG_ITEM("protocol", SWITCH_CONFIG_STRING, CONFIG_RELOADABLE, &profile->protocol_type, "MEGACO", &switch_config_string_strdup, "", "MG Protocol type"), @@ -156,6 +176,11 @@ static switch_xml_config_item_t *get_instructions(megaco_profile_t *profile) { SWITCH_CONFIG_ITEM("port", SWITCH_CONFIG_STRING, 0, &profile->port, "2944", &switch_config_string_strdup, "", "port"), SWITCH_CONFIG_ITEM("domain-name", SWITCH_CONFIG_STRING, 0, &profile->my_domain, "", &switch_config_string_strdup, "", "domain name"), SWITCH_CONFIG_ITEM("message-identifier", SWITCH_CONFIG_STRING, 0, &profile->mid, "", &switch_config_string_strdup, "", "message identifier "), + + SWITCH_CONFIG_ITEM("default-codec", SWITCH_CONFIG_ENUM, CONFIG_RELOADABLE, &profile->default_codec, "PCMU", &opt_default_codec_enum, "", "default codec"), + SWITCH_CONFIG_ITEM("rtp-port-range", SWITCH_CONFIG_STRING, CONFIG_REQUIRED, &profile->rtp_port_range, "1-65535", &switch_config_string_strdup, "", "rtp port range"), + SWITCH_CONFIG_ITEM("rtp-termination-id-prefix", SWITCH_CONFIG_STRING, CONFIG_RELOADABLE, &profile->rtp_termination_id_prefix, "", &switch_config_string_strdup, "", "rtp termination prefix"), + SWITCH_CONFIG_ITEM("rtp-termination-id-len", SWITCH_CONFIG_INT, CONFIG_RELOADABLE, &profile->rtp_termination_id_len, "", &opt_termination_id_len, "", "rtp termination id"), SWITCH_CONFIG_ITEM_END() }; diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index 2e0db8cb62..d4c6e43077 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -32,6 +32,14 @@ typedef enum { PF_RUNNING = (1 << 0) } megaco_profile_flags_t; +typedef enum { + MEGACO_CODEC_PCMA, + MEGACO_CODEC_PCMU, + MEGACO_CODEC_G729, + MEGACO_CODEC_G723_1, + MEGACO_CODEC_ILBC, +} megaco_codec_t; + typedef struct mg_peer_profile_s{ char *name; switch_memory_pool_t *pool; @@ -47,18 +55,22 @@ typedef struct mg_peer_profile_s{ typedef struct megaco_profile_s { char *name; - switch_memory_pool_t *pool; - switch_thread_rwlock_t *rwlock; /* < Reference counting rwlock */ - megaco_profile_flags_t flags; - int idx; /* Trillium MEGACO SAP identification*/ - char* mid; /* MG H.248 MID */ - char* my_domain; /* local domain name */ - char* my_ipaddr; /* local domain name */ - char* port; /* port */ - char* protocol_type; /* MEGACO/MGCP */ - int protocol_version; /* Protocol supported version */ - int total_peers; - char* peer_list[MG_MAX_PEERS]; /* MGC Peer ID LIST */ + switch_memory_pool_t *pool; + switch_thread_rwlock_t *rwlock; /* < Reference counting rwlock */ + megaco_profile_flags_t flags; + int idx; /* Trillium MEGACO SAP identification*/ + char* mid; /* MG H.248 MID */ + char* my_domain; /* local domain name */ + char* my_ipaddr; /* local domain name */ + char* port; /* port */ + char* protocol_type; /* MEGACO/MGCP */ + int protocol_version; /* Protocol supported version */ + int total_peers; + megaco_codec_t default_codec; + char* rtp_port_range; + char* rtp_termination_id_prefix; + int rtp_termination_id_len; + char* peer_list[MG_MAX_PEERS]; /* MGC Peer ID LIST */ } megaco_profile_t; From ae17b90f68f411d5d27420282adedaac26fab417 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 19 Jun 2012 17:54:01 -0400 Subject: [PATCH 254/822] Changed megaco commands to mg --- .../mod_media_gateway/mod_media_gateway.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 322dbd4221..bcc66cc396 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -66,16 +66,16 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load) switch_core_hash_init(&megaco_globals.peer_profile_hash, pool); switch_thread_rwlock_create(&megaco_globals.peer_profile_rwlock, pool); - SWITCH_ADD_API(api_interface, "megaco", "megaco", megaco_function, MEGACO_FUNCTION_SYNTAX); + SWITCH_ADD_API(api_interface, "mg", "media_gateway", megaco_function, MEGACO_FUNCTION_SYNTAX); - switch_console_set_complete("add megaco profile ::megaco::list_profiles start"); - switch_console_set_complete("add megaco profile ::megaco::list_profiles stop"); - switch_console_set_complete("add megaco profile ::megaco::list_profiles status"); - switch_console_set_complete("add megaco profile ::megaco::list_profiles xmlstatus"); - switch_console_set_complete("add megaco profile ::megaco::list_profiles peerxmlstatus"); - switch_console_set_complete("add megaco logging ::megaco::list_profiles enable"); - switch_console_set_complete("add megaco logging ::megaco::list_profiles disable"); - switch_console_add_complete_func("::megaco::list_profiles", list_profiles); + switch_console_set_complete("add mg profile ::mg::list_profiles start"); + switch_console_set_complete("add mg profile ::mg::list_profiles stop"); + switch_console_set_complete("add mg profile ::mg::list_profiles status"); + switch_console_set_complete("add mg profile ::mg::list_profiles xmlstatus"); + switch_console_set_complete("add mg profile ::mg::list_profiles peerxmlstatus"); + switch_console_set_complete("add mg logging ::mg::list_profiles enable"); + switch_console_set_complete("add mg logging ::mg::list_profiles disable"); + switch_console_add_complete_func("::mg::list_profiles", list_profiles); /* Initialize MEGACO Stack */ From 6aa8c9b80dcf77dba76b96f0da62a99953dfd04c Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 19 Jun 2012 22:35:37 -0400 Subject: [PATCH 255/822] freetdm: Improvements to ftdm core flag CLI command --- libs/freetdm/src/ftdm_io.c | 210 +++++++++++++++--- libs/freetdm/src/include/private/ftdm_types.h | 4 + 2 files changed, 186 insertions(+), 28 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 78e65dfe88..bdb66c635a 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -40,6 +40,7 @@ #define _GNU_SOURCE #include "private/ftdm_core.h" #include +#include #ifdef WIN32 #include #endif @@ -66,7 +67,8 @@ static ftdm_status_t ftdm_call_set_call_id(ftdm_channel_t *fchan, ftdm_caller_da static ftdm_status_t ftdm_call_clear_call_id(ftdm_caller_data_t *caller_data); static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan); static ftdm_status_t ftdm_channel_sig_indicate(ftdm_channel_t *ftdmchan, ftdm_channel_indication_t indication, ftdm_usrmsg_t *usrmsg); - +static const char *channel_val2str(unsigned long long flag); +static unsigned long long channel_str2val(const char *flag_name); static int time_is_init = 0; @@ -4339,7 +4341,7 @@ static struct { ftdm_io_interface_t *pika_interface; } interfaces; -static void print_channels_by_flag(ftdm_stream_handle_t *stream, int32_t flagval, int not, int *count) +static void print_channels_by_flag(ftdm_stream_handle_t *stream, ftdm_span_t *inspan, uint32_t inchan_id, int32_t flagval, int not, int *count) { ftdm_hash_iterator_t *i = NULL; ftdm_span_t *span; @@ -4349,40 +4351,85 @@ static void print_channels_by_flag(ftdm_stream_handle_t *stream, int32_t flagval const void *key = NULL; void *val = NULL; uint32_t flag = (1 << flagval); + int mycount = 0; *count = 0; ftdm_mutex_lock(globals.mutex); - for (i = hashtable_first(globals.span_hash); i; i = hashtable_next(i)) { - hashtable_this(i, &key, NULL, &val); - if (!key || !val) { - break; - } - span = val; - citer = ftdm_span_get_chan_iterator(span, NULL); + if (inspan) { + citer = ftdm_span_get_chan_iterator(inspan, NULL); if (!citer) { - continue; + goto end; } for (curr = citer ; curr; curr = ftdm_iterator_next(curr)) { fchan = ftdm_iterator_current(curr); - if (not && !ftdm_test_flag(fchan, flag)) { - stream->write_function(stream, "[s%dc%d][%d:%d] has not flag %d\n", - fchan->span_id, fchan->chan_id, - fchan->physical_span_id, fchan->physical_chan_id, - flagval); - (*count)++; - } else if (!not && ftdm_test_flag(fchan, flag)) { - stream->write_function(stream, "[s%dc%d][%d:%d] has flag %d\n", - fchan->span_id, fchan->chan_id, - fchan->physical_span_id, fchan->physical_chan_id, - flagval); - (*count)++; + if (!inchan_id || inchan_id == fchan->chan_id) { + if (not) { + if (!ftdm_test_flag(fchan, flag)) { + stream->write_function(stream, "[s%dc%d][%d:%d] flag !%d(!%s) ON \n", + fchan->span_id, fchan->chan_id, + fchan->physical_span_id, fchan->physical_chan_id, + flagval, channel_val2str(flagval)); + + mycount++; + } else { + stream->write_function(stream, "[s%dc%d][%d:%d] flag !%d(!%s) OFF \n", + fchan->span_id, fchan->chan_id, + fchan->physical_span_id, fchan->physical_chan_id, + flagval, channel_val2str(flagval)); + } + } else if (!not) { + if (ftdm_test_flag(fchan, flag)) { + stream->write_function(stream, "[s%dc%d][%d:%d] flag %d(%s) ON\n", + fchan->span_id, fchan->chan_id, + fchan->physical_span_id, fchan->physical_chan_id, + flagval, channel_val2str(flagval)); + + mycount++; + } else { + stream->write_function(stream, "[s%dc%d][%d:%d] flag %d(%s) OFF \n", + fchan->span_id, fchan->chan_id, + fchan->physical_span_id, fchan->physical_chan_id, + flagval, channel_val2str(flagval)); + } + } } } ftdm_iterator_free(citer); - } + } else { + for (i = hashtable_first(globals.span_hash); i; i = hashtable_next(i)) { + hashtable_this(i, &key, NULL, &val); + if (!key || !val) { + break; + } + span = val; + citer = ftdm_span_get_chan_iterator(span, NULL); + if (!citer) { + continue; + } + for (curr = citer ; curr; curr = ftdm_iterator_next(curr)) { + fchan = ftdm_iterator_current(curr); + if (not && !ftdm_test_flag(fchan, flag)) { + stream->write_function(stream, "[s%dc%d][%d:%d] has not flag %d\n", + fchan->span_id, fchan->chan_id, + fchan->physical_span_id, fchan->physical_chan_id, + flagval); + mycount++; + } else if (!not && ftdm_test_flag(fchan, flag)) { + stream->write_function(stream, "[s%dc%d][%d:%d] has flag %d\n", + fchan->span_id, fchan->chan_id, + fchan->physical_span_id, fchan->physical_chan_id, + flagval); + mycount++; + } + } + ftdm_iterator_free(citer); + } + } + *count = mycount; +end: ftdm_mutex_unlock(globals.mutex); } @@ -4434,12 +4481,88 @@ static void print_core_usage(ftdm_stream_handle_t *stream) { stream->write_function(stream, "--------------------------------------------------------------------------------\n" - "ftdm core state [!] - List all channels in or not in the given state\n" - "ftdm core flag - List all channels with the given flag value set\n" + "ftdm core state [!] - List all channels in or not in the given state\n" + "ftdm core flag [!] [] [] - List all channels with the given flag value set\n" "ftdm core calls - List all known calls to the FreeTDM core\n" "--------------------------------------------------------------------------------\n"); } +typedef struct channel_flags_str { + const char *name; + unsigned long long channel_flag; +} channel_flag_str_t; + +static channel_flag_str_t channel_flag_strs[] = { + { "configured" , FTDM_CHANNEL_CONFIGURED}, + { "ready", FTDM_CHANNEL_READY}, + { "open", FTDM_CHANNEL_OPEN}, + { "dtmf-detect", FTDM_CHANNEL_DTMF_DETECT}, + { "suppress-dtmf", FTDM_CHANNEL_SUPRESS_DTMF}, + { "transcode", FTDM_CHANNEL_TRANSCODE}, + { "buffer", FTDM_CHANNEL_BUFFER}, + { "in-thread", FTDM_CHANNEL_INTHREAD}, + { "wink", FTDM_CHANNEL_WINK}, + { "flash", FTDM_CHANNEL_FLASH}, + { "state-change", FTDM_CHANNEL_STATE_CHANGE}, + { "hold", FTDM_CHANNEL_HOLD}, + { "in-use", FTDM_CHANNEL_INUSE}, + { "off-hook", FTDM_CHANNEL_OFFHOOK}, + { "ringing", FTDM_CHANNEL_RINGING}, + { "progress-detect", FTDM_CHANNEL_PROGRESS_DETECT}, + { "callerid-detect", FTDM_CHANNEL_CALLERID_DETECT}, + { "outbound", FTDM_CHANNEL_OUTBOUND}, + { "suspended", FTDM_CHANNEL_SUSPENDED}, + { "3-way", FTDM_CHANNEL_3WAY}, + { "progress", FTDM_CHANNEL_PROGRESS}, + { "media", FTDM_CHANNEL_MEDIA}, + { "answered", FTDM_CHANNEL_ANSWERED}, + { "mute", FTDM_CHANNEL_MUTE}, + { "use-rx-gain", FTDM_CHANNEL_USE_RX_GAIN}, + { "use-tx-gain", FTDM_CHANNEL_USE_TX_GAIN}, + { "in-alarm", FTDM_CHANNEL_IN_ALARM}, + { "sig-up", FTDM_CHANNEL_SIG_UP}, + { "user-hangup", FTDM_CHANNEL_USER_HANGUP}, + { "rx-disabled", FTDM_CHANNEL_RX_DISABLED}, + { "tx-disabled", FTDM_CHANNEL_TX_DISABLED}, + { "call-started", FTDM_CHANNEL_CALL_STARTED}, + { "non-block", FTDM_CHANNEL_NONBLOCK}, + { "ind-ack-pending", FTDM_CHANNEL_IND_ACK_PENDING}, + { "blocking", FTDM_CHANNEL_BLOCKING}, + { "media", FTDM_CHANNEL_DIGITAL_MEDIA}, + { "native-sigbridge", FTDM_CHANNEL_NATIVE_SIGBRIDGE}, + { "invalid", FTDM_CHANNEL_MAX_FLAG}, +}; + +static unsigned long long channel_str2val(const char *flag_name) +{ + int i; + for (i = 0; i < ftdm_array_len(channel_flag_strs); i++) { + if (!strcasecmp(channel_flag_strs[i].name, flag_name)) { + return channel_flag_strs[i].channel_flag; + } + } + return FTDM_CHANNEL_MAX_FLAG; +} + +static const char *channel_val2str(unsigned long long flag) +{ + int i; + for (i = 0; i < ftdm_array_len(channel_flag_strs); i++) { + if (channel_flag_strs[i].channel_flag == flag) { + return channel_flag_strs[i].name; + } + } + return channel_flag_strs[FTDM_CHANNEL_MAX_FLAG].name; +} + +static void print_channel_flag_values(ftdm_stream_handle_t *stream) +{ + int i; + for (i = 0; i < ftdm_array_len(channel_flag_strs); i++) { + stream->write_function(stream, "%s\n", channel_flag_strs[i].name); + } +} + static char *handle_core_command(const char *cmd) { char *mycmd = NULL; @@ -4449,11 +4572,12 @@ static char *handle_core_command(const char *cmd) char *argv[10] = { 0 }; char *state = NULL; char *flag = NULL; - uint32_t flagval = 0; + unsigned long long flagval = 0; uint32_t current_call_id = 0; ftdm_caller_data_t *calldata = NULL; ftdm_channel_t *fchan = NULL; ftdm_channel_state_t i = FTDM_CHANNEL_STATE_INVALID; + ftdm_span_t *fspan = NULL; ftdm_stream_handle_t stream = { 0 }; FTDM_STANDARD_STREAM(stream); @@ -4494,6 +4618,7 @@ static char *handle_core_command(const char *cmd) print_channels_by_state(&stream, i, not, &count); stream.write_function(&stream, "\nTotal channels %s %s: %d\n", not ? "not in state" : "in state", ftdm_channel_state2str(i), count); } else if (!strcasecmp(argv[0], "flag")) { + uint32_t chan_id = 0; if (argc < 2) { stream.write_function(&stream, "core flag command requires an argument\n"); print_core_usage(&stream); @@ -4504,8 +4629,37 @@ static char *handle_core_command(const char *cmd) not = 1; flag++; } - flagval = atoi(flag); - print_channels_by_flag(&stream, flagval, not, &count); + + if (isalpha(flag[0])) { + flagval = channel_str2val(flag); + if (flagval == FTDM_CHANNEL_MAX_FLAG) { + stream.write_function(&stream, "\nInvalid channel flag value. Possible channel flags\n"); + print_channel_flag_values(&stream); + goto done; + } + } else { + flagval = atoi(flag); + } + + /* Specific span specified */ + if (argv[2]) { + ftdm_span_find_by_name(argv[2], &fspan); + if (!fspan) { + stream.write_function(&stream, "-ERR span:%s not found\n", argv[2]); + goto done; + } + } + + /* Specific channel specified */ + if (argv[3]) { + chan_id = atoi(argv[3]); + if (chan_id >= ftdm_span_get_chan_count(fspan)) { + stream.write_function(&stream, "-ERR invalid channel %d\n", chan_id); + goto done; + } + } + + print_channels_by_flag(&stream, fspan, chan_id, flagval, not, &count); stream.write_function(&stream, "\nTotal channels %s %d: %d\n", not ? "without flag" : "with flag", flagval, count); } else if (!strcasecmp(argv[0], "calls")) { ftdm_mutex_lock(globals.call_id_mutex); diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h index 17e273c425..7df764e52f 100755 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -268,6 +268,10 @@ typedef enum { /*!< Native signaling bridge is enabled */ #define FTDM_CHANNEL_NATIVE_SIGBRIDGE (1ULL << 37) +/*!< This no more flags after this flag */ +#define FTDM_CHANNEL_MAX_FLAG (1ULL << 38) +/*! Date: Wed, 20 Jun 2012 00:35:10 -0400 Subject: [PATCH 256/822] Changed megaco.conf.xml to media_gateway.conf.xml --- .../conf/media_gateway.conf.xml | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/mod/endpoints/mod_media_gateway/conf/media_gateway.conf.xml diff --git a/src/mod/endpoints/mod_media_gateway/conf/media_gateway.conf.xml b/src/mod/endpoints/mod_media_gateway/conf/media_gateway.conf.xml new file mode 100644 index 0000000000..91f8f0cc63 --- /dev/null +++ b/src/mod/endpoints/mod_media_gateway/conf/media_gateway.conf.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 50e3e563da2a3e0ea795dcc2b226317749e8ab11 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 20 Jun 2012 00:38:05 -0400 Subject: [PATCH 257/822] Updated conf --- .../conf/media_gateway.conf.xml | 74 ++++++++++++------- 1 file changed, 48 insertions(+), 26 deletions(-) mode change 100644 => 100755 src/mod/endpoints/mod_media_gateway/conf/media_gateway.conf.xml diff --git a/src/mod/endpoints/mod_media_gateway/conf/media_gateway.conf.xml b/src/mod/endpoints/mod_media_gateway/conf/media_gateway.conf.xml old mode 100644 new mode 100755 index 91f8f0cc63..aa314fbe5b --- a/src/mod/endpoints/mod_media_gateway/conf/media_gateway.conf.xml +++ b/src/mod/endpoints/mod_media_gateway/conf/media_gateway.conf.xml @@ -1,28 +1,50 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + From a54ec05fdbffd34097210abff84c27099e434dc1 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 20 Jun 2012 02:06:31 -0400 Subject: [PATCH 258/822] fix for compilation error on 64-bit --- libs/freetdm/src/ftdm_io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index bdb66c635a..4dca25e452 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -4552,7 +4552,7 @@ static const char *channel_val2str(unsigned long long flag) return channel_flag_strs[i].name; } } - return channel_flag_strs[FTDM_CHANNEL_MAX_FLAG].name; + return "invalid"; } static void print_channel_flag_values(ftdm_stream_handle_t *stream) From 31d48a8c3af263a0f6133c874d15cf53420bba29 Mon Sep 17 00:00:00 2001 From: kapil Date: Wed, 20 Jun 2012 12:01:04 +0530 Subject: [PATCH 259/822] adding "<>" or "[]" from the code itself , instead of passing from config xml for MID field --- .../mod_media_gateway/media_gateway_xml.c | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index 2d584ed0ed..ba5c20aabb 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -12,6 +12,7 @@ static switch_xml_config_item_t *get_instructions(megaco_profile_t *profile) ; static switch_xml_config_item_t *get_peer_instructions(mg_peer_profile_t *profile) ; static int mg_sap_id; +static switch_status_t modify_mid(char* mid); /****************************************************************************************************************************/ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) @@ -57,6 +58,10 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) profile->total_peers++; } + if(SWITCH_STATUS_FALSE == (status = modify_mid(profile->mid))){ + goto done; + } + profile->idx = ++mg_sap_id; /* we should break from here , profile name should be unique */ @@ -92,6 +97,10 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) goto done; } + if(SWITCH_STATUS_FALSE == (status = modify_mid(peer_profile->mid))){ + goto done; + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"peer_profile name[%s], ipaddr[%s] port[%s], mid[%s] transport_type[%s], encoding_type[%s] \n", peer_profile->name, peer_profile->ipaddr, peer_profile->port,peer_profile->mid, peer_profile->transport_type, peer_profile->encoding_type); @@ -190,3 +199,54 @@ static switch_xml_config_item_t *get_instructions(megaco_profile_t *profile) { } /****************************************************************************************************************************/ + +static switch_status_t modify_mid(char* mid) +{ + char* dup = NULL; + char* val[10]; + int count; + + switch_assert(mid); + + /* If MID type is IP then add mid into [] brackets , + * If MID type is domain then add mid into <> brackets * + */ + + dup = strdup(mid); + count = switch_split(dup, '.', val); + + if(!count) { + /* Input string is not separated by '.', check if its separated by '-' as format could be xxx-xx-xxx/xxx-xx-xx-xxx */ + free(dup); + dup = strdup(mid); + if(0 == (count = switch_split(dup, '-', val))){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid input MID string[%s]\n",mid); + return SWITCH_STATUS_FALSE; + } + } + + if(('<' == val[0][0]) || ('[' == val[0][0])){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MID[%s] is already prefixed with proper brackets \n",mid); + return SWITCH_STATUS_SUCCESS; + } + + /*first check could be if count is 3 means domain name as generally we have xxx-xx-xxx/xxx.xx.xxx domain */ + if(3 == count){ + /* domain-type, add value into <> */ + free(dup); + dup = strdup(mid); + sprintf(mid,"<%s>",dup); + }else if(4 == count){ + /* IP address in xxx.xxx.xxx.xxx format */ + free(dup); + dup = strdup(mid); + sprintf(mid,"[%s]",dup); + }else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid input MID string[%s]\n",mid); + return SWITCH_STATUS_FALSE; + } + + + free(dup); + return SWITCH_STATUS_SUCCESS; +} From 2512694e4313f4491a795c28bb010cbca0c9a8b6 Mon Sep 17 00:00:00 2001 From: kapil Date: Wed, 20 Jun 2012 12:12:28 +0530 Subject: [PATCH 260/822] removing warnings --- .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index b8cc34480f..594fdb97ad 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -3167,11 +3167,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, " %s \n",g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[peer_id].name); len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.retryCount); -#ifdef BIT_64 - len = len + sprintf(buf + len, " %d \n", (int64_t) cfm.t.ssta.s.peerSta.assocSta.spAssocId); -#else - len = len + sprintf(buf + len, " %lld \n", (int64_t) cfm.t.ssta.s.peerSta.assocSta.spAssocId); -#endif + len = len + sprintf(buf + len, " %d \n", (int)cfm.t.ssta.s.peerSta.assocSta.spAssocId); len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcInProg); len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcLevel); @@ -3197,11 +3193,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); len = len + sprintf(buf + len," %s \n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.sctSapSta.state)); len = len + sprintf(buf + len," %s \n", (cfm.t.ssta.s.sctSapSta.endpOpen)?"END_POINT_OPENED_SUCCESSFULLY":"END_POINT_NOT_OPEN"); -#ifdef BIT_64 - len = len + sprintf(buf + len," %d \n", (int64_t) cfm.t.ssta.s.sctSapSta.spEndpId); -#else - len = len + sprintf(buf + len," %lld \n", (int64_t) cfm.t.ssta.s.sctSapSta.spEndpId); -#endif + len = len + sprintf(buf + len," %d \n", (int) cfm.t.ssta.s.sctSapSta.spEndpId); len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.nmbPrimRetry); len = len + sprintf(buf + len, "\n"); } From 7b97ff470f21c7e2afcacfce16767acdf602120f Mon Sep 17 00:00:00 2001 From: kapil Date: Wed, 20 Jun 2012 13:53:51 +0530 Subject: [PATCH 261/822] adding "xmlshow m2ua clusterstatus" CLI command. --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 142 ++++++++++++++---- .../ftmod_sangoma_ss7_m2ua.c | 24 ++- 2 files changed, 134 insertions(+), 32 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 594fdb97ad..1adf6dd607 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -124,6 +124,7 @@ static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream); static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char* m2ua_profile_name); static ftdm_status_t handle_show_m2ua_peer_status(ftdm_stream_handle_t *stream, char* m2ua_profile_name); +static ftdm_status_t handle_show_m2ua_cluster_status(ftdm_stream_handle_t *stream, char* m2ua_profile_name); static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream); static ftdm_status_t handle_show_nif_profile(ftdm_stream_handle_t *stream, char* profile_name); int get_assoc_resp_buf(char* buf,SbMgmt* cfm); @@ -427,10 +428,17 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha { char* profile_name = argv[++c]; c++; + /***************************************************************/ if(!strcasecmp(argv[c],"peerstatus")){ + /***************************************************************/ handle_show_m2ua_peer_status(stream, profile_name); - } - else{ + /***************************************************************/ + }else if(!strcasecmp(argv[c],"clusterstatus")){ + /***************************************************************/ + handle_show_m2ua_cluster_status(stream, profile_name); + /***************************************************************/ + } else{ + /***************************************************************/ stream->write_function(stream, "Unknown \"show m2ua \" command..\n"); goto handle_cli_error_argc; } @@ -933,6 +941,7 @@ static ftdm_status_t handle_print_usage(ftdm_stream_handle_t *stream) stream->write_function(stream, "ftdm ss7 xmlshow m2ua \n"); stream->write_function(stream, "ftdm ss7 xmlshow m2ua \n"); stream->write_function(stream, "ftdm ss7 xmlshow m2ua peerstatus\n"); + stream->write_function(stream, "ftdm ss7 xmlshow m2ua clusterstatus\n"); stream->write_function(stream, "ftdm ss7 xmlshow nif \n"); stream->write_function(stream, "ftdm ss7 xmlshow nif \n"); stream->write_function(stream, "\n"); @@ -3086,7 +3095,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); if(ftmod_m2ua_ssta_req(STMWGEN, 0x00, &cfm)) { - stream->write_function(stream," Request to Trillium M2UA layer failed \n"); + stream->write_function(stream," Request to layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3115,7 +3124,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, " %s \n", g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].name); if(ftmod_m2ua_ssta_req(STMWDLSAP,x,&cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to M2UA layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3129,7 +3138,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) memset((U8 *)&cfm, 0, sizeof(MwMgmt)); if(ftmod_m2ua_ssta_req(STMWCLUSTER,g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].clusterId,&cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to M2UA layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3160,7 +3169,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) if(LMW_PEER_DOWN != rsp.t.ssta.s.clusterSta.peerSt[idx].peerState){ if(ftmod_m2ua_ssta_req(STMWPEER, peer_id, &cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to M2UA layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3187,7 +3196,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) memset((U8 *)&cfm, 0, sizeof(MwMgmt)); if(ftmod_m2ua_ssta_req(STMWSCTSAP,x,&cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to M2UA layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3206,7 +3215,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); stream->write_function(stream,"\n%s\n",buf); - return FTDM_FAIL; + return FTDM_SUCCESS; } @@ -3259,7 +3268,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char len = len + sprintf(buf + len, " %s \n", m2ua_profile_name); if(ftmod_m2ua_ssta_req(STMWDLSAP,x,&cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to M2UA layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3272,7 +3281,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char } if(ftmod_m2ua_ssta_req(STMWCLUSTER, g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].clusterId, &cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to M2UA layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3298,7 +3307,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char memset((U8 *)&cfm, 0, sizeof(MwMgmt)); if(ftmod_m2ua_ssta_req(STMWPEER, rsp.t.ssta.s.clusterSta.peerSt[idx].peerId, &cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to M2UA layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3321,7 +3330,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char } if(ftmod_m2ua_ssta_req(STMWSCTSAP,x,&cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to M2UA layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3340,7 +3349,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char stream->write_function(stream,"\n%s\n",buf); - return FTDM_FAIL; + return FTDM_SUCCESS; } @@ -3366,7 +3375,7 @@ static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); if(ftmod_sctp_ssta_req(STSBGEN, 0x00, &cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to SCTP layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3386,7 +3395,7 @@ static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream) #ifdef LSB12 if(ftmod_sctp_ssta_req(STSBTMR, 0x00, &cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to SCTP layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3418,7 +3427,7 @@ static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); if(ftmod_sctp_ssta_req(STSBSCTSAP,x,&cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to SCTP layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3428,7 +3437,7 @@ static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream) } if(ftmod_sctp_ssta_req(STSBTSAP,x,&cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to SCTP layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3443,7 +3452,7 @@ static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, " SCT_ASSOC_STATE_CLOSED \n"); len = len + sprintf(buf + len, "\n"); }else{ - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to SCTP layer failed \n"); return FTDM_FAIL; } } else { @@ -3612,7 +3621,7 @@ static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char len = len + sprintf(buf + len, "\n"); if(ftmod_sctp_ssta_req(STSBSCTSAP,x,&cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to SCTP layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3622,7 +3631,7 @@ static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char } if(ftmod_sctp_ssta_req(STSBTSAP,x,&cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to SCTP layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3638,7 +3647,7 @@ static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char len = len + sprintf(buf + len, " SCT_ASSOC_STATE_CLOSED \n"); len = len + sprintf(buf + len, "\n"); }else{ - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to SCTP layer failed \n"); return FTDM_FAIL; } } else { @@ -3678,7 +3687,7 @@ static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); if(ftmod_nif_ssta_req(STNWGEN, 0x00, &cfm)) { - stream->write_function(stream," Request to Trillium NIF layer failed \n"); + stream->write_function(stream," Request to NIF layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3701,7 +3710,7 @@ static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); if(ftmod_nif_ssta_req(STNWDLSAP,x,&cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to NIF layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3723,7 +3732,7 @@ static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream) len = len + sprintf(buf + len, "\n"); stream->write_function(stream,"\n%s\n",buf); - return FTDM_FAIL; + return FTDM_SUCCESS; } /****************************************************************************** @@ -3770,7 +3779,7 @@ static ftdm_status_t handle_show_nif_profile(ftdm_stream_handle_t *stream, char* len = len + sprintf(buf + len, "\n"); if(ftmod_nif_ssta_req(STNWDLSAP,x,&cfm)) { - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to NIF layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3788,7 +3797,7 @@ static ftdm_status_t handle_show_nif_profile(ftdm_stream_handle_t *stream, char* stream->write_function(stream,"\n%s\n",buf); - return FTDM_FAIL; + return FTDM_SUCCESS; } /******************************************************************************/ @@ -3848,7 +3857,7 @@ static ftdm_status_t handle_show_m2ua_peer_status(ftdm_stream_handle_t *stream, peer = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[peer_id]; if(ftmod_m2ua_ssta_req(STMWPEER, peer_id, &cfm)) { - stream->write_function(stream," Request to Trillium M2UA layer failed \n"); + stream->write_function(stream," Request to M2UA layer failed \n"); return FTDM_FAIL; } else { len = len + sprintf(buf + len, "\n"); @@ -3867,7 +3876,7 @@ static ftdm_status_t handle_show_m2ua_peer_status(ftdm_stream_handle_t *stream, len = len + sprintf(buf + len, " SCT_ASSOC_STATE_CLOSED \n"); len = len + sprintf(buf + len, "\n"); }else{ - stream->write_function(stream," Request to Trillium SCTP layer failed \n"); + stream->write_function(stream," Request to SCTP layer failed \n"); return FTDM_FAIL; } } else { @@ -3879,7 +3888,82 @@ static ftdm_status_t handle_show_m2ua_peer_status(ftdm_stream_handle_t *stream, stream->write_function(stream,"\n%s\n",buf); - return FTDM_FAIL; + return FTDM_SUCCESS; +} + +/****************************************************************************** +* Fun: handle_show_m2ua_cluster_status() +* Desc: display requested m2ua profile cluster information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: Kapil Gupta +*******************************************************************************/ + +static ftdm_status_t handle_show_m2ua_cluster_status(ftdm_stream_handle_t *stream, char* m2ua_profile_name) +{ + char* xmlhdr = (char*)""; + char buf[4096]; + int x = 0x00; + int found = 0x00; + int len = 0x00; + int idx = 0x00; + MwMgmt cfm; + SbMgmt sctp_cfm; + sng_m2ua_cluster_cfg_t* clust = NULL; + sng_m2ua_cfg_t* m2ua = NULL; + + memset((U8 *)&cfm, 0, sizeof(MwMgmt)); + memset((U8 *)&sctp_cfm, 0, sizeof(SbMgmt)); + memset(&buf[0], 0, sizeof(buf)); + + len = len + sprintf(buf + len, "%s\n", xmlhdr); + + /*iterate through all the m2ua links and get required profile */ + x = 1; + while(xwrite_function(stream,"Requested M2UA profile[%s] not configured\n", m2ua_profile_name); + return FTDM_FAIL; + } + + m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x]; + clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[m2ua->clusterId]; + + if(ftmod_m2ua_ssta_req(STMWCLUSTER,g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].clusterId,&cfm)) { + stream->write_function(stream," Request to M2UA layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %s \n",clust->name); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_CLUSTER_STATE(cfm.t.ssta.s.clusterSta.state)); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.clusterSta.nmbPeer); + for(idx = 0; idx < cfm.t.ssta.s.clusterSta.nmbPeer; idx++) + { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %s \n", g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[cfm.t.ssta.s.clusterSta.peerSt[idx].peerId].name); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.clusterSta.peerSt[idx].peerId); + len = len + sprintf(buf + len, " %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.clusterSta.peerSt[idx].peerState)); + len = len + sprintf(buf + len, "\n"); + } + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.clusterSta.nmbActPeer); + + len = len + sprintf(buf + len, "\n"); + } + + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_SUCCESS; } /******************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c index ccaf3ce418..5b173bfc8b 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c @@ -793,10 +793,10 @@ static int ftmod_m2ua_peer_config(int id) ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_sctsap_config: M2UA SCTSAP for M2UA Intf Id[%d] config SUCCESS \n", id); } if(ftmod_m2ua_peer_config1(id, peer_id)){ - ftdm_log (FTDM_LOG_ERROR, " ftmod_m2ua_peer_config1: M2UA Peer configuration for M2UA Intf Id[%d] config FAILED \n", id); + ftdm_log (FTDM_LOG_ERROR, " ftmod_m2ua_peer_config1: M2UA Peer[%d] configuration for M2UA Intf Id[%d] config FAILED \n", peer_id, id); return 0x01; }else{ - ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_peer_config1: M2UA Peer configuration for M2UA Intf Id[%d] config SUCCESS \n", id); + ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_peer_config1: M2UA Peer[%d] configuration for M2UA Intf Id[%d] config SUCCESS \n", peer_id, id); } clust->sct_sap_id = id; @@ -813,13 +813,28 @@ static int ftmod_m2ua_peer_config(int id) static int ftmod_m2ua_sctsap_config(int sct_sap_id, int sctp_id) { int i; + int ret; Pst pst; MwMgmt cfg; + MwMgmt cfm; sng_sctp_link_t *sctp = &g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[sctp_id]; + + memset((U8 *)&cfg, 0, sizeof(MwMgmt)); + memset((U8 *)&cfm, 0, sizeof(MwMgmt)); memset((U8 *)&pst, 0, sizeof(Pst)); + /* check is sct_sap is already configured */ + if(!ftmod_m2ua_ssta_req(STMWSCTSAP, sct_sap_id, &cfm )){ + ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_sctsap_config: SCT SAP [%s] is already configured \n", sctp->name); + return 0x00; + } + + if(LCM_REASON_INVALID_SAP == cfm.cfm.reason){ + ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_sctsap_config: SCT SAP [%s] is not configured..configuring now \n", sctp->name); + } + smPstInit(&pst); pst.dstEnt = ENTMW; @@ -880,8 +895,11 @@ static int ftmod_m2ua_sctsap_config(int sct_sap_id, int sctp_id) cfg.t.cfg.s.sctSapCfg.reConfig.mem.region = S_REG; cfg.t.cfg.s.sctSapCfg.reConfig.mem.pool = S_POOL; - return (sng_cfg_m2ua (&pst, &cfg)); + if (0 == (ret = sng_cfg_m2ua (&pst, &cfg))){ + sctp->flags |= SNGSS7_CONFIGURED; + } + return ret; } /****************************************************************************************************/ From eae74df4e680a2e465512a59fbe8743a2c788b3b Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 20 Jun 2012 12:02:10 -0400 Subject: [PATCH 262/822] change loglevels and enable debug --- src/mod/endpoints/mod_media_gateway/media_gateway_stack.c | 2 ++ src/mod/endpoints/mod_media_gateway/mod_media_gateway.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c index abe46a5837..37fdabfda5 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c @@ -255,6 +255,8 @@ switch_status_t sng_mgco_start(megaco_profile_t* profile ) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mgco_mg_tsap_enable_cntrl SUCCESS \n"); } + mgco_mg_enble_debug(); + return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 58a8794fad..026151a6f2 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -116,14 +116,14 @@ void handle_sng_log(uint8_t level, char *fmt, ...) case SNG_LOGLEVEL_DEBUG: log_level = SWITCH_LOG_DEBUG; break; case SNG_LOGLEVEL_INFO: log_level = SWITCH_LOG_INFO; break; case SNG_LOGLEVEL_WARN: log_level = SWITCH_LOG_WARNING; break; - case SNG_LOGLEVEL_ERROR: log_level = SWITCH_LOG_ERROR; break; + case SNG_LOGLEVEL_ERROR: log_level = SWITCH_LOG_DEBUG; break; case SNG_LOGLEVEL_CRIT: log_level = SWITCH_LOG_CRIT; break; default: log_level = SWITCH_LOG_DEBUG; break; }; vsprintf(&print_buf[0], fmt, ptr); - switch_log_printf(SWITCH_CHANNEL_LOG, log_level, " MOD_MEGACO: %s \n", &print_buf[0]); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, log_level, " MOD_MEGACO: %s \n", &print_buf[0]); va_end(ptr); } From 166249b0b915d637dd478d87a3dd61cd3f7d6cc8 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 20 Jun 2012 12:30:08 -0400 Subject: [PATCH 263/822] Check in TDM and RTP controllable channels (incomplete) --- libs/freetdm/mod_freetdm/Makefile.in | 1 + libs/freetdm/mod_freetdm/mod_freetdm.c | 4 +- libs/freetdm/mod_freetdm/tdm.c | 413 +++++++++++ .../sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c | 45 +- .../libsofia-sip-ua/sdp/sofia-sip/sdp.h | 10 +- src/mod/endpoints/mod_sofia/Makefile.am | 2 +- src/mod/endpoints/mod_sofia/mod_sofia.c | 2 + src/mod/endpoints/mod_sofia/mod_sofia.h | 1 + src/mod/endpoints/mod_sofia/rtp.c | 653 ++++++++++++++++++ 9 files changed, 1110 insertions(+), 21 deletions(-) create mode 100644 libs/freetdm/mod_freetdm/tdm.c create mode 100644 src/mod/endpoints/mod_sofia/rtp.c diff --git a/libs/freetdm/mod_freetdm/Makefile.in b/libs/freetdm/mod_freetdm/Makefile.in index ceea0dfbba..33ca03b440 100644 --- a/libs/freetdm/mod_freetdm/Makefile.in +++ b/libs/freetdm/mod_freetdm/Makefile.in @@ -4,6 +4,7 @@ BASE=../../.. FT_DIR=.. VERBOSE=1 FTLA=$(FT_DIR)/libfreetdm.la +LOCAL_OBJS=tdm.o LOCAL_CFLAGS=-I$(FT_DIR)/src/include -I$(FT_DIR)/src/isdn/include $(FT_CFLAGS) LOCAL_LDFLAGS=-L$(FT_DIR) -lfreetdm include $(BASE)/build/modmake.rules diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 35690b1e24..c24ab4967e 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -873,7 +873,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc if (!tech_pvt->ftdmchan) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "no ftdmchan set in channel %s!\n", name); return SWITCH_STATUS_FALSE; - } + } span_id = ftdm_channel_get_span_id(tech_pvt->ftdmchan); chan_id = ftdm_channel_get_id(tech_pvt->ftdmchan); @@ -906,7 +906,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc ftdm_channel_wait(tech_pvt->ftdmchan, &wflags, ftdm_channel_get_io_interval(tech_pvt->ftdmchan) * 10); if (!(wflags & FTDM_WRITE)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Dropping frame! (write note ready) in channel %s device %d:%d!\n", name, span_id, chan_id); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Dropping frame! (write not ready) in channel %s device %d:%d!\n", name, span_id, chan_id); return SWITCH_STATUS_SUCCESS; } diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c new file mode 100644 index 0000000000..935411867b --- /dev/null +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -0,0 +1,413 @@ +/* +* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application +* Copyright (C) 2005-2011, Anthony Minessale II +* +* Version: MPL 1.1 +* +* The contents of this file are subject to the Mozilla Public License Version +* 1.1 (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" basis, +* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +* for the specific language governing rights and limitations under the +* License. +* +* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application +* +* The Initial Developer of the Original Code is +* Anthony Minessale II +* Portions created by the Initial Developer are Copyright (C) +* the Initial Developer. All Rights Reserved. +* +* Contributor(s): +* +* Mathieu Rene +* +* tdm.c -- FreeTDM Controllable Channel Module +* +*/ + +#include +#include "freetdm.h" + +void ctdm_init(switch_loadable_module_interface_t *module_interface); + +/* Parameters */ + +#define kSPAN_ID "span" +#define kCHAN_ID "chan" + +static struct { + switch_memory_pool_t *pool; + switch_endpoint_interface_t *endpoint_interface; +} ctdm; + +typedef struct { + int span_id; + int chan_id; + ftdm_channel_t *ftdm_channel; + switch_core_session_t *session; + switch_codec_t read_codec, write_codec; + switch_frame_t read_frame; +} ctdm_private_t; + +static switch_status_t channel_on_init(switch_core_session_t *session); +static switch_status_t channel_on_destroy(switch_core_session_t *session); +static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, + switch_memory_pool_t **pool, + switch_originate_flag_t flags, switch_call_cause_t *cancel_cause); +static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id); +static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id); +static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg); +static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf); + +switch_state_handler_table_t ctdm_state_handlers = { + .on_init = channel_on_init, + .on_destroy = channel_on_destroy +}; + +switch_io_routines_t ctdm_io_routines = { + .send_dtmf = channel_send_dtmf, + .outgoing_channel = channel_outgoing_channel, + .read_frame = channel_read_frame, + .write_frame = channel_write_frame, + .receive_message = channel_receive_message +}; + +void ctdm_init(switch_loadable_module_interface_t *module_interface) +{ + switch_endpoint_interface_t *endpoint_interface; + ctdm.pool = module_interface->pool; + endpoint_interface = switch_loadable_module_create_interface(module_interface, SWITCH_ENDPOINT_INTERFACE); + endpoint_interface->interface_name = "tdm"; + endpoint_interface->io_routines = &ctdm_io_routines; + endpoint_interface->state_handler = &ctdm_state_handlers; + ctdm.endpoint_interface = endpoint_interface; + +} + +static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, + switch_memory_pool_t **pool, + switch_originate_flag_t flags, switch_call_cause_t *cancel_cause) +{ + const char *szspanid = switch_event_get_header(var_event, kSPAN_ID), + *szchanid = switch_event_get_header(var_event, kCHAN_ID); + int chan_id; + int span_id; + + ftdm_span_t *span; + ftdm_channel_t *chan; + switch_channel_t *channel; + char name[128]; + const char *dname; + ftdm_codec_t codec; + uint32_t interval; + + ctdm_private_t *tech_pvt; + + if (zstr(szchanid) || zstr(szspanid)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Both "kSPAN_ID" and "kCHAN_ID" have to be set.\n"); + goto fail; + } + + chan_id = atoi(szchanid); + span_id = atoi(szspanid); + + + if (!(*new_session = switch_core_session_request(ctdm.endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, 0, pool))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't request session.\n"); + goto fail; + } + + channel = switch_core_session_get_channel(*new_session); + + if (ftdm_channel_open(span_id, chan_id, &chan) != FTDM_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't open span or channel.\n"); + goto fail; + } + + span = ftdm_channel_get_span(chan); + + tech_pvt = switch_core_session_alloc(*new_session, sizeof *tech_pvt); + tech_pvt->chan_id = chan_id; + tech_pvt->span_id = span_id; + tech_pvt->ftdm_channel = chan; + tech_pvt->session = *new_session; + switch_core_session_set_private(*new_session, tech_pvt); + + snprintf(name, sizeof(name), "tdm/%d:%d", span_id, chan_id); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect outbound channel %s\n", name); + switch_channel_set_name(channel, name); + + switch_channel_set_state(channel, CS_INIT); + + if (FTDM_SUCCESS != ftdm_channel_command(chan, FTDM_COMMAND_GET_CODEC, &codec)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to retrieve channel codec.\n"); + return SWITCH_STATUS_GENERR; + } + + if (FTDM_SUCCESS != ftdm_channel_command(chan, FTDM_COMMAND_GET_INTERVAL, &interval)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to retrieve channel interval.\n"); + return SWITCH_STATUS_GENERR; + } + + switch(codec) { + case FTDM_CODEC_ULAW: + { + dname = "PCMU"; + } + break; + case FTDM_CODEC_ALAW: + { + dname = "PCMA"; + } + break; + case FTDM_CODEC_SLIN: + { + dname = "L16"; + } + break; + default: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid codec value retrieved from channel, codec value: %d\n", codec); + goto fail; + } + } + + + if (switch_core_codec_init(&tech_pvt->read_codec, + dname, + NULL, + 8000, + interval, + 1, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); + goto fail; + } else { + if (switch_core_codec_init(&tech_pvt->write_codec, + dname, + NULL, + 8000, + interval, + 1, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); + switch_core_codec_destroy(&tech_pvt->read_codec); + goto fail; + } + } + + if (switch_core_session_set_read_codec(*new_session, &tech_pvt->read_codec) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set read codec?\n"); + goto fail; + } + + if (switch_core_session_set_write_codec(*new_session, &tech_pvt->write_codec) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set write codec?\n"); + } + + if (switch_core_session_thread_launch(*new_session) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't start session thread.\n"); + goto fail; + } + + return SWITCH_CAUSE_SUCCESS; + +fail: + + if (tech_pvt) { + if (tech_pvt->ftdm_channel) { + ftdm_channel_close(&tech_pvt->ftdm_channel); + } + + if (tech_pvt->read_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->read_codec); + } + + if (tech_pvt->write_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->write_codec); + } + } + + if (*new_session) { + switch_core_session_destroy(new_session); + } + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; +} + +static switch_status_t channel_on_init(switch_core_session_t *session) +{ + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_on_destroy(switch_core_session_t *session) +{ + ctdm_private_t *tech_pvt = switch_core_session_get_private(session); + + if ((tech_pvt = switch_core_session_get_private(session))) { + + if (tech_pvt->read_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->read_codec); + } + + if (tech_pvt->write_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->write_codec); + } + } + + ftdm_channel_close(&tech_pvt->ftdm_channel); + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id) +{ + ftdm_wait_flag_t wflags = FTDM_READ; + ftdm_status_t status; + ctdm_private_t *tech_pvt; + const char *name; + switch_channel_t *channel; + int chunk; + uint32_t span_id, chan_id; + ftdm_size_t len; + char dtmf[128] = ""; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + name = switch_channel_get_name(channel); + +top: + wflags = FTDM_READ; + chunk = ftdm_channel_get_io_interval(tech_pvt->ftdm_channel) * 2; + status = ftdm_channel_wait(tech_pvt->ftdm_channel, &wflags, chunk); + + + span_id = ftdm_channel_get_span_id(tech_pvt->ftdm_channel); + chan_id = ftdm_channel_get_id(tech_pvt->ftdm_channel); + + if (status == FTDM_FAIL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to read from channel %s device %d:%d!\n", name, span_id, chan_id); + goto fail; + } + + if (status == FTDM_TIMEOUT) { + goto top; + } + + if (!(wflags & FTDM_READ)) { + goto top; + } + + len = tech_pvt->read_frame.buflen; + if (ftdm_channel_read(tech_pvt->ftdm_channel, tech_pvt->read_frame.data, &len) != FTDM_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to read from channel %s device %d:%d!\n", name, span_id, chan_id); + } + + *frame = &tech_pvt->read_frame; + tech_pvt->read_frame.datalen = (uint32_t)len; + tech_pvt->read_frame.samples = tech_pvt->read_frame.datalen; + + if (ftdm_channel_get_codec(tech_pvt->ftdm_channel) == FTDM_CODEC_SLIN) { + tech_pvt->read_frame.samples /= 2; + } + + while (ftdm_channel_dequeue_dtmf(tech_pvt->ftdm_channel, dtmf, sizeof(dtmf))) { + switch_dtmf_t _dtmf = { 0, switch_core_default_dtmf_duration(0) }; + char *p; + for (p = dtmf; p && *p; p++) { + if (is_dtmf(*p)) { + _dtmf.digit = *p; + ftdm_log(FTDM_LOG_DEBUG, "Queuing DTMF [%c] in channel %s device %d:%d\n", *p, name, span_id, chan_id); + switch_channel_queue_dtmf(channel, &_dtmf); + } + } + } + + return SWITCH_STATUS_SUCCESS; + +fail: + return SWITCH_STATUS_GENERR; +} + +static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id) +{ + ftdm_wait_flag_t wflags = FTDM_WRITE; + ctdm_private_t *tech_pvt; + const char *name; + switch_channel_t *channel; + uint32_t span_id, chan_id; + ftdm_size_t len; + unsigned char data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0}; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + span_id = ftdm_channel_get_span_id(tech_pvt->ftdm_channel); + chan_id = ftdm_channel_get_id(tech_pvt->ftdm_channel); + + name = switch_channel_get_name(channel); + + if (switch_test_flag(frame, SFF_CNG)) { + frame->data = data; + frame->buflen = sizeof(data); + if ((frame->datalen = tech_pvt->write_codec.implementation->encoded_bytes_per_packet) > frame->buflen) { + goto fail; + } + memset(data, 255, frame->datalen); + } + + wflags = FTDM_WRITE; + ftdm_channel_wait(tech_pvt->ftdm_channel, &wflags, ftdm_channel_get_io_interval(tech_pvt->ftdm_channel) * 10); + + if (!(wflags & FTDM_WRITE)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Dropping frame! (write not ready) in channel %s device %d:%d!\n", name, span_id, chan_id); + return SWITCH_STATUS_SUCCESS; + } + + len = frame->datalen; + if (ftdm_channel_write(tech_pvt->ftdm_channel, frame->data, frame->buflen, &len) != FTDM_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Failed to write to channel %s device %d:%d!\n", name, span_id, chan_id); + } + + return SWITCH_STATUS_SUCCESS; + +fail: + return SWITCH_STATUS_GENERR; +} + +static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf) +{ + ctdm_private_t *tech_pvt = NULL; + char tmp[2] = ""; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + tmp[0] = dtmf->digit; + ftdm_channel_command(tech_pvt->ftdm_channel, FTDM_COMMAND_SEND_DTMF, tmp); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + return SWITCH_STATUS_SUCCESS; +} + diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c index 027544a00a..781c0963f8 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c +++ b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c @@ -81,6 +81,7 @@ struct sdp_parser_s { unsigned pr_insane : 1; unsigned pr_c_missing : 1; unsigned pr_config : 1; + unsigned pr_megaco : 1; }; #define is_posdigit(c) ((c) >= '1' && (c) <= '9') @@ -176,6 +177,7 @@ sdp_parse(su_home_t *home, char const msg[], issize_t msgsize, int flags) if (flags & sdp_f_config) p->pr_c_missing = 1, p->pr_config = 1; p->pr_mode_manual = (flags & sdp_f_mode_manual) != 0; + p->pr_megaco = (flags & sdp_f_megaco) != 0; p->pr_session_mode = sdp_sendrecv; parse_message(p); @@ -1502,8 +1504,18 @@ static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result) { while (*r) { unsigned long value; + if (((p->pr_config && r[0] == '*') || (p->pr_megaco && r[0] == MEGACO_CHOOSE_TOK)) && (r[1] == ' ' || r[1] == '\0')) { + PARSE_ALLOC(p, sdp_rtpmap_t, rm); - if (parse_ul(p, &r, &value, 128) == 0) { + *result = rm; result = &rm->rm_next; + + rm->rm_predef = 1; + rm->rm_any = 1; + rm->rm_encoding = "*"; + rm->rm_rate = 0; + + return; + } else if (parse_ul(p, &r, &value, 128) == 0 && value < 128) { PARSE_ALLOC(p, sdp_rtpmap_t, rm); assert(0 <= value && value < 128); @@ -1519,21 +1531,8 @@ static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result) rm->rm_encoding = ""; rm->rm_rate = 0; } - } - else if (p->pr_config && r[0] == '*' && (r[1] == ' ' || r[1] == '\0')) { - PARSE_ALLOC(p, sdp_rtpmap_t, rm); - - *result = rm; result = &rm->rm_next; - - rm->rm_predef = 1; - rm->rm_any = 1; - rm->rm_encoding = "*"; - rm->rm_rate = 0; - - return; - } - else { - parsing_error(p, "m= invalid format for RTP/AVT"); + } else { + parsing_error(p, "m= invalid format for RTP/AVP"); return; } @@ -1797,6 +1796,13 @@ static int parse_ul(sdp_parser_t *p, char **r, return 0; } + if (p->pr_megaco && *ul == MEGACO_CHOOSE_TOK) { + *result = MEGACO_CHOOSE; + (*r)++; + *r += strspn(*r, SPACE TAB); + return 0; + } + return -1; } @@ -1824,6 +1830,13 @@ static int parse_ull(sdp_parser_t *p, char **r, return 0; } + if (p->pr_megaco && *s == MEGACO_CHOOSE_TOK) { + *result = MEGACO_CHOOSE; + (*r)++; + *r += strspn(*r, SPACE TAB); + return 0; + } + return -1; } diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h b/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h index e4af3836a3..74d6adea4f 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h +++ b/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h @@ -24,6 +24,10 @@ #ifndef SDP_H #define SDP_H + +#define MEGACO_CHOOSE_TOK '$' +#define MEGACO_CHOOSE (UINT16_MAX + 1) + /**@file sofia-sip/sdp.h Simple SDP (RFC 2327) Interface. * * @author Pekka Pessi @@ -260,7 +264,7 @@ typedef enum { /** Media announcement. * * This structure describes one media type, e.g., audio. The description - * contains the transport address (IP address and port) used for the group, + * contains the transport address (IP address and port) used for the group,/Users/mrene/Downloads * the transport protocol used, the media formats or RTP payload types, and * optionally media-specific bandwidth specification, encryption key and * attributes. @@ -525,7 +529,9 @@ enum sdp_parse_flags_e { /** Do not generate or parse SDP mode */ sdp_f_mode_manual = 512, /** Always generate media-level mode attributes */ - sdp_f_mode_always = 1024 + sdp_f_mode_always = 1024, + /** Allow optional (choose) parameters */ + sdp_f_megaco = 2048 }; /** SDP parser handle. */ diff --git a/src/mod/endpoints/mod_sofia/Makefile.am b/src/mod/endpoints/mod_sofia/Makefile.am index fb0ab25e0b..efd6b2c385 100644 --- a/src/mod/endpoints/mod_sofia/Makefile.am +++ b/src/mod/endpoints/mod_sofia/Makefile.am @@ -9,7 +9,7 @@ SOFIAUA_BUILDDIR=$(SOFIA_BUILDDIR)/libsofia-sip-ua SOFIALA=$(SOFIAUA_BUILDDIR)/libsofia-sip-ua.la mod_LTLIBRARIES = mod_sofia.la -mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sip-dig.c mod_sofia.h +mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sip-dig.c rtp.c mod_sofia.h mod_sofia_la_CFLAGS = $(AM_CFLAGS) -I. $(SOFIA_CMD_LINE_CFLAGS) mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/bnf -I$(SOFIAUA_BUILDDIR)/bnf mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/http -I$(SOFIAUA_BUILDDIR)/http diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index e47fb85c46..0f598573c0 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -5634,6 +5634,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load) SWITCH_ADD_API(api_interface, "sofia_count_reg", "Count Sofia registration", sofia_count_reg_function, "[profile/]@"); SWITCH_ADD_API(api_interface, "sofia_dig", "SIP DIG", sip_dig_function, ""); SWITCH_ADD_CHAT(chat_interface, SOFIA_CHAT_PROTO, sofia_presence_chat_send); + + crtp_init(*module_interface); /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_SUCCESS; diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 217c95af8c..fa4fdc0b10 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -1152,3 +1152,4 @@ void sofia_process_dispatch_event(sofia_dispatch_event_t **dep); char *sofia_glue_get_host(const char *str, switch_memory_pool_t *pool); void sofia_presence_check_subscriptions(sofia_profile_t *profile, time_t now); void sofia_msg_thread_start(int idx); +void crtp_init(switch_loadable_module_interface_t *module_interface); diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c new file mode 100644 index 0000000000..8920e684a7 --- /dev/null +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -0,0 +1,653 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2011, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Mathieu Rene + * + * rtp.c -- RTP Controllable Channel Module + * + */ + +#include +#include "mod_sofia.h" + +#define kRSDP "r_sdp" +#define kLSDP "l_sdp" +#define kBINDADDRESS "bind_address" +#define kCODECSTRING "codec_string" + +static struct { + switch_memory_pool_t *pool; + switch_endpoint_interface_t *endpoint_interface; +} crtp; + +typedef struct { + switch_core_session_t *session; + switch_channel_t *channel; + switch_codec_t read_codec, write_codec; + switch_frame_t read_frame; + + switch_rtp_bug_flag_t rtp_bugs; + switch_rtp_t *rtp_session; + + const char *bind_address; + + + const switch_codec_implementation_t *negotiated_codecs[SWITCH_MAX_CODECS]; + int num_negotiated_codecs; + + char *origin; + + int local_port; + +} crtp_private_t; + +static switch_status_t channel_on_init(switch_core_session_t *session); +static switch_status_t channel_on_destroy(switch_core_session_t *session); +static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, + switch_memory_pool_t **pool, + switch_originate_flag_t flags, switch_call_cause_t *cancel_cause); +static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id); +static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id); +static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg); +static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf); + +switch_state_handler_table_t crtp_state_handlers = { + .on_init = channel_on_init, + .on_destroy = channel_on_destroy +}; + +switch_io_routines_t crtp_io_routines = { + .outgoing_channel = channel_outgoing_channel, + .read_frame = channel_read_frame, + .write_frame = channel_write_frame, + .receive_message = channel_receive_message, + .send_dtmf = channel_send_dtmf +}; + +SWITCH_STANDARD_API(test_function) +{ + return SWITCH_STATUS_SUCCESS; +} + +void crtp_init(switch_loadable_module_interface_t *module_interface) +{ + switch_endpoint_interface_t *endpoint_interface; + switch_api_interface_t *api_interface; + crtp.pool = module_interface->pool; + endpoint_interface = switch_loadable_module_create_interface(module_interface, SWITCH_ENDPOINT_INTERFACE); + endpoint_interface->interface_name = "rtp"; + endpoint_interface->io_routines = &crtp_io_routines; + endpoint_interface->state_handler = &crtp_state_handlers; + crtp.endpoint_interface = endpoint_interface; + +// SWITCH_ADD_API(api_interface, "rtp_test", "test", test_function, ""); +} + + +typedef struct parsed_sdp_s { + const char *c; /*!< Connection */ + + +} parsed_sdp_t; + + +//static switch_status_t check_codec + +/* + * Setup the local RTP side + * A lot of values can be chosen by the MG, those will have $ as a placeholder. + * We need to validate the SDP, making sure we can support everything that's offered on our behalf, + * amend it if we don't support everything, or systematically reject it if we cannot support it. + * + * Would this function be called using NULL as l_sdp, we will generate an SDP payload. + */ + +static switch_status_t setup_local_rtp(crtp_private_t *tech_pvt, const char *l_sdp, const char *codec_string) +{ + switch_core_session_t const * session = tech_pvt->session; + int num_codecs; + const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS] = { 0 }; + + char *codec_order[SWITCH_MAX_CODECS] = { 0 }; + int codec_order_last; + + + /* Load in the list of codecs we support. If we have a codec string we use our priorities first */ + if (codec_string) { + char *tmp_codec_string; + if ((tmp_codec_string = switch_core_session_strdup(tech_pvt->session, codec_string))) { + codec_order_last = switch_separate_string(tmp_codec_string, ',', codec_order, SWITCH_MAX_CODECS); + num_codecs = switch_loadable_module_get_codecs_sorted(codecs, SWITCH_MAX_CODECS, codec_order, codec_order_last); + } + } else { + num_codecs = switch_loadable_module_get_codecs(codecs, switch_arraylen(codecs)); + } + + /* TODO: Look at remote settings */ + + if (zstr(l_sdp)) { + /* Generate a local SDP here */ + const char *sdpbuf = switch_core_session_sprintf(session, "v=0\nIN IP4 %s\nm=audio %d RTP/AVP %d"); + + } else { + /* Parse the SDP and remove anything we cannot support, then validate it to make sure it contains at least one codec + * so that we reject invalid ones. */ +#if 1 + uint8_t match = 0; + int first = 0, last = 0; + int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0; + int sendonly = 0, recvonly = 0; + int greedy = 0, x = 0, skip = 0, mine = 0; + int got_crypto = 0, got_audio = 0, got_avp = 0, got_savp = 0, got_udptl = 0; +#endif + int sdp_modified = 0; + int cur_codec = 0; + + sdp_parser_t *parser = NULL; + sdp_session_t *sdp, *lsdp; + sdp_media_t *m; + sdp_attribute_t *attr; + su_home_t *sdp_home; + + if (!(parser = sdp_parse(NULL, l_sdp, (int) strlen(l_sdp), sdp_f_megaco /* accept $ values */ | sdp_f_insane /* accept omitted o= */))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Malformed SDP\n"); + goto fail; + } + + if (!(sdp = sdp_session(parser))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't get session from sdp.\n"); + goto fail; + } + sdp_home = sdp_parser_home(parser); + for (m = sdp->sdp_media; m; m = m->m_next) { + + if (m->m_type == sdp_media_audio) { + sdp_rtpmap_t *map; + + for (attr = m->m_attributes; attr; attr = attr->a_next) { + if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) { + ptime = atoi(attr->a_value); + } else if (!strcasecmp(attr->a_name, "maxptime") && attr->a_value) { + maxptime = atoi(attr->a_value); + } + } + + sdp_connection_t *connection; + connection = sdp->sdp_connection; + if (m->m_connections) { + connection = m->m_connections; + } + + /* Check for wildcards in m= (media) and c= (connection) */ + if (!zstr(connection->c_address)) { + if (!strcmp(connection->c_address, "$")) { + connection->c_address = su_strdup(sdp_home, tech_pvt->bind_address); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Using bind address: %s\n", tech_pvt->bind_address); + switch_channel_set_variable(tech_pvt->channel, kBINDADDRESS, tech_pvt->bind_address); + sdp_modified = 1; + } else if (strcmp(connection->c_address, tech_pvt->bind_address)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MGC requested to bind on [%s] which is different than the configuration [%s]\n", + connection->c_address, tech_pvt->bind_address); + goto fail; + } + + if (m->m_port == MEGACO_CHOOSE) { + tech_pvt->local_port = m->m_port = switch_rtp_request_port(tech_pvt->bind_address); + switch_channel_set_variable_printf(tech_pvt->channel, "rtp_local_port", "%d", tech_pvt->local_port); + if (!tech_pvt->local_port) { + /* Port request failed */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No available RTP ports on [%s]\n", tech_pvt->bind_address); + goto fail; + } + sdp_modified = 1; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Using local port: %d\n", tech_pvt->local_port); + } + } + + /* Validate codecs */ + for (map = m->m_rtpmaps; map; map = map->rm_next) { + if (map->rm_any) { + /* Pick our first favorite codec */ + if (codecs[cur_codec]) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Choosing a codec: %s/%d\n", codecs[cur_codec]->iananame, codecs[cur_codec]->ianacode); + map->rm_encoding = su_strdup(sdp_home, codecs[cur_codec]->iananame); + map->rm_pt = codecs[cur_codec]->ianacode; + map->rm_any = 0; + map->rm_predef = codecs[cur_codec]->ianacode < 96; + cur_codec++; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No more codecs in preferences!\n"); + goto fail; + } + } + } + } else if (m->m_type == sdp_media_image && m->m_port) { + /* TODO: Handle T38 */ + + } + } + char sdpbuf[2048] = ""; + sdp_printer_t *printer = sdp_print(sdp_home, sdp, sdpbuf, sizeof(sdpbuf), 0); + switch_channel_set_variable(tech_pvt->channel, kLSDP, sdpbuf); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Setting local SDP: [%s]\n", sdpbuf); + sdp_printer_free(printer); + + goto done; + + fail: + if (tech_pvt->local_port) { + switch_rtp_release_port(tech_pvt->bind_address, tech_pvt->local_port); + } + + if (parser) { + sdp_parser_free(parser); + } + + return SWITCH_STATUS_FALSE; + } + +done: + return SWITCH_STATUS_SUCCESS; + +} + +#if 0 +static void setup_rtp(crtp_private_t *tech_pvt, const char *r_sdp, const char *l_sdp) +{ + switch_core_session_t const * session = tech_pvt->session; + uint8_t match = 0; + int first = 0, last = 0; + int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0; + int sendonly = 0, recvonly = 0; + int greedy = 0, x = 0, skip = 0, mine = 0; + int got_crypto = 0, got_audio = 0, got_avp = 0, got_savp = 0, got_udptl = 0; + + sdp_parser_t *parser = NULL, *l_parser = NULL; + sdp_session_t *sdp, *lsdp; + sdp_media_t *m; + sdp_attribute_t *attr; + + + int scrooge = 0; + + + if (zstr(r_sdp)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No SDP\n"); + goto fail; + } + + if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Malformed SDP\n"); + goto fail; + } + + if (!(sdp = sdp_session(parser))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't get session from sdp.\n"); + goto fail; + } + + for (m = sdp->sdp_media; m; m = m->m_next) { + sdp_connection_t *connection; + ptime = dptime; + maxptime = dmaxptime; + + if (m->m_proto == sdp_proto_srtp) { + got_savp++; + } else if (m->m_proto == sdp_proto_rtp) { + got_avp++; + } else if (m->m_proto == sdp_proto_udptl) { + got_udptl++; + } + + if (got_udptl && m->m_type == sdp_media_image && m->m_port) { + //switch_t38_options_t *t38_options = tech_process_udptl(tech_pvt, sdp, m); + + /* TODO: Process T38 */ + + } else if (m->m_type == sdp_media_audio && m->m_port && !got_audio) { + sdp_rtpmap_t *map; + + connection = sdp->sdp_connection; + if (m->m_connections) { + connection = m->m_connections; + } + + if (!connection) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n"); + match = 0; + break; + } + + /* Begin Codec Negotiation */ + for (map = m->m_rtpmaps; map; map = map->rm_next) { + int32_t i; + uint32_t near_rate = 0; + const switch_codec_implementation_t *mimp = NULL, *near_match = NULL; + const char *rm_encoding; + uint32_t map_bit_rate = 0; + int codec_ms = 0; + switch_codec_fmtp_t codec_fmtp = { 0 }; + + if (x++ < skip) { + continue; + } + + if (!(rm_encoding = map->rm_encoding)) { + rm_encoding = ""; + } + + if (!strcasecmp(rm_encoding, "telephone-event")) { + if (!best_te || map->rm_rate == tech_pvt->rm_rate) { + best_te = (switch_payload_t) map->rm_pt; + }9 + } + + if (!cng_pt && !strcasecmp(rm_encoding, "CN")) { + cng_pt = (switch_payload_t) map->rm_pt; + if (tech_pvt->rtp_session) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", cng_pt); + switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt); + } + } + + if (match) { + continue; + } + + if (greedy) { + first = mine; + last = first + 1; + } else { + first = 0; + last = num_codecs; + } + + codec_ms = ptime; + + if (maxptime && (!codec_ms || codec_ms > maxptime)) { + codec_ms = maxptime; + } + + if (!codec_ms) { + codec_ms = switch_default_ptime(rm_encoding, map->rm_pt); + } + + map_bit_rate = switch_known_bitrate((switch_payload_t)map->rm_pt); + + if (!ptime && !strcasecmp(map->rm_encoding, "g723")) { + ptime = codec_ms = 30; + } + + if (zstr(map->rm_fmtp)) { + if (!strcasecmp(map->rm_encoding, "ilbc")) { + ptime = codec_ms = 30; + map_bit_rate = 13330; + } + } else { + if ((switch_core_codec_parse_fmtp(map->rm_encoding, map->rm_fmtp, map->rm_rate, &codec_fmtp)) == SWITCH_STATUS_SUCCESS) { + if (codec_fmtp.bits_per_second) { + map_bit_rate = codec_fmtp.bits_per_second; + } + if (codec_fmtp.microseconds_per_packet) { + codec_ms = (codec_fmtp.microseconds_per_packet / 1000); + } + } + } + + + for (i = first; i < last && i < total_codecs; i++) { + const switch_codec_implementation_t *imp = codec_array[i]; + uint32_t bit_rate = imp->bits_per_second; + uint32_t codec_rate = imp->samples_per_second; + if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) { + continue; + } + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio Codec Compare [%s:%d:%u:%d:%u]/[%s:%d:%u:%d:%u]\n", + rm_encoding, map->rm_pt, (int) map->rm_rate, codec_ms, map_bit_rate, + imp->iananame, imp->ianacode, codec_rate, imp->microseconds_per_packet / 1000, bit_rate); + if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) { + match = (map->rm_pt == imp->ianacode) ? 1 : 0; + } else { + match = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1; + } + + if (match && bit_rate && map_bit_rate && map_bit_rate != bit_rate && strcasecmp(map->rm_encoding, "ilbc")) { + /* nevermind */ + match = 0; + } + + if (match) { + if (scrooge) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, + "Bah HUMBUG! Sticking with %s@%uh@%ui\n", + imp->iananame, imp->samples_per_second, imp->microseconds_per_packet / 1000); + } else { + if ((ptime && codec_ms && codec_ms * 1000 != imp->microseconds_per_packet) || map->rm_rate != codec_rate) { + near_rate = map->rm_rate; + near_match = imp; + match = 0; + continue; + } + } + mimp = imp; + break; + } else { + match = 0; + } + } + } + + /* End */ + + + } + } + +fail: + if (parser) { + sdp_parser_free(parser); + } +} +#endif + +static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, + switch_memory_pool_t **pool, + switch_originate_flag_t flags, switch_call_cause_t *cancel_cause) +{ + switch_channel_t *channel; + char name[128]; + const char *dname = "PCMU"; + uint32_t interval = 20; + crtp_private_t *tech_pvt; + const char *r_sdp = switch_event_get_header(var_event, kRSDP); + const char *l_sdp = switch_event_get_header(var_event, kLSDP); + const char *codec_string = switch_event_get_header_nil(var_event, kCODECSTRING); + + + if (!(*new_session = switch_core_session_request(crtp.endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, 0, pool))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't request session.\n"); + goto fail; + } + + channel = switch_core_session_get_channel(*new_session); + + + + tech_pvt = switch_core_session_alloc(*new_session, sizeof *tech_pvt); + tech_pvt->session = *new_session; + tech_pvt->channel = channel; + tech_pvt->bind_address = switch_core_session_strdup(*new_session, switch_event_get_header_nil(var_event, kBINDADDRESS)); + switch_core_session_set_private(*new_session, tech_pvt); + + if (setup_local_rtp(tech_pvt, l_sdp, codec_string) != SWITCH_STATUS_SUCCESS) { + goto fail; + } + + snprintf(name, sizeof(name), "rtp/ctrl"); /* TODO add addresses */ + switch_channel_set_name(channel, name); + + switch_channel_set_state(channel, CS_INIT); + + if (switch_core_codec_init(&tech_pvt->read_codec, + dname, + NULL, + 8000, + interval, + 1, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); + goto fail; + } else { + if (switch_core_codec_init(&tech_pvt->write_codec, + dname, + NULL, + 8000, + interval, + 1, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); + switch_core_codec_destroy(&tech_pvt->read_codec); + goto fail; + } + } + + if (switch_core_session_set_read_codec(*new_session, &tech_pvt->read_codec) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set read codec?\n"); + goto fail; + } + + if (switch_core_session_set_write_codec(*new_session, &tech_pvt->write_codec) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set write codec?\n"); + } + + if (switch_core_session_thread_launch(*new_session) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't start session thread.\n"); + goto fail; + } + + switch_channel_mark_answered(channel); + + return SWITCH_CAUSE_SUCCESS; + +fail: + if (tech_pvt) { + if (tech_pvt->read_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->read_codec); + } + + if (tech_pvt->write_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->write_codec); + } + } + + if (*new_session) { + switch_core_session_destroy(new_session); + } + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; +} + +static switch_status_t channel_on_init(switch_core_session_t *session) +{ + + switch_channel_t *channel = switch_core_session_get_channel(session); + + switch_channel_set_state(channel, CS_ROUTING); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_on_destroy(switch_core_session_t *session) +{ + crtp_private_t *tech_pvt = switch_core_session_get_private(session); + + if ((tech_pvt = switch_core_session_get_private(session))) { + + if (tech_pvt->read_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->read_codec); + } + + if (tech_pvt->write_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->write_codec); + } + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id) +{ + crtp_private_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); + + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id) +{ + crtp_private_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); + + + return SWITCH_STATUS_SUCCESS; + +} + +static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf) +{ + crtp_private_t *tech_pvt = NULL; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + return SWITCH_STATUS_SUCCESS; +} + From 43ffafcb4b44772cf3abfca21b7addec354d4380 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 20 Jun 2012 12:30:37 -0400 Subject: [PATCH 264/822] wrong operand to sizeof --- libs/freetdm/src/ftdm_io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 78e65dfe88..c081c655d8 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -169,7 +169,7 @@ static void stop_chan_io_dump(ftdm_io_dump_t *dump) return; } ftdm_safe_free(dump->buffer); - memset(dump, 0, sizeof(dump)); + memset(dump, 0, sizeof(*dump)); } static ftdm_status_t start_chan_io_dump(ftdm_channel_t *chan, ftdm_io_dump_t *dump, ftdm_size_t size) From 8da3d119ab8e5f9ba4998e68b02993d707c1b3f0 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 20 Jun 2012 13:20:35 -0400 Subject: [PATCH 265/822] Added display of M2UA signalling channels for CLI command show status --- .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index b8cc34480f..c7bd95947b 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -1451,6 +1451,33 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, x++; } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x]id != 0) */ + /* Look spans that are being used by M2UA SG links */ + for (x = 1; x < ftdm_array_len(g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif); x++) { + if (g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[x].id) { + if (g_ftdm_sngss7_data.cfg.mtp2Link[g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[x].mtp2LnkNmb].id) { + uint32_t mtp1_id = g_ftdm_sngss7_data.cfg.mtp2Link[g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[x].mtp2LnkNmb].id; + if (g_ftdm_sngss7_data.cfg.mtp1Link[mtp1_id].id) { + if (g_ftdm_sngss7_data.cfg.mtp1Link[mtp1_id].span == span) { + if (chan) { + if (chan == g_ftdm_sngss7_data.cfg.mtp1Link[mtp1_id].chan) { + stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|SIGNALING LINK\n", + g_ftdm_sngss7_data.cfg.mtp1Link[mtp1_id].span, + g_ftdm_sngss7_data.cfg.mtp1Link[mtp1_id].chan, + 0); + } + } else { + stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|SIGNALING LINK\n", + g_ftdm_sngss7_data.cfg.mtp1Link[mtp1_id].span, + g_ftdm_sngss7_data.cfg.mtp1Link[mtp1_id].chan, + 0); + } + } + } + + } + } + } + return FTDM_SUCCESS; } From 6a1229c8f9f878ca46bbadfeeebd6a456a8ace87 Mon Sep 17 00:00:00 2001 From: kapil Date: Thu, 21 Jun 2012 01:09:51 +0530 Subject: [PATCH 266/822] fixing compilation error --- src/mod/endpoints/mod_media_gateway/media_gateway_stack.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c index ebc7b869f6..591bb5f13d 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c @@ -257,8 +257,6 @@ switch_status_t sng_mgco_start(megaco_profile_t* profile ) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mgco_mg_tsap_enable_cntrl SUCCESS \n"); } - mgco_mg_enble_debug(); - return SWITCH_STATUS_SUCCESS; } From b44bcd57637020397483b655aa35af26a3581d95 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 20 Jun 2012 16:28:00 -0400 Subject: [PATCH 267/822] Added core spanflag CLI command --- libs/freetdm/mod_freetdm/mod_freetdm.c | 3 +- libs/freetdm/src/ftdm_io.c | 271 +++++++++++++----- libs/freetdm/src/include/private/ftdm_types.h | 2 + 3 files changed, 205 insertions(+), 71 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 63abc9f284..12cb7e5ef7 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -5069,7 +5069,8 @@ static ftdm_cli_entry_t ftdm_cli_options[] = /* Fake handlers as they are handled within freetdm library, * we should provide a way inside freetdm to query for completions from signaling modules */ { "core state", "[!]", "", NULL }, - { "core flag", "[!]", "", NULL }, + { "core flag", "[!] [] []", "", NULL }, + { "core spanflag", "[!] []", "", NULL }, { "core calls", "", "", NULL }, }; diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index a9cb0b4f2a..6052971274 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -63,12 +63,78 @@ struct tm *localtime_r(const time_t *clock, struct tm *result); ftdm_time_t time_last_throttle_log = 0; ftdm_time_t time_current_throttle_log = 0; +typedef struct val_str { + const char *str; + unsigned long long val; +} val_str_t; + +static val_str_t channel_flag_strs[] = { + { "configured" , FTDM_CHANNEL_CONFIGURED}, + { "ready", FTDM_CHANNEL_READY}, + { "open", FTDM_CHANNEL_OPEN}, + { "dtmf-detect", FTDM_CHANNEL_DTMF_DETECT}, + { "suppress-dtmf", FTDM_CHANNEL_SUPRESS_DTMF}, + { "transcode", FTDM_CHANNEL_TRANSCODE}, + { "buffer", FTDM_CHANNEL_BUFFER}, + { "in-thread", FTDM_CHANNEL_INTHREAD}, + { "wink", FTDM_CHANNEL_WINK}, + { "flash", FTDM_CHANNEL_FLASH}, + { "state-change", FTDM_CHANNEL_STATE_CHANGE}, + { "hold", FTDM_CHANNEL_HOLD}, + { "in-use", FTDM_CHANNEL_INUSE}, + { "off-hook", FTDM_CHANNEL_OFFHOOK}, + { "ringing", FTDM_CHANNEL_RINGING}, + { "progress-detect", FTDM_CHANNEL_PROGRESS_DETECT}, + { "callerid-detect", FTDM_CHANNEL_CALLERID_DETECT}, + { "outbound", FTDM_CHANNEL_OUTBOUND}, + { "suspended", FTDM_CHANNEL_SUSPENDED}, + { "3-way", FTDM_CHANNEL_3WAY}, + { "progress", FTDM_CHANNEL_PROGRESS}, + { "media", FTDM_CHANNEL_MEDIA}, + { "answered", FTDM_CHANNEL_ANSWERED}, + { "mute", FTDM_CHANNEL_MUTE}, + { "use-rx-gain", FTDM_CHANNEL_USE_RX_GAIN}, + { "use-tx-gain", FTDM_CHANNEL_USE_TX_GAIN}, + { "in-alarm", FTDM_CHANNEL_IN_ALARM}, + { "sig-up", FTDM_CHANNEL_SIG_UP}, + { "user-hangup", FTDM_CHANNEL_USER_HANGUP}, + { "rx-disabled", FTDM_CHANNEL_RX_DISABLED}, + { "tx-disabled", FTDM_CHANNEL_TX_DISABLED}, + { "call-started", FTDM_CHANNEL_CALL_STARTED}, + { "non-block", FTDM_CHANNEL_NONBLOCK}, + { "ind-ack-pending", FTDM_CHANNEL_IND_ACK_PENDING}, + { "blocking", FTDM_CHANNEL_BLOCKING}, + { "media", FTDM_CHANNEL_DIGITAL_MEDIA}, + { "native-sigbridge", FTDM_CHANNEL_NATIVE_SIGBRIDGE}, + { "invalid", FTDM_CHANNEL_MAX_FLAG}, +}; + +static val_str_t span_flag_strs[] = { + { "configured", FTDM_SPAN_CONFIGURED}, + { "started", FTDM_SPAN_STARTED}, + { "state-change", FTDM_SPAN_STATE_CHANGE}, + { "suspended", FTDM_SPAN_SUSPENDED}, + { "in-thread", FTDM_SPAN_IN_THREAD}, + { "stop-thread", FTDM_SPAN_STOP_THREAD}, + { "use-chan-queue", FTDM_SPAN_USE_CHAN_QUEUE}, + { "suggest-chan-id", FTDM_SPAN_SUGGEST_CHAN_ID}, + { "use-av-rate", FTDM_SPAN_USE_AV_RATE}, + { "power-saving", FTDM_SPAN_PWR_SAVING}, + { "signals-queue", FTDM_SPAN_USE_SIGNALS_QUEUE}, + { "proceed-state", FTDM_SPAN_USE_PROCEED_STATE}, + { "skip-state", FTDM_SPAN_USE_SKIP_STATES}, + { "non-stoppable", FTDM_SPAN_NON_STOPPABLE}, + { "use-transfer", FTDM_SPAN_USE_TRANSFER}, +}; + static ftdm_status_t ftdm_call_set_call_id(ftdm_channel_t *fchan, ftdm_caller_data_t *caller_data); static ftdm_status_t ftdm_call_clear_call_id(ftdm_caller_data_t *caller_data); static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan); static ftdm_status_t ftdm_channel_sig_indicate(ftdm_channel_t *ftdmchan, ftdm_channel_indication_t indication, ftdm_usrmsg_t *usrmsg); -static const char *channel_val2str(unsigned long long flag); -static unsigned long long channel_str2val(const char *flag_name); + +static const char *ftdm_val2str(unsigned long long val, val_str_t *val_str_table, ftdm_size_t array_size, const char *default_str); +static unsigned long long ftdm_str2val(const char *str, val_str_t *val_str_table, ftdm_size_t array_size, unsigned long long default_val); + static int time_is_init = 0; @@ -1051,7 +1117,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_add_channel(ftdm_span_t *span, ftdm_socket_t i++; } - ftdm_set_flag(new_chan, FTDM_CHANNEL_CONFIGURED | FTDM_CHANNEL_READY); + ftdm_set_flag(new_chan, FTDM_CHANNEL_CONFIGURED | FTDM_CHANNEL_READY); new_chan->state = FTDM_CHANNEL_STATE_DOWN; new_chan->state_status = FTDM_STATE_STATUS_COMPLETED; *chan = new_chan; @@ -4370,28 +4436,28 @@ static void print_channels_by_flag(ftdm_stream_handle_t *stream, ftdm_span_t *in stream->write_function(stream, "[s%dc%d][%d:%d] flag !%d(!%s) ON \n", fchan->span_id, fchan->chan_id, fchan->physical_span_id, fchan->physical_chan_id, - flagval, channel_val2str(flagval)); + flagval, ftdm_val2str(flag, channel_flag_strs, ftdm_array_len(channel_flag_strs), "invalid")); mycount++; } else { stream->write_function(stream, "[s%dc%d][%d:%d] flag !%d(!%s) OFF \n", fchan->span_id, fchan->chan_id, fchan->physical_span_id, fchan->physical_chan_id, - flagval, channel_val2str(flagval)); + flagval, ftdm_val2str(flag, channel_flag_strs, ftdm_array_len(channel_flag_strs), "invalid")); } - } else if (!not) { + } else { if (ftdm_test_flag(fchan, flag)) { - stream->write_function(stream, "[s%dc%d][%d:%d] flag %d(%s) ON\n", + stream->write_function(stream, "[s%dc%d][%d:%d] flag %d(%s) ON\n", fchan->span_id, fchan->chan_id, fchan->physical_span_id, fchan->physical_chan_id, - flagval, channel_val2str(flagval)); + flagval, ftdm_val2str(flag, channel_flag_strs, ftdm_array_len(channel_flag_strs), "invalid")); mycount++; } else { stream->write_function(stream, "[s%dc%d][%d:%d] flag %d(%s) OFF \n", fchan->span_id, fchan->chan_id, fchan->physical_span_id, fchan->physical_chan_id, - flagval, channel_val2str(flagval)); + flagval, ftdm_val2str(flag, channel_flag_strs, ftdm_array_len(channel_flag_strs), "invalid")); } } } @@ -4412,16 +4478,16 @@ static void print_channels_by_flag(ftdm_stream_handle_t *stream, ftdm_span_t *in for (curr = citer ; curr; curr = ftdm_iterator_next(curr)) { fchan = ftdm_iterator_current(curr); if (not && !ftdm_test_flag(fchan, flag)) { - stream->write_function(stream, "[s%dc%d][%d:%d] has not flag %d\n", + stream->write_function(stream, "[s%dc%d][%d:%d] flag !%d(!%s)\n", fchan->span_id, fchan->chan_id, fchan->physical_span_id, fchan->physical_chan_id, - flagval); + flagval, ftdm_val2str(flag, channel_flag_strs, ftdm_array_len(channel_flag_strs), "invalid")); mycount++; } else if (!not && ftdm_test_flag(fchan, flag)) { - stream->write_function(stream, "[s%dc%d][%d:%d] has flag %d\n", + stream->write_function(stream, "[s%dc%d][%d:%d] flag %d(%s)\n", fchan->span_id, fchan->chan_id, fchan->physical_span_id, fchan->physical_chan_id, - flagval); + flagval, ftdm_val2str(flag, channel_flag_strs, ftdm_array_len(channel_flag_strs), "invalid")); mycount++; } } @@ -4433,6 +4499,68 @@ end: ftdm_mutex_unlock(globals.mutex); } +static void print_spans_by_flag(ftdm_stream_handle_t *stream, ftdm_span_t *inspan, int32_t flagval, int not, int *count) +{ + ftdm_hash_iterator_t *i = NULL; + ftdm_span_t *span; + const void *key = NULL; + void *val = NULL; + uint32_t flag = (1 << flagval); + int mycount = 0; + + *count = 0; + + ftdm_mutex_lock(globals.mutex); + + if (inspan) { + if (not) { + if (!ftdm_test_flag(inspan, flag)) { + stream->write_function(stream, "[s%d] flag !%d(!%s) ON \n", + inspan->span_id, + flagval, ftdm_val2str(flag, span_flag_strs, ftdm_array_len(span_flag_strs), "invalid")); + + mycount++; + } else { + stream->write_function(stream, "[s%d] flag !%d(!%s) OFF \n", + inspan->span_id, + flagval, ftdm_val2str(flag, span_flag_strs, ftdm_array_len(span_flag_strs), "invalid")); + } + } else { + if (ftdm_test_flag(inspan, flag)) { + stream->write_function(stream, "[s%d] flag %d(%s) ON \n", + inspan->span_id, + flagval, ftdm_val2str(flag, span_flag_strs, ftdm_array_len(span_flag_strs), "invalid")); + mycount++; + } else { + stream->write_function(stream, "[s%d] flag %d(%s) OFF \n", + inspan->span_id, + flagval, ftdm_val2str(flag, span_flag_strs, ftdm_array_len(span_flag_strs), "invalid")); + } + } + } else { + for (i = hashtable_first(globals.span_hash); i; i = hashtable_next(i)) { + hashtable_this(i, &key, NULL, &val); + if (!key || !val) { + break; + } + span = val; + if (not && !ftdm_test_flag(span, flag)) { + stream->write_function(stream, "[s%d] flag !%d(!%s)\n", + span->span_id, + flagval, ftdm_val2str(flag, span_flag_strs, ftdm_array_len(span_flag_strs), "invalid")); + mycount++; + } else if (!not && ftdm_test_flag(span, flag)) { + stream->write_function(stream, "[s%d] flag %d(%s)\n", + span->span_id, + flagval, ftdm_val2str(flag, span_flag_strs, ftdm_array_len(span_flag_strs), "invalid")); + mycount++; + } + } + } + *count = mycount; + ftdm_mutex_unlock(globals.mutex); +} + static void print_channels_by_state(ftdm_stream_handle_t *stream, ftdm_channel_state_t state, int not, int *count) { ftdm_hash_iterator_t *i = NULL; @@ -4483,83 +4611,47 @@ static void print_core_usage(ftdm_stream_handle_t *stream) "--------------------------------------------------------------------------------\n" "ftdm core state [!] - List all channels in or not in the given state\n" "ftdm core flag [!] [] [] - List all channels with the given flag value set\n" + "ftdm core spanflag [!] [] - List all spans with the given span flag value set\n" "ftdm core calls - List all known calls to the FreeTDM core\n" "--------------------------------------------------------------------------------\n"); } -typedef struct channel_flags_str { - const char *name; - unsigned long long channel_flag; -} channel_flag_str_t; -static channel_flag_str_t channel_flag_strs[] = { - { "configured" , FTDM_CHANNEL_CONFIGURED}, - { "ready", FTDM_CHANNEL_READY}, - { "open", FTDM_CHANNEL_OPEN}, - { "dtmf-detect", FTDM_CHANNEL_DTMF_DETECT}, - { "suppress-dtmf", FTDM_CHANNEL_SUPRESS_DTMF}, - { "transcode", FTDM_CHANNEL_TRANSCODE}, - { "buffer", FTDM_CHANNEL_BUFFER}, - { "in-thread", FTDM_CHANNEL_INTHREAD}, - { "wink", FTDM_CHANNEL_WINK}, - { "flash", FTDM_CHANNEL_FLASH}, - { "state-change", FTDM_CHANNEL_STATE_CHANGE}, - { "hold", FTDM_CHANNEL_HOLD}, - { "in-use", FTDM_CHANNEL_INUSE}, - { "off-hook", FTDM_CHANNEL_OFFHOOK}, - { "ringing", FTDM_CHANNEL_RINGING}, - { "progress-detect", FTDM_CHANNEL_PROGRESS_DETECT}, - { "callerid-detect", FTDM_CHANNEL_CALLERID_DETECT}, - { "outbound", FTDM_CHANNEL_OUTBOUND}, - { "suspended", FTDM_CHANNEL_SUSPENDED}, - { "3-way", FTDM_CHANNEL_3WAY}, - { "progress", FTDM_CHANNEL_PROGRESS}, - { "media", FTDM_CHANNEL_MEDIA}, - { "answered", FTDM_CHANNEL_ANSWERED}, - { "mute", FTDM_CHANNEL_MUTE}, - { "use-rx-gain", FTDM_CHANNEL_USE_RX_GAIN}, - { "use-tx-gain", FTDM_CHANNEL_USE_TX_GAIN}, - { "in-alarm", FTDM_CHANNEL_IN_ALARM}, - { "sig-up", FTDM_CHANNEL_SIG_UP}, - { "user-hangup", FTDM_CHANNEL_USER_HANGUP}, - { "rx-disabled", FTDM_CHANNEL_RX_DISABLED}, - { "tx-disabled", FTDM_CHANNEL_TX_DISABLED}, - { "call-started", FTDM_CHANNEL_CALL_STARTED}, - { "non-block", FTDM_CHANNEL_NONBLOCK}, - { "ind-ack-pending", FTDM_CHANNEL_IND_ACK_PENDING}, - { "blocking", FTDM_CHANNEL_BLOCKING}, - { "media", FTDM_CHANNEL_DIGITAL_MEDIA}, - { "native-sigbridge", FTDM_CHANNEL_NATIVE_SIGBRIDGE}, - { "invalid", FTDM_CHANNEL_MAX_FLAG}, -}; - -static unsigned long long channel_str2val(const char *flag_name) +static unsigned long long ftdm_str2val(const char *str, val_str_t *val_str_table, ftdm_size_t array_size, unsigned long long default_val) { int i; - for (i = 0; i < ftdm_array_len(channel_flag_strs); i++) { - if (!strcasecmp(channel_flag_strs[i].name, flag_name)) { - return channel_flag_strs[i].channel_flag; + for (i = 0; i < array_size; i++) { + if (!strcasecmp(val_str_table[i].str, str)) { + return val_str_table[i].val; } } - return FTDM_CHANNEL_MAX_FLAG; + return default_val; } -static const char *channel_val2str(unsigned long long flag) +static const char *ftdm_val2str(unsigned long long val, val_str_t *val_str_table, ftdm_size_t array_size, const char *default_str) { int i; - for (i = 0; i < ftdm_array_len(channel_flag_strs); i++) { - if (channel_flag_strs[i].channel_flag == flag) { - return channel_flag_strs[i].name; + for (i = 0; i < array_size; i++) { + if (val_str_table[i].val == val) { + return val_str_table[i].str; } } - return "invalid"; + return default_str; } static void print_channel_flag_values(ftdm_stream_handle_t *stream) { int i; for (i = 0; i < ftdm_array_len(channel_flag_strs); i++) { - stream->write_function(stream, "%s\n", channel_flag_strs[i].name); + stream->write_function(stream, "%s\n", channel_flag_strs[i].str); + } +} + +static void print_span_flag_values(ftdm_stream_handle_t *stream) +{ + int i; + for (i = 0; i < ftdm_array_len(span_flag_strs); i++) { + stream->write_function(stream, "%s\n", span_flag_strs[i].str); } } @@ -4631,12 +4723,13 @@ static char *handle_core_command(const char *cmd) } if (isalpha(flag[0])) { - flagval = channel_str2val(flag); + flagval = ftdm_str2val(flag, channel_flag_strs, ftdm_array_len(channel_flag_strs), FTDM_CHANNEL_MAX_FLAG); if (flagval == FTDM_CHANNEL_MAX_FLAG) { stream.write_function(&stream, "\nInvalid channel flag value. Possible channel flags\n"); print_channel_flag_values(&stream); goto done; } + flagval = flagval >> 1; } else { flagval = atoi(flag); } @@ -4661,6 +4754,44 @@ static char *handle_core_command(const char *cmd) print_channels_by_flag(&stream, fspan, chan_id, flagval, not, &count); stream.write_function(&stream, "\nTotal channels %s %d: %d\n", not ? "without flag" : "with flag", flagval, count); + } else if (!strcasecmp(argv[0], "spanflag")) { + if (argc < 2) { + stream.write_function(&stream, "core spanflag command requires an argument\n"); + print_core_usage(&stream); + goto done; + } + + flag = argv[1]; + if (argv[1][0] == '!') { + not = 1; + flag++; + } + + if (isalpha(flag[0])) { + flagval = ftdm_str2val(flag, span_flag_strs, ftdm_array_len(span_flag_strs), FTDM_SPAN_MAX_FLAG); + if (flagval == FTDM_SPAN_MAX_FLAG) { + stream.write_function(&stream, "\nInvalid span flag value. Possible span flags\n"); + print_span_flag_values(&stream); + goto done; + } + flagval = flagval >> 1; + } else { + flagval = atoi(flag); + } + + /* Specific span specified */ + if (argv[2]) { + ftdm_span_find_by_name(argv[2], &fspan); + if (!fspan) { + stream.write_function(&stream, "-ERR span:%s not found\n", argv[2]); + goto done; + } + } + + print_spans_by_flag(&stream, fspan, flagval, not, &count); + if (!fspan) { + stream.write_function(&stream, "\nTotal spans %s %d: %d\n", not ? "without flag" : "with flag", flagval, count); + } } else if (!strcasecmp(argv[0], "calls")) { ftdm_mutex_lock(globals.call_id_mutex); current_call_id = globals.last_call_id; diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h index 7df764e52f..19d496bea4 100755 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -197,6 +197,8 @@ typedef enum { FTDM_SPAN_NON_STOPPABLE = (1 << 13), /* If this flag is set, then this span supports TRANSFER state */ FTDM_SPAN_USE_TRANSFER = (1 << 14), + /* This is the last flag, no more flags bigger than this */ + FTDM_SPAN_MAX_FLAG = (1 << 15), } ftdm_span_flag_t; /*! \brief Channel supported features */ From 79702bc0d2aa1fe4086c6108633181bf2d9a0a68 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 20 Jun 2012 21:34:04 -0400 Subject: [PATCH 268/822] start implementing command handlers --- .gitignore | 3 + libs/freetdm/mod_freetdm/tdm.c | 2 +- src/include/switch_apr.h | 3 +- .../mod_media_gateway/media_gateway_stack.c | 3 +- .../mod_media_gateway/media_gateway_xml.c | 1 + .../mod_media_gateway/mod_media_gateway.c | 189 ++++++++++++++++++ 6 files changed, 197 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 55e1e9856b..3c0fd7cf40 100644 --- a/.gitignore +++ b/.gitignore @@ -199,3 +199,6 @@ src/mod/formats/mod_shout/*/*/mod_shout.log /src/mod/languages/mod_managed/x64/Release_CLR/FREESWITCH.MANAGED.DLL.metagen /src/mod/languages/mod_managed/x64/Release_CLR/RSAENH.DLL.bi /src/mod/languages/mod_managed/x64/Release_CLR/TZRES.DLL.bi + +src/include/switch_apr.h +.gitignore \ No newline at end of file diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index 935411867b..61a145ed3b 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -109,7 +109,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi ftdm_codec_t codec; uint32_t interval; - ctdm_private_t *tech_pvt; + ctdm_private_t *tech_pvt = NULL; if (zstr(szchanid) || zstr(szspanid)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Both "kSPAN_ID" and "kCHAN_ID" have to be set.\n"); diff --git a/src/include/switch_apr.h b/src/include/switch_apr.h index 0c8673570f..e125eb9390 100644 --- a/src/include/switch_apr.h +++ b/src/include/switch_apr.h @@ -773,7 +773,8 @@ typedef gid_t switch_gid_t; typedef ino_t switch_ino_t; typedef dev_t switch_dev_t; #endif - typedef off64_t switch_off_t; + +typedef off_t switch_off_t; /** * Structure for referencing file information diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c index ebc7b869f6..51935b9c8d 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c @@ -256,8 +256,7 @@ switch_status_t sng_mgco_start(megaco_profile_t* profile ) else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mgco_mg_tsap_enable_cntrl SUCCESS \n"); } - - mgco_mg_enble_debug(); + //mgco_mg_enable_debug(); return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index ba5c20aabb..d43a0e96ce 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -243,6 +243,7 @@ static switch_status_t modify_mid(char* mid) sprintf(mid,"[%s]",dup); }else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid input MID string[%s]\n",mid); + free(dup); return SWITCH_STATUS_FALSE; } diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 30de4f86fc..b249e98896 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -130,11 +130,200 @@ void handle_sng_log(uint8_t level, char *fmt, ...) va_end(ptr); } +static void mgco_print_sdp(CmSdpInfoSet *sdp) +{ + int i; + +// XXX check if we can use that for debug: +// cmUnpkCmSdpInfoSet(<#CmSdpInfoSet *param#>, <#Ptr ptr#>, <#CmIntfVer intfVer#>, <#Buffer *mBuf#>); + + + if (sdp->numComp.pres == NOTPRSNT) { + return; + } + + for (i = 0; i < sdp->numComp.val; i++) { + CmSdpInfo *s = sdp->info[i]; + int mediaId; + + if (s->conn.addrType.pres && s->conn.addrType.val == CM_SDP_ADDR_TYPE_IPV4 && + s->conn.netType.type.val == CM_SDP_NET_TYPE_IN && + s->conn.u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) { + + if (s->conn.u.ip4.addrType.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Address: %d.%d.%d.%d\n", + s->conn.u.ip4.u.uniIp.b[0].val, + s->conn.u.ip4.u.uniIp.b[1].val, + s->conn.u.ip4.u.uniIp.b[2].val, + s->conn.u.ip4.u.uniIp.b[3].val); + } + if (s->attrSet.numComp.pres) { + for (mediaId = 0; mediaId < s->attrSet.numComp.val; mediaId++) { + CmSdpAttr *a = s->attrSet.attr[mediaId]; + + } + } + + if (s->mediaDescSet.numComp.pres) { + for (mediaId = 0; mediaId < s->mediaDescSet.numComp.val; mediaId++) { + CmSdpMediaDesc *desc = s->mediaDescSet.mediaDesc[mediaId]; + + if (desc->field.mediaType.val == CM_SDP_MEDIA_AUDIO && + desc->field.id.type.val == CM_SDP_VCID_PORT && + desc->field.id.u.port.type.val == CM_SDP_PORT_INT && + desc->field.id.u.port.u.portInt.port.type.val == CM_SDP_SPEC) { + int port = desc->field.id.u.port.u.portInt.port.val.val; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Port: %d\n", port); + + } + + } + } + + } + + } +} + /*****************************************************************************************************************************/ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) { + size_t txnIter; + /*TODO*/ + if(msg->body.type.val == MGT_TXN) + { + /* Loop over transaction list */ + for(txnIter=0;txnIterbody.u.tl.num.val;txnIter++) + { + switch(msg->body.u.tl.txns[txnIter]->type.val) { + case MGT_TXNREQ: + { + MgMgcoTxnReq* txnReq; + MgMgcoTransId transId; /* XXX */ + int axnIter; + txnReq = &(msg->body.u.tl.txns[txnIter]->u.req); + + /* Loop over action list */ + for (axnIter=0;axnIteral.num.val;axnIter++) { + MgMgcoActionReq *actnReq; + MgMgcoContextId ctxId; + int cmdIter; + + actnReq = txnReq->al.actns[axnIter]; + ctxId = actnReq->cxtId; /* XXX */ + + if (actnReq->pres.pres == NOTPRSNT) { + continue; + } + + /* Loop over command list */ + for (cmdIter=0; cmdIter < (actnReq->cl.num.val); cmdIter++) { + MgMgcoCommandReq *cmdReq = actnReq->cl.cmds[cmdIter]; + MgMgcoTermId *termId = NULLP; + + switch (cmdReq->cmd.type.val) { + case MGT_ADD: + { + MgMgcoAmmReq *addReq = &cmdReq->cmd.u.add; + MgMgcoTermId termId = addReq->termId; + int descId; + for (descId = 0; descId < addReq->dl.num.val; descId++) { + switch (addReq->dl.descs[descId]->type.val) { + case MGT_MEDIADESC: + { + int mediaId; + for (mediaId = 0; mediaId < addReq->dl.descs[descId]->u.media.num.val; mediaId++) { + MgMgcoMediaPar *mediaPar = addReq->dl.descs[descId]->u.media.parms[mediaId]; + switch (mediaPar->type.val) { + case MGT_MEDIAPAR_LOCAL: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Textual SDP %s\n", mediaPar->u.local.sdpStr.pres ? "present" : "absent"); + break; + } + case MGT_MEDIAPAR_REMOTE: + { + break; + } + + case MGT_MEDIAPAR_LOCCTL: + { + break; + } + case MGT_MEDIAPAR_TERMST: + break; + case MGT_MEDIAPAR_STRPAR: + { + MgMgcoStreamDesc *mgStream = &mediaPar->u.stream; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Textual SDP %s\n", mgStream->sl.remote.sdpStr.pres ? "present" : "absent"); + + if (mgStream->sl.remote.pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got remote stream media description:\n"); + mgco_print_sdp(&mgStream->sl.remote.sdp); + } + + if (mgStream->sl.local.pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got local stream media description:\n"); + mgco_print_sdp(&mgStream->sl.local.sdp); + } + + break; + } + } + } + } + case MGT_MODEMDESC: + case MGT_MUXDESC: + case MGT_REQEVTDESC: + case MGT_EVBUFDESC: + case MGT_SIGNALSDESC: + case MGT_DIGMAPDESC: + case MGT_AUDITDESC: + case MGT_STATSDESC: + break; + } + } + break; + } + case MGT_MODIFY: + { + MgMgcoAmmReq *addReq = &cmdReq->cmd.u.mod; + break; + } + case MGT_MOVE: + { + MgMgcoAmmReq *addReq = &cmdReq->cmd.u.move; + break; + + } + case MGT_SUB: + { + MgMgcoSubAudReq *addReq = &cmdReq->cmd.u.sub; + } + case MGT_SVCCHG: + case MGT_NTFY: + case MGT_AUDITCAP: + case MGT_AUDITVAL: + break; + } + + } + } + + break; + } + case MGT_TXNREPLY: + { + break; + } + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received unknown command %d in transaction\n", msg->body.u.tl.txns[txnIter]->type.val); + break; + } + } + } } /*****************************************************************************************************************************/ From c18c32f8005dfef6f074eb0a3c9f78c7d104259c Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 20 Jun 2012 22:43:54 -0400 Subject: [PATCH 269/822] Fix for compile warnings rtp.c --- src/mod/endpoints/mod_sofia/rtp.c | 39 +++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 8920e684a7..23a94b9261 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -88,15 +88,19 @@ switch_io_routines_t crtp_io_routines = { .send_dtmf = channel_send_dtmf }; +#if 0 SWITCH_STANDARD_API(test_function) { return SWITCH_STATUS_SUCCESS; } +#endif void crtp_init(switch_loadable_module_interface_t *module_interface) { switch_endpoint_interface_t *endpoint_interface; +#if 0 /* DAVIDY */ switch_api_interface_t *api_interface; +#endif crtp.pool = module_interface->pool; endpoint_interface = switch_loadable_module_create_interface(module_interface, SWITCH_ENDPOINT_INTERFACE); endpoint_interface->interface_name = "rtp"; @@ -128,12 +132,18 @@ typedef struct parsed_sdp_s { static switch_status_t setup_local_rtp(crtp_private_t *tech_pvt, const char *l_sdp, const char *codec_string) { - switch_core_session_t const * session = tech_pvt->session; - int num_codecs; - const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS] = { 0 }; - - char *codec_order[SWITCH_MAX_CODECS] = { 0 }; int codec_order_last; + int num_codecs; +#if 0 /* DAVIDY */ + switch_core_session_t const * session = tech_pvt->session; +#endif + const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS] = { 0 }; + char *codec_order[SWITCH_MAX_CODECS] = { 0 }; +#if 1 /* DAVIDY */ + char *sdpbuf = NULL; + sdp_connection_t *connection = NULL; + sdp_printer_t *printer = NULL; +#endif /* Load in the list of codecs we support. If we have a codec string we use our priorities first */ @@ -151,24 +161,30 @@ static switch_status_t setup_local_rtp(crtp_private_t *tech_pvt, const char *l_s if (zstr(l_sdp)) { /* Generate a local SDP here */ +#if 0 /* DAVIDY */ const char *sdpbuf = switch_core_session_sprintf(session, "v=0\nIN IP4 %s\nm=audio %d RTP/AVP %d"); +#endif } else { /* Parse the SDP and remove anything we cannot support, then validate it to make sure it contains at least one codec * so that we reject invalid ones. */ -#if 1 +#if 0 uint8_t match = 0; int first = 0, last = 0; int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0; int sendonly = 0, recvonly = 0; - int greedy = 0, x = 0, skip = 0, mine = 0; - int got_crypto = 0, got_audio = 0, got_avp = 0, got_savp = 0, got_udptl = 0; + int greedy = 0, x = 0, skip = 0; #endif + int ptime = 0, maxptime = 0; int sdp_modified = 0; int cur_codec = 0; sdp_parser_t *parser = NULL; +#if 1 /* DAVIDY */ + sdp_session_t *sdp; +#else sdp_session_t *sdp, *lsdp; +#endif sdp_media_t *m; sdp_attribute_t *attr; su_home_t *sdp_home; @@ -196,7 +212,6 @@ static switch_status_t setup_local_rtp(crtp_private_t *tech_pvt, const char *l_s } } - sdp_connection_t *connection; connection = sdp->sdp_connection; if (m->m_connections) { connection = m->m_connections; @@ -250,8 +265,10 @@ static switch_status_t setup_local_rtp(crtp_private_t *tech_pvt, const char *l_s } } +#if 0 /* DAVIDY */ char sdpbuf[2048] = ""; - sdp_printer_t *printer = sdp_print(sdp_home, sdp, sdpbuf, sizeof(sdpbuf), 0); +#endif + printer = sdp_print(sdp_home, sdp, sdpbuf, sizeof(sdpbuf), 0); switch_channel_set_variable(tech_pvt->channel, kLSDP, sdpbuf); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Setting local SDP: [%s]\n", sdpbuf); sdp_printer_free(printer); @@ -486,7 +503,9 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi const char *dname = "PCMU"; uint32_t interval = 20; crtp_private_t *tech_pvt; +#if 0 const char *r_sdp = switch_event_get_header(var_event, kRSDP); +#endif const char *l_sdp = switch_event_get_header(var_event, kLSDP); const char *codec_string = switch_event_get_header_nil(var_event, kCODECSTRING); From ca5b100d17072c95a269d4d2d533dc1f2d6d1b07 Mon Sep 17 00:00:00 2001 From: kapil Date: Thu, 21 Jun 2012 11:36:20 +0530 Subject: [PATCH 270/822] code commit for multiple peer cli command --- .../mod_media_gateway/media_gateway_cli.c | 73 +++++++++++-------- .../mod_media_gateway/media_gateway_stack.c | 59 ++++++++------- .../mod_media_gateway/media_gateway_xml.c | 10 ++- .../mod_media_gateway/mod_media_gateway.c | 2 +- src/mod/endpoints/mod_sofia/rtp.c | 2 +- 5 files changed, 80 insertions(+), 66 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c index 720032673c..e21fc9d3af 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c @@ -138,6 +138,7 @@ done: switch_status_t megaco_profile_peer_xmlstatus(switch_stream_handle_t *stream, megaco_profile_t* mg_cfg) { int idx = 0x00; + int peerIdx = 0x00; int len = 0x00; MgMngmt cfm; char* xmlhdr = ""; @@ -152,33 +153,37 @@ switch_status_t megaco_profile_peer_xmlstatus(switch_stream_handle_t *stream, me memset((U8 *)&cfm, 0, sizeof(cfm)); memset((char *)&prntBuf, 0, sizeof(prntBuf)); - mg_peer = megaco_peer_profile_locate(mg_cfg->peer_list[0]); - - if(!mg_peer){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG peer configuration found for peername[%s] against profilename[%s]\n",mg_cfg->peer_list[0],mg_cfg->name); - return SWITCH_STATUS_FALSE; - } - - idx = mg_cfg->idx; len = len + sprintf(&prntBuf[0] + len,"%s\n",xmlhdr); - len = len + sprintf(&prntBuf[0] + len,"\n"); - len = len + sprintf(&prntBuf[0] + len,"%s\n",mg_cfg->peer_list[0]); + len = len + sprintf(&prntBuf[0] + len,"\n"); - /* TODO - as of now supporting only one peer .. need to add logic to iterate through all the peers associated with this profile..*/ + for(peerIdx =0; peerIdx < mg_cfg->total_peers; peerIdx++){ - /* send request to MEGACO Trillium stack to get peer information*/ - sng_mgco_mg_get_status(STGCPENT, &cfm, mg_cfg, mg_peer); + mg_peer = megaco_peer_profile_locate(mg_cfg->peer_list[peerIdx]); - ip = ntohl(cfm.t.ssta.s.mgPeerSta.peerAddrTbl.netAddr[i].u.ipv4NetAddr); - cmInetNtoa(ip, &asciiAddr); - len = len + sprintf(prntBuf+len, "%s\n",asciiAddr); + if(!mg_peer){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG peer configuration found for peername[%s] against profilename[%s]\n",mg_cfg->peer_list[peerIdx],mg_cfg->name); + return SWITCH_STATUS_FALSE; + } - len = len + sprintf(prntBuf+len, "%s\n",PRNT_MG_PEER_STATE(cfm.t.ssta.s.mgPeerSta.peerState)); + len = len + sprintf(&prntBuf[0] + len,"\n"); + len = len + sprintf(&prntBuf[0] + len,"%s\n",mg_peer->name); - len = len + sprintf(&prntBuf[0] + len,"\n"); + /* send request to MEGACO Trillium stack to get peer information*/ + sng_mgco_mg_get_status(STGCPENT, &cfm, mg_cfg, mg_peer); + + ip = ntohl(cfm.t.ssta.s.mgPeerSta.peerAddrTbl.netAddr[i].u.ipv4NetAddr); + cmInetNtoa(ip, &asciiAddr); + len = len + sprintf(prntBuf+len, "%s\n",asciiAddr); + + len = len + sprintf(prntBuf+len, "%s\n",PRNT_MG_PEER_STATE(cfm.t.ssta.s.mgPeerSta.peerState)); + + len = len + sprintf(&prntBuf[0] + len,"\n"); + } + + len = len + sprintf(&prntBuf[0] + len,"\n"); stream->write_function(stream, "\n%s\n",&prntBuf[0]); @@ -190,6 +195,7 @@ switch_status_t megaco_profile_peer_xmlstatus(switch_stream_handle_t *stream, me switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, megaco_profile_t* mg_cfg) { int idx = 0x00; + int peerIdx = 0x00; int len = 0x00; MgMngmt cfm; char* xmlhdr = ""; @@ -204,13 +210,7 @@ switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, megaco_ memset((U8 *)&cfm, 0, sizeof(cfm)); memset((char *)&prntBuf, 0, sizeof(prntBuf)); - mg_peer = megaco_peer_profile_locate(mg_cfg->peer_list[0]); - - if(!mg_peer){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG peer configuration found for peername[%s] against profilename[%s]\n",mg_cfg->peer_list[0],mg_cfg->name); - return SWITCH_STATUS_FALSE; - } - + idx = mg_cfg->idx; @@ -221,17 +221,26 @@ switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, megaco_ /****************************************************************************************************************/ /* Print Peer Information ***************************************************************************************/ - /* TODO - as of now supporting only one peer .. need to add logic to iterate through all the peers associated with this profile..*/ - len = len + sprintf(&prntBuf[0] + len,"\n"); - len = len + sprintf(&prntBuf[0] + len,"\n",mg_peer->name); - /* send request to MEGACO Trillium stack to get peer information*/ - sng_mgco_mg_get_status(STGCPENT, &cfm, mg_cfg, mg_peer); + for(peerIdx =0; peerIdx < mg_cfg->total_peers; peerIdx++){ - get_peer_xml_buffer(&prntBuf[0] + len, &cfm.t.ssta.s.mgPeerSta); + mg_peer = megaco_peer_profile_locate(mg_cfg->peer_list[peerIdx]); - len = len + sprintf(&prntBuf[0] + len,"\n"); + if(!mg_peer){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," No MG peer configuration found for peername[%s] against profilename[%s]\n",mg_cfg->peer_list[peerIdx],mg_cfg->name); + return SWITCH_STATUS_FALSE; + } + + len = len + sprintf(&prntBuf[0] + len,"\n",mg_peer->name); + + /* send request to MEGACO Trillium stack to get peer information*/ + sng_mgco_mg_get_status(STGCPENT, &cfm, mg_cfg, mg_peer); + + get_peer_xml_buffer(&prntBuf[0] + len, &cfm.t.ssta.s.mgPeerSta); + + len = len + sprintf(&prntBuf[0] + len,"\n"); + } len = len + sprintf(&prntBuf[0] + len,"\n"); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c index 591bb5f13d..d6fe2c5614 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c @@ -183,7 +183,6 @@ switch_status_t sng_mgco_cfg(megaco_profile_t* profile) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO," mgco_mu_ssap_config SUCCESS \n"); } - if(mgco_mg_tsap_config(profile)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," mgco_mg_tsap_config FAILED \n"); return SWITCH_STATUS_FALSE; @@ -1001,7 +1000,7 @@ int mgco_mg_tsap_config(megaco_profile_t* profile) /* FILL TSAP config */ cfg->tSAPId = profile->idx; cfg->spId = profile->idx; - cfg->provType = mg_get_tpt_type(profile); + cfg->provType = LMG_PROV_TYPE_TUCL; /* FILL TUCL Information */ cfg->memId.region = S_REG; @@ -1045,7 +1044,7 @@ int mgco_mg_peer_config(megaco_profile_t* mg_cfg) Pst pst; /* Post for layer manager */ U32 peerIdx = 0; CmInetIpAddr ipAddr = 0; - mg_peer_profile_t* mg_peer = megaco_peer_profile_locate(mg_cfg->peer_list[0]); + mg_peer_profile_t* mg_peer = NULL; memset(&mgMngmt, 0, sizeof(mgMngmt)); cfg = &(mgMngmt.t.cfg.c.mgGcpEntCfg); @@ -1063,39 +1062,43 @@ int mgco_mg_peer_config(megaco_profile_t* mg_cfg) mgMngmt.hdr.elmId.elmnt = STGCPENT; cfg->numPeer = mg_cfg->total_peers; - cfg->peerCfg[peerIdx].sSAPId = mg_cfg->idx; /* SSAP ID */; - cfg->peerCfg[peerIdx].port = atoi(mg_peer->port); - cfg->peerCfg[peerIdx].tsapId = mg_cfg->idx; + for(peerIdx =0; peerIdx < mg_cfg->total_peers; peerIdx++){ - cfg->peerCfg[peerIdx].mtuSize = MG_MAX_MTU_SIZE; + mg_peer = megaco_peer_profile_locate(mg_cfg->peer_list[peerIdx]); + cfg->peerCfg[peerIdx].sSAPId = mg_cfg->idx; /* SSAP ID */; + cfg->peerCfg[peerIdx].port = atoi(mg_peer->port); + cfg->peerCfg[peerIdx].tsapId = mg_cfg->idx; - cfg->peerCfg[peerIdx].peerAddrTbl.count = 1; - cfg->peerCfg[peerIdx].peerAddrTbl.netAddr[0].type = - CM_NETADDR_IPV4; + cfg->peerCfg[peerIdx].mtuSize = MG_MAX_MTU_SIZE; - if(ROK == cmInetAddr((S8*)&mg_peer->ipaddr[0],&ipAddr)) - { - cfg->peerCfg[peerIdx].peerAddrTbl.netAddr[0].u.ipv4NetAddr = ntohl(ipAddr); - } - else - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "cmInetAddr failed \n"); - cfg->peerCfg[peerIdx].peerAddrTbl.count = 0; - } + cfg->peerCfg[peerIdx].peerAddrTbl.count = 1; + cfg->peerCfg[peerIdx].peerAddrTbl.netAddr[0].type = + CM_NETADDR_IPV4; + + if(ROK == cmInetAddr((S8*)&mg_peer->ipaddr[0],&ipAddr)) + { + cfg->peerCfg[peerIdx].peerAddrTbl.netAddr[0].u.ipv4NetAddr = ntohl(ipAddr); + } + else + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "cmInetAddr failed \n"); + cfg->peerCfg[peerIdx].peerAddrTbl.count = 0; + } #ifdef GCP_MG - cfg->peerCfg[peerIdx].transportType = mg_get_tpt_type_from_str(mg_peer->transport_type); - cfg->peerCfg[peerIdx].encodingScheme = mg_get_enc_type_from_str(mg_peer->encoding_type); - cfg->peerCfg[peerIdx].mgcPriority = 0; - cfg->peerCfg[peerIdx].useAHScheme = FALSE; - cfg->peerCfg[peerIdx].mid.pres = PRSNT_NODEF; - cfg->peerCfg[peerIdx].mid.len = strlen((char*)mg_peer->mid); - cmMemcpy((U8 *)cfg->peerCfg[peerIdx].mid.val, - (CONSTANT U8*)(char*)mg_peer->mid, - cfg->peerCfg[peerIdx].mid.len); + cfg->peerCfg[peerIdx].transportType = mg_get_tpt_type_from_str(mg_peer->transport_type); + cfg->peerCfg[peerIdx].encodingScheme = mg_get_enc_type_from_str(mg_peer->encoding_type); + cfg->peerCfg[peerIdx].mgcPriority = peerIdx; + cfg->peerCfg[peerIdx].useAHScheme = FALSE; + cfg->peerCfg[peerIdx].mid.pres = PRSNT_NODEF; + cfg->peerCfg[peerIdx].mid.len = strlen((char*)mg_peer->mid); + cmMemcpy((U8 *)cfg->peerCfg[peerIdx].mid.val, + (CONSTANT U8*)(char*)mg_peer->mid, + cfg->peerCfg[peerIdx].mid.len); #endif /* GCP_MG */ + } return(sng_cfg_mg(&pst, &mgMngmt)); } diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index ba5c20aabb..f174361f03 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -78,11 +78,12 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) goto done; } - count = 0x00; - event = NULL; for (mg_peer = switch_xml_child(mg_peers, "mg_peer"); mg_peer; mg_peer = mg_peer->next) { const char *name = switch_xml_attr_soft(mg_peer, "name"); for(idx=0; idxtotal_peers; idx++){ + count = 0x00; + event = NULL; + peer_profile = NULL; if (!strcmp(name, profile->peer_list[idx])) { /* peer profile */ peer_profile = switch_core_alloc(profile->pool, sizeof(*peer_profile)); @@ -93,7 +94,7 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) count = switch_event_import_xml(switch_xml_child(mg_peer, "param"), "name", "value", &event); if(SWITCH_STATUS_FALSE == (status = switch_xml_config_parse_event(event, count, reload, instructions1))){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " Peer XML Parsing failed \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " Peer XML Parsing failed \n"); goto done; } @@ -136,6 +137,7 @@ switch_status_t mg_config_cleanup(megaco_profile_t* profile) static switch_xml_config_item_t *get_peer_instructions(mg_peer_profile_t *profile) { switch_xml_config_item_t *dup; + switch_xml_config_item_t instructions[] = { /* parameter name type reloadable pointer default value options structure */ SWITCH_CONFIG_ITEM("ip", SWITCH_CONFIG_STRING, CONFIG_RELOADABLE, &profile->ipaddr, "", &switch_config_string_strdup, "", "Peer IP"), @@ -145,7 +147,7 @@ static switch_xml_config_item_t *get_peer_instructions(mg_peer_profile_t *profil SWITCH_CONFIG_ITEM("message-identifier", SWITCH_CONFIG_STRING, 0, &profile->mid, "", &switch_config_string_strdup, "", "peer message identifier "), SWITCH_CONFIG_ITEM_END() }; - + dup = malloc(sizeof(instructions)); memcpy(dup, instructions, sizeof(instructions)); return dup; diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 30de4f86fc..ea6e9fe53b 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -118,7 +118,7 @@ void handle_sng_log(uint8_t level, char *fmt, ...) case SNG_LOGLEVEL_DEBUG: log_level = SWITCH_LOG_DEBUG; break; case SNG_LOGLEVEL_INFO: log_level = SWITCH_LOG_INFO; break; case SNG_LOGLEVEL_WARN: log_level = SWITCH_LOG_WARNING; break; - case SNG_LOGLEVEL_ERROR: log_level = SWITCH_LOG_DEBUG; break; + case SNG_LOGLEVEL_ERROR: log_level = SWITCH_LOG_ERROR; break; case SNG_LOGLEVEL_CRIT: log_level = SWITCH_LOG_CRIT; break; default: log_level = SWITCH_LOG_DEBUG; break; }; diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 23a94b9261..4a8107f859 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -502,7 +502,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi char name[128]; const char *dname = "PCMU"; uint32_t interval = 20; - crtp_private_t *tech_pvt; + crtp_private_t *tech_pvt = NULL; #if 0 const char *r_sdp = switch_event_get_header(var_event, kRSDP); #endif From 3693867388d241078a113ef1c37cdb9f95a23896 Mon Sep 17 00:00:00 2001 From: kapil Date: Thu, 21 Jun 2012 19:22:14 +0530 Subject: [PATCH 271/822] adding TCP transport support --- src/mod/endpoints/mod_media_gateway/media_gateway_stack.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c index d6fe2c5614..55fd3ee9b0 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c @@ -782,6 +782,8 @@ int mgco_mg_gen_config(void) cfg->noEDInst = 1; #endif /* CM_ABNF_MT_LIB */ + cfg->entType = LMG_ENT_GW; + #ifdef GCP_CH cfg->numBinsPeerCmdHl = 20; cfg->numBinsTransReqHl = 50; From 97d89de3fc5011168f7a5eb903316fb6d1221bed Mon Sep 17 00:00:00 2001 From: kapil Date: Thu, 21 Jun 2012 19:23:22 +0530 Subject: [PATCH 272/822] MEGACO over TCP support --- src/mod/endpoints/mod_media_gateway/media_gateway_stack.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c index 55fd3ee9b0..0cec5a829e 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c @@ -1310,7 +1310,6 @@ sng_mg_transport_types_e mg_get_tpt_type_from_str(char* tpt_type) if(!strcasecmp(tpt_type, "UDP")){ return SNG_MG_TPT_UDP; }else if(!strcasecmp(tpt_type,"TCP")){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "TCP Transport for H.248 Protocol Not Yet Supported \n"); return SNG_MG_TPT_TCP; }else if(!strcasecmp(tpt_type,"STCP")){ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "STCP Transport for H.248 Protocol Not Yet Supported \n"); From c5c7b09007bcbd767e507f86bc2cb69081936ed6 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 22 Jun 2012 11:35:00 -0400 Subject: [PATCH 273/822] Rolling back to find out what's breaking build --- conf/insideout/autoload_configs/modules.conf.xml | 2 +- conf/vanilla/autoload_configs/modules.conf.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/insideout/autoload_configs/modules.conf.xml b/conf/insideout/autoload_configs/modules.conf.xml index 8793a003ba..9970d7724d 100644 --- a/conf/insideout/autoload_configs/modules.conf.xml +++ b/conf/insideout/autoload_configs/modules.conf.xml @@ -60,7 +60,7 @@ - + diff --git a/conf/vanilla/autoload_configs/modules.conf.xml b/conf/vanilla/autoload_configs/modules.conf.xml index 50353ac849..cb45a1598c 100644 --- a/conf/vanilla/autoload_configs/modules.conf.xml +++ b/conf/vanilla/autoload_configs/modules.conf.xml @@ -80,7 +80,7 @@ - + From adca0985a4274d7d67643d9549581f1743d13db9 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 22 Jun 2012 13:20:04 -0400 Subject: [PATCH 274/822] Rolling back to find out what's breaking build --- build/modules.conf.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/modules.conf.in b/build/modules.conf.in index 2bdedc6237..e17118c6f6 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -8,10 +8,10 @@ applications/mod_spandsp #applications/mod_rad_auth dialplans/mod_dialplan_xml endpoints/mod_sofia -endpoints/mod_media_gateway +#endpoints/mod_media_gateway ../../libs/freetdm/mod_freetdm xml_int/mod_xml_cdr event_handlers/mod_event_socket codecs/mod_sangoma_codec -event_handlers/mod_radius_cdr +#event_handlers/mod_radius_cdr From 607da0f56c1b7a1c9227d39b53a53ab9a4b9ceca Mon Sep 17 00:00:00 2001 From: James Zhang Date: Fri, 22 Jun 2012 17:05:15 -0400 Subject: [PATCH 275/822] ss7: adding ss7_iam_fwd_ind_hex as x-header and channel variables in hex format. Read the forward call indicator IE and print it into channel variable ss7_iam_fwd_ind_hex. If this variable exists, put it in the x-header. This implementation takes bits of A, CB, D, E, F, HG, I from the hex value. Bits of KJ, L, P-M are not taken and set to 0. The hex value is H-A-P-I, H is the highest bit to A, and next is P-I. I is the lowest bit in the whole field, and H is the highest bit in the whole field. Refer to Q.763 chapter 3.23. --- libs/freetdm/mod_freetdm/mod_freetdm.c | 5 ++ .../ftmod_sangoma_ss7_handle.c | 1 + .../ftmod_sangoma_ss7_main.h | 1 + .../ftmod_sangoma_ss7_support.c | 54 +++++++++++++++++-- 4 files changed, 58 insertions(+), 3 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index e889d1ebba..ed57b8c0c3 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1874,6 +1874,11 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-Plan", "%d", channel_caller_data->rdnis.plan); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-CPC", "%s", ftdm_calling_party_category2str(channel_caller_data->cpc)); + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_iam_fwd_ind_hex"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-IAM-FWD-IND-HEX", "%s", var_value); + } + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_access_transport_urlenc"); if (!ftdm_strlen_zero(var_value)) { switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-Access-Transport-URLENC", "%s", var_value); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 48e4bc4735..beacecc180 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -221,6 +221,7 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ } else { SS7_INFO_CHAN(ftdmchan,"No Called party (DNIS) information in IAM!%s\n", " "); } + copy_fwdCallInd_hex_from_sngss7(ftdmchan, &siConEvnt->fwdCallInd); copy_access_transport_from_sngss7(ftdmchan, &siConEvnt->accTrnspt); copy_ocn_from_sngss7(ftdmchan, &siConEvnt->origCdNum); copy_redirgNum_from_sngss7(ftdmchan, &siConEvnt->redirgNum); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index a6dde4d704..3b62f67850 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -926,6 +926,7 @@ ftdm_status_t copy_cgPtyCat_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyCat *cgPt ftdm_status_t copy_cgPtyCat_from_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyCat *cgPtyCat); ftdm_status_t copy_accTrnspt_to_sngss7(ftdm_channel_t *ftdmchan, SiAccTrnspt *accTrnspt); ftdm_status_t copy_natConInd_to_sngss7(ftdm_channel_t *ftdmchan, SiNatConInd *natConInd); +ftdm_status_t copy_fwdCallInd_hex_from_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd *fwdCallInd); ftdm_status_t copy_fwdCallInd_to_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd *fwdCallInd); ftdm_status_t copy_txMedReq_to_sngss7(ftdm_channel_t *ftdmchan, SiTxMedReq *txMedReq); ftdm_status_t copy_usrServInfoA_to_sngss7(ftdm_channel_t *ftdmchan, SiUsrServInfo *usrServInfoA); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index b2edc2b497..bafd2d3f8d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -88,7 +88,7 @@ FTDM_STR2ENUM(ftmod_ss7_blk_state2flag, ftmod_ss7_blk_flag2str, sng_ckt_block_fl static uint8_t get_trillium_val(ftdm2trillium_t *vals, uint8_t ftdm_val, uint8_t default_val); static uint8_t get_ftdm_val(ftdm2trillium_t *vals, uint8_t trillium_val, uint8_t default_val); ftdm_status_t four_char_to_hex(const char* in, uint16_t* out) ; - +ftdm_status_t hex_to_four_char(uint16_t in, char* out); /* Maps generic FreeTDM CPC codes to SS7 CPC codes */ ftdm2trillium_t cpc_codes[] = { @@ -976,6 +976,54 @@ ftdm_status_t four_char_to_hex(const char* in, uint16_t* out) return FTDM_SUCCESS; } + +ftdm_status_t hex_to_four_char(uint16_t in, char* out) +{ + char val=0; + int mask = 0xf; + int i=0; + if (!out) { + return FTDM_SUCCESS; + } + + for (i=3; i>=0; i--) { + val = (in & (mask<<(4*i))) >> (4*i); + sprintf (out+(3-i), "%x", val); + } + + return FTDM_SUCCESS; +} + +ftdm_status_t copy_fwdCallInd_hex_from_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd *fwdCallInd) +{ + char val[5]; + uint16_t val_hex = 0; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + memset (val, 0, 5*sizeof(char)); + if (fwdCallInd->eh.pres != PRSNT_NODEF ) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No forward call indicator IE available\n"); + return FTDM_SUCCESS; + } + + val_hex |= fwdCallInd->natIntCallInd.val << 8; + val_hex |= (fwdCallInd->end2EndMethInd.val & 0x1) << 9; + val_hex |= ((fwdCallInd->end2EndMethInd.val & 0x2)>>1) << 10; + val_hex |= fwdCallInd->intInd.val << 11; + val_hex |= fwdCallInd->end2EndInfoInd.val << 12; + val_hex |= fwdCallInd->isdnUsrPrtInd.val << 13; + val_hex |= (fwdCallInd->isdnUsrPrtPrfInd.val & 0x1) << 14; + val_hex |= ((fwdCallInd->isdnUsrPrtPrfInd.val & 0x2)>>1) << 15; + + val_hex |= fwdCallInd->isdnAccInd.val; + hex_to_four_char(val_hex, val) ; + + sngss7_add_var(sngss7_info, "ss7_iam_fwd_ind_hex", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Forwad Call Indicator Hex: 0x%s\n", val); + + return FTDM_SUCCESS; +} + ftdm_status_t copy_fwdCallInd_to_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd *fwdCallInd) { const char *val = NULL; @@ -1000,9 +1048,9 @@ ftdm_status_t copy_fwdCallInd_to_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd * SS7_ERROR ("Wrong value set in iam_fwd_ind_HEX variable. Please correct the error. Setting to default values.\n" ); } else { fwdCallInd->natIntCallInd.val = (val_hex & 0x100)>>8; - fwdCallInd->end2EndMethInd.val = (val_hex & 0x600)>>9; + fwdCallInd->end2EndMethInd.val = (val_hex & 0x600)>>9; fwdCallInd->intInd.val = (val_hex & 0x800)>>11; - fwdCallInd->end2EndInfoInd.val = (val_hex & 0x1000)>>12; + fwdCallInd->end2EndInfoInd.val = (val_hex & 0x1000)>>12; fwdCallInd->isdnUsrPrtInd.val = (val_hex & 0x2000)>>13; fwdCallInd->isdnUsrPrtPrfInd.val = (val_hex & 0xC000)>>14; fwdCallInd->isdnUsrPrtPrfInd.val = (fwdCallInd->isdnUsrPrtPrfInd.val==0x03)?0x0:fwdCallInd->isdnUsrPrtPrfInd.val; From fd634d6bc9ce57fdbf2c469b7dde6e8b6b21cd3f Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Fri, 22 Jun 2012 19:10:08 -0400 Subject: [PATCH 276/822] still figuring out lib --- .../mod_media_gateway/mod_media_gateway.c | 66 ++++++++++++++++--- 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 4a3c32c9fe..1423df9cda 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -134,9 +134,6 @@ static void mgco_print_sdp(CmSdpInfoSet *sdp) { int i; -// XXX check if we can use that for debug: -// cmUnpkCmSdpInfoSet(<#CmSdpInfoSet *param#>, <#Ptr ptr#>, <#CmIntfVer intfVer#>, <#Buffer *mBuf#>); - if (sdp->numComp.pres == NOTPRSNT) { return; @@ -161,6 +158,7 @@ static void mgco_print_sdp(CmSdpInfoSet *sdp) for (mediaId = 0; mediaId < s->attrSet.numComp.val; mediaId++) { CmSdpAttr *a = s->attrSet.attr[mediaId]; + } } @@ -177,12 +175,9 @@ static void mgco_print_sdp(CmSdpInfoSet *sdp) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Port: %d\n", port); } - } } - } - } } @@ -191,6 +186,9 @@ static void mgco_print_sdp(CmSdpInfoSet *sdp) void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) { size_t txnIter; + switch_memory_pool_t *pool; + + switch_core_new_memory_pool(&pool); /*TODO*/ if(msg->body.type.val == MGT_TXN) @@ -198,6 +196,7 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) /* Loop over transaction list */ for(txnIter=0;txnIterbody.u.tl.num.val;txnIter++) { + switch(msg->body.u.tl.txns[txnIter]->type.val) { case MGT_TXNREQ: { @@ -223,12 +222,44 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) for (cmdIter=0; cmdIter < (actnReq->cl.num.val); cmdIter++) { MgMgcoCommandReq *cmdReq = actnReq->cl.cmds[cmdIter]; MgMgcoTermId *termId = NULLP; + /* The reply we'll send */ + MgMgcoCommand mgCmd = {0}; + mgCmd.peerId = msg->lcl.id; + mgCmd.transId = transId; + mgCmd.u.mgCmdInd[0] = cmdReq; + + + /* XXX Handle choose context before this */ + + mgCmd.contextId = ctxId; + mgCmd.transId = transId; + + mgCmd.cmdStatus.pres = PRSNT_NODEF; + + if(cmdIter == (actnReq->cl.num.val -1)) + { + mgCmd.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; + if(axnIter == (txnReq->al.num.val-1)) + { + mgCmd.cmdStatus.val= CH_CMD_STATUS_END_OF_TXN; + } + } + else + { + mgCmd.cmdStatus.val = CH_CMD_STATUS_PENDING; + } + + /* XXX handle props */ + mgCmd.cmdType.pres = PRSNT_NODEF; + mgCmd.cmdType.val = CH_CMD_TYPE_REQ; + mgCmd.u.mgCmdReq[0] = cmdReq; + sng_mgco_send_cmd(suId, &mgCmd); + switch (cmdReq->cmd.type.val) { case MGT_ADD: { MgMgcoAmmReq *addReq = &cmdReq->cmd.u.add; - MgMgcoTermId termId = addReq->termId; int descId; for (descId = 0; descId < addReq->dl.num.val; descId++) { switch (addReq->dl.descs[descId]->type.val) { @@ -240,24 +271,28 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) switch (mediaPar->type.val) { case MGT_MEDIAPAR_LOCAL: { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Textual SDP %s\n", mediaPar->u.local.sdpStr.pres ? "present" : "absent"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCAL"); break; } case MGT_MEDIAPAR_REMOTE: { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_REMOTE"); break; } case MGT_MEDIAPAR_LOCCTL: { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCCTL"); break; } case MGT_MEDIAPAR_TERMST: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_TERMST"); break; + } case MGT_MEDIAPAR_STRPAR: { MgMgcoStreamDesc *mgStream = &mediaPar->u.stream; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Textual SDP %s\n", mgStream->sl.remote.sdpStr.pres ? "present" : "absent"); if (mgStream->sl.remote.pres.pres) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got remote stream media description:\n"); @@ -269,6 +304,7 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) mgco_print_sdp(&mgStream->sl.local.sdp); } + break; } } @@ -285,6 +321,9 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) break; } } + + + break; } case MGT_MODIFY: @@ -316,6 +355,7 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) } case MGT_TXNREPLY: { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MGT_TXNREPLY\n"); break; } default: @@ -324,18 +364,21 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) } } } + + switch_core_destroy_memory_pool(&pool); } /*****************************************************************************************************************************/ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s\n", __PRETTY_FUNCTION__); /*TODO*/ } /*****************************************************************************************************************************/ void handle_mgco_sta_ind(Pst *pst, SuId suId, MgMgtSta* sta) { - /*TODO*/ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s\n", __PRETTY_FUNCTION__); /*TODO*/ } /*****************************************************************************************************************************/ @@ -343,18 +386,21 @@ void handle_mgco_sta_ind(Pst *pst, SuId suId, MgMgtSta* sta) void handle_mgco_txn_sta_ind(Pst *pst, SuId suId, MgMgcoInd* txn_sta_ind) { /*TODO*/ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s\n", __PRETTY_FUNCTION__); } /*****************************************************************************************************************************/ void handle_mgco_cntrl_cfm(Pst *pst, SuId suId, MgMgtCntrl* cntrl, Reason reason) { /*TODO*/ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s\n", __PRETTY_FUNCTION__); } /*****************************************************************************************************************************/ void handle_mgco_audit_cfm(Pst *pst, SuId suId, MgMgtAudit* audit, Reason reason) { /*TODO*/ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s\n", __PRETTY_FUNCTION__); } /*****************************************************************************************************************************/ From e3eed73ecbe2687598983579bee78b2c202f327c Mon Sep 17 00:00:00 2001 From: kapil Date: Mon, 25 Jun 2012 12:12:04 +0530 Subject: [PATCH 277/822] adding mg and peer profile cleanup code during shutdown and removing "unused variables" warnings --- .../mod_media_gateway/media_gateway.c | 15 +++++++ .../mod_media_gateway/media_gateway_xml.c | 9 +++++ .../mod_media_gateway/mod_media_gateway.c | 39 ++++++++++++++++--- .../mod_media_gateway/mod_media_gateway.h | 2 + 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 98d433179e..3cd5856bd2 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -107,6 +107,21 @@ switch_status_t megaco_profile_destroy(megaco_profile_t **profile) return SWITCH_STATUS_SUCCESS; } +switch_status_t megaco_peer_profile_destroy(mg_peer_profile_t **profile) +{ + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Stopping peer profile: %s\n", (*profile)->name); + + switch_core_hash_delete_wrlock(megaco_globals.peer_profile_hash, (*profile)->name, megaco_globals.peer_profile_rwlock); + + mg_peer_config_cleanup(*profile); + + switch_core_destroy_memory_pool(&(*profile)->pool); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Stopped peer profile: %s\n", (*profile)->name); + + return SWITCH_STATUS_SUCCESS; +} + /* For Emacs: * Local Variables: * mode:c diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index 9e6b7fc1ad..c48032e30c 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -133,6 +133,15 @@ switch_status_t mg_config_cleanup(megaco_profile_t* profile) return SWITCH_STATUS_SUCCESS; } +/****************************************************************************************************************************/ +switch_status_t mg_peer_config_cleanup(mg_peer_profile_t* profile) +{ + switch_xml_config_item_t *instructions = (profile ? get_peer_instructions(profile) : NULL); + switch_xml_config_cleanup(instructions); + + return SWITCH_STATUS_SUCCESS; +} + /****************************************************************************************************************************/ static switch_xml_config_item_t *get_peer_instructions(mg_peer_profile_t *profile) { switch_xml_config_item_t *dup; diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 1423df9cda..b056d91bba 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -97,6 +97,32 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load) SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_media_gateway_shutdown) { + void *val = NULL; + const void *key = NULL; + switch_ssize_t keylen; + switch_hash_index_t *hi = NULL; + megaco_profile_t* profile = NULL; + mg_peer_profile_t* peer_profile = NULL; + + /* destroy all the mg profiles */ + while ((hi = switch_hash_first(NULL, megaco_globals.profile_hash))) { + switch_hash_this(hi, &key, &keylen, &val); + profile = (megaco_profile_t *) val; + megaco_profile_destroy(&profile); + profile = NULL; + } + + hi = NULL; + key = NULL; + val = NULL; + /* destroy all the mg peer profiles */ + while ((hi = switch_hash_first(NULL, megaco_globals.peer_profile_hash))) { + switch_hash_this(hi, &key, &keylen, &val); + peer_profile = (mg_peer_profile_t *) val; + megaco_peer_profile_destroy(&peer_profile); + peer_profile = NULL; + } + sng_mgco_stack_shutdown(); return SWITCH_STATUS_SUCCESS; @@ -156,7 +182,7 @@ static void mgco_print_sdp(CmSdpInfoSet *sdp) } if (s->attrSet.numComp.pres) { for (mediaId = 0; mediaId < s->attrSet.numComp.val; mediaId++) { - CmSdpAttr *a = s->attrSet.attr[mediaId]; + /*CmSdpAttr *a = s->attrSet.attr[mediaId];*/ } @@ -221,9 +247,10 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) /* Loop over command list */ for (cmdIter=0; cmdIter < (actnReq->cl.num.val); cmdIter++) { MgMgcoCommandReq *cmdReq = actnReq->cl.cmds[cmdIter]; - MgMgcoTermId *termId = NULLP; + /*MgMgcoTermId *termId = NULLP;*/ /* The reply we'll send */ - MgMgcoCommand mgCmd = {0}; + MgMgcoCommand mgCmd; + memset(&mgCmd, 0, sizeof(mgCmd)); mgCmd.peerId = msg->lcl.id; mgCmd.transId = transId; mgCmd.u.mgCmdInd[0] = cmdReq; @@ -328,18 +355,18 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) } case MGT_MODIFY: { - MgMgcoAmmReq *addReq = &cmdReq->cmd.u.mod; + /*MgMgcoAmmReq *addReq = &cmdReq->cmd.u.mod;*/ break; } case MGT_MOVE: { - MgMgcoAmmReq *addReq = &cmdReq->cmd.u.move; + /*MgMgcoAmmReq *addReq = &cmdReq->cmd.u.move;*/ break; } case MGT_SUB: { - MgMgcoSubAudReq *addReq = &cmdReq->cmd.u.sub; + /*MgMgcoSubAudReq *addReq = &cmdReq->cmd.u.sub;*/ } case MGT_SVCCHG: case MGT_NTFY: diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index d4c6e43077..8aa0dae0d3 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -84,6 +84,8 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload); switch_status_t sng_mgco_start(megaco_profile_t* profile); switch_status_t sng_mgco_stop(megaco_profile_t* profile); switch_status_t mg_config_cleanup(megaco_profile_t* profile); +switch_status_t mg_peer_config_cleanup(mg_peer_profile_t* profile); +switch_status_t megaco_peer_profile_destroy(mg_peer_profile_t **profile); switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stream); From b6737e31a30afe9901f327b7b29120281c0e2754 Mon Sep 17 00:00:00 2001 From: kapil Date: Mon, 25 Jun 2012 20:07:51 +0530 Subject: [PATCH 278/822] adding command handler to handle command indication from megaco stack --- .../mod_media_gateway/media_gateway_stack.c | 2 + .../mod_media_gateway/media_gateway_stack.h | 8 + .../mod_media_gateway/media_gateway_xml.c | 6 +- .../mod_media_gateway/mod_media_gateway.c | 296 +++++++++++++++++- 4 files changed, 307 insertions(+), 5 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c index 0cec5a829e..8a300ff97e 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c @@ -945,6 +945,8 @@ int mgco_mg_ssap_config(megaco_profile_t* profile) return SWITCH_STATUS_FALSE; } + pCfg->chEnabled = 0x01; + pCfg->userInfo.pres.pres = PRSNT_NODEF; pCfg->userInfo.id.pres = NOTPRSNT; pCfg->userInfo.mid.pres = PRSNT_NODEF; diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index 9bbe90b7df..6c2cbc7abd 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -62,4 +62,12 @@ switch_status_t sng_mgco_init(sng_mg_event_interface_t* event); switch_status_t sng_mgco_stack_shutdown(void); int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, megaco_profile_t* mg_cfg, mg_peer_profile_t* mg_peer); +/****************************************************************************************************************/ +/* MG Stack defines */ + +/* Free Commands inside MG CH command */ +#define mg_free_cmd(_cmd) mgFreeEventMem(_cmd) + +/****************************************************************************************************************/ + #endif /* _MEGACO_STACK_H_ */ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index c48032e30c..f1259ed544 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -27,6 +27,7 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) char *var, *val; mg_peer_profile_t* peer_profile = NULL; switch_xml_config_item_t *instructions1 = NULL; + switch_memory_pool_t *pool; if (!(xml = switch_xml_open_cfg(file, &cfg, NULL))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not open %s\n", file); @@ -86,8 +87,9 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) peer_profile = NULL; if (!strcmp(name, profile->peer_list[idx])) { /* peer profile */ - peer_profile = switch_core_alloc(profile->pool, sizeof(*peer_profile)); - peer_profile->pool = profile->pool; + switch_core_new_memory_pool(&pool); + peer_profile = switch_core_alloc(pool, sizeof(*peer_profile)); + peer_profile->pool = pool; peer_profile->name = switch_core_strdup(peer_profile->pool, name); switch_thread_rwlock_create(&peer_profile->rwlock, peer_profile->pool); instructions1 = (peer_profile ? get_peer_instructions(peer_profile) : NULL); diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index b056d91bba..56d40ec41d 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -9,12 +9,18 @@ #include "mod_media_gateway.h" #include "media_gateway_stack.h" + +/**************************************************************************************************************/ struct megaco_globals megaco_globals; static sng_mg_event_interface_t sng_event; +/**************************************************************************************************************/ SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_media_gateway_shutdown); SWITCH_MODULE_DEFINITION(mod_media_gateway, mod_media_gateway_load, mod_media_gateway_shutdown, NULL); +switch_status_t handle_mg_add_cmd(MgMgcoAmmReq *addReq); + +/**************************************************************************************************************/ SWITCH_STANDARD_API(megaco_function) { @@ -247,7 +253,7 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) /* Loop over command list */ for (cmdIter=0; cmdIter < (actnReq->cl.num.val); cmdIter++) { MgMgcoCommandReq *cmdReq = actnReq->cl.cmds[cmdIter]; - /*MgMgcoTermId *termId = NULLP;*/ + /*MgMgcoTermId *term_id = NULLP;*/ /* The reply we'll send */ MgMgcoCommand mgCmd; memset(&mgCmd, 0, sizeof(mgCmd)); @@ -398,8 +404,81 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) /*****************************************************************************************************************************/ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s\n", __PRETTY_FUNCTION__); - /*TODO*/ + uint32_t txn_id = 0x00; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: Received Command Type[%s] \n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(cmd->cmdType.val)); + + /* validate Transaction Id */ + if (NOTPRSNT != cmd->transId.pres) + txn_id = cmd->transId.val; + else + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: Transaction Id not present, rejecting\n", __PRETTY_FUNCTION__); + /*TODO - can invoke "MgUiMgtMgcoErrReq" to report error to MEGACO stack */ + /* deallocate the msg */ + mg_free_cmd(cmd); + return ; + } + + mgAccEvntPrntMgMgcoCommand(cmd, stdout); + + switch(cmd->cmdType.val) + { + case CH_CMD_TYPE_IND: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: Received Command indication for command[%s]\n", + __PRETTY_FUNCTION__,PRNT_MG_CMD(cmd->u.mgCmdInd[0]->cmd.type.val)); + + switch(cmd->u.mgCmdInd[0]->cmd.type.val) + { + case MGT_ADD: + { + handle_mg_add_cmd(&cmd->u.mgCmdInd[0]->cmd.u.add); + break; + } + + case MGT_MODIFY: + { + /*MgMgcoAmmReq *addReq = &cmdReq->cmd.u.mod;*/ + break; + } + case MGT_MOVE: + { + /*MgMgcoAmmReq *addReq = &cmdReq->cmd.u.move;*/ + break; + + } + case MGT_SUB: + { + /*MgMgcoSubAudReq *addReq = &cmdReq->cmd.u.sub;*/ + } + case MGT_SVCCHG: + case MGT_NTFY: + case MGT_AUDITCAP: + case MGT_AUDITVAL: + break; + } + + break; + } + case CH_CMD_TYPE_REQ: + { + break; + } + case CH_CMD_TYPE_RSP: + { + break; + } + case CH_CMD_TYPE_CFM: + { + break; + } + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Invalid command type[%d]\n",cmd->cmdType.val); + return; + } + + return; } /*****************************************************************************************************************************/ @@ -430,7 +509,218 @@ void handle_mgco_audit_cfm(Pst *pst, SuId suId, MgMgtAudit* audit, Reason reason switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s\n", __PRETTY_FUNCTION__); } + /*****************************************************************************************************************************/ +/* +* +* Fun: mg_get_term_id_list +* +* Desc: Utility function to get MgMgcoTermIdLst structure +* from MgMgcoCommand structure. +* GCP_VER_2_1 - we will have term id list instead of single term id +* +* Ret: If success, return pointer to MgMgcoTermIdLst. +* If failure, return Null. +* +* Notes: None +* +*/ + +MgMgcoTermIdLst *mg_get_term_id_list(MgMgcoCommand *cmd) +{ + uint8_t cmd_type = MGT_NONE; + uint8_t api_type = CM_CMD_TYPE_NONE; + MgMgcoTermIdLst * term_id = NULL; + + + /*-- mgCmdInd type represents the data structure for both + * incoming and outgoing requests, hence we can get the + * command type from there itself --*/ + cmd_type = cmd->u.mgCmdInd[0]->cmd.type.val; + + /*-- Find apiType --*/ + api_type = cmd->cmdType.val; + + switch (api_type) + { + case CH_CMD_TYPE_REQ: + case CH_CMD_TYPE_IND: + /* Based on Command Type, get to the TermId structure */ + switch (cmd_type) + { + case MGT_ADD: + if (cmd->u.mgCmdInd[0]->cmd.u.add.pres.pres) + term_id = &cmd->u.mgCmdInd[0]->cmd.u.add.termIdLst; + break; + + case MGT_MOVE: + if (cmd->u.mgCmdInd[0]->cmd.u.move.pres.pres) + term_id = &cmd->u.mgCmdInd[0]->cmd.u.move.termIdLst; + break; + + case MGT_MODIFY: + if (cmd->u.mgCmdInd[0]->cmd.u.mod.pres.pres) + term_id = &cmd->u.mgCmdInd[0]->cmd.u.mod.termIdLst; + break; + + case MGT_SUB: + if (cmd->u.mgCmdInd[0]->cmd.u.sub.pres.pres) + term_id = &cmd->u.mgCmdInd[0]->cmd.u.sub.termIdLst; + break; + + case MGT_AUDITCAP: + if (cmd->u.mgCmdInd[0]->cmd.u.acap.pres.pres) + term_id = &cmd->u.mgCmdInd[0]->cmd.u.acap.termIdLst; + break; + + case MGT_AUDITVAL: + if (cmd->u.mgCmdInd[0]->cmd.u.aval.pres.pres) + term_id = &cmd->u.mgCmdInd[0]->cmd.u.aval.termIdLst; + break; + + case MGT_NTFY: + if (cmd->u.mgCmdInd[0]->cmd.u.ntfy.pres.pres) + term_id = &cmd->u.mgCmdInd[0]->cmd.u.ntfy.termIdLst; + break; + + case MGT_SVCCHG: + if (cmd->u.mgCmdInd[0]->cmd.u.svc.pres.pres) + term_id = &cmd->u.mgCmdInd[0]->cmd.u.svc.termIdLst; + break; + + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); + break; + } + break; + + case CH_CMD_TYPE_RSP: + case CH_CMD_TYPE_CFM: + + cmd_type = cmd->u.mgCmdRsp[0]->type.val; + + switch (cmd_type) + { + case MGT_ADD: + if (cmd->u.mgCmdRsp[0]->u.add.pres.pres) + term_id = &cmd->u.mgCmdRsp[0]->u.add.termIdLst; + break; + + case MGT_MOVE: + if (cmd->u.mgCmdRsp[0]->u.move.pres.pres) + term_id = &cmd->u.mgCmdRsp[0]->u.move.termIdLst; + break; + + case MGT_MODIFY: + if (cmd->u.mgCmdRsp[0]->u.mod.pres.pres) + term_id = &cmd->u.mgCmdRsp[0]->u.mod.termIdLst; + break; + + case MGT_SUB: + if (cmd->u.mgCmdRsp[0]->u.sub.pres.pres) + term_id = &cmd->u.mgCmdRsp[0]->u.sub.termIdLst; + break; + + case MGT_SVCCHG: + if (cmd->u.mgCmdRsp[0]->u.svc.pres.pres) + term_id = &cmd->u.mgCmdRsp[0]->u.svc.termIdLst; + break; + + case MGT_AUDITVAL: + if (cmd->u.mgCmdRsp[0]->u.aval.u.other.pres.pres) + term_id = &cmd->u.mgCmdRsp[0]->u.aval.u.other.termIdLst; + break; + + case MGT_AUDITCAP: + if (cmd->u.mgCmdRsp[0]->u.acap.u.other.pres.pres) + term_id = &cmd->u.mgCmdRsp[0]->u.acap.u.other.termIdLst; + break; + + case MGT_NTFY: + if (cmd->u.mgCmdRsp[0]->u.ntfy.pres.pres) + term_id = &cmd->u.mgCmdRsp[0]->u.ntfy.termIdLst; + break; + + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); + } /* switch command type for reply */ + break; + + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported api_type[%s]!\n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(api_type)); + break; + } /* switch -api_type */ + + return (term_id); +} + +/*****************************************************************************************************************************/ + +switch_status_t handle_mg_add_cmd(MgMgcoAmmReq *addReq) +{ + int descId; + for (descId = 0; descId < addReq->dl.num.val; descId++) { + switch (addReq->dl.descs[descId]->type.val) { + case MGT_MEDIADESC: + { + int mediaId; + for (mediaId = 0; mediaId < addReq->dl.descs[descId]->u.media.num.val; mediaId++) { + MgMgcoMediaPar *mediaPar = addReq->dl.descs[descId]->u.media.parms[mediaId]; + switch (mediaPar->type.val) { + case MGT_MEDIAPAR_LOCAL: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCAL"); + break; + } + case MGT_MEDIAPAR_REMOTE: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_REMOTE"); + break; + } + + case MGT_MEDIAPAR_LOCCTL: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCCTL"); + break; + } + case MGT_MEDIAPAR_TERMST: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_TERMST"); + break; + } + case MGT_MEDIAPAR_STRPAR: + { + MgMgcoStreamDesc *mgStream = &mediaPar->u.stream; + + if (mgStream->sl.remote.pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got remote stream media description:\n"); + mgco_print_sdp(&mgStream->sl.remote.sdp); + } + + if (mgStream->sl.local.pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got local stream media description:\n"); + mgco_print_sdp(&mgStream->sl.local.sdp); + } + + break; + } + } + } + } + case MGT_MODEMDESC: + case MGT_MUXDESC: + case MGT_REQEVTDESC: + case MGT_EVBUFDESC: + case MGT_SIGNALSDESC: + case MGT_DIGMAPDESC: + case MGT_AUDITDESC: + case MGT_STATSDESC: + break; + } + } + + return SWITCH_STATUS_SUCCESS; +} /*****************************************************************************************************************************/ From e777de3eefc161e32709534ae63454a8f20d0c5f Mon Sep 17 00:00:00 2001 From: kapil Date: Tue, 26 Jun 2012 13:05:23 +0530 Subject: [PATCH 279/822] adding mg stack add command code and sendign dummy rsp of add --- .../mod_media_gateway/mod_media_gateway.c | 180 ++++++++++++++++++ 1 file changed, 180 insertions(+) diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 56d40ec41d..d24fa93008 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -19,6 +19,11 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_media_gateway_shutdown); SWITCH_MODULE_DEFINITION(mod_media_gateway, mod_media_gateway_load, mod_media_gateway_shutdown, NULL); switch_status_t handle_mg_add_cmd(MgMgcoAmmReq *addReq); +switch_status_t mg_stack_free_mem(MgMgcoMsg* msg); +switch_status_t mg_stack_free_mem(MgMgcoMsg* msg); +switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ); +switch_status_t mg_send_add_rsp(SuId suId, MgMgcoCommand *req); +S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, CONSTANT U8 *str, CmMemListCp *memCp); /**************************************************************************************************************/ @@ -434,6 +439,7 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) case MGT_ADD: { handle_mg_add_cmd(&cmd->u.mgCmdInd[0]->cmd.u.add); + mg_send_add_rsp(suId, cmd); break; } @@ -493,6 +499,9 @@ void handle_mgco_txn_sta_ind(Pst *pst, SuId suId, MgMgcoInd* txn_sta_ind) { /*TODO*/ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s\n", __PRETTY_FUNCTION__); + + /*dump information*/ + /*mgAccEvntPrntMgMgcoInd(txn_sta_ind, stdout);*/ } /*****************************************************************************************************************************/ @@ -719,9 +728,180 @@ switch_status_t handle_mg_add_cmd(MgMgcoAmmReq *addReq) } } + return SWITCH_STATUS_SUCCESS; } + +/*****************************************************************************************************************************/ +switch_status_t mg_send_add_rsp(SuId suId, MgMgcoCommand *req) +{ + MgMgcoCommand cmd; + int ret = 0x00; + MgMgcoTermId *termId; + + memset(&cmd,0, sizeof(cmd)); + + /*copy transaction-id*/ + memcpy(&cmd.transId, &req->transId,sizeof(MgMgcoTransId)); + + /*copy context-id*/ /*TODO - in case of $ context should be generated by app, we should not simply copy incoming structure */ + memcpy(&cmd.contextId, &req->contextId,sizeof(MgMgcoContextId)); + + /*copy peer identifier */ + memcpy(&cmd.peerId, &req->peerId,sizeof(TknU32)); + + /*fill response structue */ + if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&cmd.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ + return ret; + } + + cmd.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; + cmd.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; + cmd.u.mgCmdRsp[0]->type.val = MGT_ADD; + cmd.u.mgCmdRsp[0]->u.add.pres.pres = PRSNT_NODEF; + + + cmd.u.mgCmdRsp[0]->u.add.termIdLst.num.pres = PRSNT_NODEF; + cmd.u.mgCmdRsp[0]->u.add.termIdLst.num.val = 1; + + mgUtlAllocMgMgcoTermIdLst(&cmd.u.mgCmdRsp[0]->u.add.termIdLst, &req->u.mgCmdReq[0]->cmd.u.add.termIdLst); + +#ifdef GCP_VER_2_1 + termId = cmd.u.mgCmdRsp[0]->u.add.termIdLst.terms[0]; +#else + termId = &(cmd.u.mgCmdRsp[0]->u.add.termId); +#endif + mg_fill_mgco_termid(termId, (CONSTANT U8*)"term1",&req->u.mgCmdRsp[0]->memCp); + + /* We will always send one command at a time..*/ + cmd.cmdStatus.pres = PRSNT_NODEF; + cmd.cmdStatus.val = CH_CMD_STATUS_END_OF_CMD; + + cmd.cmdType.pres = PRSNT_NODEF; + cmd.cmdType.val = CH_CMD_TYPE_RSP; + + + ret = sng_mgco_send_cmd(suId, &cmd); + + + return ret; +} + +/*****************************************************************************************************************************/ +switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ) +{ + Mem sMem; + + sMem.region = 0; + sMem.pool = 0; + + if ( _memSize <= 0 ) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_alloc_mem: invalid size\n"); + return SWITCH_STATUS_FALSE; + } + + if ( ROK != cmAllocEvnt( _memSize, MG_MAXBLKSIZE, &sMem, _memPtr ) ) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_alloc_mem: cmAllocEvnt return failure for _memSize=%d\n",_memSize); + return SWITCH_STATUS_FALSE; + } + + // Note: memset done inside stack api + + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t mg_stack_get_mem(MgMgcoMsg* msg, Ptr* _memPtr, Size _memSize ) +{ + if ( _memSize <= 0 ) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_get_mem: invalid size\n"); + return SWITCH_STATUS_FALSE; + } + + if ( !msg ) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_get_mem: invalid message\n"); + return SWITCH_STATUS_FALSE; + } + + if ( cmGetMem( (Ptr)msg, _memSize, (Ptr*)_memPtr ) != ROK ) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed alloc_mg_stack_mem: get memory failed _memSize=%d\n", _memSize ); + return SWITCH_STATUS_FALSE; + } + + // Note: memset done inside stack api + + return SWITCH_STATUS_SUCCESS; +} + + +switch_status_t mg_stack_free_mem(MgMgcoMsg* msg) +{ + if ( !msg ) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_get_mem: invalid message\n"); + return SWITCH_STATUS_FALSE; + } + + cmFreeMem( (Ptr)msg ); + + return SWITCH_STATUS_SUCCESS; +} + +#define MG_ACC_GETMEM(_ptr,_len,_memCp,_ret) \ +{ \ + ret = cmGetMem((_memCp), (_len), (Ptr *)&(_ptr)); \ + if( ret == ROK) \ + cmMemset((U8 *)(_ptr), (U8)0, (PTR)(_len)); \ +} + + +S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, CONSTANT U8 *str, CmMemListCp *memCp) +{ +#ifdef GCP_ASN + Size size; +#endif + S16 ret = ROK; + + termId->name.pres.pres = PRSNT_NODEF; + /* mg011.105: Bug fixes */ + termId->name.lcl.pres = PRSNT_NODEF; + termId->name.lcl.len = cmStrlen((CONSTANT U8*)str); + MG_ACC_GETMEM((termId->name.lcl.val), termId->name.lcl.len, memCp, ret); + if( ret != ROK) + RETVALUE(ret); + + cmMemcpy((U8*)(termId->name.lcl.val), (CONSTANT U8*)str,termId->name.lcl.len); + +#ifdef GCP_ASN + /* Remove comment to fill other term ID + termId->wildcard.num.pres = NOTPRSNT; */ + /* Remove comment to fill wilcard term ID */ + termId->wildcard.num.pres = PRSNT_NODEF; + termId->wildcard.num.val = 1; + size = ((sizeof(MgMgcoWildcardField*))); + MG_ACC_GETMEM((termId->wildcard.wildcard),size,memCp, ret); + if( ret != ROK) + RETVALUE(ret); + + MG_ACC_GETMEM( ((termId->wildcard.wildcard)[0]),sizeof(MgMgcoWildcardField), + memCp, ret); + if( ret != ROK) + RETVALUE(ret); + + termId->wildcard.wildcard[0]->pres = PRSNT_NODEF; + termId->wildcard.wildcard[0]->len = 1; + termId->wildcard.wildcard[0]->val[0] = 0x55; +#endif /* GCP_ASN */ + + RETVALUE(ROK); +} + + /*****************************************************************************************************************************/ /* For Emacs: From c82c11b02a3dc54e1a68ed29bd3c5024dc4dd603 Mon Sep 17 00:00:00 2001 From: kapil Date: Tue, 26 Jun 2012 17:45:01 +0530 Subject: [PATCH 280/822] adding code to send add response --- src/mod/endpoints/mod_media_gateway/mod_media_gateway.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index d24fa93008..bca39abb30 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -739,6 +739,7 @@ switch_status_t mg_send_add_rsp(SuId suId, MgMgcoCommand *req) MgMgcoCommand cmd; int ret = 0x00; MgMgcoTermId *termId; + MgMgcoCtxt ctxt; memset(&cmd,0, sizeof(cmd)); @@ -784,6 +785,12 @@ switch_status_t mg_send_add_rsp(SuId suId, MgMgcoCommand *req) ret = sng_mgco_send_cmd(suId, &cmd); + memcpy(&ctxt.transId,&req->transId,sizeof(MgMgcoTransId)); + memcpy(&ctxt.cntxtId, &req->contextId,sizeof(MgMgcoContextId)); + memcpy(&ctxt.peerId, &req->peerId,sizeof(TknU32)); + ctxt.cmdStatus.pres = PRSNT_NODEF; + ctxt.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; + ret = sng_mgco_send_axn_req(suId, &ctxt); return ret; } From fcaeb37cfd3c0c8aa70992223702c1b325288c67 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 26 Jun 2012 21:25:56 -0400 Subject: [PATCH 281/822] further rollback --- build/modules.conf.in | 3 --- 1 file changed, 3 deletions(-) diff --git a/build/modules.conf.in b/build/modules.conf.in index 2bdedc6237..e93ce2c677 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -5,13 +5,10 @@ applications/mod_dptools applications/mod_commands applications/mod_hash applications/mod_spandsp -#applications/mod_rad_auth dialplans/mod_dialplan_xml endpoints/mod_sofia -endpoints/mod_media_gateway ../../libs/freetdm/mod_freetdm xml_int/mod_xml_cdr event_handlers/mod_event_socket codecs/mod_sangoma_codec -event_handlers/mod_radius_cdr From 80f72823b3a0427b6b24851e146984976e0e799a Mon Sep 17 00:00:00 2001 From: James Zhang Date: Wed, 27 Jun 2012 12:31:35 -0400 Subject: [PATCH 282/822] ss7: add ss7_iam_nature_connection_hex to support Nature of Connection Indicator in IAM message. - ss7_iam_nature_connection_hex is the channel variable to carry HEX value from/to IAM message - X-FreeTDM-IAM-NATURE-CONN-HEX is the x-header string to carry HEX value from/to sip invite message - This IE is 8 bit hex, which turns into 2 chars - Only Satellite indicator, Continuity check indicator, and Echo control device indicator are supported. Spare value are not taken. Spare value is always set to all zero. - example: To set 00010101 (bit H-A), set X-FreeTDM-IAM-NATURE-CONN-HEX string value to 15 in the sip invite message to NSG. When NSG send out sip invite, if the incoming IAM message comes with Nature of Connection IE, NSG will put X-FreeTDM-IAM-NATURE-CONN-HEX in the invite x-header. For example, if the IE value is 00001010 in the IAM, NSG will send X-FreeTDM-IAM-NATURE-CONN-HEX with value string of "0A". - Two characters are madatory. "0A" must be specified rather than "A". If invalid format or characters are found, this x-header will be ommited. - Valid characters include 0-9, A-F, and a-f --- libs/freetdm/mod_freetdm/mod_freetdm.c | 11 ++ .../ftmod_sangoma_ss7_handle.c | 1 + .../ftmod_sangoma_ss7_main.h | 2 + .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c | 4 + .../ftmod_sangoma_ss7_support.c | 130 ++++++++++++++++++ 5 files changed, 148 insertions(+) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index ed57b8c0c3..a3e9fd4568 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1558,6 +1558,11 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi if (sipvar) { ftdm_usrmsg_add_var(&usrmsg, "ss7_iam_fwd_ind_hex", sipvar); } + + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-IAM-NATURE-CONN-HEX"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_iam_nature_connection_hex", sipvar); + } } if (switch_test_flag(outbound_profile, SWITCH_CPF_SCREEN)) { @@ -1873,7 +1878,13 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-NADI", "%d", channel_caller_data->rdnis.type); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-Plan", "%d", channel_caller_data->rdnis.plan); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-CPC", "%s", ftdm_calling_party_category2str(channel_caller_data->cpc)); + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_iam_nature_connection_hex"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-IAM-NATURE-CONN-HEX", "%s", var_value); + } + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_iam_fwd_ind_hex"); if (!ftdm_strlen_zero(var_value)) { switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-IAM-FWD-IND-HEX", "%s", var_value); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index beacecc180..a4802b1853 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -221,6 +221,7 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ } else { SS7_INFO_CHAN(ftdmchan,"No Called party (DNIS) information in IAM!%s\n", " "); } + copy_NatureOfConnection_from_sngss7(ftdmchan, &siConEvnt->natConInd); copy_fwdCallInd_hex_from_sngss7(ftdmchan, &siConEvnt->fwdCallInd); copy_access_transport_from_sngss7(ftdmchan, &siConEvnt->accTrnspt); copy_ocn_from_sngss7(ftdmchan, &siConEvnt->origCdNum); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 3b62f67850..1e064f2522 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -930,6 +930,8 @@ ftdm_status_t copy_fwdCallInd_hex_from_sngss7(ftdm_channel_t *ftdmchan, SiFwdCal ftdm_status_t copy_fwdCallInd_to_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd *fwdCallInd); ftdm_status_t copy_txMedReq_to_sngss7(ftdm_channel_t *ftdmchan, SiTxMedReq *txMedReq); ftdm_status_t copy_usrServInfoA_to_sngss7(ftdm_channel_t *ftdmchan, SiUsrServInfo *usrServInfoA); +ftdm_status_t copy_NatureOfConnection_from_sngss7(ftdm_channel_t *ftdmchan, SiNatConInd *natConInd ); +ftdm_status_t copy_NatureOfConnection_to_sngss7(ftdm_channel_t *ftdmchan, SiNatConInd *natConInd); ftdm_status_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven); ftdm_status_t append_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index bf693c0999..4f177a3957 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -163,6 +163,8 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum); copy_access_transport_to_sngss7(ftdmchan, &iam.accTrnspt); + + copy_NatureOfConnection_to_sngss7(ftdmchan, &iam.natConInd); } else { /* Nature of Connection Indicators */ copy_natConInd_to_sngss7(ftdmchan, &iam.natConInd); @@ -209,6 +211,8 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) This will overwirte the IE value set be above old implementation. */ copy_access_transport_to_sngss7(ftdmchan, &iam.accTrnspt); + + copy_NatureOfConnection_to_sngss7(ftdmchan, &iam.natConInd); SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM clg = \"%s\" (NADI=%d), cld = \"%s\" (NADI=%d), loc = %s (NADI=%d)\n", sngss7_info->circuit->cic, diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index bafd2d3f8d..2f4c18d4c3 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -90,6 +90,10 @@ static uint8_t get_ftdm_val(ftdm2trillium_t *vals, uint8_t trillium_val, uint8_t ftdm_status_t four_char_to_hex(const char* in, uint16_t* out) ; ftdm_status_t hex_to_four_char(uint16_t in, char* out); + +ftdm_status_t hex_to_char(uint16_t in, char* out, int len); +ftdm_status_t char_to_hex(const char* in, uint16_t* out, int len); + /* Maps generic FreeTDM CPC codes to SS7 CPC codes */ ftdm2trillium_t cpc_codes[] = { {FTDM_CPC_UNKNOWN, CAT_UNKNOWN}, @@ -976,7 +980,79 @@ ftdm_status_t four_char_to_hex(const char* in, uint16_t* out) return FTDM_SUCCESS; } +ftdm_status_t char_to_hex(const char* in, uint16_t* out, int len) +{ + int i= len; + char *val = ftdm_malloc(len*sizeof(char)); + + if (!val ||!in || len>strlen(in)) { + return FTDM_FAIL; + } + + while(i) + { + switch((char)*(in+(len-i))) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + *(val+(len-i)) = *(in+(len-i)) - 48; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + *(val+(len-i)) = *(in+(len-i)) - 55; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + *(val+(len-i)) = *(in+(len-i)) - 87; + break; + default: + SS7_ERROR("Invalid character found when decoding hex string, %c!\n", *(in+(len-i)) ); + break; + } + i--; + }; + for (i=0; i<=len-1; i++) { + *out = *out << 4; + *out |= *(val+i); + } + + return FTDM_SUCCESS; +} + + + +ftdm_status_t hex_to_char(uint16_t in, char* out, int len) +{ + char val=0; + int mask = 0xf; + int i=0; + if (!out) { + return FTDM_SUCCESS; + } + + for (i=len-1; i>=0; i--) { + val = (in & (mask<<(4*i))) >> (4*i); + sprintf (out+(len-1-i), "%x", val); + } + + return FTDM_SUCCESS; +} ftdm_status_t hex_to_four_char(uint16_t in, char* out) { char val=0; @@ -994,6 +1070,60 @@ ftdm_status_t hex_to_four_char(uint16_t in, char* out) return FTDM_SUCCESS; } +ftdm_status_t copy_NatureOfConnection_to_sngss7(ftdm_channel_t *ftdmchan, SiNatConInd *natConInd) +{ + const char *val = NULL; + + natConInd->eh.pres = PRSNT_NODEF; + natConInd->satInd.pres = PRSNT_NODEF; + natConInd->contChkInd.pres = PRSNT_NODEF;; + natConInd->echoCntrlDevInd.pres = PRSNT_NODEF; + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_nature_connection_hex"); + if (!ftdm_strlen_zero(val)) { + uint16_t val_hex = 0; + if (char_to_hex (val, &val_hex, 2) == FTDM_FAIL) { + SS7_ERROR ("Wrong value set in ss7_iam_nature_connection_hex variable. Please correct the error. Setting to default values.\n" ); + } else { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "hex = 0x%x\n", val_hex); + natConInd->satInd.val = (val_hex & 0x3); + natConInd->contChkInd.val = (val_hex & 0xc)>>2; + natConInd->echoCntrlDevInd.val = (val_hex & 0x10) >> 4; + + return FTDM_SUCCESS; + } + } + + natConInd->satInd.val = 0; + natConInd->contChkInd.val = 0; + natConInd->echoCntrlDevInd.val = 0; + + return FTDM_SUCCESS; +} + +ftdm_status_t copy_NatureOfConnection_from_sngss7(ftdm_channel_t *ftdmchan, SiNatConInd *natConInd ) +{ + char val[3]; + uint16_t val_hex = 0; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + memset (val, 0, 3*sizeof(char)); + if (natConInd->eh.pres != PRSNT_NODEF ) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No nature of connection indicator IE available\n"); + return FTDM_SUCCESS; + } + + val_hex |= natConInd->satInd.val; + val_hex |= natConInd->contChkInd.val << 2; + val_hex |= natConInd->echoCntrlDevInd.val <<4; + hex_to_char(val_hex, val, 2) ; + + sngss7_add_var(sngss7_info, "ss7_iam_nature_connection_hex", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Nature of connection indicator Hex: 0x%s\n", val); + + return FTDM_SUCCESS; +} + ftdm_status_t copy_fwdCallInd_hex_from_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd *fwdCallInd) { char val[5]; From cd61d0b59edd8845daf2533ef7bc6d3059766551 Mon Sep 17 00:00:00 2001 From: kapil Date: Fri, 29 Jun 2012 21:51:15 +0530 Subject: [PATCH 283/822] adding code to send error response back to MG stack,in case of any app failure --- .../mod_media_gateway/media_gateway_stack.h | 29 ++++++ .../mod_media_gateway/media_gateway_xml.c | 5 +- .../mod_media_gateway/mod_media_gateway.c | 93 ++++++++++++++++++- 3 files changed, 124 insertions(+), 3 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index 6c2cbc7abd..328806b746 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -43,6 +43,35 @@ typedef enum{ (_val == SNG_MG_ENCODING_BINARY)?"SNG_MG_ENCODING_BINARY":\ "SNG_MG_ENCODING_NONE") +typedef struct _mgStr +{ + U8 len; + U8 val[128]; +} MgStr; + +#define MG_TXN_INVALID 0 + +#define mg_zero(_buf, _size) {cmMemset((U8 *)(_buf), 0, _size);} + +/* Set pres field */ +#define mg_util_set_pres(_pres) \ + (_pres) = PRSNT_NODEF; + +/* Set token value */ +#define mg_util_set_val_pres(tkn,_val) \ + mg_util_set_pres((tkn).pres); \ + (tkn).val = _val; + + +#define mg_mem_copy(_dst, _src, _len) \ + cmMemcpy((U8*) (_dst), (const U8*) (_src), _len) + +#define mg_get_mem(_memPtr, _size, _allocPtr, ret) \ +{ \ + (*ret) = cmGetMem((Ptr *)(_memPtr),(_size) ,(Ptr *)&(_allocPtr)); \ +} + + void handle_sng_log(uint8_t level, char *fmt, ...); void handle_mgco_sta_ind(Pst *pst, SuId suId, MgMgtSta* msg); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index f1259ed544..5acba0d954 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -153,7 +153,7 @@ static switch_xml_config_item_t *get_peer_instructions(mg_peer_profile_t *profil /* parameter name type reloadable pointer default value options structure */ SWITCH_CONFIG_ITEM("ip", SWITCH_CONFIG_STRING, CONFIG_RELOADABLE, &profile->ipaddr, "", &switch_config_string_strdup, "", "Peer IP"), SWITCH_CONFIG_ITEM("port", SWITCH_CONFIG_STRING, 0, &profile->port, "", &switch_config_string_strdup, "", "peer port"), - SWITCH_CONFIG_ITEM("encoding-scheme", SWITCH_CONFIG_STRING, 0, &profile->encoding_type, "TEXT", &switch_config_string_strdup, "", "peer encoding type"), + SWITCH_CONFIG_ITEM("encoding-scheme", SWITCH_CONFIG_STRING, 0, &profile->encoding_type, "", &switch_config_string_strdup, "", "peer encoding type"), SWITCH_CONFIG_ITEM("transport-type", SWITCH_CONFIG_STRING, 0, &profile->transport_type, "", &switch_config_string_strdup, "", "peer transport type "), SWITCH_CONFIG_ITEM("message-identifier", SWITCH_CONFIG_STRING, 0, &profile->mid, "", &switch_config_string_strdup, "", "peer message identifier "), SWITCH_CONFIG_ITEM_END() @@ -239,6 +239,7 @@ static switch_status_t modify_mid(char* mid) } if(('<' == val[0][0]) || ('[' == val[0][0])){ + free(dup); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MID[%s] is already prefixed with proper brackets \n",mid); return SWITCH_STATUS_SUCCESS; } @@ -256,7 +257,7 @@ static switch_status_t modify_mid(char* mid) sprintf(mid,"[%s]",dup); }else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid input MID string[%s]\n",mid); - free(dup); + free(dup); return SWITCH_STATUS_FALSE; } diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index bca39abb30..d549becc70 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -24,6 +24,8 @@ switch_status_t mg_stack_free_mem(MgMgcoMsg* msg); switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ); switch_status_t mg_send_add_rsp(SuId suId, MgMgcoCommand *req); S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, CONSTANT U8 *str, CmMemListCp *memCp); +void mg_util_set_txn_string(MgStr *errTxt, U32 *txnId); +switch_status_t mg_build_mgco_err_request(MgMgcoInd **errcmd,U32 trans_id, MgMgcoContextId *ctxt_id, U32 err, MgStr *errTxt); /**************************************************************************************************************/ @@ -410,6 +412,10 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) { uint32_t txn_id = 0x00; + MgMgcoInd *mgErr; + MgStr errTxt; + MgMgcoContextId ctxtId; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: Received Command Type[%s] \n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(cmd->cmdType.val)); @@ -419,7 +425,20 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: Transaction Id not present, rejecting\n", __PRETTY_FUNCTION__); - /*TODO - can invoke "MgUiMgtMgcoErrReq" to report error to MEGACO stack */ + + /*-- Send Error to MG Stack --*/ + mg_zero(&ctxtId, sizeof(MgMgcoContextId)); + ctxtId.type.pres = NOTPRSNT; + ctxtId.val.pres = NOTPRSNT; + + mg_util_set_txn_string(&errTxt, &txn_id); + + if (SWITCH_STATUS_FALSE == mg_build_mgco_err_request(&mgErr, txn_id, &ctxtId, + MGT_MGCO_RSP_CODE_INVLD_IDENTIFIER, &errTxt)) + { + sng_mgco_send_err(suId, mgErr); + } + /* deallocate the msg */ mg_free_cmd(cmd); return ; @@ -908,6 +927,78 @@ S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, CONSTANT U8 *str, CmMemListCp RETVALUE(ROK); } +switch_status_t mg_build_mgco_err_request(MgMgcoInd **errcmd,U32 trans_id, MgMgcoContextId *ctxt_id, U32 err, MgStr *errTxt) +{ + MgMgcoInd *mgErr; + S16 ret; + + mgErr = NULLP; + ret = ROK; + + /* Allocate for AG error */ + mg_stack_alloc_mem((Ptr*)&mgErr, sizeof(MgMgcoInd)); + if (NULL == mgErr) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " mg_build_mgco_err_request Failed : memory alloc \n"); + return SWITCH_STATUS_FALSE; + } + + /* Set transaction Id in the error request */ + mg_util_set_val_pres(mgErr->transId, trans_id); + + /* Copy the context Id */ + mg_mem_copy(&mgErr->cntxtId, + ctxt_id, + sizeof(MgMgcoContextId)); + + /* Set the peerId */ + mgErr->peerId.pres = NOTPRSNT; + + /* Set the error code */ + mg_util_set_pres(mgErr->err.pres.pres); + mg_util_set_pres(mgErr->err.code.pres); + mg_util_set_val_pres(mgErr->err.code, err); + + if(errTxt->len) + { + mg_get_mem(&mgErr->memCp, (errTxt->len)*sizeof(U8), mgErr->err.text.val, &ret); + if (ROK != ret) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " mg_build_mgco_err_request Failed : memory alloc \n"); + return SWITCH_STATUS_FALSE; + } + mgErr->err.text.pres = PRSNT_NODEF; + mgErr->err.text.len = errTxt->len; + mg_mem_copy(mgErr->err.text.val, errTxt->val, errTxt->len); + } + + /* Set the output value */ + *errcmd = mgErr; + + return SWITCH_STATUS_SUCCESS; +} + +void mg_util_set_txn_string(MgStr *errTxt, U32 *txnId) +{ + mg_zero((errTxt->val), sizeof(errTxt->val)); + errTxt->len = 0; + + errTxt->val[errTxt->len] = '\"'; + errTxt->len += 1; + + if (MG_TXN_INVALID == txnId ) + { + mg_mem_copy((&errTxt->val[errTxt->len]), "TransactionId=0", 15); + errTxt->len += 15; + } + + errTxt->val[errTxt->len] = '\"'; + errTxt->len += 1; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s:" + "info, error-text is: %s\n", __PRETTY_FUNCTION__,errTxt->val); + +} + + /*****************************************************************************************************************************/ From 24a458683a3e6a0f9390e5ab7318f4cd0b14788e Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 29 Jun 2012 12:54:09 -0400 Subject: [PATCH 284/822] Skip filling locPtyNum if caller_data->loc.digits is NULL --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 2f4c18d4c3..867a8f7c07 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -247,13 +247,14 @@ ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *loc { const char *val = NULL; const char *loc_nadi = NULL; - int pres_val = PRSNT_NODEF; + int pres_val = PRSNT_NODEF; sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; if (!strcasecmp(caller_data->loc.digits, "NULL")) { pres_val = NOTPRSNT; + return FTDM_SUCCESS; } locPtyNum->eh.pres = pres_val; From 658ce0ba91f39eb062ba32f7efbcd18929cef818 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Fri, 29 Jun 2012 16:30:51 -0400 Subject: [PATCH 285/822] work out contexts, cleanup rtp endpoint in preparation for mg-based setup --- .../mod_media_gateway/media_gateway.c | 100 ++++- .../mod_media_gateway/media_gateway_xml.c | 2 + .../mod_media_gateway/mod_media_gateway.c | 198 ++++++--- .../mod_media_gateway/mod_media_gateway.h | 65 ++- src/mod/endpoints/mod_sofia/rtp.c | 395 +----------------- 5 files changed, 302 insertions(+), 458 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 3cd5856bd2..e618b5ef6c 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -46,6 +46,97 @@ void megaco_peer_profile_release(mg_peer_profile_t *profile) switch_thread_rwlock_unlock(profile->rwlock); } +mg_context_t *megaco_get_context(megaco_profile_t *profile, uint32_t context_id) +{ + mg_context_t *result = NULL; + + if (context_id > MG_MAX_CONTEXTS) { + return NULL; + } + + switch_thread_rwlock_rdlock(profile->contexts_rwlock); + + /* Context exists */ + if (profile->contexts_bitmap[context_id % 8] & (1 << (context_id / 8))) { + for (result = profile->contexts[context_id % MG_CONTEXT_MODULO]; result; result = result->next) { + if (result->context_id == context_id) { + break; + } + } + } + + switch_thread_rwlock_unlock(profile->contexts_rwlock); + + return result; +} + +/* Returns a fresh new context */ +mg_context_t *megaco_choose_context(megaco_profile_t *profile) +{ + mg_context_t *ctx; + + switch_thread_rwlock_wrlock(profile->contexts_rwlock); + /* Try the next one */ + if (profile->next_context_id >= MG_MAX_CONTEXTS) { + profile->next_context_id = 1; + } + + /* Look for an available context */ + for (; profile->next_context_id < MG_MAX_CONTEXTS; profile->next_context_id++) { + if ((profile->contexts_bitmap[profile->next_context_id % 8] & (1 << (profile->next_context_id / 8))) == 0) { + /* Found! */ + profile->contexts_bitmap[profile->next_context_id % 8] |= 1 << (profile->next_context_id / 8); + int i = profile->next_context_id % MG_CONTEXT_MODULO; + ctx = malloc(sizeof *ctx); + ctx->context_id = profile->next_context_id; + ctx->profile = profile; + + if (!profile->contexts[i]) { + profile->contexts[i] = ctx; + } else { + mg_context_t *it; + for (it = profile->contexts[i]; it && it->next; it = it->next) + ; + it->next = ctx; + } + + profile->next_context_id++; + break; + } + } + + switch_thread_rwlock_unlock(profile->contexts_rwlock); + + return ctx; +} + +void megaco_release_context(mg_context_t *ctx) +{ + uint32_t context_id = ctx->context_id; + megaco_profile_t *profile = ctx->profile; + int i = context_id % MG_CONTEXT_MODULO; + + switch_thread_rwlock_wrlock(profile->contexts_rwlock); + if (profile->contexts[i] == ctx) { + profile->contexts[i] = ctx->next; + } else { + mg_context_t *it = profile->contexts[i]->next, *prev = profile->contexts[i]; + for (; it; prev = it, it = it->next) { + if (it == ctx) { + prev->next = it->next; + break; + } + } + } + + profile->contexts_bitmap[context_id % 8] &= ~(1 << (context_id / 8)); + + memset(ctx, 0, sizeof *ctx); + free(ctx); + + switch_thread_rwlock_unlock(profile->contexts_rwlock); +} + switch_status_t megaco_profile_start(const char *profilename) { switch_memory_pool_t *pool; @@ -59,9 +150,14 @@ switch_status_t megaco_profile_start(const char *profilename) profile = switch_core_alloc(pool, sizeof(*profile)); profile->pool = pool; profile->name = switch_core_strdup(pool, profilename); + profile->next_context_id++; switch_thread_rwlock_create(&profile->rwlock, pool); + + switch_thread_rwlock_create(&profile->contexts_rwlock, pool); +// switch_core_hash_init(&profile->contexts_hash, pool); + if (SWITCH_STATUS_SUCCESS != config_profile(profile, SWITCH_FALSE)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error configuring profile %s\n", profile->name); goto fail; @@ -94,6 +190,8 @@ switch_status_t megaco_profile_destroy(megaco_profile_t **profile) if(SWITCH_STATUS_FALSE == sng_mgco_stop((*profile))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error stopping MEGACO Stack for profile %s\n", (*profile)->name); } + + /* TODO: Cleanup contexts */ switch_thread_rwlock_unlock((*profile)->rwlock); @@ -104,7 +202,7 @@ switch_status_t megaco_profile_destroy(megaco_profile_t **profile) switch_core_destroy_memory_pool(&(*profile)->pool); - return SWITCH_STATUS_SUCCESS; + return SWITCH_STATUS_SUCCESS; } switch_status_t megaco_peer_profile_destroy(mg_peer_profile_t **profile) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index f1259ed544..3eee1504d8 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -131,6 +131,7 @@ switch_status_t mg_config_cleanup(megaco_profile_t* profile) { switch_xml_config_item_t *instructions = (profile ? get_instructions(profile) : NULL); switch_xml_config_cleanup(instructions); + free(instructions); return SWITCH_STATUS_SUCCESS; } @@ -140,6 +141,7 @@ switch_status_t mg_peer_config_cleanup(mg_peer_profile_t* profile) { switch_xml_config_item_t *instructions = (profile ? get_peer_instructions(profile) : NULL); switch_xml_config_cleanup(instructions); + free(instructions); return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index bca39abb30..b9f38fb798 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -18,7 +18,7 @@ static sng_mg_event_interface_t sng_event; SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_media_gateway_shutdown); SWITCH_MODULE_DEFINITION(mod_media_gateway, mod_media_gateway_load, mod_media_gateway_shutdown, NULL); -switch_status_t handle_mg_add_cmd(MgMgcoAmmReq *addReq); +switch_status_t handle_mg_add_cmd(SuId suId, MgMgcoCommand *req, MgMgcoAmmReq *addReq); switch_status_t mg_stack_free_mem(MgMgcoMsg* msg); switch_status_t mg_stack_free_mem(MgMgcoMsg* msg); switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ); @@ -195,7 +195,6 @@ static void mgco_print_sdp(CmSdpInfoSet *sdp) for (mediaId = 0; mediaId < s->attrSet.numComp.val; mediaId++) { /*CmSdpAttr *a = s->attrSet.attr[mediaId];*/ - } } @@ -218,6 +217,74 @@ static void mgco_print_sdp(CmSdpInfoSet *sdp) } } + +static switch_status_t mgco_parse_local_sdp(mg_termination_t *term, CmSdpInfoSet *sdp) +{ + int i; + CmSdpInfoSet *local_sdp; + /* Parse the local SDP while copying the important bits over to our local structure, + * while taking care of editing choose request and replacing them by real values */ + + if (!term->u.rtp.local_sdp) { + local_sdp = term->u.rtp.local_sdp = switch_core_alloc(term->context->pool, sizeof *term->u.rtp.local_sdp); + } + + + if (sdp->numComp.pres == NOTPRSNT) { + return SWITCH_STATUS_FALSE; + } + + for (i = 0; i < sdp->numComp.val; i++) { + CmSdpInfo *s = sdp->info[i]; + int mediaId; + + local_sdp->info[i] = switch_core_alloc(term->context->pool, sizeof *(local_sdp->info[i])); + *(local_sdp->info[i]) = *(sdp->info[i]); + + if (s->conn.addrType.pres && s->conn.addrType.val == CM_SDP_ADDR_TYPE_IPV4 && + s->conn.netType.type.val == CM_SDP_NET_TYPE_IN && + s->conn.u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) { + + if (s->conn.u.ip4.addrType.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Local address: %d.%d.%d.%d\n", + s->conn.u.ip4.u.uniIp.b[0].val, + s->conn.u.ip4.u.uniIp.b[1].val, + s->conn.u.ip4.u.uniIp.b[2].val, + s->conn.u.ip4.u.uniIp.b[3].val); + + /* TODO: Double-check bind address for this profile */ + + } + if (s->attrSet.numComp.pres) { + for (mediaId = 0; mediaId < s->attrSet.numComp.val; mediaId++) { + CmSdpAttr *a = s->attrSet.attr[mediaId]; + local_sdp->info[i]->attrSet.attr[mediaId] = switch_core_alloc(term->context->pool, sizeof(CmSdpAttr)); + *(local_sdp->info[i]->attrSet.attr[mediaId]) = *a; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Media %p\n", a); + } + } + + if (s->mediaDescSet.numComp.pres) { + for (mediaId = 0; mediaId < s->mediaDescSet.numComp.val; mediaId++) { + CmSdpMediaDesc *desc = s->mediaDescSet.mediaDesc[mediaId]; + local_sdp->info[i]->mediaDescSet.mediaDesc[mediaId] = switch_core_alloc(term->context->pool, sizeof(CmSdpMediaDesc)); + *(local_sdp->info[i]->mediaDescSet.mediaDesc[mediaId]) = *desc; + + if (desc->field.mediaType.val == CM_SDP_MEDIA_AUDIO && + desc->field.id.type.val == CM_SDP_VCID_PORT && + desc->field.id.u.port.type.val == CM_SDP_PORT_INT && + desc->field.id.u.port.u.portInt.port.type.val == CM_SDP_SPEC) { + int port = desc->field.id.u.port.u.portInt.port.val.val; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Port: %d\n", port); + + } + } + } + } + } +} + /*****************************************************************************************************************************/ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) @@ -330,17 +397,17 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) } case MGT_MEDIAPAR_STRPAR: { - MgMgcoStreamDesc *mgStream = &mediaPar->u.stream; - - if (mgStream->sl.remote.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got remote stream media description:\n"); - mgco_print_sdp(&mgStream->sl.remote.sdp); - } - - if (mgStream->sl.local.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got local stream media description:\n"); - mgco_print_sdp(&mgStream->sl.local.sdp); - } +// MgMgcoStreamDesc *mgStream = &mediaPar->u.stream; +// +// if (mgStream->sl.remote.pres.pres) { +// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got remote stream media description:\n"); +// mgco_print_sdp(&mgStream->sl.remote.sdp); +// } +// +// if (mgStream->sl.local.pres.pres) { +// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got local stream media description:\n"); +// mgco_print_sdp(&mgStream->sl.local.sdp); +// } break; @@ -438,8 +505,7 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) { case MGT_ADD: { - handle_mg_add_cmd(&cmd->u.mgCmdInd[0]->cmd.u.add); - mg_send_add_rsp(suId, cmd); + handle_mg_add_cmd(suId, cmd, &cmd->u.mgCmdInd[0]->cmd.u.add); break; } @@ -598,7 +664,7 @@ MgMgcoTermIdLst *mg_get_term_id_list(MgMgcoCommand *cmd) break; default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); break; } break; @@ -651,12 +717,12 @@ MgMgcoTermIdLst *mg_get_term_id_list(MgMgcoCommand *cmd) break; default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); } /* switch command type for reply */ break; default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported api_type[%s]!\n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(api_type)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported api_type[%s]!\n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(api_type)); break; } /* switch -api_type */ @@ -665,9 +731,40 @@ MgMgcoTermIdLst *mg_get_term_id_list(MgMgcoCommand *cmd) /*****************************************************************************************************************************/ -switch_status_t handle_mg_add_cmd(MgMgcoAmmReq *addReq) +switch_status_t handle_mg_add_cmd(SuId suId, MgMgcoCommand *req, MgMgcoAmmReq *addReq) { - int descId; + int descId; + mg_context_t *ctx = NULL; + + MgMgcoCommand cmd; + int ret = 0x00; + MgMgcoTermId *termId; + MgMgcoCtxt ctxt; + + memset(&cmd,0, sizeof(cmd)); + + /*copy transaction-id*/ + memcpy(&cmd.transId, &req->transId, sizeof(MgMgcoTransId)); + + if (req->contextId.type.val == MGT_CXTID_CHOOSE) { + ctx = megaco_choose_context(NULL); + } else if (req->contextId.type.val == MGT_CXTID_OTHER) { + ctx = megaco_get_context(NULL, req->contextId.val.val); + } + + + /*copy context-id*/ /*TODO - in case of $ context should be generated by app, we should not simply copy incoming structure */ + memcpy(&cmd.contextId, &req->contextId, sizeof(MgMgcoContextId)); + + /*copy peer identifier */ + memcpy(&cmd.peerId, &req->peerId, sizeof(TknU32)); + + /*fill response structue */ + if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&cmd.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ + return ret; + } + + for (descId = 0; descId < addReq->dl.num.val; descId++) { switch (addReq->dl.descs[descId]->type.val) { case MGT_MEDIADESC: @@ -727,72 +824,43 @@ switch_status_t handle_mg_add_cmd(MgMgcoAmmReq *addReq) break; } } - - - return SWITCH_STATUS_SUCCESS; -} - - -/*****************************************************************************************************************************/ -switch_status_t mg_send_add_rsp(SuId suId, MgMgcoCommand *req) -{ - MgMgcoCommand cmd; - int ret = 0x00; - MgMgcoTermId *termId; - MgMgcoCtxt ctxt; - - memset(&cmd,0, sizeof(cmd)); - - /*copy transaction-id*/ - memcpy(&cmd.transId, &req->transId,sizeof(MgMgcoTransId)); - - /*copy context-id*/ /*TODO - in case of $ context should be generated by app, we should not simply copy incoming structure */ - memcpy(&cmd.contextId, &req->contextId,sizeof(MgMgcoContextId)); - - /*copy peer identifier */ - memcpy(&cmd.peerId, &req->peerId,sizeof(TknU32)); - - /*fill response structue */ - if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&cmd.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ - return ret; - } - - cmd.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; + + cmd.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; cmd.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; cmd.u.mgCmdRsp[0]->type.val = MGT_ADD; cmd.u.mgCmdRsp[0]->u.add.pres.pres = PRSNT_NODEF; - - + + cmd.u.mgCmdRsp[0]->u.add.termIdLst.num.pres = PRSNT_NODEF; cmd.u.mgCmdRsp[0]->u.add.termIdLst.num.val = 1; - + mgUtlAllocMgMgcoTermIdLst(&cmd.u.mgCmdRsp[0]->u.add.termIdLst, &req->u.mgCmdReq[0]->cmd.u.add.termIdLst); - + #ifdef GCP_VER_2_1 termId = cmd.u.mgCmdRsp[0]->u.add.termIdLst.terms[0]; #else termId = &(cmd.u.mgCmdRsp[0]->u.add.termId); #endif + /* FIXME */ mg_fill_mgco_termid(termId, (CONSTANT U8*)"term1",&req->u.mgCmdRsp[0]->memCp); - + /* We will always send one command at a time..*/ cmd.cmdStatus.pres = PRSNT_NODEF; cmd.cmdStatus.val = CH_CMD_STATUS_END_OF_CMD; - + cmd.cmdType.pres = PRSNT_NODEF; cmd.cmdType.val = CH_CMD_TYPE_RSP; - - + + ret = sng_mgco_send_cmd(suId, &cmd); - + memcpy(&ctxt.transId,&req->transId,sizeof(MgMgcoTransId)); - memcpy(&ctxt.cntxtId, &req->contextId,sizeof(MgMgcoContextId)); + memcpy(&ctxt.cntxtId, &cmd.contextId,sizeof(MgMgcoContextId)); memcpy(&ctxt.peerId, &req->peerId,sizeof(TknU32)); ctxt.cmdStatus.pres = PRSNT_NODEF; ctxt.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; - ret = sng_mgco_send_axn_req(suId, &ctxt); - return ret; + return sng_mgco_send_axn_req(suId, &ctxt);; } /*****************************************************************************************************************************/ @@ -811,7 +879,7 @@ switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ) if ( ROK != cmAllocEvnt( _memSize, MG_MAXBLKSIZE, &sMem, _memPtr ) ) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_alloc_mem: cmAllocEvnt return failure for _memSize=%d\n",_memSize); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_alloc_mem: cmAllocEvnt return failure for _memSize=%d\n", (int)_memSize); return SWITCH_STATUS_FALSE; } @@ -850,7 +918,7 @@ switch_status_t mg_stack_free_mem(MgMgcoMsg* msg) { if ( !msg ) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_get_mem: invalid message\n"); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_free_mem: invalid message\n"); return SWITCH_STATUS_FALSE; } diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index 8aa0dae0d3..91dc74210c 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -15,6 +15,8 @@ #define MG_MAX_PEERS 5 +#define MG_CONTEXT_MAX_TERMS 3 + #define MEGACO_CLI_SYNTAX "profile|logging" #define MEGACO_LOGGING_CLI_SYNTAX "logging [enable|disable]" #define MEGACO_FUNCTION_SYNTAX "profile [name] [start | stop] [status] [xmlstatus] [peerxmlstatus]" @@ -50,10 +52,57 @@ typedef struct mg_peer_profile_s{ char* mid; /* Peer H.248 MID */ char* transport_type; /* UDP/TCP */ char* encoding_type; /* Encoding TEXT/Binary */ -}mg_peer_profile_t; +} mg_peer_profile_t; -typedef struct megaco_profile_s { +typedef enum { + MG_TERM_FREE = 0, + MG_TERM_TDM, + MG_TERM_RTP +} mg_termination_type_t; + +typedef struct megaco_profile_s megaco_profile_t; +typedef struct mg_context_s mg_context_t; + +typedef struct mg_termination_s { + mg_termination_type_t type; + const char *uuid; + mg_context_t *context; + + union { + struct { + const char *codec; + int ptime; + const char *remote_address; + switch_port_t remote_port; + switch_port_t local_port; + + CmSdpInfoSet *local_sdp; + CmSdpInfoSet *remote_sdp; + + unsigned mode:2; + unsigned :0; + } rtp; + struct { + int span; + int channel; + } tdm; + } u; +} mg_termination_t; + + +struct mg_context_s { + uint32_t context_id; + mg_termination_t terminations[MG_CONTEXT_MAX_TERMS]; + megaco_profile_t *profile; + mg_context_t *next; + switch_memory_pool_t *pool; +}; + +#define MG_CONTEXT_MODULO 16 +#define MG_MAX_CONTEXTS 32768 + +struct megaco_profile_s { char *name; switch_memory_pool_t *pool; switch_thread_rwlock_t *rwlock; /* < Reference counting rwlock */ @@ -71,7 +120,12 @@ typedef struct megaco_profile_s { char* rtp_termination_id_prefix; int rtp_termination_id_len; char* peer_list[MG_MAX_PEERS]; /* MGC Peer ID LIST */ -} megaco_profile_t; + + switch_thread_rwlock_t *contexts_rwlock; + uint32_t next_context_id; + uint8_t contexts_bitmap[MG_MAX_CONTEXTS/8]; /* Availability matrix, enough bits for a 32768 bitmap */ + mg_context_t *contexts[MG_CONTEXT_MODULO]; +}; megaco_profile_t *megaco_profile_locate(const char *name); @@ -80,6 +134,11 @@ void megaco_profile_release(megaco_profile_t *profile); switch_status_t megaco_profile_start(const char *profilename); switch_status_t megaco_profile_destroy(megaco_profile_t **profile); + +mg_context_t *megaco_get_context(megaco_profile_t *profile, uint32_t context_id); +mg_context_t *megaco_choose_context(megaco_profile_t *profile); +void megaco_release_context(mg_context_t *ctx); + switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload); switch_status_t sng_mgco_start(megaco_profile_t* profile); switch_status_t sng_mgco_stop(megaco_profile_t* profile); diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 4a8107f859..e99eef1b76 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -32,10 +32,11 @@ #include #include "mod_sofia.h" -#define kRSDP "r_sdp" -#define kLSDP "l_sdp" #define kBINDADDRESS "bind_address" -#define kCODECSTRING "codec_string" +#define kLOCALADDR "local_addr" +#define kLOCALPORT "local_port" +#define kREMOTEADDR "remote_addr" +#define kREMOTEPORT "remote_port" static struct { switch_memory_pool_t *pool; @@ -88,19 +89,16 @@ switch_io_routines_t crtp_io_routines = { .send_dtmf = channel_send_dtmf }; -#if 0 SWITCH_STANDARD_API(test_function) { return SWITCH_STATUS_SUCCESS; } -#endif void crtp_init(switch_loadable_module_interface_t *module_interface) { switch_endpoint_interface_t *endpoint_interface; -#if 0 /* DAVIDY */ switch_api_interface_t *api_interface; -#endif + crtp.pool = module_interface->pool; endpoint_interface = switch_loadable_module_create_interface(module_interface, SWITCH_ENDPOINT_INTERFACE); endpoint_interface->interface_name = "rtp"; @@ -108,390 +106,9 @@ void crtp_init(switch_loadable_module_interface_t *module_interface) endpoint_interface->state_handler = &crtp_state_handlers; crtp.endpoint_interface = endpoint_interface; -// SWITCH_ADD_API(api_interface, "rtp_test", "test", test_function, ""); + SWITCH_ADD_API(api_interface, "rtp_test", "test", test_function, ""); } - -typedef struct parsed_sdp_s { - const char *c; /*!< Connection */ - - -} parsed_sdp_t; - - -//static switch_status_t check_codec - -/* - * Setup the local RTP side - * A lot of values can be chosen by the MG, those will have $ as a placeholder. - * We need to validate the SDP, making sure we can support everything that's offered on our behalf, - * amend it if we don't support everything, or systematically reject it if we cannot support it. - * - * Would this function be called using NULL as l_sdp, we will generate an SDP payload. - */ - -static switch_status_t setup_local_rtp(crtp_private_t *tech_pvt, const char *l_sdp, const char *codec_string) -{ - int codec_order_last; - int num_codecs; -#if 0 /* DAVIDY */ - switch_core_session_t const * session = tech_pvt->session; -#endif - const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS] = { 0 }; - char *codec_order[SWITCH_MAX_CODECS] = { 0 }; -#if 1 /* DAVIDY */ - char *sdpbuf = NULL; - sdp_connection_t *connection = NULL; - sdp_printer_t *printer = NULL; -#endif - - - /* Load in the list of codecs we support. If we have a codec string we use our priorities first */ - if (codec_string) { - char *tmp_codec_string; - if ((tmp_codec_string = switch_core_session_strdup(tech_pvt->session, codec_string))) { - codec_order_last = switch_separate_string(tmp_codec_string, ',', codec_order, SWITCH_MAX_CODECS); - num_codecs = switch_loadable_module_get_codecs_sorted(codecs, SWITCH_MAX_CODECS, codec_order, codec_order_last); - } - } else { - num_codecs = switch_loadable_module_get_codecs(codecs, switch_arraylen(codecs)); - } - - /* TODO: Look at remote settings */ - - if (zstr(l_sdp)) { - /* Generate a local SDP here */ -#if 0 /* DAVIDY */ - const char *sdpbuf = switch_core_session_sprintf(session, "v=0\nIN IP4 %s\nm=audio %d RTP/AVP %d"); -#endif - - } else { - /* Parse the SDP and remove anything we cannot support, then validate it to make sure it contains at least one codec - * so that we reject invalid ones. */ -#if 0 - uint8_t match = 0; - int first = 0, last = 0; - int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0; - int sendonly = 0, recvonly = 0; - int greedy = 0, x = 0, skip = 0; -#endif - int ptime = 0, maxptime = 0; - int sdp_modified = 0; - int cur_codec = 0; - - sdp_parser_t *parser = NULL; -#if 1 /* DAVIDY */ - sdp_session_t *sdp; -#else - sdp_session_t *sdp, *lsdp; -#endif - sdp_media_t *m; - sdp_attribute_t *attr; - su_home_t *sdp_home; - - if (!(parser = sdp_parse(NULL, l_sdp, (int) strlen(l_sdp), sdp_f_megaco /* accept $ values */ | sdp_f_insane /* accept omitted o= */))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Malformed SDP\n"); - goto fail; - } - - if (!(sdp = sdp_session(parser))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't get session from sdp.\n"); - goto fail; - } - sdp_home = sdp_parser_home(parser); - for (m = sdp->sdp_media; m; m = m->m_next) { - - if (m->m_type == sdp_media_audio) { - sdp_rtpmap_t *map; - - for (attr = m->m_attributes; attr; attr = attr->a_next) { - if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) { - ptime = atoi(attr->a_value); - } else if (!strcasecmp(attr->a_name, "maxptime") && attr->a_value) { - maxptime = atoi(attr->a_value); - } - } - - connection = sdp->sdp_connection; - if (m->m_connections) { - connection = m->m_connections; - } - - /* Check for wildcards in m= (media) and c= (connection) */ - if (!zstr(connection->c_address)) { - if (!strcmp(connection->c_address, "$")) { - connection->c_address = su_strdup(sdp_home, tech_pvt->bind_address); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Using bind address: %s\n", tech_pvt->bind_address); - switch_channel_set_variable(tech_pvt->channel, kBINDADDRESS, tech_pvt->bind_address); - sdp_modified = 1; - } else if (strcmp(connection->c_address, tech_pvt->bind_address)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MGC requested to bind on [%s] which is different than the configuration [%s]\n", - connection->c_address, tech_pvt->bind_address); - goto fail; - } - - if (m->m_port == MEGACO_CHOOSE) { - tech_pvt->local_port = m->m_port = switch_rtp_request_port(tech_pvt->bind_address); - switch_channel_set_variable_printf(tech_pvt->channel, "rtp_local_port", "%d", tech_pvt->local_port); - if (!tech_pvt->local_port) { - /* Port request failed */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No available RTP ports on [%s]\n", tech_pvt->bind_address); - goto fail; - } - sdp_modified = 1; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Using local port: %d\n", tech_pvt->local_port); - } - } - - /* Validate codecs */ - for (map = m->m_rtpmaps; map; map = map->rm_next) { - if (map->rm_any) { - /* Pick our first favorite codec */ - if (codecs[cur_codec]) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Choosing a codec: %s/%d\n", codecs[cur_codec]->iananame, codecs[cur_codec]->ianacode); - map->rm_encoding = su_strdup(sdp_home, codecs[cur_codec]->iananame); - map->rm_pt = codecs[cur_codec]->ianacode; - map->rm_any = 0; - map->rm_predef = codecs[cur_codec]->ianacode < 96; - cur_codec++; - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No more codecs in preferences!\n"); - goto fail; - } - } - } - } else if (m->m_type == sdp_media_image && m->m_port) { - /* TODO: Handle T38 */ - - } - } -#if 0 /* DAVIDY */ - char sdpbuf[2048] = ""; -#endif - printer = sdp_print(sdp_home, sdp, sdpbuf, sizeof(sdpbuf), 0); - switch_channel_set_variable(tech_pvt->channel, kLSDP, sdpbuf); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Setting local SDP: [%s]\n", sdpbuf); - sdp_printer_free(printer); - - goto done; - - fail: - if (tech_pvt->local_port) { - switch_rtp_release_port(tech_pvt->bind_address, tech_pvt->local_port); - } - - if (parser) { - sdp_parser_free(parser); - } - - return SWITCH_STATUS_FALSE; - } - -done: - return SWITCH_STATUS_SUCCESS; - -} - -#if 0 -static void setup_rtp(crtp_private_t *tech_pvt, const char *r_sdp, const char *l_sdp) -{ - switch_core_session_t const * session = tech_pvt->session; - uint8_t match = 0; - int first = 0, last = 0; - int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0; - int sendonly = 0, recvonly = 0; - int greedy = 0, x = 0, skip = 0, mine = 0; - int got_crypto = 0, got_audio = 0, got_avp = 0, got_savp = 0, got_udptl = 0; - - sdp_parser_t *parser = NULL, *l_parser = NULL; - sdp_session_t *sdp, *lsdp; - sdp_media_t *m; - sdp_attribute_t *attr; - - - int scrooge = 0; - - - if (zstr(r_sdp)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No SDP\n"); - goto fail; - } - - if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Malformed SDP\n"); - goto fail; - } - - if (!(sdp = sdp_session(parser))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't get session from sdp.\n"); - goto fail; - } - - for (m = sdp->sdp_media; m; m = m->m_next) { - sdp_connection_t *connection; - ptime = dptime; - maxptime = dmaxptime; - - if (m->m_proto == sdp_proto_srtp) { - got_savp++; - } else if (m->m_proto == sdp_proto_rtp) { - got_avp++; - } else if (m->m_proto == sdp_proto_udptl) { - got_udptl++; - } - - if (got_udptl && m->m_type == sdp_media_image && m->m_port) { - //switch_t38_options_t *t38_options = tech_process_udptl(tech_pvt, sdp, m); - - /* TODO: Process T38 */ - - } else if (m->m_type == sdp_media_audio && m->m_port && !got_audio) { - sdp_rtpmap_t *map; - - connection = sdp->sdp_connection; - if (m->m_connections) { - connection = m->m_connections; - } - - if (!connection) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n"); - match = 0; - break; - } - - /* Begin Codec Negotiation */ - for (map = m->m_rtpmaps; map; map = map->rm_next) { - int32_t i; - uint32_t near_rate = 0; - const switch_codec_implementation_t *mimp = NULL, *near_match = NULL; - const char *rm_encoding; - uint32_t map_bit_rate = 0; - int codec_ms = 0; - switch_codec_fmtp_t codec_fmtp = { 0 }; - - if (x++ < skip) { - continue; - } - - if (!(rm_encoding = map->rm_encoding)) { - rm_encoding = ""; - } - - if (!strcasecmp(rm_encoding, "telephone-event")) { - if (!best_te || map->rm_rate == tech_pvt->rm_rate) { - best_te = (switch_payload_t) map->rm_pt; - }9 - } - - if (!cng_pt && !strcasecmp(rm_encoding, "CN")) { - cng_pt = (switch_payload_t) map->rm_pt; - if (tech_pvt->rtp_session) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", cng_pt); - switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt); - } - } - - if (match) { - continue; - } - - if (greedy) { - first = mine; - last = first + 1; - } else { - first = 0; - last = num_codecs; - } - - codec_ms = ptime; - - if (maxptime && (!codec_ms || codec_ms > maxptime)) { - codec_ms = maxptime; - } - - if (!codec_ms) { - codec_ms = switch_default_ptime(rm_encoding, map->rm_pt); - } - - map_bit_rate = switch_known_bitrate((switch_payload_t)map->rm_pt); - - if (!ptime && !strcasecmp(map->rm_encoding, "g723")) { - ptime = codec_ms = 30; - } - - if (zstr(map->rm_fmtp)) { - if (!strcasecmp(map->rm_encoding, "ilbc")) { - ptime = codec_ms = 30; - map_bit_rate = 13330; - } - } else { - if ((switch_core_codec_parse_fmtp(map->rm_encoding, map->rm_fmtp, map->rm_rate, &codec_fmtp)) == SWITCH_STATUS_SUCCESS) { - if (codec_fmtp.bits_per_second) { - map_bit_rate = codec_fmtp.bits_per_second; - } - if (codec_fmtp.microseconds_per_packet) { - codec_ms = (codec_fmtp.microseconds_per_packet / 1000); - } - } - } - - - for (i = first; i < last && i < total_codecs; i++) { - const switch_codec_implementation_t *imp = codec_array[i]; - uint32_t bit_rate = imp->bits_per_second; - uint32_t codec_rate = imp->samples_per_second; - if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) { - continue; - } - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio Codec Compare [%s:%d:%u:%d:%u]/[%s:%d:%u:%d:%u]\n", - rm_encoding, map->rm_pt, (int) map->rm_rate, codec_ms, map_bit_rate, - imp->iananame, imp->ianacode, codec_rate, imp->microseconds_per_packet / 1000, bit_rate); - if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) { - match = (map->rm_pt == imp->ianacode) ? 1 : 0; - } else { - match = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1; - } - - if (match && bit_rate && map_bit_rate && map_bit_rate != bit_rate && strcasecmp(map->rm_encoding, "ilbc")) { - /* nevermind */ - match = 0; - } - - if (match) { - if (scrooge) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, - "Bah HUMBUG! Sticking with %s@%uh@%ui\n", - imp->iananame, imp->samples_per_second, imp->microseconds_per_packet / 1000); - } else { - if ((ptime && codec_ms && codec_ms * 1000 != imp->microseconds_per_packet) || map->rm_rate != codec_rate) { - near_rate = map->rm_rate; - near_match = imp; - match = 0; - continue; - } - } - mimp = imp; - break; - } else { - match = 0; - } - } - } - - /* End */ - - - } - } - -fail: - if (parser) { - sdp_parser_free(parser); - } -} -#endif - static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session, From c6b5bc2bda5498b14b50595aa45e8e9023368ca1 Mon Sep 17 00:00:00 2001 From: kapil Date: Sun, 1 Jul 2012 12:13:18 +0530 Subject: [PATCH 286/822] adding AUDIT for root Packages response code, adding media_gateway_cmd_handler.c for all commands related logic/APIs. adding media_gateway_packages.c to have list of all supported packages. adding media_gateway_utils.c for all media gateway utility APIs --- src/mod/endpoints/mod_media_gateway/Makefile | 2 +- .../media_gateway_cmd_handler.c | 642 ++++++++++++++++++ .../media_gateway_packages.c | 135 ++++ .../mod_media_gateway/media_gateway_stack.h | 64 +- .../mod_media_gateway/media_gateway_utils.c | 430 ++++++++++++ .../mod_media_gateway/mod_media_gateway.c | 565 +-------------- 6 files changed, 1300 insertions(+), 538 deletions(-) create mode 100644 src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c create mode 100644 src/mod/endpoints/mod_media_gateway/media_gateway_packages.c create mode 100644 src/mod/endpoints/mod_media_gateway/media_gateway_utils.c diff --git a/src/mod/endpoints/mod_media_gateway/Makefile b/src/mod/endpoints/mod_media_gateway/Makefile index 2a8f5e7ac8..66ad05c428 100644 --- a/src/mod/endpoints/mod_media_gateway/Makefile +++ b/src/mod/endpoints/mod_media_gateway/Makefile @@ -7,6 +7,6 @@ ifeq ($(ARCH),x86_64) endif BASE=../../../.. -LOCAL_OBJS=media_gateway.o media_gateway_stack.o media_gateway_xml.o media_gateway_cli.o media_gateway_stack_alarms.o +LOCAL_OBJS=media_gateway.o media_gateway_stack.o media_gateway_xml.o media_gateway_cli.o media_gateway_stack_alarms.o media_gateway_cmd_handler.o media_gateway_utils.o media_gateway_packages.o LOCAL_LDFLAGS=-lsng_mg include $(BASE)/build/modmake.rules diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c new file mode 100644 index 0000000000..c81d80bd18 --- /dev/null +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -0,0 +1,642 @@ +/* +* Copyright (c) 2012, Sangoma Technologies +* Mathieu Rene +* All rights reserved. +* +* +*/ + +#include "mod_media_gateway.h" +#include "media_gateway_stack.h" + + +/*****************************************************************************************************************************/ + +/* +* +* Fun: handle_mg_add_cmd +* +* Desc: this api will handle the ADD request received from MG stack +* +* +*/ +switch_status_t handle_mg_add_cmd(MgMgcoAmmReq *addReq) +{ + int descId; + for (descId = 0; descId < addReq->dl.num.val; descId++) { + switch (addReq->dl.descs[descId]->type.val) { + case MGT_MEDIADESC: + { + int mediaId; + for (mediaId = 0; mediaId < addReq->dl.descs[descId]->u.media.num.val; mediaId++) { + MgMgcoMediaPar *mediaPar = addReq->dl.descs[descId]->u.media.parms[mediaId]; + switch (mediaPar->type.val) { + case MGT_MEDIAPAR_LOCAL: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCAL"); + break; + } + case MGT_MEDIAPAR_REMOTE: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_REMOTE"); + break; + } + + case MGT_MEDIAPAR_LOCCTL: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCCTL"); + break; + } + case MGT_MEDIAPAR_TERMST: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_TERMST"); + break; + } + case MGT_MEDIAPAR_STRPAR: + { + MgMgcoStreamDesc *mgStream = &mediaPar->u.stream; + + if (mgStream->sl.remote.pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got remote stream media description:\n"); + mgco_print_sdp(&mgStream->sl.remote.sdp); + } + + if (mgStream->sl.local.pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got local stream media description:\n"); + mgco_print_sdp(&mgStream->sl.local.sdp); + } + + break; + } + } + } + } + case MGT_MODEMDESC: + case MGT_MUXDESC: + case MGT_REQEVTDESC: + case MGT_EVBUFDESC: + case MGT_SIGNALSDESC: + case MGT_DIGMAPDESC: + case MGT_AUDITDESC: + case MGT_STATSDESC: + break; + } + } + + + return SWITCH_STATUS_SUCCESS; +} + +/*****************************************************************************************************************************/ +/* +* +* Fun: mg_send_add_rsp +* +* Desc: this api will send the ADD response based on ADD request received from MG stack +* +* TODO - Dummy response , needs to have proper ADD response code +*/ +switch_status_t mg_send_add_rsp(SuId suId, MgMgcoCommand *req) +{ + MgMgcoCommand cmd; + int ret = 0x00; + MgMgcoTermId *termId; + + memset(&cmd,0, sizeof(cmd)); + + /*copy transaction-id*/ + memcpy(&cmd.transId, &req->transId,sizeof(MgMgcoTransId)); + + /*copy context-id*/ /*TODO - in case of $ context should be generated by app, we should not simply copy incoming structure */ + memcpy(&cmd.contextId, &req->contextId,sizeof(MgMgcoContextId)); + + /*copy peer identifier */ + memcpy(&cmd.peerId, &req->peerId,sizeof(TknU32)); + + /*fill response structue */ + if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&cmd.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ + return ret; + } + + cmd.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; + cmd.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; + cmd.u.mgCmdRsp[0]->type.val = MGT_ADD; + cmd.u.mgCmdRsp[0]->u.add.pres.pres = PRSNT_NODEF; + + + cmd.u.mgCmdRsp[0]->u.add.termIdLst.num.pres = PRSNT_NODEF; + cmd.u.mgCmdRsp[0]->u.add.termIdLst.num.val = 1; + + mgUtlAllocMgMgcoTermIdLst(&cmd.u.mgCmdRsp[0]->u.add.termIdLst, &req->u.mgCmdReq[0]->cmd.u.add.termIdLst); + +#ifdef GCP_VER_2_1 + termId = cmd.u.mgCmdRsp[0]->u.add.termIdLst.terms[0]; +#else + termId = &(cmd.u.mgCmdRsp[0]->u.add.termId); +#endif + mg_fill_mgco_termid(termId, (CONSTANT U8*)"term1",&req->u.mgCmdRsp[0]->memCp); + + /* We will always send one command at a time..*/ + cmd.cmdStatus.pres = PRSNT_NODEF; + cmd.cmdStatus.val = CH_CMD_STATUS_END_OF_CMD; + + cmd.cmdType.pres = PRSNT_NODEF; + cmd.cmdType.val = CH_CMD_TYPE_RSP; + + ret = sng_mgco_send_cmd(suId, &cmd); + + return ret; +} + +/*****************************************************************************************************************************/ +/* +* +* Fun: mg_send_end_of_axn +* +* Desc: this api will send the END_OF_AXN event to MG stack to indicate that application is done with processing +* +* +*/ +switch_status_t mg_send_end_of_axn(SuId suId, MgMgcoTransId* transId, MgMgcoContextId* ctxtId, TknU32* peerId) +{ + int ret = 0x00; + MgMgcoCtxt ctxt; + + memset(&ctxt,0, sizeof(ctxt)); + memcpy(&ctxt.transId,transId,sizeof(MgMgcoTransId)); + memcpy(&ctxt.cntxtId, ctxtId,sizeof(MgMgcoContextId)); + memcpy(&ctxt.peerId, peerId,sizeof(TknU32)); + ctxt.cmdStatus.pres = PRSNT_NODEF; + ctxt.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + "mg_send_end_of_axn: Sending END_OF_AXN for transId[%d], peerId[%d], context[type = %s, value = %d]\n", + (uint32_t)transId->val, peerId->val, PRNT_MG_CTXT_TYPE(ctxtId->type.val), (uint32_t)ctxtId->val.val); + + ret = sng_mgco_send_axn_req(suId, &ctxt); + + return SWITCH_STATUS_SUCCESS; +} + +/*****************************************************************************************************************************/ +/* +* +* Fun: mg_build_mgco_err_request +* +* Desc: this api will send the Error event to MG stack to indicate failure in application +* +* +*/ + +switch_status_t mg_build_mgco_err_request(MgMgcoInd **errcmd,U32 trans_id, MgMgcoContextId *ctxt_id, U32 err, MgStr *errTxt) +{ + MgMgcoInd *mgErr; + S16 ret; + + mgErr = NULLP; + ret = ROK; + + /* Allocate for AG error */ + mg_stack_alloc_mem((Ptr*)&mgErr, sizeof(MgMgcoInd)); + if (NULL == mgErr) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " mg_build_mgco_err_request Failed : memory alloc \n"); + return SWITCH_STATUS_FALSE; + } + + /* Set transaction Id in the error request */ + MG_SET_VAL_PRES(mgErr->transId, trans_id); + + /* Copy the context Id */ + MG_MEM_COPY(&mgErr->cntxtId, + ctxt_id, + sizeof(MgMgcoContextId)); + + /* Set the peerId */ + mgErr->peerId.pres = NOTPRSNT; + + /* Set the error code */ + MG_SET_PRES(mgErr->err.pres.pres); + MG_SET_PRES(mgErr->err.code.pres); + MG_SET_VAL_PRES(mgErr->err.code, err); + + if(errTxt->len) + { + MG_GETMEM(mgErr->err.text.val, (errTxt->len)*sizeof(U8), &mgErr->memCp, &ret); + if (ROK != ret) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " mg_build_mgco_err_request Failed : memory alloc \n"); + return SWITCH_STATUS_FALSE; + } + mgErr->err.text.pres = PRSNT_NODEF; + mgErr->err.text.len = errTxt->len; + MG_MEM_COPY(mgErr->err.text.val, errTxt->val, errTxt->len); + } + + /* Set the output value */ + *errcmd = mgErr; + + return SWITCH_STATUS_SUCCESS; +} + + +/*****************************************************************************************************************************/ +switch_status_t handle_mg_audit_cmd( SuId suId, MgMgcoCommand *auditReq) +{ + MgMgcoContextId *ctxtId; + MgMgcoTermIdLst *term_list; + MgStr errTxt; + MgMgcoInd *mgErr; + MgMgcoTermId *termId; + MgMgcoSubAudReq *audit; + MgMgcoAuditDesc *audit_desc; + MgMgcoAuditItem *audit_item; + int i; + int err_code; + + audit = &auditReq->u.mgCmdReq[0]->cmd.u.aval; + + if(NOTPRSNT == audit->pres.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Audit structure not present..rejecting \n"); + return SWITCH_STATUS_FALSE; + } + + audit_desc = &audit->audit; + + if((NOTPRSNT == audit_desc->pres.pres) || ( NOTPRSNT == audit_desc->num.pres)){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Audit Descriptor not present..rejecting \n"); + return SWITCH_STATUS_FALSE; + } + + /* dump AUDIT message information */ + /*mgAccEvntPrntMgMgcoSubAudReq(auditReq,stdout);*/ + + /*-- Get context id --*/ + ctxtId = &auditReq->contextId; + + /*-- Get termination list --*/ + term_list = mg_get_term_id_list(auditReq); + termId = term_list->terms[0]; + + /*-- Start with Context level checks --*/ + /*-- CHOOSE Context not allowed --*/ + if ((NOTPRSNT != ctxtId->type.pres) && + (MGT_CXTID_CHOOSE == ctxtId->type.val)) { + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, + "failed, Ctxt: CHOOSE not allowed in Audit Value\n"); + + /* set correct error code */ + mg_util_set_ctxt_string(&errTxt,ctxtId); + err_code = MGT_MGCO_RSP_CODE_INVLD_IDENTIFIER; + goto error; + } + /*-- CHOOSE Termination not allowed --*/ + else if ((NOTPRSNT != termId->type.pres) && + (MGT_TERMID_CHOOSE == termId->type.val)) { + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, + "failed, Term: CHOOSE not allowed in Audit Value\n"); + + mg_util_set_term_string(&errTxt,termId); + err_code = MGT_MGCO_RSP_CODE_INVLD_IDENTIFIER; + goto error; + } + + /*-- For Audit Values, ROOT Termination is allowed with Context = ALL but not allowed with Other --*/ + /*-- Check whether the termination is present in the given context --*/ + if (((NOTPRSNT != termId->type.pres) && + (MGT_TERMID_ROOT == termId->type.val)) && + ((NOTPRSNT != ctxtId->type.pres) && + (MGT_CXTID_OTHER == ctxtId->type.val))) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, + "failed, Term: Invalid combination, ROOT Term with OTHER CONTEXT\n"); + + mg_util_set_ctxt_string(&errTxt,ctxtId); + err_code = MGT_MGCO_RSP_CODE_INVLD_IDENTIFIER; + goto error; + } + + /* validation done , now processing command */ + + for (i = 0; i < audit_desc->num.val; i++) { + + audit_item = audit_desc->al[i]; + + if (!audit_item) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, + "Audit Descriptor is NULL.. rejecting \n"); + return SWITCH_STATUS_FALSE; + } + + /*TODO - If we are not supporint AUDIT type then can send "MGT_MGCO_RSP_CODE_UNSUPPORTED_DESC" error to MG stack */ + if (NOTPRSNT != audit_item->auditItem.pres) { + + switch(audit_item->auditItem.val) + { + case MGT_MEDIADESC: + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"Auditing MEDIA \n"); + break; + } + case MGT_MODEMDESC: + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"Auditing MODEM \n"); + break; + } + case MGT_MUXDESC: + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"Auditing MULTIPLEX \n"); + break; + } + case MGT_REQEVTDESC: + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"Auditing Events \n"); + break; + } + case MGT_SIGNALSDESC: + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"Auditing Signals \n"); + break; + } + case MGT_DIGMAPDESC: + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"Auditing Digit Maps \n"); + break; + } + case MGT_OBSEVTDESC: + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"Auditing Buffer Events \n"); + break; + } + case MGT_EVBUFDESC: + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"Auditing Events Buffer \n"); + break; + } + case MGT_STATSDESC: + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"Auditing Statistics \n"); + break; + } + case MGT_PKGSDESC: + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"Auditing Packages \n"); + handle_pkg_audit(suId, auditReq); + break; + } + case MGT_INDAUD_TERMAUDDESC: + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"Individual Term Audit \n"); + break; + } + default: + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Invalid Audit Descriptor[%d] request\n",audit_item->auditItem.val); + err_code = MGT_MGCO_RSP_CODE_UNSUPPORTED_DESC; + goto error; + } + }/*switch(audit_item->auditItem.val)*/ + }/*if (NOTPRSNT != audit_item->auditItem.pres)*/ + }/*for loop - audit_desc->num.val */ + + return SWITCH_STATUS_SUCCESS; + +error: + if (SWITCH_STATUS_SUCCESS == mg_build_mgco_err_request(&mgErr, auditReq->transId.val, ctxtId, err_code, &errTxt)) { + sng_mgco_send_err(suId, mgErr); + } + + /* deallocate the msg */ + mg_free_cmd(auditReq); + return SWITCH_STATUS_FALSE; +} + +/*****************************************************************************************************************************/ +switch_status_t handle_pkg_audit( SuId suId, MgMgcoCommand *auditReq) +{ + switch_status_t ret; + MgMgcoCommand reply; + MgMgcoTermIdLst *term_list; + MgMgcoTermId *termId; + MgMgcoSubAudReq *audit; + MgMgcoAuditDesc *audit_desc; + MgMgcoAuditReply *adtRep = NULLP; + U16 numOfParms; + MgMgcoCtxt ctxt; + + memset(&reply, 0, sizeof(reply)); + audit = &auditReq->u.mgCmdReq[0]->cmd.u.aval; + + if(NOTPRSNT == audit->pres.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Audit structure not present..rejecting \n"); + return SWITCH_STATUS_FALSE; + } + + audit_desc = &audit->audit; + + if((NOTPRSNT == audit_desc->pres.pres) || ( NOTPRSNT == audit_desc->num.pres)){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Audit Descriptor not present..rejecting \n"); + return SWITCH_STATUS_FALSE; + } + + /* dump AUDIT message information */ + /*mgAccEvntPrntMgMgcoSubAudReq(auditReq,stdout);*/ + + /*-- Get termination list --*/ + term_list = mg_get_term_id_list(auditReq); + termId = term_list->terms[0]; + + + /*copy transaction-id*/ + memcpy(&reply.transId, &auditReq->transId,sizeof(MgMgcoTransId)); + /*copy context-id*/ + memcpy(&reply.contextId, &auditReq->contextId,sizeof(MgMgcoContextId)); + /*copy peer identifier */ + memcpy(&reply.peerId, &auditReq->peerId,sizeof(TknU32)); + + /*fill response structue */ + if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&reply.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ + return ret; + } + + reply.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; + reply.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; + reply.u.mgCmdRsp[0]->type.val = MGT_AUDITVAL; + + + adtRep = &(reply.u.mgCmdRsp[0]->u.aval); + + adtRep->type.pres = PRSNT_NODEF; + adtRep->type.val = MGT_TERMAUDIT; + adtRep->u.other.pres.pres = PRSNT_NODEF; + mgUtlAllocMgMgcoTermIdLst(&adtRep->u.other.termIdLst, term_list); + + /* Grow the list of reply parameters */ + if (mgUtlGrowList((void ***)&adtRep->u.other.audit.parms, sizeof(MgMgcoAudRetParm), + &adtRep->u.other.audit.num, &reply.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + numOfParms = adtRep->u.other.audit.num.val; + adtRep->u.other.audit.parms[numOfParms - 1]->type.pres = PRSNT_NODEF; + adtRep->u.other.audit.parms[numOfParms - 1]->type.val = MGT_PKGSDESC; + + if(SWITCH_STATUS_FALSE == mg_build_pkg_desc(&adtRep->u.other.audit.parms[numOfParms - 1]->u.pkgs)){ + return SWITCH_STATUS_FALSE; + } + + /* We will always send one command at a time..*/ + reply.cmdStatus.pres = PRSNT_NODEF; + reply.cmdStatus.val = CH_CMD_STATUS_END_OF_CMD; + + reply.cmdType.pres = PRSNT_NODEF; + reply.cmdType.val = CH_CMD_TYPE_RSP; + + + ret = sng_mgco_send_cmd(suId, &reply); + + memcpy(&ctxt.transId,&auditReq->transId,sizeof(MgMgcoTransId)); + memcpy(&ctxt.cntxtId, &auditReq->contextId,sizeof(MgMgcoContextId)); + memcpy(&ctxt.peerId, &auditReq->peerId,sizeof(TknU32)); + ctxt.cmdStatus.pres = PRSNT_NODEF; + ctxt.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; + ret = sng_mgco_send_axn_req(suId, &ctxt); + + return ret; + + + +} +/*****************************************************************************************************************************/ +switch_status_t mg_send_audit_rsp(SuId suId, MgMgcoCommand *req) +{ + MgMgcoCommand cmd; + int ret = 0x00; + MgMgcoTermId *termId; + MgMgcoCtxt ctxt; + MgMgcoAuditReply *adtRep = NULLP; + + memset(&cmd,0, sizeof(cmd)); + + /*copy transaction-id*/ + memcpy(&cmd.transId, &req->transId,sizeof(MgMgcoTransId)); + + /*copy context-id*/ /*TODO - in case of $ context should be generated by app, we should not simply copy incoming structure */ + memcpy(&cmd.contextId, &req->contextId,sizeof(MgMgcoContextId)); + + /*copy peer identifier */ + memcpy(&cmd.peerId, &req->peerId,sizeof(TknU32)); + + /*fill response structue */ + if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&cmd.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ + return ret; + } + + cmd.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; + cmd.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; + cmd.u.mgCmdRsp[0]->wild.pres = NOTPRSNT; + cmd.u.mgCmdRsp[0]->type.val = MGT_AUDITVAL; + + adtRep = &(cmd.u.mgCmdRsp[0]->u.aval); + + /* Set type as Cxt Audit */ + MG_INIT_TOKEN_VALUE(&(adtRep->type), MGT_CXTAUDIT); + /* Set no of Terminations to 1 */ + MG_INIT_TOKEN_VALUE(&(adtRep->u.cxt.num), 1); + + + + cmd.u.mgCmdRsp[0]->u.aval.u.cxt.num.pres = PRSNT_NODEF; + cmd.u.mgCmdRsp[0]->u.aval.u.cxt.num.val = 1; + + mgUtlAllocMgMgcoTermIdLst(&cmd.u.mgCmdRsp[0]->u.aval.u.cxt, &req->u.mgCmdReq[0]->cmd.u.aval.termIdLst); + +#ifdef GCP_VER_2_1 + termId = cmd.u.mgCmdRsp[0]->u.add.termIdLst.terms[0]; +#else + termId = &(cmd.u.mgCmdRsp[0]->u.add.termId); +#endif + mg_fill_mgco_termid(termId, (CONSTANT U8*)"term1",&req->u.mgCmdRsp[0]->memCp); + + /* We will always send one command at a time..*/ + cmd.cmdStatus.pres = PRSNT_NODEF; + cmd.cmdStatus.val = CH_CMD_STATUS_END_OF_CMD; + + cmd.cmdType.pres = PRSNT_NODEF; + cmd.cmdType.val = CH_CMD_TYPE_RSP; + + + ret = sng_mgco_send_cmd(suId, &cmd); + + memcpy(&ctxt.transId,&req->transId,sizeof(MgMgcoTransId)); + memcpy(&ctxt.cntxtId, &req->contextId,sizeof(MgMgcoContextId)); + memcpy(&ctxt.peerId, &req->peerId,sizeof(TknU32)); + ctxt.cmdStatus.pres = PRSNT_NODEF; + ctxt.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; + ret = sng_mgco_send_axn_req(suId, &ctxt); + + return ret; +} + +/*****************************************************************************************************************************/ +switch_status_t mg_send_modify_rsp(SuId suId, MgMgcoCommand *req) +{ + MgMgcoCommand cmd; + int ret = 0x00; + MgMgcoTermId *termId; + MgMgcoCtxt ctxt; + + memset(&cmd,0, sizeof(cmd)); + + /*copy transaction-id*/ + memcpy(&cmd.transId, &req->transId,sizeof(MgMgcoTransId)); + + /*copy context-id*/ /*TODO - in case of $ context should be generated by app, we should not simply copy incoming structure */ + memcpy(&cmd.contextId, &req->contextId,sizeof(MgMgcoContextId)); + + /*copy peer identifier */ + memcpy(&cmd.peerId, &req->peerId,sizeof(TknU32)); + + /*fill response structue */ + if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&cmd.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ + return ret; + } + + cmd.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; + cmd.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; + cmd.u.mgCmdRsp[0]->type.val = MGT_MODIFY; + cmd.u.mgCmdRsp[0]->u.mod.pres.pres = PRSNT_NODEF; + cmd.u.mgCmdRsp[0]->u.mod.termIdLst.num.pres = PRSNT_NODEF; + cmd.u.mgCmdRsp[0]->u.mod.termIdLst.num.val = 1; + + mgUtlAllocMgMgcoTermIdLst(&cmd.u.mgCmdRsp[0]->u.mod.termIdLst, &req->u.mgCmdReq[0]->cmd.u.mod.termIdLst); + +#ifdef GCP_VER_2_1 + termId = cmd.u.mgCmdRsp[0]->u.mod.termIdLst.terms[0]; +#else + termId = &(cmd.u.mgCmdRsp[0]->u.mod.termId); +#endif + mg_fill_mgco_termid(termId, (CONSTANT U8*)"term1",&req->u.mgCmdRsp[0]->memCp); + + /* We will always send one command at a time..*/ + cmd.cmdStatus.pres = PRSNT_NODEF; + cmd.cmdStatus.val = CH_CMD_STATUS_END_OF_CMD; + + cmd.cmdType.pres = PRSNT_NODEF; + cmd.cmdType.val = CH_CMD_TYPE_RSP; + + + ret = sng_mgco_send_cmd(suId, &cmd); + + memcpy(&ctxt.transId,&req->transId,sizeof(MgMgcoTransId)); + memcpy(&ctxt.cntxtId, &req->contextId,sizeof(MgMgcoContextId)); + memcpy(&ctxt.peerId, &req->peerId,sizeof(TknU32)); + ctxt.cmdStatus.pres = PRSNT_NODEF; + ctxt.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; + ret = sng_mgco_send_axn_req(suId, &ctxt); + + return ret; +} + +/*****************************************************************************************************************************/ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_packages.c b/src/mod/endpoints/mod_media_gateway/media_gateway_packages.c new file mode 100644 index 0000000000..19c1b1dae7 --- /dev/null +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_packages.c @@ -0,0 +1,135 @@ +/* +* Copyright (c) 2012, Sangoma Technologies +* Mathieu Rene +* All rights reserved. +* +* +*/ + +#include "mod_media_gateway.h" +#include "media_gateway_stack.h" + + +MgPackage_t mg_pkg_list [] = +{ + { /* INDEX : 0 */ + MGT_PKG_GENERIC, /* Package Id 1 : Generic package */ + 1, /* Version 1 */ + "g", /* Package name */ + }, + { /* INDEX : 1 */ + MGT_PKG_ROOT, + 2, /* Version 1 */ + "root", /* Package name */ + }, + { /* INDEX : 2 */ + MGT_PKG_TONEDET, /*4*/ + 1, /* Version 1 */ + "tonedet", /* Package name */ + }, + { /* INDEX : 3 */ + MGT_PKG_DTMFDET, /*6*/ + 1, /* Version 1 */ + "dd", /* Package name */ + }, + { /* INDEX : 4 */ + MGT_PKG_NETWORK, /*11*/ + 1, /* Version 1 */ + "nt", /* Package name */ + }, + { /* INDEX : 5 */ + MGT_PKG_RTP, /*12*/ + 1, /* Version 1 */ + "rtp", /* Package name */ + }, + { /* INDEX : 6 */ + MGT_PKG_TDM_CKT, /*13*/ + 1, /* Version 1 */ + "tdmc", /* Package name */ + }, + { /* INDEX : 7 */ + MGT_PKG_QTY_ALT, /*55*/ + 1, /* Version 1 */ + "qac", /* Package name */ + }, + { /* INDEX : 8 */ + MGT_PKG_EN_ALERT, /*59*/ + 2, /* Version 2 */ + "alert", /* Package name */ + }, + { /* INDEX : 9 */ + MGT_PKG_AN_DISP, /*60*/ + 2, /* Version 1 */ + "andisp", /* Package name */ + }, + { /* INDEX : 10 */ + MGT_PKG_INACTTIMER, /*69*/ + 1, /* Version 1 */ + "it", /* Package name */ + }, + { /* INDEX : 11 */ + MGT_PKG_STIMAL, /* 147 */ + 1, /* Version 1 */ + "stimal ", /* Package name */ + }, + { /* INDEX : 12 */ + MGT_PKG_CALLPROGGEN, /* 7 */ + 1, /* Version 1 */ + "cg", /* Package name */ + }, + { /* INDEX : 13 */ + MGT_PKG_GENERIC_ANNC, /* 29 */ + 1, /* Version 1 */ + "an", /* Package name */ + }, + { /* INDEX : 14 */ + MGT_PKG_XD_CALPG_TNGN, /* 36 */ + 1, /* Version 1 */ + "xcg", /* Package name */ + }, + { /* INDEX : 15 */ + MGT_PKG_BSC_SRV_TN, /* 37 */ + 1, /* Version 1 */ + "srvtn", /* Package name */ + }, + { /* INDEX : 16 */ + MGT_PKG_ETSI_NR, + 1, /* Version 1 */ + "etsi_nr", /* Package name */ + }, + /* Add more packages */ +}; + +/***************************************************************************************/ +switch_status_t mg_build_pkg_desc(MgMgcoPkgsDesc* pkg) +{ + uint16_t i = 0x00; + uint16_t num_of_pkgs = sizeof(mg_pkg_list)/sizeof(MgPackage_t); + + printf("mg_build_pkg_desc: num_of_pkgs[%d]\n",num_of_pkgs); + + for (i = 0; i < num_of_pkgs; i++) { + + if (mgUtlGrowList((void ***)&pkg->items, + sizeof(MgMgcoPkgsItem), &pkg->num, NULLP) != ROK) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,"Package descriptor Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + pkg->items[pkg->num.val - 1 ]->pres.pres = PRSNT_NODEF; + pkg->items[pkg->num.val - 1 ]->name.type.pres = PRSNT_NODEF; + pkg->items[pkg->num.val - 1 ]->name.type.val = MGT_GEN_TYPE_KNOWN; + + pkg->items[pkg->num.val - 1 ]->name.u.val.pres = PRSNT_NODEF; + pkg->items[pkg->num.val - 1 ]->name.u.val.val = mg_pkg_list[i].package_id; + + pkg->items[pkg->num.val - 1 ]->ver.pres = PRSNT_NODEF; + pkg->items[pkg->num.val - 1 ]->ver.val = mg_pkg_list[i].version; + + printf("mg_build_pkg_desc: Inserted pkg_id[%d] with version[%d] into pkg list index[%d]\n",mg_pkg_list[i].package_id,mg_pkg_list[i].version,i); + } + + return SWITCH_STATUS_SUCCESS; +} +/***************************************************************************************/ + diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index 328806b746..752fabd6ea 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -49,29 +49,55 @@ typedef struct _mgStr U8 val[128]; } MgStr; +#define MAX_PACKAGE_NAME 128 + +typedef struct _mgPackage +{ + uint8_t package_id; + uint16_t version; + uint8_t name[MAX_PACKAGE_NAME+1]; +}MgPackage_t; + +extern MgPackage_t mg_pkg_list[]; + + #define MG_TXN_INVALID 0 -#define mg_zero(_buf, _size) {cmMemset((U8 *)(_buf), 0, _size);} +#define MG_ZERO(_buf, _size) {cmMemset((U8 *)(_buf), 0, _size);} /* Set pres field */ -#define mg_util_set_pres(_pres) \ +#define MG_SET_PRES(_pres) \ (_pres) = PRSNT_NODEF; /* Set token value */ -#define mg_util_set_val_pres(tkn,_val) \ - mg_util_set_pres((tkn).pres); \ +#define MG_SET_VAL_PRES(tkn,_val) \ + MG_SET_PRES((tkn).pres); \ (tkn).val = _val; -#define mg_mem_copy(_dst, _src, _len) \ +#define MG_MEM_COPY(_dst, _src, _len) \ cmMemcpy((U8*) (_dst), (const U8*) (_src), _len) -#define mg_get_mem(_memPtr, _size, _allocPtr, ret) \ -{ \ - (*ret) = cmGetMem((Ptr *)(_memPtr),(_size) ,(Ptr *)&(_allocPtr)); \ + +#define MG_INIT_TOKEN_VALUE(_tkn, _val) \ +{ \ + (_tkn)->pres = PRSNT_NODEF; \ + (_tkn)->val = (_val); \ } +#define MG_GETMEM(_ptr,_len,_memCp,_ret) \ +{ \ + ret = cmGetMem((_memCp), (_len), (Ptr *)&(_ptr)); \ + if( ret == ROK) \ + cmMemset((U8 *)(_ptr), (U8)0, (PTR)(_len)); \ +} +#define MG_INIT_TKNSTR(_tkn, _val, _len) \ +{ \ + (_tkn)->pres = PRSNT_NODEF; \ + (_tkn)->len = (U8)(_len); \ + cmMemcpy((U8 *)(_tkn)->val, (CONSTANT U8 *)(_val), (_len)); \ +} void handle_sng_log(uint8_t level, char *fmt, ...); void handle_mgco_sta_ind(Pst *pst, SuId suId, MgMgtSta* msg); @@ -91,6 +117,28 @@ switch_status_t sng_mgco_init(sng_mg_event_interface_t* event); switch_status_t sng_mgco_stack_shutdown(void); int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, megaco_profile_t* mg_cfg, mg_peer_profile_t* mg_peer); +switch_status_t mg_send_end_of_axn(SuId suId, MgMgcoTransId* transId, MgMgcoContextId* ctxtId, TknU32* peerId); +void mgco_print_sdp(CmSdpInfoSet *sdp); +void mg_util_set_ctxt_string ( MgStr *errTxt, MgMgcoContextId *ctxtId); +switch_status_t handle_mg_add_cmd(MgMgcoAmmReq *addReq); +switch_status_t mg_stack_free_mem(MgMgcoMsg* msg); +switch_status_t mg_stack_free_mem(MgMgcoMsg* msg); +switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ); +switch_status_t mg_send_add_rsp(SuId suId, MgMgcoCommand *req); +S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, CONSTANT U8 *str, CmMemListCp *memCp); +void mg_util_set_txn_string(MgStr *errTxt, U32 *txnId); +switch_status_t mg_build_mgco_err_request(MgMgcoInd **errcmd,U32 trans_id, MgMgcoContextId *ctxt_id, U32 err, MgStr *errTxt); +switch_status_t mg_send_audit_rsp(SuId suId, MgMgcoCommand *req); +switch_status_t handle_mg_audit_cmd(SuId suId, MgMgcoCommand *auditReq); + +switch_status_t mg_send_modify_rsp(SuId suId, MgMgcoCommand *req); +void mg_util_set_term_string ( MgStr *errTxt, MgMgcoTermId *termId); +MgMgcoTermIdLst *mg_get_term_id_list(MgMgcoCommand *cmd); +switch_status_t handle_pkg_audit( SuId suId, MgMgcoCommand *auditReq); +switch_status_t mg_build_pkg_desc(MgMgcoPkgsDesc* pkg); + + + /****************************************************************************************************************/ /* MG Stack defines */ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c new file mode 100644 index 0000000000..81bde4871b --- /dev/null +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -0,0 +1,430 @@ +/* +* Copyright (c) 2012, Sangoma Technologies +* Mathieu Rene +* All rights reserved. +* +* +*/ + +#include "mod_media_gateway.h" +#include "media_gateway_stack.h" + + +/*****************************************************************************************************************************/ +switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ) +{ + Mem sMem; + + sMem.region = 0; + sMem.pool = 0; + + if ( _memSize <= 0 ) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_alloc_mem: invalid size\n"); + return SWITCH_STATUS_FALSE; + } + + if ( ROK != cmAllocEvnt( _memSize, MG_MAXBLKSIZE, &sMem, _memPtr ) ) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_alloc_mem: cmAllocEvnt return failure for _memSize=%d\n",(int)_memSize); + return SWITCH_STATUS_FALSE; + } + + // Note: memset done inside stack api + + return SWITCH_STATUS_SUCCESS; +} + +/*****************************************************************************************************************************/ + +switch_status_t mg_stack_get_mem(MgMgcoMsg* msg, Ptr* _memPtr, Size _memSize ) +{ + if ( _memSize <= 0 ) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_get_mem: invalid size\n"); + return SWITCH_STATUS_FALSE; + } + + if ( !msg ) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_get_mem: invalid message\n"); + return SWITCH_STATUS_FALSE; + } + + if ( cmGetMem( (Ptr)msg, _memSize, (Ptr*)_memPtr ) != ROK ) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed alloc_mg_stack_mem: get memory failed _memSize=%d\n", (int)_memSize ); + return SWITCH_STATUS_FALSE; + } + + // Note: memset done inside stack api + + return SWITCH_STATUS_SUCCESS; +} + +/*****************************************************************************************************************************/ + +switch_status_t mg_stack_free_mem(MgMgcoMsg* msg) +{ + if ( !msg ) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_get_mem: invalid message\n"); + return SWITCH_STATUS_FALSE; + } + + cmFreeMem( (Ptr)msg ); + + return SWITCH_STATUS_SUCCESS; +} + + +/*****************************************************************************************************************************/ + +S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, CONSTANT U8 *str, CmMemListCp *memCp) +{ +#ifdef GCP_ASN + Size size; +#endif + S16 ret = ROK; + + termId->name.pres.pres = PRSNT_NODEF; + /* mg011.105: Bug fixes */ + termId->name.lcl.pres = PRSNT_NODEF; + termId->name.lcl.len = cmStrlen((CONSTANT U8*)str); + MG_GETMEM(termId->name.lcl.val, termId->name.lcl.len, memCp, ret); + if( ret != ROK) + RETVALUE(ret); + + cmMemcpy((U8*)(termId->name.lcl.val), (CONSTANT U8*)str,termId->name.lcl.len); + +#ifdef GCP_ASN + /* Remove comment to fill other term ID + termId->wildcard.num.pres = NOTPRSNT; */ + /* Remove comment to fill wilcard term ID */ + termId->wildcard.num.pres = PRSNT_NODEF; + termId->wildcard.num.val = 1; + size = ((sizeof(MgMgcoWildcardField*))); + MG_GETMEM((termId->wildcard.wildcard),size,memCp, ret); + if( ret != ROK) + RETVALUE(ret); + + MG_GETMEM( ((termId->wildcard.wildcard)[0]),sizeof(MgMgcoWildcardField), + memCp, ret); + if( ret != ROK) + RETVALUE(ret); + + termId->wildcard.wildcard[0]->pres = PRSNT_NODEF; + termId->wildcard.wildcard[0]->len = 1; + termId->wildcard.wildcard[0]->val[0] = 0x55; +#endif /* GCP_ASN */ + + RETVALUE(ROK); +} + +/*****************************************************************************************************************************/ +/* +* +* Fun: mg_get_term_id_list +* +* Desc: Utility function to get MgMgcoTermIdLst structure +* from MgMgcoCommand structure. +* GCP_VER_2_1 - we will have term id list instead of single term id +* +* Ret: If success, return pointer to MgMgcoTermIdLst. +* If failure, return Null. +* +* Notes: None +* +*/ + +MgMgcoTermIdLst *mg_get_term_id_list(MgMgcoCommand *cmd) +{ + uint8_t cmd_type = MGT_NONE; + uint8_t api_type = CM_CMD_TYPE_NONE; + MgMgcoTermIdLst * term_id = NULL; + + + /*-- mgCmdInd type represents the data structure for both + * incoming and outgoing requests, hence we can get the + * command type from there itself --*/ + cmd_type = cmd->u.mgCmdInd[0]->cmd.type.val; + + /*-- Find apiType --*/ + api_type = cmd->cmdType.val; + + switch (api_type) + { + case CH_CMD_TYPE_REQ: + case CH_CMD_TYPE_IND: + /* Based on Command Type, get to the TermId structure */ + switch (cmd_type) + { + case MGT_ADD: + if (cmd->u.mgCmdInd[0]->cmd.u.add.pres.pres) + term_id = &cmd->u.mgCmdInd[0]->cmd.u.add.termIdLst; + break; + + case MGT_MOVE: + if (cmd->u.mgCmdInd[0]->cmd.u.move.pres.pres) + term_id = &cmd->u.mgCmdInd[0]->cmd.u.move.termIdLst; + break; + + case MGT_MODIFY: + if (cmd->u.mgCmdInd[0]->cmd.u.mod.pres.pres) + term_id = &cmd->u.mgCmdInd[0]->cmd.u.mod.termIdLst; + break; + + case MGT_SUB: + if (cmd->u.mgCmdInd[0]->cmd.u.sub.pres.pres) + term_id = &cmd->u.mgCmdInd[0]->cmd.u.sub.termIdLst; + break; + + case MGT_AUDITCAP: + if (cmd->u.mgCmdInd[0]->cmd.u.acap.pres.pres) + term_id = &cmd->u.mgCmdInd[0]->cmd.u.acap.termIdLst; + break; + + case MGT_AUDITVAL: + if (cmd->u.mgCmdInd[0]->cmd.u.aval.pres.pres) + term_id = &cmd->u.mgCmdInd[0]->cmd.u.aval.termIdLst; + break; + + case MGT_NTFY: + if (cmd->u.mgCmdInd[0]->cmd.u.ntfy.pres.pres) + term_id = &cmd->u.mgCmdInd[0]->cmd.u.ntfy.termIdLst; + break; + + case MGT_SVCCHG: + if (cmd->u.mgCmdInd[0]->cmd.u.svc.pres.pres) + term_id = &cmd->u.mgCmdInd[0]->cmd.u.svc.termIdLst; + break; + + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); + break; + } + break; + + case CH_CMD_TYPE_RSP: + case CH_CMD_TYPE_CFM: + + cmd_type = cmd->u.mgCmdRsp[0]->type.val; + + switch (cmd_type) + { + case MGT_ADD: + if (cmd->u.mgCmdRsp[0]->u.add.pres.pres) + term_id = &cmd->u.mgCmdRsp[0]->u.add.termIdLst; + break; + + case MGT_MOVE: + if (cmd->u.mgCmdRsp[0]->u.move.pres.pres) + term_id = &cmd->u.mgCmdRsp[0]->u.move.termIdLst; + break; + + case MGT_MODIFY: + if (cmd->u.mgCmdRsp[0]->u.mod.pres.pres) + term_id = &cmd->u.mgCmdRsp[0]->u.mod.termIdLst; + break; + + case MGT_SUB: + if (cmd->u.mgCmdRsp[0]->u.sub.pres.pres) + term_id = &cmd->u.mgCmdRsp[0]->u.sub.termIdLst; + break; + + case MGT_SVCCHG: + if (cmd->u.mgCmdRsp[0]->u.svc.pres.pres) + term_id = &cmd->u.mgCmdRsp[0]->u.svc.termIdLst; + break; + + case MGT_AUDITVAL: + if (cmd->u.mgCmdRsp[0]->u.aval.u.other.pres.pres) + term_id = &cmd->u.mgCmdRsp[0]->u.aval.u.other.termIdLst; + break; + + case MGT_AUDITCAP: + if (cmd->u.mgCmdRsp[0]->u.acap.u.other.pres.pres) + term_id = &cmd->u.mgCmdRsp[0]->u.acap.u.other.termIdLst; + break; + + case MGT_NTFY: + if (cmd->u.mgCmdRsp[0]->u.ntfy.pres.pres) + term_id = &cmd->u.mgCmdRsp[0]->u.ntfy.termIdLst; + break; + + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); + } /* switch command type for reply */ + break; + + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported api_type[%s]!\n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(api_type)); + break; + } /* switch -api_type */ + + return (term_id); +} + + +/*****************************************************************************************************************************/ + +void mg_util_set_txn_string(MgStr *errTxt, U32 *txnId) +{ + MG_ZERO(errTxt->val, sizeof(errTxt->val)); + errTxt->len = 0; + + errTxt->val[errTxt->len] = '\"'; + errTxt->len += 1; + + if (MG_TXN_INVALID == txnId ) + { + MG_MEM_COPY((&errTxt->val[errTxt->len]), "TransactionId=0", 15); + errTxt->len += 15; + } + + errTxt->val[errTxt->len] = '\"'; + errTxt->len += 1; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s:" + "info, error-text is: %s\n", __PRETTY_FUNCTION__,errTxt->val); + +} + +/*****************************************************************************************************************************/ +void mg_util_set_ctxt_string ( MgStr *errTxt, MgMgcoContextId *ctxtId) +{ + MG_ZERO((errTxt->val), sizeof(errTxt->val)); + errTxt->len = 0; + if(ctxtId->type.pres != NOTPRSNT) + { + errTxt->val[errTxt->len] = '\"'; + errTxt->len += 1; + if(ctxtId->type.val == MGT_CXTID_NULL) + { + errTxt->val[errTxt->len] = '-'; + errTxt->len += 1; + } + else if(ctxtId->type.val == MGT_CXTID_ALL) + { + errTxt->val[errTxt->len] = '*'; + errTxt->len += 1; + } + else if(ctxtId->type.val == MGT_CXTID_CHOOSE) + { + errTxt->val[errTxt->len] = '$'; + errTxt->len += 1; + } + else if((ctxtId->type.val == MGT_CXTID_OTHER) && (ctxtId->val.pres != NOTPRSNT)) + { + sprintf((char*)&errTxt->val[errTxt->len], "%d", ctxtId->val.val); + errTxt->len += cmStrlen((U8*)(&errTxt->val[errTxt->len])); + } + + errTxt->val[errTxt->len] = '\"'; + errTxt->len += 1; + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s:" + "info, error-text is: %s\n", __PRETTY_FUNCTION__,errTxt->val); +} + + +/*****************************************************************************************************************************/ +void mgco_print_sdp(CmSdpInfoSet *sdp) +{ + int i; + + + if (sdp->numComp.pres == NOTPRSNT) { + return; + } + + for (i = 0; i < sdp->numComp.val; i++) { + CmSdpInfo *s = sdp->info[i]; + int mediaId; + + if (s->conn.addrType.pres && s->conn.addrType.val == CM_SDP_ADDR_TYPE_IPV4 && + s->conn.netType.type.val == CM_SDP_NET_TYPE_IN && + s->conn.u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) { + + if (s->conn.u.ip4.addrType.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Address: %d.%d.%d.%d\n", + s->conn.u.ip4.u.uniIp.b[0].val, + s->conn.u.ip4.u.uniIp.b[1].val, + s->conn.u.ip4.u.uniIp.b[2].val, + s->conn.u.ip4.u.uniIp.b[3].val); + } + if (s->attrSet.numComp.pres) { + for (mediaId = 0; mediaId < s->attrSet.numComp.val; mediaId++) { + /*CmSdpAttr *a = s->attrSet.attr[mediaId];*/ + + + } + } + + if (s->mediaDescSet.numComp.pres) { + for (mediaId = 0; mediaId < s->mediaDescSet.numComp.val; mediaId++) { + CmSdpMediaDesc *desc = s->mediaDescSet.mediaDesc[mediaId]; + + if (desc->field.mediaType.val == CM_SDP_MEDIA_AUDIO && + desc->field.id.type.val == CM_SDP_VCID_PORT && + desc->field.id.u.port.type.val == CM_SDP_PORT_INT && + desc->field.id.u.port.u.portInt.port.type.val == CM_SDP_SPEC) { + int port = desc->field.id.u.port.u.portInt.port.val.val; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Port: %d\n", port); + + } + } + } + } + } +} + +/*****************************************************************************************************************************/ +void mg_util_set_term_string ( MgStr *errTxt, MgMgcoTermId *termId) +{ + MG_ZERO((errTxt->val), sizeof(errTxt->val)); + errTxt->len = 0; + + if(termId->type.pres != NOTPRSNT) + { + errTxt->val[errTxt->len] = '\"'; + errTxt->len += 1; + + if(termId->type.val == MGT_TERMID_ROOT) + { + MG_MEM_COPY((&errTxt->val[errTxt->len]), "ROOT", 4); + errTxt->len += 4; + } + else if(termId->type.val == MGT_TERMID_ALL) + { + errTxt->val[errTxt->len] = '*'; + errTxt->len += 1; + } + else if(termId->type.val == MGT_TERMID_CHOOSE) + { + errTxt->val[errTxt->len] = '$'; + errTxt->len += 1; + } + else if((termId->type.val == MGT_TERMID_OTHER) && (termId->name.pres.pres != NOTPRSNT)) + { + if(termId->name.lcl.pres != NOTPRSNT) + { + MG_MEM_COPY(&(errTxt->val[errTxt->len]), termId->name.lcl.val, sizeof(U8) * termId->name.lcl.len); + errTxt->len += termId->name.lcl.len; + } + if(termId->name.dom.pres != NOTPRSNT) + { + MG_MEM_COPY(&(errTxt->val[errTxt->len]), + termId->name.dom.val, sizeof(U8) * termId->name.dom.len); + errTxt->len += termId->name.dom.len; + } + } + errTxt->val[errTxt->len] = '\"'; + errTxt->len += 1; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s:" + "info, error-text is: %s\n", __PRETTY_FUNCTION__,errTxt->val); +} +/*****************************************************************************************************************************/ diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index d549becc70..e1c5ea2439 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -18,15 +18,6 @@ static sng_mg_event_interface_t sng_event; SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_media_gateway_shutdown); SWITCH_MODULE_DEFINITION(mod_media_gateway, mod_media_gateway_load, mod_media_gateway_shutdown, NULL); -switch_status_t handle_mg_add_cmd(MgMgcoAmmReq *addReq); -switch_status_t mg_stack_free_mem(MgMgcoMsg* msg); -switch_status_t mg_stack_free_mem(MgMgcoMsg* msg); -switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ); -switch_status_t mg_send_add_rsp(SuId suId, MgMgcoCommand *req); -S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, CONSTANT U8 *str, CmMemListCp *memCp); -void mg_util_set_txn_string(MgStr *errTxt, U32 *txnId); -switch_status_t mg_build_mgco_err_request(MgMgcoInd **errcmd,U32 trans_id, MgMgcoContextId *ctxt_id, U32 err, MgStr *errTxt); - /**************************************************************************************************************/ SWITCH_STANDARD_API(megaco_function) @@ -169,56 +160,7 @@ void handle_sng_log(uint8_t level, char *fmt, ...) va_end(ptr); } -static void mgco_print_sdp(CmSdpInfoSet *sdp) -{ - int i; - - - if (sdp->numComp.pres == NOTPRSNT) { - return; - } - - for (i = 0; i < sdp->numComp.val; i++) { - CmSdpInfo *s = sdp->info[i]; - int mediaId; - - if (s->conn.addrType.pres && s->conn.addrType.val == CM_SDP_ADDR_TYPE_IPV4 && - s->conn.netType.type.val == CM_SDP_NET_TYPE_IN && - s->conn.u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) { - if (s->conn.u.ip4.addrType.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Address: %d.%d.%d.%d\n", - s->conn.u.ip4.u.uniIp.b[0].val, - s->conn.u.ip4.u.uniIp.b[1].val, - s->conn.u.ip4.u.uniIp.b[2].val, - s->conn.u.ip4.u.uniIp.b[3].val); - } - if (s->attrSet.numComp.pres) { - for (mediaId = 0; mediaId < s->attrSet.numComp.val; mediaId++) { - /*CmSdpAttr *a = s->attrSet.attr[mediaId];*/ - - - } - } - - if (s->mediaDescSet.numComp.pres) { - for (mediaId = 0; mediaId < s->mediaDescSet.numComp.val; mediaId++) { - CmSdpMediaDesc *desc = s->mediaDescSet.mediaDesc[mediaId]; - - if (desc->field.mediaType.val == CM_SDP_MEDIA_AUDIO && - desc->field.id.type.val == CM_SDP_VCID_PORT && - desc->field.id.u.port.type.val == CM_SDP_PORT_INT && - desc->field.id.u.port.u.portInt.port.type.val == CM_SDP_SPEC) { - int port = desc->field.id.u.port.u.portInt.port.val.val; - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Port: %d\n", port); - - } - } - } - } - } -} /*****************************************************************************************************************************/ @@ -415,27 +357,26 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) MgMgcoInd *mgErr; MgStr errTxt; MgMgcoContextId ctxtId; + MgMgcoTermIdLst* termLst; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: Received Command Type[%s] \n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(cmd->cmdType.val)); /* validate Transaction Id */ - if (NOTPRSNT != cmd->transId.pres) + if (NOTPRSNT != cmd->transId.pres){ txn_id = cmd->transId.val; - else - { + } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: Transaction Id not present, rejecting\n", __PRETTY_FUNCTION__); /*-- Send Error to MG Stack --*/ - mg_zero(&ctxtId, sizeof(MgMgcoContextId)); + MG_ZERO(&ctxtId, sizeof(MgMgcoContextId)); ctxtId.type.pres = NOTPRSNT; ctxtId.val.pres = NOTPRSNT; - mg_util_set_txn_string(&errTxt, &txn_id); + mg_util_set_txn_string(&errTxt, (U32*)&txn_id); - if (SWITCH_STATUS_FALSE == mg_build_mgco_err_request(&mgErr, txn_id, &ctxtId, - MGT_MGCO_RSP_CODE_INVLD_IDENTIFIER, &errTxt)) - { + if (SWITCH_STATUS_SUCCESS == mg_build_mgco_err_request(&mgErr, txn_id, &ctxtId, + MGT_MGCO_RSP_CODE_INVLD_IDENTIFIER, &errTxt)) { sng_mgco_send_err(suId, mgErr); } @@ -444,7 +385,16 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) return ; } - mgAccEvntPrntMgMgcoCommand(cmd, stdout); + /* Get the termination Id list from the command(Note: GCP_2_1 has termination list , else it will be termination Id) */ + termLst = mg_get_term_id_list(cmd); + if ((NULL == termLst) || (NOTPRSNT == termLst->num.pres)) { + /* termination-id not present , error */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Termination-Id Not received..rejecting command \n"); + mg_free_cmd(cmd); + return ; + } + + /*mgAccEvntPrntMgMgcoCommand(cmd, stdout);*/ switch(cmd->cmdType.val) { @@ -465,6 +415,7 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) case MGT_MODIFY: { /*MgMgcoAmmReq *addReq = &cmdReq->cmd.u.mod;*/ + mg_send_modify_rsp(suId, cmd); break; } case MGT_MOVE: @@ -478,9 +429,27 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) /*MgMgcoSubAudReq *addReq = &cmdReq->cmd.u.sub;*/ } case MGT_SVCCHG: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Service-Change Method Not Yet Supported\n"); + break; + } case MGT_NTFY: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NOTIFY Method Not Yet Supported\n"); + break; + } case MGT_AUDITCAP: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Audit-Capability Method Not Yet Supported\n"); + break; + } case MGT_AUDITVAL: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received Audit-Value Method \n"); + handle_mg_audit_cmd(suId, cmd); + mg_send_audit_rsp(suId,cmd); + break; + } break; } @@ -538,468 +507,6 @@ void handle_mgco_audit_cfm(Pst *pst, SuId suId, MgMgtAudit* audit, Reason reason } -/*****************************************************************************************************************************/ -/* -* -* Fun: mg_get_term_id_list -* -* Desc: Utility function to get MgMgcoTermIdLst structure -* from MgMgcoCommand structure. -* GCP_VER_2_1 - we will have term id list instead of single term id -* -* Ret: If success, return pointer to MgMgcoTermIdLst. -* If failure, return Null. -* -* Notes: None -* -*/ - -MgMgcoTermIdLst *mg_get_term_id_list(MgMgcoCommand *cmd) -{ - uint8_t cmd_type = MGT_NONE; - uint8_t api_type = CM_CMD_TYPE_NONE; - MgMgcoTermIdLst * term_id = NULL; - - - /*-- mgCmdInd type represents the data structure for both - * incoming and outgoing requests, hence we can get the - * command type from there itself --*/ - cmd_type = cmd->u.mgCmdInd[0]->cmd.type.val; - - /*-- Find apiType --*/ - api_type = cmd->cmdType.val; - - switch (api_type) - { - case CH_CMD_TYPE_REQ: - case CH_CMD_TYPE_IND: - /* Based on Command Type, get to the TermId structure */ - switch (cmd_type) - { - case MGT_ADD: - if (cmd->u.mgCmdInd[0]->cmd.u.add.pres.pres) - term_id = &cmd->u.mgCmdInd[0]->cmd.u.add.termIdLst; - break; - - case MGT_MOVE: - if (cmd->u.mgCmdInd[0]->cmd.u.move.pres.pres) - term_id = &cmd->u.mgCmdInd[0]->cmd.u.move.termIdLst; - break; - - case MGT_MODIFY: - if (cmd->u.mgCmdInd[0]->cmd.u.mod.pres.pres) - term_id = &cmd->u.mgCmdInd[0]->cmd.u.mod.termIdLst; - break; - - case MGT_SUB: - if (cmd->u.mgCmdInd[0]->cmd.u.sub.pres.pres) - term_id = &cmd->u.mgCmdInd[0]->cmd.u.sub.termIdLst; - break; - - case MGT_AUDITCAP: - if (cmd->u.mgCmdInd[0]->cmd.u.acap.pres.pres) - term_id = &cmd->u.mgCmdInd[0]->cmd.u.acap.termIdLst; - break; - - case MGT_AUDITVAL: - if (cmd->u.mgCmdInd[0]->cmd.u.aval.pres.pres) - term_id = &cmd->u.mgCmdInd[0]->cmd.u.aval.termIdLst; - break; - - case MGT_NTFY: - if (cmd->u.mgCmdInd[0]->cmd.u.ntfy.pres.pres) - term_id = &cmd->u.mgCmdInd[0]->cmd.u.ntfy.termIdLst; - break; - - case MGT_SVCCHG: - if (cmd->u.mgCmdInd[0]->cmd.u.svc.pres.pres) - term_id = &cmd->u.mgCmdInd[0]->cmd.u.svc.termIdLst; - break; - - default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); - break; - } - break; - - case CH_CMD_TYPE_RSP: - case CH_CMD_TYPE_CFM: - - cmd_type = cmd->u.mgCmdRsp[0]->type.val; - - switch (cmd_type) - { - case MGT_ADD: - if (cmd->u.mgCmdRsp[0]->u.add.pres.pres) - term_id = &cmd->u.mgCmdRsp[0]->u.add.termIdLst; - break; - - case MGT_MOVE: - if (cmd->u.mgCmdRsp[0]->u.move.pres.pres) - term_id = &cmd->u.mgCmdRsp[0]->u.move.termIdLst; - break; - - case MGT_MODIFY: - if (cmd->u.mgCmdRsp[0]->u.mod.pres.pres) - term_id = &cmd->u.mgCmdRsp[0]->u.mod.termIdLst; - break; - - case MGT_SUB: - if (cmd->u.mgCmdRsp[0]->u.sub.pres.pres) - term_id = &cmd->u.mgCmdRsp[0]->u.sub.termIdLst; - break; - - case MGT_SVCCHG: - if (cmd->u.mgCmdRsp[0]->u.svc.pres.pres) - term_id = &cmd->u.mgCmdRsp[0]->u.svc.termIdLst; - break; - - case MGT_AUDITVAL: - if (cmd->u.mgCmdRsp[0]->u.aval.u.other.pres.pres) - term_id = &cmd->u.mgCmdRsp[0]->u.aval.u.other.termIdLst; - break; - - case MGT_AUDITCAP: - if (cmd->u.mgCmdRsp[0]->u.acap.u.other.pres.pres) - term_id = &cmd->u.mgCmdRsp[0]->u.acap.u.other.termIdLst; - break; - - case MGT_NTFY: - if (cmd->u.mgCmdRsp[0]->u.ntfy.pres.pres) - term_id = &cmd->u.mgCmdRsp[0]->u.ntfy.termIdLst; - break; - - default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); - } /* switch command type for reply */ - break; - - default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported api_type[%s]!\n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(api_type)); - break; - } /* switch -api_type */ - - return (term_id); -} - -/*****************************************************************************************************************************/ - -switch_status_t handle_mg_add_cmd(MgMgcoAmmReq *addReq) -{ - int descId; - for (descId = 0; descId < addReq->dl.num.val; descId++) { - switch (addReq->dl.descs[descId]->type.val) { - case MGT_MEDIADESC: - { - int mediaId; - for (mediaId = 0; mediaId < addReq->dl.descs[descId]->u.media.num.val; mediaId++) { - MgMgcoMediaPar *mediaPar = addReq->dl.descs[descId]->u.media.parms[mediaId]; - switch (mediaPar->type.val) { - case MGT_MEDIAPAR_LOCAL: - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCAL"); - break; - } - case MGT_MEDIAPAR_REMOTE: - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_REMOTE"); - break; - } - - case MGT_MEDIAPAR_LOCCTL: - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCCTL"); - break; - } - case MGT_MEDIAPAR_TERMST: - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_TERMST"); - break; - } - case MGT_MEDIAPAR_STRPAR: - { - MgMgcoStreamDesc *mgStream = &mediaPar->u.stream; - - if (mgStream->sl.remote.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got remote stream media description:\n"); - mgco_print_sdp(&mgStream->sl.remote.sdp); - } - - if (mgStream->sl.local.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got local stream media description:\n"); - mgco_print_sdp(&mgStream->sl.local.sdp); - } - - break; - } - } - } - } - case MGT_MODEMDESC: - case MGT_MUXDESC: - case MGT_REQEVTDESC: - case MGT_EVBUFDESC: - case MGT_SIGNALSDESC: - case MGT_DIGMAPDESC: - case MGT_AUDITDESC: - case MGT_STATSDESC: - break; - } - } - - - return SWITCH_STATUS_SUCCESS; -} - - -/*****************************************************************************************************************************/ -switch_status_t mg_send_add_rsp(SuId suId, MgMgcoCommand *req) -{ - MgMgcoCommand cmd; - int ret = 0x00; - MgMgcoTermId *termId; - MgMgcoCtxt ctxt; - - memset(&cmd,0, sizeof(cmd)); - - /*copy transaction-id*/ - memcpy(&cmd.transId, &req->transId,sizeof(MgMgcoTransId)); - - /*copy context-id*/ /*TODO - in case of $ context should be generated by app, we should not simply copy incoming structure */ - memcpy(&cmd.contextId, &req->contextId,sizeof(MgMgcoContextId)); - - /*copy peer identifier */ - memcpy(&cmd.peerId, &req->peerId,sizeof(TknU32)); - - /*fill response structue */ - if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&cmd.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ - return ret; - } - - cmd.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; - cmd.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; - cmd.u.mgCmdRsp[0]->type.val = MGT_ADD; - cmd.u.mgCmdRsp[0]->u.add.pres.pres = PRSNT_NODEF; - - - cmd.u.mgCmdRsp[0]->u.add.termIdLst.num.pres = PRSNT_NODEF; - cmd.u.mgCmdRsp[0]->u.add.termIdLst.num.val = 1; - - mgUtlAllocMgMgcoTermIdLst(&cmd.u.mgCmdRsp[0]->u.add.termIdLst, &req->u.mgCmdReq[0]->cmd.u.add.termIdLst); - -#ifdef GCP_VER_2_1 - termId = cmd.u.mgCmdRsp[0]->u.add.termIdLst.terms[0]; -#else - termId = &(cmd.u.mgCmdRsp[0]->u.add.termId); -#endif - mg_fill_mgco_termid(termId, (CONSTANT U8*)"term1",&req->u.mgCmdRsp[0]->memCp); - - /* We will always send one command at a time..*/ - cmd.cmdStatus.pres = PRSNT_NODEF; - cmd.cmdStatus.val = CH_CMD_STATUS_END_OF_CMD; - - cmd.cmdType.pres = PRSNT_NODEF; - cmd.cmdType.val = CH_CMD_TYPE_RSP; - - - ret = sng_mgco_send_cmd(suId, &cmd); - - memcpy(&ctxt.transId,&req->transId,sizeof(MgMgcoTransId)); - memcpy(&ctxt.cntxtId, &req->contextId,sizeof(MgMgcoContextId)); - memcpy(&ctxt.peerId, &req->peerId,sizeof(TknU32)); - ctxt.cmdStatus.pres = PRSNT_NODEF; - ctxt.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; - ret = sng_mgco_send_axn_req(suId, &ctxt); - - return ret; -} - -/*****************************************************************************************************************************/ -switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ) -{ - Mem sMem; - - sMem.region = 0; - sMem.pool = 0; - - if ( _memSize <= 0 ) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_alloc_mem: invalid size\n"); - return SWITCH_STATUS_FALSE; - } - - if ( ROK != cmAllocEvnt( _memSize, MG_MAXBLKSIZE, &sMem, _memPtr ) ) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_alloc_mem: cmAllocEvnt return failure for _memSize=%d\n",_memSize); - return SWITCH_STATUS_FALSE; - } - - // Note: memset done inside stack api - - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t mg_stack_get_mem(MgMgcoMsg* msg, Ptr* _memPtr, Size _memSize ) -{ - if ( _memSize <= 0 ) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_get_mem: invalid size\n"); - return SWITCH_STATUS_FALSE; - } - - if ( !msg ) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_get_mem: invalid message\n"); - return SWITCH_STATUS_FALSE; - } - - if ( cmGetMem( (Ptr)msg, _memSize, (Ptr*)_memPtr ) != ROK ) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed alloc_mg_stack_mem: get memory failed _memSize=%d\n", _memSize ); - return SWITCH_STATUS_FALSE; - } - - // Note: memset done inside stack api - - return SWITCH_STATUS_SUCCESS; -} - - -switch_status_t mg_stack_free_mem(MgMgcoMsg* msg) -{ - if ( !msg ) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_get_mem: invalid message\n"); - return SWITCH_STATUS_FALSE; - } - - cmFreeMem( (Ptr)msg ); - - return SWITCH_STATUS_SUCCESS; -} - -#define MG_ACC_GETMEM(_ptr,_len,_memCp,_ret) \ -{ \ - ret = cmGetMem((_memCp), (_len), (Ptr *)&(_ptr)); \ - if( ret == ROK) \ - cmMemset((U8 *)(_ptr), (U8)0, (PTR)(_len)); \ -} - - -S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, CONSTANT U8 *str, CmMemListCp *memCp) -{ -#ifdef GCP_ASN - Size size; -#endif - S16 ret = ROK; - - termId->name.pres.pres = PRSNT_NODEF; - /* mg011.105: Bug fixes */ - termId->name.lcl.pres = PRSNT_NODEF; - termId->name.lcl.len = cmStrlen((CONSTANT U8*)str); - MG_ACC_GETMEM((termId->name.lcl.val), termId->name.lcl.len, memCp, ret); - if( ret != ROK) - RETVALUE(ret); - - cmMemcpy((U8*)(termId->name.lcl.val), (CONSTANT U8*)str,termId->name.lcl.len); - -#ifdef GCP_ASN - /* Remove comment to fill other term ID - termId->wildcard.num.pres = NOTPRSNT; */ - /* Remove comment to fill wilcard term ID */ - termId->wildcard.num.pres = PRSNT_NODEF; - termId->wildcard.num.val = 1; - size = ((sizeof(MgMgcoWildcardField*))); - MG_ACC_GETMEM((termId->wildcard.wildcard),size,memCp, ret); - if( ret != ROK) - RETVALUE(ret); - - MG_ACC_GETMEM( ((termId->wildcard.wildcard)[0]),sizeof(MgMgcoWildcardField), - memCp, ret); - if( ret != ROK) - RETVALUE(ret); - - termId->wildcard.wildcard[0]->pres = PRSNT_NODEF; - termId->wildcard.wildcard[0]->len = 1; - termId->wildcard.wildcard[0]->val[0] = 0x55; -#endif /* GCP_ASN */ - - RETVALUE(ROK); -} - -switch_status_t mg_build_mgco_err_request(MgMgcoInd **errcmd,U32 trans_id, MgMgcoContextId *ctxt_id, U32 err, MgStr *errTxt) -{ - MgMgcoInd *mgErr; - S16 ret; - - mgErr = NULLP; - ret = ROK; - - /* Allocate for AG error */ - mg_stack_alloc_mem((Ptr*)&mgErr, sizeof(MgMgcoInd)); - if (NULL == mgErr) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " mg_build_mgco_err_request Failed : memory alloc \n"); - return SWITCH_STATUS_FALSE; - } - - /* Set transaction Id in the error request */ - mg_util_set_val_pres(mgErr->transId, trans_id); - - /* Copy the context Id */ - mg_mem_copy(&mgErr->cntxtId, - ctxt_id, - sizeof(MgMgcoContextId)); - - /* Set the peerId */ - mgErr->peerId.pres = NOTPRSNT; - - /* Set the error code */ - mg_util_set_pres(mgErr->err.pres.pres); - mg_util_set_pres(mgErr->err.code.pres); - mg_util_set_val_pres(mgErr->err.code, err); - - if(errTxt->len) - { - mg_get_mem(&mgErr->memCp, (errTxt->len)*sizeof(U8), mgErr->err.text.val, &ret); - if (ROK != ret) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " mg_build_mgco_err_request Failed : memory alloc \n"); - return SWITCH_STATUS_FALSE; - } - mgErr->err.text.pres = PRSNT_NODEF; - mgErr->err.text.len = errTxt->len; - mg_mem_copy(mgErr->err.text.val, errTxt->val, errTxt->len); - } - - /* Set the output value */ - *errcmd = mgErr; - - return SWITCH_STATUS_SUCCESS; -} - -void mg_util_set_txn_string(MgStr *errTxt, U32 *txnId) -{ - mg_zero((errTxt->val), sizeof(errTxt->val)); - errTxt->len = 0; - - errTxt->val[errTxt->len] = '\"'; - errTxt->len += 1; - - if (MG_TXN_INVALID == txnId ) - { - mg_mem_copy((&errTxt->val[errTxt->len]), "TransactionId=0", 15); - errTxt->len += 15; - } - - errTxt->val[errTxt->len] = '\"'; - errTxt->len += 1; - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s:" - "info, error-text is: %s\n", __PRETTY_FUNCTION__,errTxt->val); - -} - - - /*****************************************************************************************************************************/ /* For Emacs: From 9beec66fcd8678b99fa484f26ea46aa3d21685a5 Mon Sep 17 00:00:00 2001 From: kapil Date: Sun, 1 Jul 2012 12:36:28 +0530 Subject: [PATCH 287/822] removing extra audit rsp api --- src/mod/endpoints/mod_media_gateway/mod_media_gateway.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index e1c5ea2439..108e43c4ff 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -447,7 +447,6 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received Audit-Value Method \n"); handle_mg_audit_cmd(suId, cmd); - mg_send_audit_rsp(suId,cmd); break; } break; From 7eb163e74e10a336d0a3801c2b87fc64683602d9 Mon Sep 17 00:00:00 2001 From: kapil Date: Sun, 1 Jul 2012 12:40:17 +0530 Subject: [PATCH 288/822] adding dummy audit rsp api --- src/mod/endpoints/mod_media_gateway/mod_media_gateway.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 108e43c4ff..96f5bcbaaf 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -447,6 +447,9 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received Audit-Value Method \n"); handle_mg_audit_cmd(suId, cmd); + /*need to call this for other types of audit.. + * ideally from the request apis we should send response..keeping now here just to send dummy responses*/ + mg_send_audit_rsp(suId, cmd); break; } break; From f88f0a8899cda05aa7fe50ff02af69939d34683f Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Mon, 2 Jul 2012 00:19:29 -0400 Subject: [PATCH 289/822] fixing warnings --- .../mod_media_gateway/media_gateway_cmd_handler.c | 9 ++++++++- .../endpoints/mod_media_gateway/media_gateway_utils.c | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index c81d80bd18..25ec2a9d52 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -169,9 +169,16 @@ switch_status_t mg_send_end_of_axn(SuId suId, MgMgcoTransId* transId, MgMgcoCont ctxt.cmdStatus.pres = PRSNT_NODEF; ctxt.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; +#ifdef BIT_64 switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "mg_send_end_of_axn: Sending END_OF_AXN for transId[%d], peerId[%d], context[type = %s, value = %d]\n", - (uint32_t)transId->val, peerId->val, PRNT_MG_CTXT_TYPE(ctxtId->type.val), (uint32_t)ctxtId->val.val); + transId->val, peerId->val, PRNT_MG_CTXT_TYPE(ctxtId->type.val), ctxtId->val.val); +#else + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + "mg_send_end_of_axn: Sending END_OF_AXN for transId[%lu], peerId[%lu], context[type = %s, value = %lu]\n", + transId->val, peerId->val, PRNT_MG_CTXT_TYPE(ctxtId->type.val), ctxtId->val.val); + +#endif ret = sng_mgco_send_axn_req(suId, &ctxt); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index 81bde4871b..6f97ee0b34 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -316,7 +316,11 @@ void mg_util_set_ctxt_string ( MgStr *errTxt, MgMgcoContextId *ctxtId) } else if((ctxtId->type.val == MGT_CXTID_OTHER) && (ctxtId->val.pres != NOTPRSNT)) { +#ifdef BIT_64 sprintf((char*)&errTxt->val[errTxt->len], "%d", ctxtId->val.val); +#else + sprintf((char*)&errTxt->val[errTxt->len], "%lu", ctxtId->val.val); +#endif errTxt->len += cmStrlen((U8*)(&errTxt->val[errTxt->len])); } From e2e3a5c34eaf76f0521f45e00205c2155b260cf7 Mon Sep 17 00:00:00 2001 From: kapil Date: Mon, 2 Jul 2012 09:55:36 +0530 Subject: [PATCH 290/822] fixing modify mid code --- .../mod_media_gateway/media_gateway_xml.c | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index 5acba0d954..64caa13a99 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -215,23 +215,25 @@ static switch_xml_config_item_t *get_instructions(megaco_profile_t *profile) { static switch_status_t modify_mid(char* mid) { - char* dup = NULL; + char dup[64]; char* val[10]; int count; switch_assert(mid); + memset(&dup[0],0,sizeof(dup)); + /* If MID type is IP then add mid into [] brackets , * If MID type is domain then add mid into <> brackets * */ - dup = strdup(mid); - count = switch_split(dup, '.', val); + strcpy(&dup[0],mid); + count = switch_split(&dup[0], '.', val); if(!count) { /* Input string is not separated by '.', check if its separated by '-' as format could be xxx-xx-xxx/xxx-xx-xx-xxx */ - free(dup); - dup = strdup(mid); + memset(&dup[0],0,sizeof(dup)); + strcpy(&dup[0],mid); if(0 == (count = switch_split(dup, '-', val))){ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid input MID string[%s]\n",mid); return SWITCH_STATUS_FALSE; @@ -239,29 +241,27 @@ static switch_status_t modify_mid(char* mid) } if(('<' == val[0][0]) || ('[' == val[0][0])){ - free(dup); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MID[%s] is already prefixed with proper brackets \n",mid); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MID = %s is already prefixed with proper brackets \n",mid); return SWITCH_STATUS_SUCCESS; } /*first check could be if count is 3 means domain name as generally we have xxx-xx-xxx/xxx.xx.xxx domain */ if(3 == count){ /* domain-type, add value into <> */ - free(dup); - dup = strdup(mid); + memset(&dup[0],0,sizeof(dup)); + strcpy(&dup[0],mid); sprintf(mid,"<%s>",dup); }else if(4 == count){ /* IP address in xxx.xxx.xxx.xxx format */ - free(dup); - dup = strdup(mid); + memset(&dup[0],0,sizeof(dup)); + strcpy(&dup[0],mid); sprintf(mid,"[%s]",dup); }else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid input MID string[%s]\n",mid); - free(dup); return SWITCH_STATUS_FALSE; } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Added proper brackets to MID = %s \n",mid); - free(dup); return SWITCH_STATUS_SUCCESS; } From 5ec258b388facf4868143bd1e3fc464391cdd2f3 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Mon, 2 Jul 2012 04:43:21 -0400 Subject: [PATCH 291/822] adding subtract rsp code (got deleted by mistake) --- .../media_gateway_cmd_handler.c | 59 +++++++++++++++++++ .../mod_media_gateway/media_gateway_stack.h | 1 + .../mod_media_gateway/mod_media_gateway.c | 11 ++-- 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 25ec2a9d52..bbc538a58f 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -647,3 +647,62 @@ switch_status_t mg_send_modify_rsp(SuId suId, MgMgcoCommand *req) } /*****************************************************************************************************************************/ +/*****************************************************************************************************************************/ +switch_status_t mg_send_subtract_rsp(SuId suId, MgMgcoCommand *req) +{ + MgMgcoCommand cmd; + int ret = 0x00; + MgMgcoTermId *termId; + MgMgcoCtxt ctxt; + + memset(&cmd,0, sizeof(cmd)); + + /*copy transaction-id*/ + memcpy(&cmd.transId, &req->transId,sizeof(MgMgcoTransId)); + + /*copy context-id*/ /*TODO - in case of $ context should be generated by app, we should not simply copy incoming structure */ + memcpy(&cmd.contextId, &req->contextId,sizeof(MgMgcoContextId)); + + /*copy peer identifier */ + memcpy(&cmd.peerId, &req->peerId,sizeof(TknU32)); + + /*fill response structue */ + if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&cmd.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ + return ret; + } + + cmd.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; + cmd.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; + cmd.u.mgCmdRsp[0]->type.val = MGT_SUB; + cmd.u.mgCmdRsp[0]->u.sub.pres.pres = PRSNT_NODEF; + cmd.u.mgCmdRsp[0]->u.sub.termIdLst.num.pres = PRSNT_NODEF; + cmd.u.mgCmdRsp[0]->u.sub.termIdLst.num.val = 1; + + mgUtlAllocMgMgcoTermIdLst(&cmd.u.mgCmdRsp[0]->u.sub.termIdLst, &req->u.mgCmdReq[0]->cmd.u.sub.termIdLst); + +#ifdef GCP_VER_2_1 + termId = cmd.u.mgCmdRsp[0]->u.sub.termIdLst.terms[0]; +#else + termId = &(cmd.u.mgCmdRsp[0]->u.sub.termId); +#endif + mg_fill_mgco_termid(termId, (CONSTANT U8*)"term1",&req->u.mgCmdRsp[0]->memCp); + + /* We will always send one command at a time..*/ + cmd.cmdStatus.pres = PRSNT_NODEF; + cmd.cmdStatus.val = CH_CMD_STATUS_END_OF_CMD; + + cmd.cmdType.pres = PRSNT_NODEF; + cmd.cmdType.val = CH_CMD_TYPE_RSP; + + + ret = sng_mgco_send_cmd(suId, &cmd); + + memcpy(&ctxt.transId,&req->transId,sizeof(MgMgcoTransId)); + memcpy(&ctxt.cntxtId, &req->contextId,sizeof(MgMgcoContextId)); + memcpy(&ctxt.peerId, &req->peerId,sizeof(TknU32)); + ctxt.cmdStatus.pres = PRSNT_NODEF; + ctxt.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; + ret = sng_mgco_send_axn_req(suId, &ctxt); + + return ret; +} diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index 752fabd6ea..c1b6db23de 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -132,6 +132,7 @@ switch_status_t mg_send_audit_rsp(SuId suId, MgMgcoCommand *req); switch_status_t handle_mg_audit_cmd(SuId suId, MgMgcoCommand *auditReq); switch_status_t mg_send_modify_rsp(SuId suId, MgMgcoCommand *req); +switch_status_t mg_send_subtract_rsp(SuId suId, MgMgcoCommand *req); void mg_util_set_term_string ( MgStr *errTxt, MgMgcoTermId *termId); MgMgcoTermIdLst *mg_get_term_id_list(MgMgcoCommand *cmd); switch_status_t handle_pkg_audit( SuId suId, MgMgcoCommand *auditReq); diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 96f5bcbaaf..b3078fd046 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -182,7 +182,7 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) case MGT_TXNREQ: { MgMgcoTxnReq* txnReq; - MgMgcoTransId transId; /* XXX */ + /*MgMgcoTransId transId; *//* XXX */ int axnIter; txnReq = &(msg->body.u.tl.txns[txnIter]->u.req); @@ -207,14 +207,13 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) MgMgcoCommand mgCmd; memset(&mgCmd, 0, sizeof(mgCmd)); mgCmd.peerId = msg->lcl.id; - mgCmd.transId = transId; mgCmd.u.mgCmdInd[0] = cmdReq; /* XXX Handle choose context before this */ mgCmd.contextId = ctxId; - mgCmd.transId = transId; + /*mgCmd.transId = transId;*/ mgCmd.cmdStatus.pres = PRSNT_NODEF; @@ -353,7 +352,7 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) /*****************************************************************************************************************************/ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) { - uint32_t txn_id = 0x00; + U32 txn_id = 0x00; MgMgcoInd *mgErr; MgStr errTxt; MgMgcoContextId ctxtId; @@ -373,7 +372,7 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) ctxtId.type.pres = NOTPRSNT; ctxtId.val.pres = NOTPRSNT; - mg_util_set_txn_string(&errTxt, (U32*)&txn_id); + mg_util_set_txn_string(&errTxt, &txn_id); if (SWITCH_STATUS_SUCCESS == mg_build_mgco_err_request(&mgErr, txn_id, &ctxtId, MGT_MGCO_RSP_CODE_INVLD_IDENTIFIER, &errTxt)) { @@ -427,6 +426,8 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) case MGT_SUB: { /*MgMgcoSubAudReq *addReq = &cmdReq->cmd.u.sub;*/ + mg_send_subtract_rsp(suId, cmd); + break; } case MGT_SVCCHG: { From 2149aaee1b8f99c2e9221b6356ac60494a008a2c Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 3 Jul 2012 10:50:04 -0400 Subject: [PATCH 292/822] Added mod_media_gateway --- build/modules.conf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/build/modules.conf.in b/build/modules.conf.in index 1d27aaad1b..783eddf41f 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -7,6 +7,7 @@ applications/mod_hash applications/mod_spandsp dialplans/mod_dialplan_xml endpoints/mod_sofia +endpoints/mod_media_gateway ../../libs/freetdm/mod_freetdm xml_int/mod_xml_cdr event_handlers/mod_event_socket From 2f985f4e784f65b649587a1a9a5b93e5ae6d0a37 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 3 Jul 2012 11:19:17 -0400 Subject: [PATCH 293/822] Removed mod_media_gateway temporarily, will put back at end --- build/modules.conf.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/modules.conf.in b/build/modules.conf.in index 783eddf41f..67844ea342 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -7,7 +7,7 @@ applications/mod_hash applications/mod_spandsp dialplans/mod_dialplan_xml endpoints/mod_sofia -endpoints/mod_media_gateway +#endpoints/mod_media_gateway ../../libs/freetdm/mod_freetdm xml_int/mod_xml_cdr event_handlers/mod_event_socket From a4c4155232bc22788a02fa672cb130ee18fad762 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 3 Jul 2012 11:48:37 -0400 Subject: [PATCH 294/822] fixing modify mid issue --- .../mod_media_gateway/media_gateway_xml.c | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index 64caa13a99..c1772ae89b 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -12,7 +12,7 @@ static switch_xml_config_item_t *get_instructions(megaco_profile_t *profile) ; static switch_xml_config_item_t *get_peer_instructions(mg_peer_profile_t *profile) ; static int mg_sap_id; -static switch_status_t modify_mid(char* mid); +static switch_status_t modify_mid(char** pmid); /****************************************************************************************************************************/ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) @@ -59,10 +59,11 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) profile->total_peers++; } - if(SWITCH_STATUS_FALSE == (status = modify_mid(profile->mid))){ + if(SWITCH_STATUS_FALSE == (status = modify_mid(&profile->mid))){ goto done; } + profile->idx = ++mg_sap_id; /* we should break from here , profile name should be unique */ @@ -100,7 +101,7 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) goto done; } - if(SWITCH_STATUS_FALSE == (status = modify_mid(peer_profile->mid))){ + if(SWITCH_STATUS_FALSE == (status = modify_mid(&peer_profile->mid))){ goto done; } @@ -213,55 +214,57 @@ static switch_xml_config_item_t *get_instructions(megaco_profile_t *profile) { /****************************************************************************************************************************/ -static switch_status_t modify_mid(char* mid) +static switch_status_t modify_mid(char** pmid) { - char dup[64]; + char* mid = *pmid; + char* dup; char* val[10]; int count; - + switch_status_t status = SWITCH_STATUS_FALSE; switch_assert(mid); - memset(&dup[0],0,sizeof(dup)); + dup = strdup(mid); /* If MID type is IP then add mid into [] brackets , * If MID type is domain then add mid into <> brackets * */ - strcpy(&dup[0],mid); - count = switch_split(&dup[0], '.', val); + count = switch_split(dup, '.', val); if(!count) { /* Input string is not separated by '.', check if its separated by '-' as format could be xxx-xx-xxx/xxx-xx-xx-xxx */ - memset(&dup[0],0,sizeof(dup)); - strcpy(&dup[0],mid); if(0 == (count = switch_split(dup, '-', val))){ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid input MID string[%s]\n",mid); - return SWITCH_STATUS_FALSE; + goto done; } } if(('<' == val[0][0]) || ('[' == val[0][0])){ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MID = %s is already prefixed with proper brackets \n",mid); - return SWITCH_STATUS_SUCCESS; + status = SWITCH_STATUS_SUCCESS; + goto done; } /*first check could be if count is 3 means domain name as generally we have xxx-xx-xxx/xxx.xx.xxx domain */ if(3 == count){ /* domain-type, add value into <> */ - memset(&dup[0],0,sizeof(dup)); - strcpy(&dup[0],mid); - sprintf(mid,"<%s>",dup); + *pmid = switch_mprintf("<%s>", mid); + free(mid); + mid = *pmid; }else if(4 == count){ /* IP address in xxx.xxx.xxx.xxx format */ - memset(&dup[0],0,sizeof(dup)); - strcpy(&dup[0],mid); - sprintf(mid,"[%s]",dup); + *pmid = switch_mprintf("[%s]", mid); + free(mid); + mid = *pmid; }else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid input MID string[%s]\n",mid); - return SWITCH_STATUS_FALSE; + goto done; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Added proper brackets to MID = %s \n",mid); - return SWITCH_STATUS_SUCCESS; + status = SWITCH_STATUS_SUCCESS; + +done: + return status; } From 5925e25626303a6b41d5a9e25ad8a90ad1537d60 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 3 Jul 2012 12:06:47 -0400 Subject: [PATCH 295/822] added mod_rad_cdr --- build/modules.conf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/build/modules.conf.in b/build/modules.conf.in index 67844ea342..2a73456541 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -12,3 +12,4 @@ endpoints/mod_sofia xml_int/mod_xml_cdr event_handlers/mod_event_socket codecs/mod_sangoma_codec +event_handlers/mod_radius_cdr From c544ff4b813b4f24c34a22fc573749cd9e8335be Mon Sep 17 00:00:00 2001 From: James Zhang Date: Tue, 3 Jul 2012 14:29:50 -0400 Subject: [PATCH 296/822] sip: add receiver report to rtcp - only one to one rtcp is supported for currently - jitter stats and loss stats are not real --- src/include/switch_types.h | 3 +- src/switch_rtp.c | 91 +++++++++++++++++++++++++++++++++++--- 2 files changed, 88 insertions(+), 6 deletions(-) diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 185fdb64af..593e921bcd 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -547,6 +547,8 @@ typedef struct { typedef struct { uint32_t packet_count; uint32_t octet_count; + + uint32_t peer_ssrc; } switch_rtcp_numbers_t; typedef struct { @@ -769,7 +771,6 @@ typedef struct { unsigned type:8; /* packet type */ unsigned length:16; /* length in 32-bit words - 1 */ } switch_rtcp_hdr_t; - #else /* BIG_ENDIAN */ typedef struct { diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 5e741c4eb7..ff03a8d054 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -264,6 +264,46 @@ struct switch_rtp { switch_size_t last_flush_packet_count; }; +struct switch_rtcp_source { + unsigned ssrc1:32; + unsigned fraction_lost:8; + unsigned cumulative_lost:24; + unsigned hi_seq_recieved:32; + unsigned interarrival_jitter:32; + unsigned lsr:32; + unsigned lsr_delay:32; +}; + + +#if SWITCH_BYTE_ORDER == __BIG_ENDIAN +struct switch_rtcp_s_desc_head { + unsigned v:2; + unsigned padding:1; + unsigned sc:5; + unsigned pt:8; + unsigned length:16; +}; + +#else /* BIG_ENDIAN */ + +struct switch_rtcp_s_desc_head { + unsigned sc:5; + unsigned padding:1; + unsigned v:2; + unsigned pt:8; + unsigned length:16; +}; + +#endif + + +struct switch_rtcp_s_desc_trunk { + unsigned ssrc:32; + unsigned cname:8; + unsigned length:8; + char text[1]; +}; + struct switch_rtcp_senderinfo { unsigned ssrc:32; unsigned ntp_msw:32; @@ -271,6 +311,9 @@ struct switch_rtcp_senderinfo { unsigned ts:32; unsigned pc:32; unsigned oc:32; + struct switch_rtcp_source sr_source; + struct switch_rtcp_s_desc_head sr_desc_head; + struct switch_rtcp_s_desc_trunk sr_desc_ssrc; }; typedef enum { @@ -1637,8 +1680,8 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session rtp_session->rtcp_send_msg.header.version = 2; rtp_session->rtcp_send_msg.header.p = 0; rtp_session->rtcp_send_msg.header.type = 200; - rtp_session->rtcp_send_msg.header.count = 0; - rtp_session->rtcp_send_msg.header.length = htons(6); + rtp_session->rtcp_send_msg.header.count = 1; + rtp_session->rtcp_send_msg.header.length = htons(12); switch_rtp_set_interval(rtp_session, ms_per_packet, samples_per_interval); @@ -2823,9 +2866,10 @@ static switch_status_t read_rtcp_packet(switch_rtp_t *rtp_session, switch_size_t rtp_session->stats.rtcp.packet_count += sr->pc; rtp_session->stats.rtcp.octet_count += sr->oc; + rtp_session->stats.rtcp.peer_ssrc = ntohl(sr->ssrc); /* sender report */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10,"Received a SR with %d report blocks, " \ + switch_log_printf(SWITCH_CHANNEL_LOG, /*SWITCH_LOG_DEBUG10*/ SWITCH_LOG_INFO,"Received a SR with %d report blocks, " \ "length in words = %d, " \ "SSRC = 0x%X, " \ "NTP MSW = %u, " \ @@ -4025,15 +4069,52 @@ static int rtp_common_write(switch_rtp_t *rtp_session, switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP) && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_RTCP_PASSTHRU) && rtp_session->rtcp_interval && (rtp_session->stats.outbound.packet_count % rtp_session->rtcp_interval) == 0) { struct switch_rtcp_senderinfo* sr = (struct switch_rtcp_senderinfo*)rtp_session->rtcp_send_msg.body; + const char* str_cname=NULL; sr->ssrc = send_msg->header.ssrc; - sr->ntp_msw = htonl((u_long)rtp_session->send_time / 1000000 + 2208988800UL); + sr->ntp_msw = htonl((u_long)(rtp_session->send_time / 1000000 + 2208988800UL)); + /* sr->ntp_lsw = htonl((u_long)(rtp_session->send_time % 1000000 * ((UINT_MAX * 1.0)/ 1000000.0))); + */ + sr->ntp_lsw = htonl((u_long)(rtp_session->send_time % 1000000 * 4294.967296)); sr->ts = send_msg->header.ts; sr->pc = htonl(rtp_session->stats.outbound.packet_count); sr->oc = htonl((rtp_session->stats.outbound.raw_bytes - rtp_session->stats.outbound.packet_count * sizeof(srtp_hdr_t))); - rtcp_bytes = sizeof(switch_rtcp_hdr_t) + sizeof(struct switch_rtcp_senderinfo); + + sr->sr_source.ssrc1 = htonl(rtp_session->stats.rtcp.peer_ssrc); + sr->sr_source.fraction_lost |= 0; + sr->sr_source.cumulative_lost |= 0; + sr->sr_source.hi_seq_recieved = htonl(rtp_session->last_seq); + sr->sr_source.interarrival_jitter = htonl(0); + sr->sr_source.lsr = htonl(0); + sr->sr_source.lsr_delay = htonl(0); + + sr->sr_desc_head.v = 0x02; + sr->sr_desc_head.padding = 0; + sr->sr_desc_head.sc = 1; + sr->sr_desc_head.pt = 202; + sr->sr_desc_head.length = htons(5); + + + sr->sr_desc_ssrc.ssrc = send_msg->header.ssrc; /*htonl(rtp_session->stats.rtcp.peer_ssrc); */ + sr->sr_desc_ssrc.cname = 0x1; + { + char bufa[30]; + str_cname = switch_get_addr(bufa, sizeof(bufa), rtp_session->rtcp_local_addr); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "Setting RTCP src-1 to %s\n", str_cname); + sr->sr_desc_ssrc.length = strlen(str_cname); + memcpy ((char*)sr->sr_desc_ssrc.text, str_cname, strlen(str_cname)); + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "Setting RTCP src-1 LENGTH to %d (%d, %s)\n", sr->sr_desc_ssrc.length, sr->sr_desc_head.length, str_cname); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "Setting msw = %d, lsw = %d \n", sr->ntp_msw, sr->ntp_lsw); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "now = %lld, now lo = %d, now hi = %d\n", (int64_t)now, (int32_t)(now&0xFFFFFFFF), (int32_t)((now>>32&0xFFFFFFFF))); + + + rtcp_bytes = sizeof(switch_rtcp_hdr_t) + sizeof(struct switch_rtcp_senderinfo) + sr->sr_desc_ssrc.length -1 ; + + #ifdef ENABLE_SRTP if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_SEND)) { int sbytes = (int) rtcp_bytes; From 5bfc1473cb0878fb013ce9493df67b977d9d5dbe Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 3 Jul 2012 16:04:43 -0400 Subject: [PATCH 297/822] Added mod_rad_auth --- build/modules.conf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/build/modules.conf.in b/build/modules.conf.in index 2a73456541..559b06e8ea 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -13,3 +13,4 @@ xml_int/mod_xml_cdr event_handlers/mod_event_socket codecs/mod_sangoma_codec event_handlers/mod_radius_cdr +applications/mod_rad_auth From fff6a923fe77d4591f4c7f925aed6a526c1735af Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 3 Jul 2012 16:35:06 -0400 Subject: [PATCH 298/822] Added freeradius-client --- src/mod/applications/mod_rad_auth/Makefile | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/mod/applications/mod_rad_auth/Makefile b/src/mod/applications/mod_rad_auth/Makefile index d2e91c24b3..79021e86fe 100644 --- a/src/mod/applications/mod_rad_auth/Makefile +++ b/src/mod/applications/mod_rad_auth/Makefile @@ -10,5 +10,20 @@ RADCLIENT_LA=${RADCLIENT_LIBDIR}/libfreeradius-client.la LOCAL_CFLAGS=-I$(RADCLIENT_DIR)/include LOCAL_LIBADD=$(RADCLIENT_LA) + include $(switch_srcdir)/build/modmake.rules +$(RADCLIENT_DIR): + $(GETLIB) $(RADCLIENT).tar.gz + +$(RADCLIENT_BUILDDIR)/Makefile: $(RADCLIENT_DIR) + mkdir -p $(RADCLIENT_BUILDDIR) + cd $(RADCLIENT_BUILDDIR) && $(DEFAULT_VARS) $(RADCLIENT_DIR)/configure $(DEFAULT_ARGS) --srcdir=$(RADCLIENT_DIR) + $(TOUCH_TARGET) + +$(RADCLIENT_LA): $(RADCLIENT_BUILDDIR)/Makefile + cd $(RADCLIENT_BUILDDIR) && CFLAGS="$(CFLAGS)" $(MAKE) + $(TOUCH_TARGET) + + + From edd718d258306d16e2142f9cf0b9955871f137e2 Mon Sep 17 00:00:00 2001 From: James Zhang Date: Wed, 4 Jul 2012 10:00:23 -0400 Subject: [PATCH 299/822] ss7: fix a wired crash on remind ticket 4972 - change dynamic memory allocation/deallocation to char array --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 2f4c18d4c3..8c5c221e0e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -643,7 +643,7 @@ ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *r ftdm_status_t copy_access_transport_from_sngss7(ftdm_channel_t *ftdmchan, SiAccTrnspt *accTrnspt) { - char *val=NULL; + char val[(MF_SIZE_TKNSTRE + 7) & 0xff8]; sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; if (accTrnspt->eh.pres != PRSNT_NODEF || accTrnspt->infoElmts.pres !=PRSNT_NODEF) { @@ -651,10 +651,8 @@ ftdm_status_t copy_access_transport_from_sngss7(ftdm_channel_t *ftdmchan, SiAccT return FTDM_SUCCESS; } - val = ftdm_malloc(3*accTrnspt->infoElmts.len); ftdm_url_encode((const char*)accTrnspt->infoElmts.val, val, accTrnspt->infoElmts.len); sngss7_add_var (sngss7_info, "ss7_access_transport_urlenc", val); - ftdm_safe_free(val); return FTDM_SUCCESS; } From 64f33c25da177ce225ff3b24c23fffad97e126fd Mon Sep 17 00:00:00 2001 From: James Zhang Date: Wed, 4 Jul 2012 10:09:19 -0400 Subject: [PATCH 300/822] ss7: fix on last fix, make enough memory for bad encode cases --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 8c5c221e0e..c47b580ef6 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -643,7 +643,7 @@ ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *r ftdm_status_t copy_access_transport_from_sngss7(ftdm_channel_t *ftdmchan, SiAccTrnspt *accTrnspt) { - char val[(MF_SIZE_TKNSTRE + 7) & 0xff8]; + char val[3*((MF_SIZE_TKNSTRE + 7) & 0xff8)]; sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; if (accTrnspt->eh.pres != PRSNT_NODEF || accTrnspt->infoElmts.pres !=PRSNT_NODEF) { From 7db1cdefb92e8da374875b43af610ffbfc6bc2be Mon Sep 17 00:00:00 2001 From: kapil Date: Wed, 4 Jul 2012 21:52:44 +0530 Subject: [PATCH 301/822] Audit code commit --- .../media_gateway_cmd_handler.c | 283 +++++++++++++++++- .../mod_media_gateway/media_gateway_stack.h | 6 +- .../mod_media_gateway/media_gateway_utils.c | 65 +++- .../mod_media_gateway/mod_media_gateway.c | 3 - 4 files changed, 346 insertions(+), 11 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index bbc538a58f..696e7579f8 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -258,6 +258,14 @@ switch_status_t handle_mg_audit_cmd( SuId suId, MgMgcoCommand *auditReq) MgMgcoAuditItem *audit_item; int i; int err_code; + MgMgcoCommand reply; + MgMgcoAuditReply *adtRep = NULLP; + U16 numOfParms; + MgMgcoMediaDesc* media; + MgMgcoCtxt ctxt; + switch_status_t ret; + + memset(&reply, 0, sizeof(reply)); audit = &auditReq->u.mgCmdReq[0]->cmd.u.aval; @@ -269,8 +277,8 @@ switch_status_t handle_mg_audit_cmd( SuId suId, MgMgcoCommand *auditReq) audit_desc = &audit->audit; if((NOTPRSNT == audit_desc->pres.pres) || ( NOTPRSNT == audit_desc->num.pres)){ - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Audit Descriptor not present..rejecting \n"); - return SWITCH_STATUS_FALSE; + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Audit Descriptor not present.. Could be HeartBeat message\n"); + return mg_send_heartbeat_audit_rsp(suId, auditReq); } /* dump AUDIT message information */ @@ -283,6 +291,9 @@ switch_status_t handle_mg_audit_cmd( SuId suId, MgMgcoCommand *auditReq) term_list = mg_get_term_id_list(auditReq); termId = term_list->terms[0]; + /*********************************************************************************************************************/ + /**************************** Validating Audit Request ***************************************************************/ + /*********************************************************************************************************************/ /*-- Start with Context level checks --*/ /*-- CHOOSE Context not allowed --*/ if ((NOTPRSNT != ctxtId->type.pres) && @@ -322,7 +333,38 @@ switch_status_t handle_mg_audit_cmd( SuId suId, MgMgcoCommand *auditReq) goto error; } - /* validation done , now processing command */ + /*********************************************************************************************************************/ + /**************************** Preparing Response Structure ***********************************************************/ + /*********************************************************************************************************************/ + /*copy transaction-id*/ + memcpy(&reply.transId, &auditReq->transId,sizeof(MgMgcoTransId)); + /*copy context-id*/ + memcpy(&reply.contextId, &auditReq->contextId,sizeof(MgMgcoContextId)); + /*copy peer identifier */ + memcpy(&reply.peerId, &auditReq->peerId,sizeof(TknU32)); + + /*fill response structue */ + if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&reply.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ + return ret; + } + + reply.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; + reply.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; + reply.u.mgCmdRsp[0]->type.val = MGT_AUDITVAL; + + + adtRep = &(reply.u.mgCmdRsp[0]->u.aval); + + adtRep->type.pres = PRSNT_NODEF; + adtRep->type.val = MGT_TERMAUDIT; + adtRep->u.other.pres.pres = PRSNT_NODEF; + mgUtlAllocMgMgcoTermIdLst(&adtRep->u.other.termIdLst, term_list); + + /* NOW for each requested AUDIT descriptor we need to add entry to adtRep->u.other.audit.parms list */ + + /*********************************************************************************************************************/ + /**************************** Processing Audit Request Descriptors **************************************************/ + /*********************************************************************************************************************/ for (i = 0; i < audit_desc->num.val; i++) { @@ -342,6 +384,25 @@ switch_status_t handle_mg_audit_cmd( SuId suId, MgMgcoCommand *auditReq) case MGT_MEDIADESC: { switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"Auditing MEDIA \n"); + + /* Grow the list of reply parameters */ + if (mgUtlGrowList((void ***)&adtRep->u.other.audit.parms, sizeof(MgMgcoAudRetParm), + &adtRep->u.other.audit.num, &reply.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + numOfParms = adtRep->u.other.audit.num.val; + adtRep->u.other.audit.parms[numOfParms - 1]->type.pres = PRSNT_NODEF; + adtRep->u.other.audit.parms[numOfParms - 1]->type.val = MGT_MEDIADESC; + + media = get_default_media_desc(); + if(!media){ + return SWITCH_STATUS_FALSE; + } + mgUtlCpyMgMgcoMediaDesc(&adtRep->u.other.audit.parms[numOfParms - 1]->u.media, media, &reply.u.mgCmdRsp[0]->memCp); + break; } case MGT_MODEMDESC: @@ -387,7 +448,22 @@ switch_status_t handle_mg_audit_cmd( SuId suId, MgMgcoCommand *auditReq) case MGT_PKGSDESC: { switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"Auditing Packages \n"); - handle_pkg_audit(suId, auditReq); + /* Grow the list of reply parameters */ + if (mgUtlGrowList((void ***)&adtRep->u.other.audit.parms, sizeof(MgMgcoAudRetParm), + &adtRep->u.other.audit.num, &reply.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + numOfParms = adtRep->u.other.audit.num.val; + adtRep->u.other.audit.parms[numOfParms - 1]->type.pres = PRSNT_NODEF; + adtRep->u.other.audit.parms[numOfParms - 1]->type.val = MGT_PKGSDESC; + + if(SWITCH_STATUS_FALSE == mg_build_pkg_desc(&adtRep->u.other.audit.parms[numOfParms - 1]->u.pkgs)){ + return SWITCH_STATUS_FALSE; + } + break; } case MGT_INDAUD_TERMAUDDESC: @@ -405,6 +481,26 @@ switch_status_t handle_mg_audit_cmd( SuId suId, MgMgcoCommand *auditReq) }/*if (NOTPRSNT != audit_item->auditItem.pres)*/ }/*for loop - audit_desc->num.val */ + /*********************************************************************************************************************/ + /**************************** Send Audit Command Reply***************************************************************/ + /*********************************************************************************************************************/ + reply.cmdStatus.pres = PRSNT_NODEF; + reply.cmdStatus.val = CH_CMD_STATUS_END_OF_CMD; + reply.cmdType.pres = PRSNT_NODEF; + reply.cmdType.val = CH_CMD_TYPE_RSP; + + /* send command reply */ + sng_mgco_send_cmd(suId, &reply); + + /* send indication to stack , so he can send response back to peer */ + memcpy(&ctxt.transId,&auditReq->transId,sizeof(MgMgcoTransId)); + memcpy(&ctxt.cntxtId, &auditReq->contextId,sizeof(MgMgcoContextId)); + memcpy(&ctxt.peerId, &auditReq->peerId,sizeof(TknU32)); + ctxt.cmdStatus.pres = PRSNT_NODEF; + ctxt.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; + sng_mgco_send_axn_req(suId, &ctxt); + /***********************************************************************************************************************************/ + return SWITCH_STATUS_SUCCESS; error: @@ -417,6 +513,181 @@ error: return SWITCH_STATUS_FALSE; } +/*****************************************************************************************************************************/ +switch_status_t mg_send_heartbeat_audit_rsp( SuId suId, MgMgcoCommand *auditReq) +{ + MgMgcoCtxt ctxt; + switch_status_t ret; + MgMgcoCommand reply; + MgMgcoTermIdLst *term_list; + MgMgcoTermId *termId; + MgMgcoSubAudReq *audit; + MgMgcoAuditReply *adtRep = NULLP; + + memset(&reply, 0, sizeof(reply)); + audit = &auditReq->u.mgCmdReq[0]->cmd.u.aval; + + if(NOTPRSNT == audit->pres.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Audit structure not present..rejecting \n"); + return SWITCH_STATUS_FALSE; + } + + /*-- Get termination list --*/ + term_list = mg_get_term_id_list(auditReq); + termId = term_list->terms[0]; + + + /*copy transaction-id*/ + memcpy(&reply.transId, &auditReq->transId,sizeof(MgMgcoTransId)); + /*copy context-id*/ + memcpy(&reply.contextId, &auditReq->contextId,sizeof(MgMgcoContextId)); + /*copy peer identifier */ + memcpy(&reply.peerId, &auditReq->peerId,sizeof(TknU32)); + + /*fill response structue */ + if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&reply.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ + return ret; + } + + reply.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; + reply.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; + reply.u.mgCmdRsp[0]->type.val = MGT_AUDITVAL; + + + adtRep = &(reply.u.mgCmdRsp[0]->u.aval); + + adtRep->type.pres = PRSNT_NODEF; + adtRep->type.val = MGT_TERMAUDIT; + adtRep->u.other.pres.pres = PRSNT_NODEF; + adtRep->u.other.audit.num.pres = 0x00; + mgUtlAllocMgMgcoTermIdLst(&adtRep->u.other.termIdLst, term_list); + + + /* We will always send one command at a time..*/ + reply.cmdStatus.pres = PRSNT_NODEF; + reply.cmdStatus.val = CH_CMD_STATUS_END_OF_CMD; + + reply.cmdType.pres = PRSNT_NODEF; + reply.cmdType.val = CH_CMD_TYPE_RSP; + + ret = sng_mgco_send_cmd(suId, &reply); + + /*will send once all audit done*/ + memcpy(&ctxt.transId,&auditReq->transId,sizeof(MgMgcoTransId)); + memcpy(&ctxt.cntxtId, &auditReq->contextId,sizeof(MgMgcoContextId)); + memcpy(&ctxt.peerId, &auditReq->peerId,sizeof(TknU32)); + ctxt.cmdStatus.pres = PRSNT_NODEF; + ctxt.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; + ret = sng_mgco_send_axn_req(suId, &ctxt); + + return ret; +} + +/*****************************************************************************************************************************/ +switch_status_t handle_media_audit( SuId suId, MgMgcoCommand *auditReq) +{ + switch_status_t ret; + MgMgcoCommand reply; + MgMgcoTermIdLst *term_list; + MgMgcoTermId *termId; + MgMgcoSubAudReq *audit; + MgMgcoAuditDesc *audit_desc; + MgMgcoAuditReply *adtRep = NULLP; + U16 numOfParms; + MgMgcoMediaDesc* media; + + + memset(&reply, 0, sizeof(reply)); + audit = &auditReq->u.mgCmdReq[0]->cmd.u.aval; + + if(NOTPRSNT == audit->pres.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Audit structure not present..rejecting \n"); + return SWITCH_STATUS_FALSE; + } + + audit_desc = &audit->audit; + + if((NOTPRSNT == audit_desc->pres.pres) || ( NOTPRSNT == audit_desc->num.pres)){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Audit Descriptor not present..rejecting \n"); + return SWITCH_STATUS_FALSE; + } + + /* dump AUDIT message information */ + /*mgAccEvntPrntMgMgcoSubAudReq(auditReq,stdout);*/ + + /*-- Get termination list --*/ + term_list = mg_get_term_id_list(auditReq); + termId = term_list->terms[0]; + + + /*copy transaction-id*/ + memcpy(&reply.transId, &auditReq->transId,sizeof(MgMgcoTransId)); + /*copy context-id*/ + memcpy(&reply.contextId, &auditReq->contextId,sizeof(MgMgcoContextId)); + /*copy peer identifier */ + memcpy(&reply.peerId, &auditReq->peerId,sizeof(TknU32)); + + /*fill response structue */ + if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&reply.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ + return ret; + } + + reply.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; + reply.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; + reply.u.mgCmdRsp[0]->type.val = MGT_AUDITVAL; + + + adtRep = &(reply.u.mgCmdRsp[0]->u.aval); + + adtRep->type.pres = PRSNT_NODEF; + adtRep->type.val = MGT_TERMAUDIT; + adtRep->u.other.pres.pres = PRSNT_NODEF; + mgUtlAllocMgMgcoTermIdLst(&adtRep->u.other.termIdLst, term_list); + + /* Grow the list of reply parameters */ + if (mgUtlGrowList((void ***)&adtRep->u.other.audit.parms, sizeof(MgMgcoAudRetParm), + &adtRep->u.other.audit.num, &reply.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + numOfParms = adtRep->u.other.audit.num.val; + adtRep->u.other.audit.parms[numOfParms - 1]->type.pres = PRSNT_NODEF; + adtRep->u.other.audit.parms[numOfParms - 1]->type.val = MGT_MEDIADESC; + + media = get_default_media_desc(); + if(!media){ + return SWITCH_STATUS_FALSE; + } + mgUtlCpyMgMgcoMediaDesc(&adtRep->u.other.audit.parms[numOfParms - 1]->u.media, media, &reply.u.mgCmdRsp[0]->memCp); + + /* We will always send one command at a time..*/ + reply.cmdStatus.pres = PRSNT_NODEF; + reply.cmdStatus.val = CH_CMD_STATUS_END_OF_CMD; + + reply.cmdType.pres = PRSNT_NODEF; + reply.cmdType.val = CH_CMD_TYPE_RSP; + + + ret = sng_mgco_send_cmd(suId, &reply); + +#if 0 + /*will send once all audit done*/ + memcpy(&ctxt.transId,&auditReq->transId,sizeof(MgMgcoTransId)); + memcpy(&ctxt.cntxtId, &auditReq->contextId,sizeof(MgMgcoContextId)); + memcpy(&ctxt.peerId, &auditReq->peerId,sizeof(TknU32)); + ctxt.cmdStatus.pres = PRSNT_NODEF; + ctxt.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; + ret = sng_mgco_send_axn_req(suId, &ctxt); +#endif + + return ret; + + + +} + /*****************************************************************************************************************************/ switch_status_t handle_pkg_audit( SuId suId, MgMgcoCommand *auditReq) { @@ -428,7 +699,6 @@ switch_status_t handle_pkg_audit( SuId suId, MgMgcoCommand *auditReq) MgMgcoAuditDesc *audit_desc; MgMgcoAuditReply *adtRep = NULLP; U16 numOfParms; - MgMgcoCtxt ctxt; memset(&reply, 0, sizeof(reply)); audit = &auditReq->u.mgCmdReq[0]->cmd.u.aval; @@ -503,12 +773,15 @@ switch_status_t handle_pkg_audit( SuId suId, MgMgcoCommand *auditReq) ret = sng_mgco_send_cmd(suId, &reply); +#if 0 + /*will send once all audit done*/ memcpy(&ctxt.transId,&auditReq->transId,sizeof(MgMgcoTransId)); memcpy(&ctxt.cntxtId, &auditReq->contextId,sizeof(MgMgcoContextId)); memcpy(&ctxt.peerId, &auditReq->peerId,sizeof(TknU32)); ctxt.cmdStatus.pres = PRSNT_NODEF; ctxt.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; ret = sng_mgco_send_axn_req(suId, &ctxt); +#endif return ret; diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index c1b6db23de..fbd598ab3c 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -121,9 +121,10 @@ switch_status_t mg_send_end_of_axn(SuId suId, MgMgcoTransId* transId, MgMgcoCont void mgco_print_sdp(CmSdpInfoSet *sdp); void mg_util_set_ctxt_string ( MgStr *errTxt, MgMgcoContextId *ctxtId); switch_status_t handle_mg_add_cmd(MgMgcoAmmReq *addReq); -switch_status_t mg_stack_free_mem(MgMgcoMsg* msg); -switch_status_t mg_stack_free_mem(MgMgcoMsg* msg); +switch_status_t mg_stack_free_mem(void* msg); switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ); +MgMgcoMediaDesc* get_default_media_desc(void); +switch_status_t handle_media_audit( SuId suId, MgMgcoCommand *auditReq); switch_status_t mg_send_add_rsp(SuId suId, MgMgcoCommand *req); S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, CONSTANT U8 *str, CmMemListCp *memCp); void mg_util_set_txn_string(MgStr *errTxt, U32 *txnId); @@ -137,6 +138,7 @@ void mg_util_set_term_string ( MgStr *errTxt, MgMgcoTermId *termId); MgMgcoTermIdLst *mg_get_term_id_list(MgMgcoCommand *cmd); switch_status_t handle_pkg_audit( SuId suId, MgMgcoCommand *auditReq); switch_status_t mg_build_pkg_desc(MgMgcoPkgsDesc* pkg); +switch_status_t mg_send_heartbeat_audit_rsp( SuId suId, MgMgcoCommand *auditReq); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index 6f97ee0b34..39f7fb71d2 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -64,7 +64,7 @@ switch_status_t mg_stack_get_mem(MgMgcoMsg* msg, Ptr* _memPtr, Size _memSize ) /*****************************************************************************************************************************/ -switch_status_t mg_stack_free_mem(MgMgcoMsg* msg) +switch_status_t mg_stack_free_mem(void* msg) { if ( !msg ) { @@ -432,3 +432,66 @@ void mg_util_set_term_string ( MgStr *errTxt, MgMgcoTermId *termId) "info, error-text is: %s\n", __PRETTY_FUNCTION__,errTxt->val); } /*****************************************************************************************************************************/ +MgMgcoMediaDesc* get_default_media_desc() +{ + MgMgcoMediaDesc *media = NULL; + MgMgcoMediaPar *mediaPar = NULL; + MgMgcoTermStateParm *trmStPar = NULL; + + mg_stack_alloc_mem((Ptr)&media, sizeof(MgMgcoMediaDesc)); + + if (!media) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "failed, memory alloc\n"); + return NULL; + } + media->num.pres = PRSNT_NODEF; + media->num.val = 1; + mg_stack_alloc_mem((Ptr)&mediaPar, sizeof(MgMgcoMediaPar)); + + if (!mediaPar) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "failed, memory alloc\n"); + mg_stack_free_mem(media); + return NULL; + } + mg_stack_alloc_mem((Ptr)&media->parms, sizeof(MgMgcoMediaPar *)); + + if (!media->parms) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "failed, memory alloc\n"); + mg_stack_free_mem((void*)mediaPar); + mg_stack_free_mem((void*)media); + return NULL; + } + mediaPar->type.pres = PRSNT_NODEF; + mediaPar->type.val = MGT_MEDIAPAR_TERMST; + mediaPar->u.tstate.numComp.pres = PRSNT_NODEF; + mediaPar->u.tstate.numComp.val = 1; + mg_stack_alloc_mem((Ptr)&trmStPar, sizeof(MgMgcoTermStateParm)); + + if (!trmStPar) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "failed, memory alloc\n"); + mg_stack_free_mem((void*)mediaPar); + mg_stack_free_mem((void*)media->parms); + mg_stack_free_mem((void*)media); + return NULL; + } + mg_stack_alloc_mem((Ptr)&mediaPar->u.tstate.trmStPar, sizeof(MgMgcoTermStateParm *)); + if (!mediaPar->u.tstate.trmStPar) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "failed, memory alloc\n"); + mg_stack_free_mem((void*)trmStPar); + mg_stack_free_mem((void*)mediaPar); + mg_stack_free_mem((void*)media->parms); + mg_stack_free_mem((void*)media); + return NULL; + } + trmStPar->type.pres = PRSNT_NODEF; + trmStPar->type.val = MGT_TERMST_SVCST; + trmStPar->u.svcState.pres = PRSNT_NODEF; + /*TODO - ADD CHECK if term is in svc or not */ + trmStPar->u.svcState.val = MGT_SVCST_INSVC; + + mediaPar->u.tstate.trmStPar[0] = trmStPar; + media->parms[0] = mediaPar; + + return media; +} +/*****************************************************************************************************************************/ diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index b3078fd046..d2f5b2b71b 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -448,9 +448,6 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received Audit-Value Method \n"); handle_mg_audit_cmd(suId, cmd); - /*need to call this for other types of audit.. - * ideally from the request apis we should send response..keeping now here just to send dummy responses*/ - mg_send_audit_rsp(suId, cmd); break; } break; From 642b1a2e6d8a2679f3ee2573852f5c4d9633dcd7 Mon Sep 17 00:00:00 2001 From: kapil Date: Thu, 5 Jul 2012 10:39:36 +0530 Subject: [PATCH 302/822] adding code for sending termination service change and respective CLI command --- .../mod_media_gateway/media_gateway_cli.c | 22 + .../media_gateway_cmd_handler.c | 114 +++- .../mod_media_gateway/media_gateway_stack.h | 20 +- .../media_gateway_stack_alarms.c | 3 + .../mod_media_gateway/media_gateway_utils.c | 511 ++++++++++++------ 5 files changed, 506 insertions(+), 164 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c index e21fc9d3af..9d1c27e007 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c @@ -94,6 +94,28 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre } else { stream->write_function(stream, "-ERR No such profile\n"); } +/**********************************************************************************/ + }else if(!strcmp(argv[2], "send")) { +/**********************************************************************************/ + /* mg profile send sc */ + printf("count = %d \n",argc); + if(argc < 7){ + goto usage; + } + if(zstr(argv[3]) || zstr(argv[4]) || zstr(argv[5]) || zstr(argv[6])){ + goto usage; + } + + if (profile) { + printf("Input to Send Service Change command : " + "Profile Name[%s], term-id[%s] method[%s] reason[%s] \n", + profile->name, argv[4], argv[5], argv[6]); + + megaco_profile_release(profile); + mg_send_service_change(profile->idx, argv[4], atoi(argv[5]), atoi(argv[6])); + } else { + stream->write_function(stream, "-ERR No such profile\n"); + } /**********************************************************************************/ }else { /**********************************************************************************/ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 696e7579f8..b4e8d04442 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -9,6 +9,15 @@ #include "mod_media_gateway.h" #include "media_gateway_stack.h" +U32 outgoing_txn_id; + +/*****************************************************************************************************************************/ +const char *mg_service_change_reason[] = { + "\"NOT USED\"", + "\"900 ServiceRestored\"", + "\"905 Termination taken out of service\"", + 0 +}; /*****************************************************************************************************************************/ @@ -134,7 +143,7 @@ switch_status_t mg_send_add_rsp(SuId suId, MgMgcoCommand *req) #else termId = &(cmd.u.mgCmdRsp[0]->u.add.termId); #endif - mg_fill_mgco_termid(termId, (CONSTANT U8*)"term1",&req->u.mgCmdRsp[0]->memCp); + /*mg_fill_mgco_termid(termId, (char*)"term1",&req->u.mgCmdRsp[0]->memCp);*/ /* We will always send one command at a time..*/ cmd.cmdStatus.pres = PRSNT_NODEF; @@ -197,7 +206,7 @@ switch_status_t mg_send_end_of_axn(SuId suId, MgMgcoTransId* transId, MgMgcoCont switch_status_t mg_build_mgco_err_request(MgMgcoInd **errcmd,U32 trans_id, MgMgcoContextId *ctxt_id, U32 err, MgStr *errTxt) { - MgMgcoInd *mgErr; + MgMgcoInd *mgErr = NULL; S16 ret; mgErr = NULLP; @@ -584,6 +593,8 @@ switch_status_t mg_send_heartbeat_audit_rsp( SuId suId, MgMgcoCommand *auditReq) } /*****************************************************************************************************************************/ +#if 0 +/* Kapil - Not using any more */ switch_status_t handle_media_audit( SuId suId, MgMgcoCommand *auditReq) { switch_status_t ret; @@ -788,7 +799,10 @@ switch_status_t handle_pkg_audit( SuId suId, MgMgcoCommand *auditReq) } +#endif /*****************************************************************************************************************************/ +#if 0 +/* Kapil - Not using any more */ switch_status_t mg_send_audit_rsp(SuId suId, MgMgcoCommand *req) { MgMgcoCommand cmd; @@ -858,6 +872,7 @@ switch_status_t mg_send_audit_rsp(SuId suId, MgMgcoCommand *req) return ret; } +#endif /*****************************************************************************************************************************/ switch_status_t mg_send_modify_rsp(SuId suId, MgMgcoCommand *req) @@ -897,7 +912,7 @@ switch_status_t mg_send_modify_rsp(SuId suId, MgMgcoCommand *req) #else termId = &(cmd.u.mgCmdRsp[0]->u.mod.termId); #endif - mg_fill_mgco_termid(termId, (CONSTANT U8*)"term1",&req->u.mgCmdRsp[0]->memCp); + /*mg_fill_mgco_termid(termId, (char*)"term1",&req->u.mgCmdRsp[0]->memCp);*/ /* We will always send one command at a time..*/ cmd.cmdStatus.pres = PRSNT_NODEF; @@ -958,7 +973,7 @@ switch_status_t mg_send_subtract_rsp(SuId suId, MgMgcoCommand *req) #else termId = &(cmd.u.mgCmdRsp[0]->u.sub.termId); #endif - mg_fill_mgco_termid(termId, (CONSTANT U8*)"term1",&req->u.mgCmdRsp[0]->memCp); + /*mg_fill_mgco_termid(termId, (char *)"term1",&req->u.mgCmdRsp[0]->memCp);*/ /* We will always send one command at a time..*/ cmd.cmdStatus.pres = PRSNT_NODEF; @@ -979,3 +994,94 @@ switch_status_t mg_send_subtract_rsp(SuId suId, MgMgcoCommand *req) return ret; } +/*****************************************************************************************************************************/ +U32 get_txn_id(){ + outgoing_txn_id++; + return outgoing_txn_id; +} +/*****************************************************************************************************************************/ +/* Note : API to send Service Change */ +/* INPUT : +* method - Service change method type (can be MGT_SVCCHGMETH_RESTART/MGT_SVCCHGMETH_FORCED (please refer to sng_ss7/cm/mgt.h for more values)) +* MgServiceChangeReason_e - Service Change reason +* SuId - Service User ID for MG SAP - it will be same like mg_profile_t->idx (refer to media_gateway_xml.c->mg_sap_id) +* term_name - String format defined termination name +*/ +switch_status_t mg_send_service_change(SuId suId, const char* term_name, uint8_t method, MgServiceChangeReason_e reason) +{ + MgMgcoSvcChgPar srvPar; + MgMgcoTermId* termId; + switch_status_t ret; + MgMgcoCommand request; + MgMgcoSvcChgReq *svc; + + MG_ZERO(&srvPar, sizeof(MgMgcoSvcChgPar)); + MG_ZERO(&request, sizeof(request)); + + + + if(SWITCH_STATUS_FALSE == (ret = mg_create_mgco_command(&request, CH_CMD_TYPE_REQ, MGT_SVCCHG))){ + goto err; + } + + /*fill txn id */ + request.transId.pres = PRSNT_NODEF; + request.transId.val = get_txn_id(); + + request.contextId.type.pres = PRSNT_NODEF; + request.contextId.type.val = MGT_CXTID_NULL; + +#if 0 + /* TODO - fill of below fields */ +#ifdef GCP_MGCO +#ifdef GCP_VER_2_1 + MgMgcoSegNum segNum; + MgMgcoSegCmpl segCmpl; +#endif +#endif /* GCP_MGCO */ +#endif + request.cmdStatus.pres = PRSNT_NODEF; + request.cmdStatus.val = CH_CMD_STATUS_END_OF_TXN; + + request.cmdType.pres = PRSNT_NODEF; + request.cmdType.val = CH_CMD_TYPE_REQ; + + svc = &request.u.mgCmdReq[0]->cmd.u.svc; + + if(SWITCH_STATUS_FALSE == (ret = mg_fill_svc_change(&svc->parm, method, mg_service_change_reason[reason]))){ + return ret; + } + + /*mgUtlCpyMgMgcoSvcChgPar(&svc->parm, &srvPar, &request.u.mgCmdReq[0]->memCp);*/ + + printf("reason[%p = %s], len[%d]\n",svc->parm.reason.val, svc->parm.reason.val, svc->parm.reason.len); + + + if (mgUtlGrowList((void ***)&svc->termIdLst.terms, sizeof(MgMgcoTermIdLst), + &svc->termIdLst.num, &request.u.mgCmdReq[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + +#ifdef GCP_VER_2_1 + termId = svc->termIdLst.terms[0]; +#else + termId = &(svc->termId); +#endif + + + mg_fill_mgco_termid(termId, (char*)term_name ,strlen(term_name), &request.u.mgCmdReq[0]->memCp); + + + printf("reason[%p = %s], len[%d]\n",svc->parm.reason.val, svc->parm.reason.val, svc->parm.reason.len); + + sng_mgco_send_cmd(suId, &request); + + return SWITCH_STATUS_SUCCESS; + +err: + mgUtlDelMgMgcoSvcChgPar(&srvPar); + return ret; +} +/*****************************************************************************************************************************/ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index fbd598ab3c..a90e6dc2c4 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -60,6 +60,13 @@ typedef struct _mgPackage extern MgPackage_t mg_pkg_list[]; +/* Service change Reason */ +typedef enum { + MG_SVC_REASON_NOTUSED = 0, + MG_SVC_REASON_900_RESTORED = 1, + MG_SVC_REASON_905_TERM_OOS = 2, + MG_SVC_REASON_LAST = 4 +} MgServiceChangeReason_e; #define MG_TXN_INVALID 0 @@ -74,6 +81,12 @@ extern MgPackage_t mg_pkg_list[]; MG_SET_PRES((tkn).pres); \ (tkn).val = _val; +#define MG_SET_TKN_VAL_PRES(_tkn, _val, _pres) \ +{ \ + (_tkn)->val = _val; \ + (_tkn)->pres = _pres; \ +} + #define MG_MEM_COPY(_dst, _src, _len) \ cmMemcpy((U8*) (_dst), (const U8*) (_src), _len) @@ -126,7 +139,7 @@ switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ); MgMgcoMediaDesc* get_default_media_desc(void); switch_status_t handle_media_audit( SuId suId, MgMgcoCommand *auditReq); switch_status_t mg_send_add_rsp(SuId suId, MgMgcoCommand *req); -S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, CONSTANT U8 *str, CmMemListCp *memCp); +S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, char* term_str, int term_len, CmMemListCp *memCp); void mg_util_set_txn_string(MgStr *errTxt, U32 *txnId); switch_status_t mg_build_mgco_err_request(MgMgcoInd **errcmd,U32 trans_id, MgMgcoContextId *ctxt_id, U32 err, MgStr *errTxt); switch_status_t mg_send_audit_rsp(SuId suId, MgMgcoCommand *req); @@ -139,6 +152,11 @@ MgMgcoTermIdLst *mg_get_term_id_list(MgMgcoCommand *cmd); switch_status_t handle_pkg_audit( SuId suId, MgMgcoCommand *auditReq); switch_status_t mg_build_pkg_desc(MgMgcoPkgsDesc* pkg); switch_status_t mg_send_heartbeat_audit_rsp( SuId suId, MgMgcoCommand *auditReq); +void mg_get_time_stamp(MgMgcoTimeStamp *timeStamp); +switch_status_t mg_fill_svc_change(MgMgcoSvcChgPar *srvPar, uint8_t method, const char *reason); +void mg_fill_null_context(MgMgcoContextId* ctxt); +switch_status_t mg_send_service_change(SuId suId, const char* term_name, uint8_t method, MgServiceChangeReason_e reason); +switch_status_t mg_create_mgco_command(MgMgcoCommand *cmd, uint8_t apiType, uint8_t cmdType); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack_alarms.c b/src/mod/endpoints/mod_media_gateway/media_gateway_stack_alarms.c index fc09a6bea4..5281a7942a 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack_alarms.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack_alarms.c @@ -208,6 +208,9 @@ void handle_mg_alarm(Pst *pst, MgMngmt *usta) case LMG_EVENT_PEER_ENABLED: { len = len + sprintf(prBuf+len, "gateway enabled"); + /* gateway enabled now we can send termination service change */ + /*TODO - probably we cannt immediate send Service change - we have to find proper place */ + /*mg_send_service_change(0x01, "A01", MGT_SVCCHGMETH_RESTART,MG_SVC_REASON_900_RESTORED );*/ break; } case LMG_EVENT_PEER_DISCOVERED: diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index 39f7fb71d2..ed70b74173 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -80,45 +80,65 @@ switch_status_t mg_stack_free_mem(void* msg) /*****************************************************************************************************************************/ -S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, CONSTANT U8 *str, CmMemListCp *memCp) +S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, char* term_str, int term_len, CmMemListCp *memCp) { #ifdef GCP_ASN - Size size; + Size size; #endif - S16 ret = ROK; + S16 ret = ROK; - termId->name.pres.pres = PRSNT_NODEF; - /* mg011.105: Bug fixes */ - termId->name.lcl.pres = PRSNT_NODEF; - termId->name.lcl.len = cmStrlen((CONSTANT U8*)str); - MG_GETMEM(termId->name.lcl.val, termId->name.lcl.len, memCp, ret); - if( ret != ROK) - RETVALUE(ret); + termId->type.pres = PRSNT_NODEF; + termId->type.val = MGT_TERMID_OTHER; - cmMemcpy((U8*)(termId->name.lcl.val), (CONSTANT U8*)str,termId->name.lcl.len); + termId->name.dom.pres = NOTPRSNT; + termId->name.dom.len = 0x00; -#ifdef GCP_ASN - /* Remove comment to fill other term ID - termId->wildcard.num.pres = NOTPRSNT; */ - /* Remove comment to fill wilcard term ID */ - termId->wildcard.num.pres = PRSNT_NODEF; - termId->wildcard.num.val = 1; - size = ((sizeof(MgMgcoWildcardField*))); - MG_GETMEM((termId->wildcard.wildcard),size,memCp, ret); - if( ret != ROK) - RETVALUE(ret); + termId->name.pres.pres = PRSNT_NODEF; + termId->name.lcl.pres = PRSNT_NODEF; + termId->name.lcl.len = term_len; + /*MG_GETMEM(termId->name.lcl.val, termId->name.lcl.len , memCp, ret);*/ + ret = mg_stack_alloc_mem((Ptr*)&termId->name.lcl.val,term_len); - MG_GETMEM( ((termId->wildcard.wildcard)[0]),sizeof(MgMgcoWildcardField), - memCp, ret); - if( ret != ROK) - RETVALUE(ret); + printf("termId->name.lcl.val[%p]\n",termId->name.lcl.val); - termId->wildcard.wildcard[0]->pres = PRSNT_NODEF; - termId->wildcard.wildcard[0]->len = 1; - termId->wildcard.wildcard[0]->val[0] = 0x55; + if( ret != ROK) + RETVALUE(ret); + + /*cmMemcpy((U8*)(termId->name.lcl.val), (CONSTANT U8*)term_str,termId->name.lcl.len);*/ + strncpy((char*)(termId->name.lcl.val), term_str, termId->name.lcl.len); + termId->name.lcl.val[termId->name.lcl.len] = '\0'; + + printf("mg_fill_mgco_termid: name.lcl.val[%s], len[%d], term_str[%s], term_len[%d]\n",termId->name.lcl.val, termId->name.lcl.len, term_str,term_len); + + +#ifdef GCP_ASN + if((termId->type.val == MGT_TERMID_ALL) || + (termId->type.val == MGT_TERMID_CHOOSE)){ + /* Remove comment to fill other term ID + termId->wildcard.num.pres = NOTPRSNT; */ + /* Remove comment to fill wilcard term ID */ + termId->wildcard.num.pres = PRSNT_NODEF; + termId->wildcard.num.val = 1; + size = ((sizeof(MgMgcoWildcardField*))); + MG_GETMEM((termId->wildcard.wildcard),size,memCp, ret); + if( ret != ROK) + RETVALUE(ret); + + MG_GETMEM( ((termId->wildcard.wildcard)[0]),sizeof(MgMgcoWildcardField), + memCp, ret); + if( ret != ROK) + RETVALUE(ret); + + termId->wildcard.wildcard[0]->pres = PRSNT_NODEF; + termId->wildcard.wildcard[0]->len = 1; + termId->wildcard.wildcard[0]->val[0] = 0x55; + + }else{ + termId->wildcard.num.pres = NOTPRSNT; + } #endif /* GCP_ASN */ - RETVALUE(ROK); + RETVALUE(ROK); } /*****************************************************************************************************************************/ @@ -270,166 +290,166 @@ MgMgcoTermIdLst *mg_get_term_id_list(MgMgcoCommand *cmd) void mg_util_set_txn_string(MgStr *errTxt, U32 *txnId) { - MG_ZERO(errTxt->val, sizeof(errTxt->val)); - errTxt->len = 0; + MG_ZERO(errTxt->val, sizeof(errTxt->val)); + errTxt->len = 0; - errTxt->val[errTxt->len] = '\"'; - errTxt->len += 1; + errTxt->val[errTxt->len] = '\"'; + errTxt->len += 1; - if (MG_TXN_INVALID == txnId ) - { - MG_MEM_COPY((&errTxt->val[errTxt->len]), "TransactionId=0", 15); - errTxt->len += 15; - } + if (MG_TXN_INVALID == txnId ) + { + MG_MEM_COPY((&errTxt->val[errTxt->len]), "TransactionId=0", 15); + errTxt->len += 15; + } - errTxt->val[errTxt->len] = '\"'; - errTxt->len += 1; + errTxt->val[errTxt->len] = '\"'; + errTxt->len += 1; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s:" - "info, error-text is: %s\n", __PRETTY_FUNCTION__,errTxt->val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s:" + "info, error-text is: %s\n", __PRETTY_FUNCTION__,errTxt->val); } /*****************************************************************************************************************************/ void mg_util_set_ctxt_string ( MgStr *errTxt, MgMgcoContextId *ctxtId) { - MG_ZERO((errTxt->val), sizeof(errTxt->val)); - errTxt->len = 0; - if(ctxtId->type.pres != NOTPRSNT) - { - errTxt->val[errTxt->len] = '\"'; - errTxt->len += 1; - if(ctxtId->type.val == MGT_CXTID_NULL) - { - errTxt->val[errTxt->len] = '-'; - errTxt->len += 1; - } - else if(ctxtId->type.val == MGT_CXTID_ALL) - { - errTxt->val[errTxt->len] = '*'; - errTxt->len += 1; - } - else if(ctxtId->type.val == MGT_CXTID_CHOOSE) - { - errTxt->val[errTxt->len] = '$'; - errTxt->len += 1; - } - else if((ctxtId->type.val == MGT_CXTID_OTHER) && (ctxtId->val.pres != NOTPRSNT)) - { + MG_ZERO((errTxt->val), sizeof(errTxt->val)); + errTxt->len = 0; + if(ctxtId->type.pres != NOTPRSNT) + { + errTxt->val[errTxt->len] = '\"'; + errTxt->len += 1; + if(ctxtId->type.val == MGT_CXTID_NULL) + { + errTxt->val[errTxt->len] = '-'; + errTxt->len += 1; + } + else if(ctxtId->type.val == MGT_CXTID_ALL) + { + errTxt->val[errTxt->len] = '*'; + errTxt->len += 1; + } + else if(ctxtId->type.val == MGT_CXTID_CHOOSE) + { + errTxt->val[errTxt->len] = '$'; + errTxt->len += 1; + } + else if((ctxtId->type.val == MGT_CXTID_OTHER) && (ctxtId->val.pres != NOTPRSNT)) + { #ifdef BIT_64 - sprintf((char*)&errTxt->val[errTxt->len], "%d", ctxtId->val.val); + sprintf((char*)&errTxt->val[errTxt->len], "%d", ctxtId->val.val); #else - sprintf((char*)&errTxt->val[errTxt->len], "%lu", ctxtId->val.val); + sprintf((char*)&errTxt->val[errTxt->len], "%lu", ctxtId->val.val); #endif - errTxt->len += cmStrlen((U8*)(&errTxt->val[errTxt->len])); - } + errTxt->len += cmStrlen((U8*)(&errTxt->val[errTxt->len])); + } - errTxt->val[errTxt->len] = '\"'; - errTxt->len += 1; - } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s:" - "info, error-text is: %s\n", __PRETTY_FUNCTION__,errTxt->val); + errTxt->val[errTxt->len] = '\"'; + errTxt->len += 1; + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s:" + "info, error-text is: %s\n", __PRETTY_FUNCTION__,errTxt->val); } /*****************************************************************************************************************************/ void mgco_print_sdp(CmSdpInfoSet *sdp) { - int i; - - - if (sdp->numComp.pres == NOTPRSNT) { - return; - } - - for (i = 0; i < sdp->numComp.val; i++) { - CmSdpInfo *s = sdp->info[i]; - int mediaId; - - if (s->conn.addrType.pres && s->conn.addrType.val == CM_SDP_ADDR_TYPE_IPV4 && - s->conn.netType.type.val == CM_SDP_NET_TYPE_IN && - s->conn.u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) { + int i; - if (s->conn.u.ip4.addrType.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Address: %d.%d.%d.%d\n", - s->conn.u.ip4.u.uniIp.b[0].val, - s->conn.u.ip4.u.uniIp.b[1].val, - s->conn.u.ip4.u.uniIp.b[2].val, - s->conn.u.ip4.u.uniIp.b[3].val); - } - if (s->attrSet.numComp.pres) { - for (mediaId = 0; mediaId < s->attrSet.numComp.val; mediaId++) { - /*CmSdpAttr *a = s->attrSet.attr[mediaId];*/ - - - } - } - if (s->mediaDescSet.numComp.pres) { - for (mediaId = 0; mediaId < s->mediaDescSet.numComp.val; mediaId++) { - CmSdpMediaDesc *desc = s->mediaDescSet.mediaDesc[mediaId]; - - if (desc->field.mediaType.val == CM_SDP_MEDIA_AUDIO && - desc->field.id.type.val == CM_SDP_VCID_PORT && - desc->field.id.u.port.type.val == CM_SDP_PORT_INT && - desc->field.id.u.port.u.portInt.port.type.val == CM_SDP_SPEC) { - int port = desc->field.id.u.port.u.portInt.port.val.val; - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Port: %d\n", port); - - } - } - } - } - } + if (sdp->numComp.pres == NOTPRSNT) { + return; + } + + for (i = 0; i < sdp->numComp.val; i++) { + CmSdpInfo *s = sdp->info[i]; + int mediaId; + + if (s->conn.addrType.pres && s->conn.addrType.val == CM_SDP_ADDR_TYPE_IPV4 && + s->conn.netType.type.val == CM_SDP_NET_TYPE_IN && + s->conn.u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) { + + if (s->conn.u.ip4.addrType.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Address: %d.%d.%d.%d\n", + s->conn.u.ip4.u.uniIp.b[0].val, + s->conn.u.ip4.u.uniIp.b[1].val, + s->conn.u.ip4.u.uniIp.b[2].val, + s->conn.u.ip4.u.uniIp.b[3].val); + } + if (s->attrSet.numComp.pres) { + for (mediaId = 0; mediaId < s->attrSet.numComp.val; mediaId++) { + /*CmSdpAttr *a = s->attrSet.attr[mediaId];*/ + + + } + } + + if (s->mediaDescSet.numComp.pres) { + for (mediaId = 0; mediaId < s->mediaDescSet.numComp.val; mediaId++) { + CmSdpMediaDesc *desc = s->mediaDescSet.mediaDesc[mediaId]; + + if (desc->field.mediaType.val == CM_SDP_MEDIA_AUDIO && + desc->field.id.type.val == CM_SDP_VCID_PORT && + desc->field.id.u.port.type.val == CM_SDP_PORT_INT && + desc->field.id.u.port.u.portInt.port.type.val == CM_SDP_SPEC) { + int port = desc->field.id.u.port.u.portInt.port.val.val; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Port: %d\n", port); + + } + } + } + } + } } /*****************************************************************************************************************************/ void mg_util_set_term_string ( MgStr *errTxt, MgMgcoTermId *termId) { - MG_ZERO((errTxt->val), sizeof(errTxt->val)); - errTxt->len = 0; + MG_ZERO((errTxt->val), sizeof(errTxt->val)); + errTxt->len = 0; - if(termId->type.pres != NOTPRSNT) - { - errTxt->val[errTxt->len] = '\"'; - errTxt->len += 1; + if(termId->type.pres != NOTPRSNT) + { + errTxt->val[errTxt->len] = '\"'; + errTxt->len += 1; - if(termId->type.val == MGT_TERMID_ROOT) - { - MG_MEM_COPY((&errTxt->val[errTxt->len]), "ROOT", 4); - errTxt->len += 4; - } - else if(termId->type.val == MGT_TERMID_ALL) - { - errTxt->val[errTxt->len] = '*'; - errTxt->len += 1; - } - else if(termId->type.val == MGT_TERMID_CHOOSE) - { - errTxt->val[errTxt->len] = '$'; - errTxt->len += 1; - } - else if((termId->type.val == MGT_TERMID_OTHER) && (termId->name.pres.pres != NOTPRSNT)) - { - if(termId->name.lcl.pres != NOTPRSNT) - { - MG_MEM_COPY(&(errTxt->val[errTxt->len]), termId->name.lcl.val, sizeof(U8) * termId->name.lcl.len); - errTxt->len += termId->name.lcl.len; - } - if(termId->name.dom.pres != NOTPRSNT) - { - MG_MEM_COPY(&(errTxt->val[errTxt->len]), - termId->name.dom.val, sizeof(U8) * termId->name.dom.len); - errTxt->len += termId->name.dom.len; - } - } - errTxt->val[errTxt->len] = '\"'; - errTxt->len += 1; - } + if(termId->type.val == MGT_TERMID_ROOT) + { + MG_MEM_COPY((&errTxt->val[errTxt->len]), "ROOT", 4); + errTxt->len += 4; + } + else if(termId->type.val == MGT_TERMID_ALL) + { + errTxt->val[errTxt->len] = '*'; + errTxt->len += 1; + } + else if(termId->type.val == MGT_TERMID_CHOOSE) + { + errTxt->val[errTxt->len] = '$'; + errTxt->len += 1; + } + else if((termId->type.val == MGT_TERMID_OTHER) && (termId->name.pres.pres != NOTPRSNT)) + { + if(termId->name.lcl.pres != NOTPRSNT) + { + MG_MEM_COPY(&(errTxt->val[errTxt->len]), termId->name.lcl.val, sizeof(U8) * termId->name.lcl.len); + errTxt->len += termId->name.lcl.len; + } + if(termId->name.dom.pres != NOTPRSNT) + { + MG_MEM_COPY(&(errTxt->val[errTxt->len]), + termId->name.dom.val, sizeof(U8) * termId->name.dom.len); + errTxt->len += termId->name.dom.len; + } + } + errTxt->val[errTxt->len] = '\"'; + errTxt->len += 1; + } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s:" - "info, error-text is: %s\n", __PRETTY_FUNCTION__,errTxt->val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s:" + "info, error-text is: %s\n", __PRETTY_FUNCTION__,errTxt->val); } /*****************************************************************************************************************************/ MgMgcoMediaDesc* get_default_media_desc() @@ -495,3 +515,176 @@ MgMgcoMediaDesc* get_default_media_desc() return media; } /*****************************************************************************************************************************/ + +switch_status_t mg_fill_svc_change(MgMgcoSvcChgPar *srvPar, uint8_t method, const char *reason) +{ + MG_SET_TKN_VAL_PRES(&srvPar->pres, 0, PRSNT_NODEF); + MG_SET_TKN_VAL_PRES(&srvPar->meth.pres, 0, PRSNT_NODEF); + MG_SET_TKN_VAL_PRES(&srvPar->meth.type, method, PRSNT_NODEF); + + /* Set the reason */ + srvPar->reason.pres = PRSNT_NODEF; + srvPar->reason.len = cmStrlen((const U8 *)reason); + + mg_stack_alloc_mem((Ptr*)&srvPar->reason.val, srvPar->reason.len); + if (NULL == srvPar->reason.val) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "failed, memory alloc\n"); + return SWITCH_STATUS_FALSE; + } + + strncpy((char*)srvPar->reason.val, + (const char *)reason, + srvPar->reason.len); + + srvPar->reason.val[srvPar->reason.len] = '\0'; + + mg_get_time_stamp(&srvPar->time); + + printf("reason[%s], len[%d]\n",srvPar->reason.val, srvPar->reason.len); + + + return SWITCH_STATUS_SUCCESS; +} +/*****************************************************************************************************************************/ + +void mg_get_time_stamp(MgMgcoTimeStamp *timeStamp) +{ + DateTime dt; + Txt dmBuf[16]; + U32 usec; + + usec = 0; + + /*-- Get system date and time via Trillium stack API --*/ + SGetRefDateTimeAdj(0, 0, &dt, &usec); + + /*-- Now fill the time and date in the target --*/ + MG_ZERO(&dmBuf[0], 16); + + sprintf(dmBuf, "%04d%02d%02d", + (S16)(dt.year) + 1900, (S16)(dt.month), (S16)(dt.day)); + cmMemcpy((U8*) &timeStamp->date.val[0], (U8*) &dmBuf[0], 8); + + MG_ZERO(&dmBuf[0], 16); + sprintf(dmBuf, "%02d%02d%02d%02d", + (S16)(dt.hour), (S16)(dt.min), (S16)(dt.sec), (S16)(usec/10000)); + cmMemcpy((U8*) &timeStamp->time.val[0], (U8*) &dmBuf[0], 8); + + /*-- Setup the other stuff --*/ + timeStamp->pres.pres = PRSNT_NODEF; + timeStamp->date.pres = PRSNT_NODEF; + timeStamp->date.len = 8; + timeStamp->time.pres = PRSNT_NODEF; + timeStamp->time.len = 8; + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"mg_get_time_stamp: time(%s)\n", dmBuf); +} +/*****************************************************************************************************************************/ +switch_status_t mg_create_mgco_command(MgMgcoCommand *cmd, uint8_t apiType, uint8_t cmdType) +{ + MgMgcoCommandReq *cmdReq; + MgMgcoCmdReply *cmdRep; + switch_status_t ret; + + cmdReq = NULL; + cmdRep = NULL; + + cmMemset((U8 *)cmd, 0, sizeof(MgMgcoCommand)); + + MG_SET_VAL_PRES(cmd->cmdType, apiType); + + /* Allocate the event structure */ + switch(apiType) + { + /* For command Request */ + case CH_CMD_TYPE_REQ: + { + if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&cmd->u.mgCmdReq[0],sizeof(MgMgcoCommandReq)))){ + return ret; + } + + if (NULL == cmd->u.mgCmdReq[0]) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"mg_create_mgco_command: failed, memory alloc\n"); + return SWITCH_STATUS_FALSE; + } + + cmdReq = cmd->u.mgCmdReq[0]; + cmdReq->pres.pres = PRSNT_NODEF; + cmdReq->cmd.type.pres = PRSNT_NODEF; + cmdReq->cmd.type.val = cmdType; + switch (cmdType) + { + case MGT_SVCCHG: + cmdReq->cmd.u.svc.pres.pres = PRSNT_NODEF; + break; + + case MGT_NTFY: + cmdReq->cmd.u.ntfy.pres.pres = PRSNT_NODEF; + break; + } /* switch cmdType */ + break; + } + + /* For command Response */ + case CH_CMD_TYPE_RSP: + { + if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&cmd->u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ + return ret; + } + + if (NULL == cmd->u.mgCmdRsp[0]) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"mg_create_mgco_command: failed, memory alloc\n"); + return SWITCH_STATUS_FALSE; + } + cmdRep = cmd->u.mgCmdRsp[0]; + cmdRep->pres.pres = PRSNT_NODEF; + cmdRep->type.pres = PRSNT_NODEF; + cmdRep->type.val = cmdType; + switch (cmdType) + { + case MGT_ADD: + cmdRep->u.add.pres.pres = PRSNT_NODEF; + break; + + case MGT_MOVE: + cmdRep->u.move.pres.pres = PRSNT_NODEF; + break; + + case MGT_MODIFY: + cmdRep->u.mod.pres.pres = PRSNT_NODEF; + break; + + case MGT_SUB: + cmdRep->u.sub.pres.pres = PRSNT_NODEF; + break; + + case MGT_SVCCHG: + cmdRep->u.svc.pres.pres = PRSNT_NODEF; + break; + + case MGT_AUDITVAL: + cmdRep->u.aval.type.pres = PRSNT_NODEF; + break; + case MGT_AUDITCAP: + cmdRep->u.acap.type.pres = PRSNT_NODEF; + break; + + } /* switch cmdType */ + break; + } + + default: + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"mg_create_mgco_command: failed, invalid Cmd type[%d]\n",apiType); + return SWITCH_STATUS_FALSE; + } /* switch -apiType */ + + return SWITCH_STATUS_SUCCESS; +} +/*****************************************************************************************************************************/ + +void mg_fill_null_context(MgMgcoContextId* ctxt) +{ + MG_SET_TKN_VAL_PRES(&ctxt->type, MGT_CXTID_NULL, PRSNT_NODEF); +} +/*****************************************************************************************************************************/ From 4ead147e100d0bc38f17922dc49bdce3ae0615db Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 6 Jul 2012 12:04:52 -0400 Subject: [PATCH 303/822] chlog:Support for send-connect-ack parameter --- .../src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h | 3 +-- .../src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c | 3 +++ .../ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c | 8 ++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h index 92054b8869..4e9c9dcadd 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h @@ -275,7 +275,6 @@ typedef struct sngisdn_span_data { uint8_t force_sending_complete; uint8_t cid_name_method; uint8_t send_cid_name; - int32_t timer_t301; int32_t timer_t302; int32_t timer_t303; @@ -292,7 +291,7 @@ typedef struct sngisdn_span_data { int32_t timer_t318; int32_t timer_t319; int32_t timer_t322; - + uint8_t send_connect_ack; char* local_numbers[SNGISDN_NUM_LOCAL_NUMBERS]; ftdm_timer_id_t timers[SNGISDN_NUM_SPAN_TIMERS]; ftdm_sched_t *sched; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c index 5b3db934a5..52c4ecd8de 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c @@ -302,6 +302,7 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_ signal_data->cid_name_method = SNGISDN_CID_NAME_AUTO; signal_data->send_cid_name = SNGISDN_OPT_DEFAULT; + signal_data->send_connect_ack = SNGISDN_OPT_DEFAULT; span->default_caller_data.dnis.plan = FTDM_NPI_INVALID; span->default_caller_data.dnis.type = FTDM_TON_INVALID; @@ -465,6 +466,8 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_ parse_timer(val, &signal_data->timer_t319); } else if (!strcasecmp(var, "timer-t322")) { parse_timer(val, &signal_data->timer_t322); + } else if (!strcasecmp(var, "send-connect-ack")) { + parse_yesno(var, val, &signal_data->send_connect_ack); } else { ftdm_log(FTDM_LOG_WARNING, "Ignoring unknown parameter %s\n", ftdm_parameters[paramindex].var); } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c index a1229dcab9..0a45f2e562 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c @@ -695,6 +695,14 @@ ftdm_status_t sngisdn_stack_cfg_q931_dlsap(ftdm_span_t *span) } } + if (signal_data->send_connect_ack != SNGISDN_OPT_DEFAULT) { + if (signal_data->send_connect_ack == SNGISDN_OPT_TRUE) { + cfg.t.cfg.s.inDLSAP.ackOpt = TRUE; + } else { + cfg.t.cfg.s.inDLSAP.ackOpt = FALSE; + } + } + /* Override the restart options if user selected that option */ if (signal_data->restart_opt != SNGISDN_OPT_DEFAULT) { if (signal_data->restart_opt == SNGISDN_OPT_TRUE) { From 03be3a3a74e57568df134bc54cc95fecc30211c1 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 2 Sep 2011 16:59:59 -0500 Subject: [PATCH 304/822] don't parse signals in the set_running_state function to avoid livelock situation --- src/include/switch_channel.h | 4 ++++ src/switch_channel.c | 9 ++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index 176b841147..a4e44083df 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -87,6 +87,10 @@ SWITCH_DECLARE(int) switch_channel_test_ready(switch_channel_t *channel, switch_ #define switch_channel_up(_channel) (switch_channel_check_signal(_channel, SWITCH_TRUE) || switch_channel_get_state(_channel) < CS_HANGUP) #define switch_channel_down(_channel) (switch_channel_check_signal(_channel, SWITCH_TRUE) || switch_channel_get_state(_channel) >= CS_HANGUP) + +#define switch_channel_up_nosig(_channel) switch_channel_get_state(_channel) < CS_HANGUP +#define switch_channel_down_nosig(_channel) switch_channel_get_state(_channel) >= CS_HANGUP + #define switch_channel_media_ack(_channel) (!switch_channel_test_cap(_channel, CC_MEDIA_ACK) || switch_channel_test_flag(_channel, CF_MEDIA_ACK)) SWITCH_DECLARE(void) switch_channel_wait_for_state(switch_channel_t *channel, switch_channel_t *other_channel, switch_channel_state_t want_state); diff --git a/src/switch_channel.c b/src/switch_channel.c index 3f96616794..c11754d48a 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -1839,8 +1839,11 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_running_state( channel->direction == SWITCH_CALL_DIRECTION_OUTBOUND ? "outbound" : "inbound"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Presence-Call-Direction", channel->direction == SWITCH_CALL_DIRECTION_OUTBOUND ? "outbound" : "inbound"); - - if (switch_channel_down(channel)) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Channel-HIT-Dialplan", + switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND || + switch_channel_test_flag(channel, CF_DIALPLAN) ? "true" : "false"); + + if (switch_channel_down_nosig(channel)) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Answer-State", "hangup"); } else if (switch_channel_test_flag(channel, CF_ANSWERED)) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Answer-State", "answered"); @@ -2123,7 +2126,7 @@ SWITCH_DECLARE(void) switch_channel_event_set_basic_data(switch_channel_t *chann switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Channel-Call-UUID", v); } - if (switch_channel_down(channel)) { + if (switch_channel_down_nosig(channel)) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Answer-State", "hangup"); } else if (switch_channel_test_flag(channel, CF_ANSWERED)) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Answer-State", "answered"); From 7381343e046d2a1eee005a4038c04f4a8d39e75f Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Mon, 16 Jul 2012 11:18:24 -0400 Subject: [PATCH 305/822] fix compile --- src/mod/endpoints/mod_sofia/rtp.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index e99eef1b76..9deddf5922 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -37,6 +37,10 @@ #define kLOCALPORT "local_port" #define kREMOTEADDR "remote_addr" #define kREMOTEPORT "remote_port" +#define kCODEC "codec" +#define kPTIME "ptime" +#define kRFC2833PT "rfc2833_pt" +#define kMODE "mode" static struct { switch_memory_pool_t *pool; @@ -53,14 +57,16 @@ typedef struct { switch_rtp_t *rtp_session; const char *bind_address; - + const char *codec; + int ptime; const switch_codec_implementation_t *negotiated_codecs[SWITCH_MAX_CODECS]; int num_negotiated_codecs; char *origin; - int local_port; + switch_port_t local_port; + switch_port_t remote_port; } crtp_private_t; @@ -89,15 +95,11 @@ switch_io_routines_t crtp_io_routines = { .send_dtmf = channel_send_dtmf }; -SWITCH_STANDARD_API(test_function) -{ - return SWITCH_STATUS_SUCCESS; -} void crtp_init(switch_loadable_module_interface_t *module_interface) { switch_endpoint_interface_t *endpoint_interface; - switch_api_interface_t *api_interface; + //switch_api_interface_t *api_interface; crtp.pool = module_interface->pool; endpoint_interface = switch_loadable_module_create_interface(module_interface, SWITCH_ENDPOINT_INTERFACE); @@ -106,7 +108,7 @@ void crtp_init(switch_loadable_module_interface_t *module_interface) endpoint_interface->state_handler = &crtp_state_handlers; crtp.endpoint_interface = endpoint_interface; - SWITCH_ADD_API(api_interface, "rtp_test", "test", test_function, ""); + //SWITCH_ADD_API(api_interface, "rtp_test", "test", test_function, ""); } static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, @@ -120,11 +122,8 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi const char *dname = "PCMU"; uint32_t interval = 20; crtp_private_t *tech_pvt = NULL; -#if 0 - const char *r_sdp = switch_event_get_header(var_event, kRSDP); -#endif - const char *l_sdp = switch_event_get_header(var_event, kLSDP); - const char *codec_string = switch_event_get_header_nil(var_event, kCODECSTRING); + //const char *l_sdp = switch_event_get_header(var_event, kLSDP); + //const char *codec_string = switch_event_get_header_nil(var_event, kCODECSTRING); if (!(*new_session = switch_core_session_request(crtp.endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, 0, pool))) { @@ -142,9 +141,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi tech_pvt->bind_address = switch_core_session_strdup(*new_session, switch_event_get_header_nil(var_event, kBINDADDRESS)); switch_core_session_set_private(*new_session, tech_pvt); - if (setup_local_rtp(tech_pvt, l_sdp, codec_string) != SWITCH_STATUS_SUCCESS) { - goto fail; - } snprintf(name, sizeof(name), "rtp/ctrl"); /* TODO add addresses */ switch_channel_set_name(channel, name); From 42cb846f39132f733d32cf05a2cf5079543b3321 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Mon, 16 Jul 2012 11:23:14 -0400 Subject: [PATCH 306/822] fix compile part 2 --- src/switch_rtp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/switch_rtp.c b/src/switch_rtp.c index ff03a8d054..bc25d3f39f 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -4109,7 +4109,7 @@ static int rtp_common_write(switch_rtp_t *rtp_session, } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "Setting RTCP src-1 LENGTH to %d (%d, %s)\n", sr->sr_desc_ssrc.length, sr->sr_desc_head.length, str_cname); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "Setting msw = %d, lsw = %d \n", sr->ntp_msw, sr->ntp_lsw); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "now = %lld, now lo = %d, now hi = %d\n", (int64_t)now, (int32_t)(now&0xFFFFFFFF), (int32_t)((now>>32&0xFFFFFFFF))); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "now = %"SWITCH_TIME_T_FMT", now lo = %d, now hi = %d\n", (int64_t)now, (int32_t)(now&0xFFFFFFFF), (int32_t)((now>>32&0xFFFFFFFF))); rtcp_bytes = sizeof(switch_rtcp_hdr_t) + sizeof(struct switch_rtcp_senderinfo) + sr->sr_desc_ssrc.length -1 ; From d139a8ef6378ae4f1eea830448aae14905df314b Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Mon, 16 Jul 2012 11:24:04 -0400 Subject: [PATCH 307/822] fix compile part 2 --- src/switch_rtp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/switch_rtp.c b/src/switch_rtp.c index bc25d3f39f..93f7c56254 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -4109,7 +4109,7 @@ static int rtp_common_write(switch_rtp_t *rtp_session, } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "Setting RTCP src-1 LENGTH to %d (%d, %s)\n", sr->sr_desc_ssrc.length, sr->sr_desc_head.length, str_cname); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "Setting msw = %d, lsw = %d \n", sr->ntp_msw, sr->ntp_lsw); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "now = %"SWITCH_TIME_T_FMT", now lo = %d, now hi = %d\n", (int64_t)now, (int32_t)(now&0xFFFFFFFF), (int32_t)((now>>32&0xFFFFFFFF))); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "now = %"SWITCH_TIME_T_FMT", now lo = %d, now hi = %d\n", (switch_time_t)now, (int32_t)(now&0xFFFFFFFF), (int32_t)((now>>32&0xFFFFFFFF))); rtcp_bytes = sizeof(switch_rtcp_hdr_t) + sizeof(struct switch_rtcp_senderinfo) + sr->sr_desc_ssrc.length -1 ; From 9a817c7aa24ef5259dc7765d82597bb11e3d2654 Mon Sep 17 00:00:00 2001 From: Kapil Date: Mon, 16 Jul 2012 12:48:57 -0400 Subject: [PATCH 308/822] service change code modification --- .../mod_media_gateway/media_gateway.c | 3 +- .../mod_media_gateway/media_gateway_cli.c | 7 +- .../media_gateway_cmd_handler.c | 27 +- .../mod_media_gateway/media_gateway_stack.h | 2 +- .../mod_media_gateway/mod_media_gateway.c | 533 +----------------- 5 files changed, 39 insertions(+), 533 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index e618b5ef6c..0c43adab6b 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -74,6 +74,7 @@ mg_context_t *megaco_get_context(megaco_profile_t *profile, uint32_t context_id) mg_context_t *megaco_choose_context(megaco_profile_t *profile) { mg_context_t *ctx; + int i = 0x0;; switch_thread_rwlock_wrlock(profile->contexts_rwlock); /* Try the next one */ @@ -86,7 +87,7 @@ mg_context_t *megaco_choose_context(megaco_profile_t *profile) if ((profile->contexts_bitmap[profile->next_context_id % 8] & (1 << (profile->next_context_id / 8))) == 0) { /* Found! */ profile->contexts_bitmap[profile->next_context_id % 8] |= 1 << (profile->next_context_id / 8); - int i = profile->next_context_id % MG_CONTEXT_MODULO; + i = profile->next_context_id % MG_CONTEXT_MODULO; ctx = malloc(sizeof *ctx); ctx->context_id = profile->next_context_id; ctx->profile = profile; diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c index 9d1c27e007..3e3b034df5 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c @@ -26,6 +26,7 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre int argc; char* argv[10]; char* dup = NULL; + int wild = 0x00; megaco_profile_t* profile = NULL; if (zstr(cmd)) { @@ -107,12 +108,16 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre } if (profile) { + if(!zstr(argv[7]) && !strcasecmp(argv[7],"wild")){ + wild = 0x01; + } + printf("Input to Send Service Change command : " "Profile Name[%s], term-id[%s] method[%s] reason[%s] \n", profile->name, argv[4], argv[5], argv[6]); megaco_profile_release(profile); - mg_send_service_change(profile->idx, argv[4], atoi(argv[5]), atoi(argv[6])); + mg_send_service_change(profile->idx, argv[4], atoi(argv[5]), atoi(argv[6]),wild); } else { stream->write_function(stream, "-ERR No such profile\n"); } diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index b4e8d04442..7855bcd9d9 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -273,10 +273,14 @@ switch_status_t handle_mg_audit_cmd( SuId suId, MgMgcoCommand *auditReq) MgMgcoMediaDesc* media; MgMgcoCtxt ctxt; switch_status_t ret; + uint8_t wild = 0x00; memset(&reply, 0, sizeof(reply)); audit = &auditReq->u.mgCmdReq[0]->cmd.u.aval; + wild = auditReq->u.mgCmdReq[0]->wild.pres; + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"%s :: wild card request = %s \n",__FUNCTION__,(1==wild)?"TRUE":"FALSE"); if(NOTPRSNT == audit->pres.pres){ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Audit structure not present..rejecting \n"); @@ -498,6 +502,11 @@ switch_status_t handle_mg_audit_cmd( SuId suId, MgMgcoCommand *auditReq) reply.cmdType.pres = PRSNT_NODEF; reply.cmdType.val = CH_CMD_TYPE_RSP; + if(wild){ + reply.u.mgCmdRsp[0]->wild.pres = PRSNT_NODEF; + } + + /* send command reply */ sng_mgco_send_cmd(suId, &reply); @@ -942,9 +951,12 @@ switch_status_t mg_send_subtract_rsp(SuId suId, MgMgcoCommand *req) int ret = 0x00; MgMgcoTermId *termId; MgMgcoCtxt ctxt; + uint8_t wild = 0x00; memset(&cmd,0, sizeof(cmd)); + wild = req->u.mgCmdReq[0]->wild.pres; + /*copy transaction-id*/ memcpy(&cmd.transId, &req->transId,sizeof(MgMgcoTransId)); @@ -959,6 +971,10 @@ switch_status_t mg_send_subtract_rsp(SuId suId, MgMgcoCommand *req) return ret; } + if(wild){ + cmd.u.mgCmdRsp[0]->wild.pres = PRSNT_NODEF; + } + cmd.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; cmd.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; cmd.u.mgCmdRsp[0]->type.val = MGT_SUB; @@ -1007,7 +1023,7 @@ U32 get_txn_id(){ * SuId - Service User ID for MG SAP - it will be same like mg_profile_t->idx (refer to media_gateway_xml.c->mg_sap_id) * term_name - String format defined termination name */ -switch_status_t mg_send_service_change(SuId suId, const char* term_name, uint8_t method, MgServiceChangeReason_e reason) +switch_status_t mg_send_service_change(SuId suId, const char* term_name, uint8_t method, MgServiceChangeReason_e reason,uint8_t wild) { MgMgcoSvcChgPar srvPar; MgMgcoTermId* termId; @@ -1054,9 +1070,6 @@ switch_status_t mg_send_service_change(SuId suId, const char* term_name, uint8_t /*mgUtlCpyMgMgcoSvcChgPar(&svc->parm, &srvPar, &request.u.mgCmdReq[0]->memCp);*/ - printf("reason[%p = %s], len[%d]\n",svc->parm.reason.val, svc->parm.reason.val, svc->parm.reason.len); - - if (mgUtlGrowList((void ***)&svc->termIdLst.terms, sizeof(MgMgcoTermIdLst), &svc->termIdLst.num, &request.u.mgCmdReq[0]->memCp) != ROK) { @@ -1073,8 +1086,12 @@ switch_status_t mg_send_service_change(SuId suId, const char* term_name, uint8_t mg_fill_mgco_termid(termId, (char*)term_name ,strlen(term_name), &request.u.mgCmdReq[0]->memCp); + if(wild){ + request.u.mgCmdReq[0]->wild.pres = PRSNT_NODEF; + } - printf("reason[%p = %s], len[%d]\n",svc->parm.reason.val, svc->parm.reason.val, svc->parm.reason.len); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"Sending %s Service Change for termId[%s] with reason[%s], len[%d]\n", + ((1==wild)?"WildCard":"Non Wild Card"), term_name, svc->parm.reason.val, svc->parm.reason.len); sng_mgco_send_cmd(suId, &request); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index a90e6dc2c4..cdbde20c13 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -155,7 +155,7 @@ switch_status_t mg_send_heartbeat_audit_rsp( SuId suId, MgMgcoCommand *auditReq) void mg_get_time_stamp(MgMgcoTimeStamp *timeStamp); switch_status_t mg_fill_svc_change(MgMgcoSvcChgPar *srvPar, uint8_t method, const char *reason); void mg_fill_null_context(MgMgcoContextId* ctxt); -switch_status_t mg_send_service_change(SuId suId, const char* term_name, uint8_t method, MgServiceChangeReason_e reason); +switch_status_t mg_send_service_change(SuId suId, const char* term_name, uint8_t method, MgServiceChangeReason_e reason,uint8_t wild); switch_status_t mg_create_mgco_command(MgMgcoCommand *cmd, uint8_t apiType, uint8_t cmdType); diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 26d36c7a05..7e4be231ca 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -19,15 +19,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_media_gateway_shutdown); SWITCH_MODULE_DEFINITION(mod_media_gateway, mod_media_gateway_load, mod_media_gateway_shutdown, NULL); -switch_status_t handle_mg_add_cmd(SuId suId, MgMgcoCommand *req, MgMgcoAmmReq *addReq); -switch_status_t mg_stack_free_mem(MgMgcoMsg* msg); -switch_status_t mg_stack_free_mem(MgMgcoMsg* msg); -switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ); -switch_status_t mg_send_add_rsp(SuId suId, MgMgcoCommand *req); -S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, CONSTANT U8 *str, CmMemListCp *memCp); -void mg_util_set_txn_string(MgStr *errTxt, U32 *txnId); -switch_status_t mg_build_mgco_err_request(MgMgcoInd **errcmd,U32 trans_id, MgMgcoContextId *ctxt_id, U32 err, MgStr *errTxt); - /**************************************************************************************************************/ SWITCH_STANDARD_API(megaco_function) @@ -169,58 +160,9 @@ void handle_sng_log(uint8_t level, char *fmt, ...) va_end(ptr); } +/*****************************************************************************************************************************/ -static void mgco_print_sdp(CmSdpInfoSet *sdp) -{ - int i; - - - if (sdp->numComp.pres == NOTPRSNT) { - return; - } - - for (i = 0; i < sdp->numComp.val; i++) { - CmSdpInfo *s = sdp->info[i]; - int mediaId; - - if (s->conn.addrType.pres && s->conn.addrType.val == CM_SDP_ADDR_TYPE_IPV4 && - s->conn.netType.type.val == CM_SDP_NET_TYPE_IN && - s->conn.u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) { - - if (s->conn.u.ip4.addrType.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Address: %d.%d.%d.%d\n", - s->conn.u.ip4.u.uniIp.b[0].val, - s->conn.u.ip4.u.uniIp.b[1].val, - s->conn.u.ip4.u.uniIp.b[2].val, - s->conn.u.ip4.u.uniIp.b[3].val); - } - if (s->attrSet.numComp.pres) { - for (mediaId = 0; mediaId < s->attrSet.numComp.val; mediaId++) { - /*CmSdpAttr *a = s->attrSet.attr[mediaId];*/ - - } - } - - if (s->mediaDescSet.numComp.pres) { - for (mediaId = 0; mediaId < s->mediaDescSet.numComp.val; mediaId++) { - CmSdpMediaDesc *desc = s->mediaDescSet.mediaDesc[mediaId]; - - if (desc->field.mediaType.val == CM_SDP_MEDIA_AUDIO && - desc->field.id.type.val == CM_SDP_VCID_PORT && - desc->field.id.u.port.type.val == CM_SDP_PORT_INT && - desc->field.id.u.port.u.portInt.port.type.val == CM_SDP_SPEC) { - int port = desc->field.id.u.port.u.portInt.port.val.val; - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Port: %d\n", port); - - } - } - } - } - } -} - - +#if 0 static switch_status_t mgco_parse_local_sdp(mg_termination_t *term, CmSdpInfoSet *sdp) { int i; @@ -263,7 +205,7 @@ static switch_status_t mgco_parse_local_sdp(mg_termination_t *term, CmSdpInfoSet CmSdpAttr *a = s->attrSet.attr[mediaId]; local_sdp->info[i]->attrSet.attr[mediaId] = switch_core_alloc(term->context->pool, sizeof(CmSdpAttr)); *(local_sdp->info[i]->attrSet.attr[mediaId]) = *a; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Media %p\n", a); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Media %p\n", (void*)a); } } @@ -286,7 +228,10 @@ static switch_status_t mgco_parse_local_sdp(mg_termination_t *term, CmSdpInfoSet } } } + + return SWITCH_STATUS_SUCCESS; } +#endif void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) { @@ -530,7 +475,8 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) { case MGT_ADD: { - handle_mg_add_cmd(suId, cmd, &cmd->u.mgCmdInd[0]->cmd.u.add); + handle_mg_add_cmd(&cmd->u.mgCmdInd[0]->cmd.u.add); + mg_send_add_rsp(suId, cmd); break; } @@ -632,469 +578,6 @@ void handle_mgco_audit_cfm(Pst *pst, SuId suId, MgMgtAudit* audit, Reason reason /*****************************************************************************************************************************/ -/* -* -* Fun: mg_get_term_id_list -* -* Desc: Utility function to get MgMgcoTermIdLst structure -* from MgMgcoCommand structure. -* GCP_VER_2_1 - we will have term id list instead of single term id -* -* Ret: If success, return pointer to MgMgcoTermIdLst. -* If failure, return Null. -* -* Notes: None -* -*/ - -MgMgcoTermIdLst *mg_get_term_id_list(MgMgcoCommand *cmd) -{ - uint8_t cmd_type = MGT_NONE; - uint8_t api_type = CM_CMD_TYPE_NONE; - MgMgcoTermIdLst * term_id = NULL; - - - /*-- mgCmdInd type represents the data structure for both - * incoming and outgoing requests, hence we can get the - * command type from there itself --*/ - cmd_type = cmd->u.mgCmdInd[0]->cmd.type.val; - - /*-- Find apiType --*/ - api_type = cmd->cmdType.val; - - switch (api_type) - { - case CH_CMD_TYPE_REQ: - case CH_CMD_TYPE_IND: - /* Based on Command Type, get to the TermId structure */ - switch (cmd_type) - { - case MGT_ADD: - if (cmd->u.mgCmdInd[0]->cmd.u.add.pres.pres) - term_id = &cmd->u.mgCmdInd[0]->cmd.u.add.termIdLst; - break; - - case MGT_MOVE: - if (cmd->u.mgCmdInd[0]->cmd.u.move.pres.pres) - term_id = &cmd->u.mgCmdInd[0]->cmd.u.move.termIdLst; - break; - - case MGT_MODIFY: - if (cmd->u.mgCmdInd[0]->cmd.u.mod.pres.pres) - term_id = &cmd->u.mgCmdInd[0]->cmd.u.mod.termIdLst; - break; - - case MGT_SUB: - if (cmd->u.mgCmdInd[0]->cmd.u.sub.pres.pres) - term_id = &cmd->u.mgCmdInd[0]->cmd.u.sub.termIdLst; - break; - - case MGT_AUDITCAP: - if (cmd->u.mgCmdInd[0]->cmd.u.acap.pres.pres) - term_id = &cmd->u.mgCmdInd[0]->cmd.u.acap.termIdLst; - break; - - case MGT_AUDITVAL: - if (cmd->u.mgCmdInd[0]->cmd.u.aval.pres.pres) - term_id = &cmd->u.mgCmdInd[0]->cmd.u.aval.termIdLst; - break; - - case MGT_NTFY: - if (cmd->u.mgCmdInd[0]->cmd.u.ntfy.pres.pres) - term_id = &cmd->u.mgCmdInd[0]->cmd.u.ntfy.termIdLst; - break; - - case MGT_SVCCHG: - if (cmd->u.mgCmdInd[0]->cmd.u.svc.pres.pres) - term_id = &cmd->u.mgCmdInd[0]->cmd.u.svc.termIdLst; - break; - - default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); - break; - } - break; - - case CH_CMD_TYPE_RSP: - case CH_CMD_TYPE_CFM: - - cmd_type = cmd->u.mgCmdRsp[0]->type.val; - - switch (cmd_type) - { - case MGT_ADD: - if (cmd->u.mgCmdRsp[0]->u.add.pres.pres) - term_id = &cmd->u.mgCmdRsp[0]->u.add.termIdLst; - break; - - case MGT_MOVE: - if (cmd->u.mgCmdRsp[0]->u.move.pres.pres) - term_id = &cmd->u.mgCmdRsp[0]->u.move.termIdLst; - break; - - case MGT_MODIFY: - if (cmd->u.mgCmdRsp[0]->u.mod.pres.pres) - term_id = &cmd->u.mgCmdRsp[0]->u.mod.termIdLst; - break; - - case MGT_SUB: - if (cmd->u.mgCmdRsp[0]->u.sub.pres.pres) - term_id = &cmd->u.mgCmdRsp[0]->u.sub.termIdLst; - break; - - case MGT_SVCCHG: - if (cmd->u.mgCmdRsp[0]->u.svc.pres.pres) - term_id = &cmd->u.mgCmdRsp[0]->u.svc.termIdLst; - break; - - case MGT_AUDITVAL: - if (cmd->u.mgCmdRsp[0]->u.aval.u.other.pres.pres) - term_id = &cmd->u.mgCmdRsp[0]->u.aval.u.other.termIdLst; - break; - - case MGT_AUDITCAP: - if (cmd->u.mgCmdRsp[0]->u.acap.u.other.pres.pres) - term_id = &cmd->u.mgCmdRsp[0]->u.acap.u.other.termIdLst; - break; - - case MGT_NTFY: - if (cmd->u.mgCmdRsp[0]->u.ntfy.pres.pres) - term_id = &cmd->u.mgCmdRsp[0]->u.ntfy.termIdLst; - break; - - default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); - } /* switch command type for reply */ - break; - - default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported api_type[%s]!\n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(api_type)); - break; - } /* switch -api_type */ - - return (term_id); -} - -/*****************************************************************************************************************************/ - -switch_status_t handle_mg_add_cmd(SuId suId, MgMgcoCommand *req, MgMgcoAmmReq *addReq) -{ - int descId; - mg_context_t *ctx = NULL; - - MgMgcoCommand cmd; - int ret = 0x00; - MgMgcoTermId *termId; - MgMgcoCtxt ctxt; - - memset(&cmd,0, sizeof(cmd)); - - /*copy transaction-id*/ - memcpy(&cmd.transId, &req->transId, sizeof(MgMgcoTransId)); - - if (req->contextId.type.val == MGT_CXTID_CHOOSE) { - ctx = megaco_choose_context(NULL); - } else if (req->contextId.type.val == MGT_CXTID_OTHER) { - ctx = megaco_get_context(NULL, req->contextId.val.val); - } - - - /*copy context-id*/ /*TODO - in case of $ context should be generated by app, we should not simply copy incoming structure */ - memcpy(&cmd.contextId, &req->contextId, sizeof(MgMgcoContextId)); - - /*copy peer identifier */ - memcpy(&cmd.peerId, &req->peerId, sizeof(TknU32)); - - /*fill response structue */ - if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&cmd.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ - return ret; - } - - - for (descId = 0; descId < addReq->dl.num.val; descId++) { - switch (addReq->dl.descs[descId]->type.val) { - case MGT_MEDIADESC: - { - int mediaId; - for (mediaId = 0; mediaId < addReq->dl.descs[descId]->u.media.num.val; mediaId++) { - MgMgcoMediaPar *mediaPar = addReq->dl.descs[descId]->u.media.parms[mediaId]; - switch (mediaPar->type.val) { - case MGT_MEDIAPAR_LOCAL: - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCAL"); - break; - } - case MGT_MEDIAPAR_REMOTE: - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_REMOTE"); - break; - } - - case MGT_MEDIAPAR_LOCCTL: - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCCTL"); - break; - } - case MGT_MEDIAPAR_TERMST: - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_TERMST"); - break; - } - case MGT_MEDIAPAR_STRPAR: - { - MgMgcoStreamDesc *mgStream = &mediaPar->u.stream; - - if (mgStream->sl.remote.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got remote stream media description:\n"); - mgco_print_sdp(&mgStream->sl.remote.sdp); - } - - if (mgStream->sl.local.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got local stream media description:\n"); - mgco_print_sdp(&mgStream->sl.local.sdp); - } - - break; - } - } - } - } - case MGT_MODEMDESC: - case MGT_MUXDESC: - case MGT_REQEVTDESC: - case MGT_EVBUFDESC: - case MGT_SIGNALSDESC: - case MGT_DIGMAPDESC: - case MGT_AUDITDESC: - case MGT_STATSDESC: - break; - } - } - - cmd.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; - cmd.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; - cmd.u.mgCmdRsp[0]->type.val = MGT_ADD; - cmd.u.mgCmdRsp[0]->u.add.pres.pres = PRSNT_NODEF; - - - cmd.u.mgCmdRsp[0]->u.add.termIdLst.num.pres = PRSNT_NODEF; - cmd.u.mgCmdRsp[0]->u.add.termIdLst.num.val = 1; - - mgUtlAllocMgMgcoTermIdLst(&cmd.u.mgCmdRsp[0]->u.add.termIdLst, &req->u.mgCmdReq[0]->cmd.u.add.termIdLst); - -#ifdef GCP_VER_2_1 - termId = cmd.u.mgCmdRsp[0]->u.add.termIdLst.terms[0]; -#else - termId = &(cmd.u.mgCmdRsp[0]->u.add.termId); -#endif - /* FIXME */ - mg_fill_mgco_termid(termId, (CONSTANT U8*)"term1",&req->u.mgCmdRsp[0]->memCp); - - /* We will always send one command at a time..*/ - cmd.cmdStatus.pres = PRSNT_NODEF; - cmd.cmdStatus.val = CH_CMD_STATUS_END_OF_CMD; - - cmd.cmdType.pres = PRSNT_NODEF; - cmd.cmdType.val = CH_CMD_TYPE_RSP; - - - ret = sng_mgco_send_cmd(suId, &cmd); - - memcpy(&ctxt.transId,&req->transId,sizeof(MgMgcoTransId)); - memcpy(&ctxt.cntxtId, &cmd.contextId,sizeof(MgMgcoContextId)); - memcpy(&ctxt.peerId, &req->peerId,sizeof(TknU32)); - ctxt.cmdStatus.pres = PRSNT_NODEF; - ctxt.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; - - return sng_mgco_send_axn_req(suId, &ctxt);; -} - -/*****************************************************************************************************************************/ -switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ) -{ - Mem sMem; - - sMem.region = 0; - sMem.pool = 0; - - if ( _memSize <= 0 ) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_alloc_mem: invalid size\n"); - return SWITCH_STATUS_FALSE; - } - - if ( ROK != cmAllocEvnt( _memSize, MG_MAXBLKSIZE, &sMem, _memPtr ) ) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_alloc_mem: cmAllocEvnt return failure for _memSize=%d\n", (int)_memSize); - return SWITCH_STATUS_FALSE; - } - - // Note: memset done inside stack api - - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t mg_stack_get_mem(MgMgcoMsg* msg, Ptr* _memPtr, Size _memSize ) -{ - if ( _memSize <= 0 ) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_get_mem: invalid size\n"); - return SWITCH_STATUS_FALSE; - } - - if ( !msg ) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_get_mem: invalid message\n"); - return SWITCH_STATUS_FALSE; - } - - if ( cmGetMem( (Ptr)msg, _memSize, (Ptr*)_memPtr ) != ROK ) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed alloc_mg_stack_mem: get memory failed _memSize=%d\n", _memSize ); - return SWITCH_STATUS_FALSE; - } - - // Note: memset done inside stack api - - return SWITCH_STATUS_SUCCESS; -} - - -switch_status_t mg_stack_free_mem(MgMgcoMsg* msg) -{ - if ( !msg ) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_free_mem: invalid message\n"); - return SWITCH_STATUS_FALSE; - } - - cmFreeMem( (Ptr)msg ); - - return SWITCH_STATUS_SUCCESS; -} - -#define MG_ACC_GETMEM(_ptr,_len,_memCp,_ret) \ -{ \ - ret = cmGetMem((_memCp), (_len), (Ptr *)&(_ptr)); \ - if( ret == ROK) \ - cmMemset((U8 *)(_ptr), (U8)0, (PTR)(_len)); \ -} - - -S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, CONSTANT U8 *str, CmMemListCp *memCp) -{ -#ifdef GCP_ASN - Size size; -#endif - S16 ret = ROK; - - termId->name.pres.pres = PRSNT_NODEF; - /* mg011.105: Bug fixes */ - termId->name.lcl.pres = PRSNT_NODEF; - termId->name.lcl.len = cmStrlen((CONSTANT U8*)str); - MG_ACC_GETMEM((termId->name.lcl.val), termId->name.lcl.len, memCp, ret); - if( ret != ROK) - RETVALUE(ret); - - cmMemcpy((U8*)(termId->name.lcl.val), (CONSTANT U8*)str,termId->name.lcl.len); - -#ifdef GCP_ASN - /* Remove comment to fill other term ID - termId->wildcard.num.pres = NOTPRSNT; */ - /* Remove comment to fill wilcard term ID */ - termId->wildcard.num.pres = PRSNT_NODEF; - termId->wildcard.num.val = 1; - size = ((sizeof(MgMgcoWildcardField*))); - MG_ACC_GETMEM((termId->wildcard.wildcard),size,memCp, ret); - if( ret != ROK) - RETVALUE(ret); - - MG_ACC_GETMEM( ((termId->wildcard.wildcard)[0]),sizeof(MgMgcoWildcardField), - memCp, ret); - if( ret != ROK) - RETVALUE(ret); - - termId->wildcard.wildcard[0]->pres = PRSNT_NODEF; - termId->wildcard.wildcard[0]->len = 1; - termId->wildcard.wildcard[0]->val[0] = 0x55; -#endif /* GCP_ASN */ - - RETVALUE(ROK); -} - -switch_status_t mg_build_mgco_err_request(MgMgcoInd **errcmd,U32 trans_id, MgMgcoContextId *ctxt_id, U32 err, MgStr *errTxt) -{ - MgMgcoInd *mgErr; - S16 ret; - - mgErr = NULLP; - ret = ROK; - - /* Allocate for AG error */ - mg_stack_alloc_mem((Ptr*)&mgErr, sizeof(MgMgcoInd)); - if (NULL == mgErr) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " mg_build_mgco_err_request Failed : memory alloc \n"); - return SWITCH_STATUS_FALSE; - } - - /* Set transaction Id in the error request */ - mg_util_set_val_pres(mgErr->transId, trans_id); - - /* Copy the context Id */ - mg_mem_copy(&mgErr->cntxtId, - ctxt_id, - sizeof(MgMgcoContextId)); - - /* Set the peerId */ - mgErr->peerId.pres = NOTPRSNT; - - /* Set the error code */ - mg_util_set_pres(mgErr->err.pres.pres); - mg_util_set_pres(mgErr->err.code.pres); - mg_util_set_val_pres(mgErr->err.code, err); - - if(errTxt->len) - { - mg_get_mem(&mgErr->memCp, (errTxt->len)*sizeof(U8), mgErr->err.text.val, &ret); - if (ROK != ret) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " mg_build_mgco_err_request Failed : memory alloc \n"); - return SWITCH_STATUS_FALSE; - } - mgErr->err.text.pres = PRSNT_NODEF; - mgErr->err.text.len = errTxt->len; - mg_mem_copy(mgErr->err.text.val, errTxt->val, errTxt->len); - } - - /* Set the output value */ - *errcmd = mgErr; - - return SWITCH_STATUS_SUCCESS; -} - -void mg_util_set_txn_string(MgStr *errTxt, U32 *txnId) -{ - mg_zero((errTxt->val), sizeof(errTxt->val)); - errTxt->len = 0; - - errTxt->val[errTxt->len] = '\"'; - errTxt->len += 1; - - if (MG_TXN_INVALID == txnId ) - { - mg_mem_copy((&errTxt->val[errTxt->len]), "TransactionId=0", 15); - errTxt->len += 15; - } - - errTxt->val[errTxt->len] = '\"'; - errTxt->len += 1; - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s:" - "info, error-text is: %s\n", __PRETTY_FUNCTION__,errTxt->val); - -} - - - /*****************************************************************************************************************************/ /* For Emacs: * Local Variables: From 0ecd5678d1217886f06da8a61be93b4032b32b2b Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Mon, 16 Jul 2012 18:31:13 -0400 Subject: [PATCH 309/822] Update the rtp endpoint so it gets a fixed configuration from var_event --- src/mod/endpoints/mod_sofia/rtp.c | 140 ++++++++++++++++++++++++------ 1 file changed, 115 insertions(+), 25 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 9deddf5922..a269ec6cc9 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -32,15 +32,16 @@ #include #include "mod_sofia.h" -#define kBINDADDRESS "bind_address" #define kLOCALADDR "local_addr" #define kLOCALPORT "local_port" #define kREMOTEADDR "remote_addr" #define kREMOTEPORT "remote_port" #define kCODEC "codec" #define kPTIME "ptime" +#define kPT "pt" #define kRFC2833PT "rfc2833_pt" #define kMODE "mode" +#define kRATE "rate" static struct { switch_memory_pool_t *pool; @@ -53,10 +54,15 @@ typedef struct { switch_codec_t read_codec, write_codec; switch_frame_t read_frame; + + switch_rtp_bug_flag_t rtp_bugs; switch_rtp_t *rtp_session; - const char *bind_address; + uint32_t timestamp_send; + + const char *local_address; + const char *remote_address; const char *codec; int ptime; @@ -67,6 +73,8 @@ typedef struct { switch_port_t local_port; switch_port_t remote_port; + switch_payload_t agreed_pt; /*XXX*/ + sofia_dtmf_t dtmf_type; } crtp_private_t; @@ -100,7 +108,7 @@ void crtp_init(switch_loadable_module_interface_t *module_interface) { switch_endpoint_interface_t *endpoint_interface; //switch_api_interface_t *api_interface; - + crtp.pool = module_interface->pool; endpoint_interface = switch_loadable_module_create_interface(module_interface, SWITCH_ENDPOINT_INTERFACE); endpoint_interface->interface_name = "rtp"; @@ -119,11 +127,30 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi { switch_channel_t *channel; char name[128]; - const char *dname = "PCMU"; - uint32_t interval = 20; - crtp_private_t *tech_pvt = NULL; - //const char *l_sdp = switch_event_get_header(var_event, kLSDP); - //const char *codec_string = switch_event_get_header_nil(var_event, kCODECSTRING); + crtp_private_t *tech_pvt = NULL; + + const char *err; + + const char *local_addr = switch_event_get_header_nil(var_event, kLOCALADDR), + *szlocal_port = switch_event_get_header_nil(var_event, kLOCALPORT), + *remote_addr = switch_event_get_header_nil(var_event, kREMOTEADDR), + *szremote_port = switch_event_get_header_nil(var_event, kREMOTEPORT), + *codec = switch_event_get_header_nil(var_event, kCODEC), + *szptime = switch_event_get_header_nil(var_event, kPTIME), + *mode = switch_event_get_header_nil(var_event, kMODE), + *szrfc2833_pt = switch_event_get_header_nil(var_event, kRFC2833PT), + *szrate = switch_event_get_header_nil(var_event, kRATE), + *szpt = switch_event_get_header_nil(var_event, kPT); + + + switch_port_t local_port = !zstr(szlocal_port) ? atoi(szlocal_port) : 0, + remote_port = !zstr(szremote_port) ? atoi(szremote_port) : 0; + + int ptime = !zstr(szptime) ? atoi(szptime) : 0, + rfc2833_pt = !zstr(szrfc2833_pt) ? atoi(szrfc2833_pt) : 0, + rate = !zstr(szrate) ? atoi(szrate) : 8000, + pt = !zstr(szpt) ? atoi(szpt) : 0; + if (!(*new_session = switch_core_session_request(crtp.endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, 0, pool))) { @@ -133,41 +160,45 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi channel = switch_core_session_get_channel(*new_session); - - tech_pvt = switch_core_session_alloc(*new_session, sizeof *tech_pvt); tech_pvt->session = *new_session; tech_pvt->channel = channel; - tech_pvt->bind_address = switch_core_session_strdup(*new_session, switch_event_get_header_nil(var_event, kBINDADDRESS)); + tech_pvt->local_address = switch_core_session_strdup(*new_session, local_addr); + tech_pvt->local_port = local_port; + tech_pvt->remote_address = switch_core_session_strdup(*new_session, remote_addr); + tech_pvt->remote_port = remote_port; + tech_pvt->ptime = ptime; + tech_pvt->agreed_pt = pt; + tech_pvt->dtmf_type = DTMF_2833; /* XXX */ + switch_core_session_set_private(*new_session, tech_pvt); - snprintf(name, sizeof(name), "rtp/ctrl"); /* TODO add addresses */ + snprintf(name, sizeof(name), "rtp/ctrl"); switch_channel_set_name(channel, name); switch_channel_set_state(channel, CS_INIT); if (switch_core_codec_init(&tech_pvt->read_codec, - dname, + codec, NULL, - 8000, - interval, + rate, + ptime, 1, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + /*SWITCH_CODEC_FLAG_ENCODE |*/ SWITCH_CODEC_FLAG_DECODE, NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); goto fail; } else { if (switch_core_codec_init(&tech_pvt->write_codec, - dname, + codec, NULL, - 8000, - interval, + rate, + ptime, 1, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + SWITCH_CODEC_FLAG_ENCODE /*| SWITCH_CODEC_FLAG_DECODE*/, NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); - switch_core_codec_destroy(&tech_pvt->read_codec); goto fail; } } @@ -178,7 +209,15 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi } if (switch_core_session_set_write_codec(*new_session, &tech_pvt->write_codec) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set write codec?\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set write codec?\n"); + goto fail; + } + + if (!(tech_pvt->rtp_session = switch_rtp_new(local_addr, local_port, remote_addr, remote_port, tech_pvt->agreed_pt, + tech_pvt->read_codec.implementation->samples_per_packet, ptime * 1000, + flags, "soft", &err, switch_core_session_get_pool(*new_session)))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't setup RTP session: [%s]\n", err); + goto fail; } if (switch_core_session_thread_launch(*new_session) != SWITCH_STATUS_SUCCESS) { @@ -214,7 +253,7 @@ static switch_status_t channel_on_init(switch_core_session_t *session) switch_channel_set_state(channel, CS_ROUTING); - return SWITCH_STATUS_SUCCESS; + return SWITCH_STATUS_SUCCESS; } static switch_status_t channel_on_destroy(switch_core_session_t *session) @@ -240,6 +279,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch { crtp_private_t *tech_pvt; switch_channel_t *channel; + switch_status_t status; channel = switch_core_session_get_channel(session); assert(channel != NULL); @@ -247,6 +287,31 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); + if (!tech_pvt->rtp_session) { + goto cng; + } + + if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) { + switch_dtmf_t dtmf = { 0 }; + switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, &dtmf); + switch_channel_queue_dtmf(channel, &dtmf); + } + + tech_pvt->read_frame.flags = SFF_NONE; + status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame, flags); + + if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { + goto cng; + } + +done: + *frame = &tech_pvt->read_frame; + return SWITCH_STATUS_SUCCESS; + +cng: + *frame = &tech_pvt->read_frame; + tech_pvt->read_frame.flags |= SFF_CNG; + tech_pvt->read_frame.datalen = 0; return SWITCH_STATUS_SUCCESS; } @@ -255,6 +320,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc { crtp_private_t *tech_pvt; switch_channel_t *channel; + int frames = 0, bytes = 0, samples = 0; channel = switch_core_session_get_channel(session); assert(channel != NULL); @@ -263,8 +329,20 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc assert(tech_pvt != NULL); - return SWITCH_STATUS_SUCCESS; + if (!switch_test_flag(frame, SFF_CNG) && !switch_test_flag(frame, SFF_PROXY_PACKET)) { + if (tech_pvt->read_codec.implementation->encoded_bytes_per_packet) { + bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_packet; + frames = ((int) frame->datalen / bytes); + } else + frames = 1; + + samples = frames * tech_pvt->read_codec.implementation->samples_per_packet; + } + + tech_pvt->timestamp_send += samples; + switch_rtp_write_frame(tech_pvt->rtp_session, frame); + return SWITCH_STATUS_SUCCESS; } static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf) @@ -274,8 +352,20 @@ static switch_status_t channel_send_dtmf(switch_core_session_t *session, const s tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); + switch(tech_pvt->dtmf_type) { + case DTMF_2833: + { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Enqueuing RFC2833 DTMF %c of length %d\n", dtmf->digit, dtmf->duration); + return switch_rtp_queue_rfc2833(tech_pvt->rtp_session, dtmf); + } + case DTMF_NONE: + default: + { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Discarding DTMF %c of length %d, DTMF type is NONE\n", dtmf->digit, dtmf->duration); + } + } - return SWITCH_STATUS_SUCCESS; + return SWITCH_STATUS_SUCCESS; } static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) From 36719e301750031ee27a4c7f29a87d72f44a3457 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Tue, 17 Jul 2012 10:15:25 -0400 Subject: [PATCH 310/822] comment out unused vars --- src/mod/endpoints/mod_sofia/rtp.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index a269ec6cc9..679a9a0e22 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -137,8 +137,8 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi *szremote_port = switch_event_get_header_nil(var_event, kREMOTEPORT), *codec = switch_event_get_header_nil(var_event, kCODEC), *szptime = switch_event_get_header_nil(var_event, kPTIME), - *mode = switch_event_get_header_nil(var_event, kMODE), - *szrfc2833_pt = switch_event_get_header_nil(var_event, kRFC2833PT), + //*mode = switch_event_get_header_nil(var_event, kMODE), + //*szrfc2833_pt = switch_event_get_header_nil(var_event, kRFC2833PT), *szrate = switch_event_get_header_nil(var_event, kRATE), *szpt = switch_event_get_header_nil(var_event, kPT); @@ -147,7 +147,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi remote_port = !zstr(szremote_port) ? atoi(szremote_port) : 0; int ptime = !zstr(szptime) ? atoi(szptime) : 0, - rfc2833_pt = !zstr(szrfc2833_pt) ? atoi(szrfc2833_pt) : 0, + //rfc2833_pt = !zstr(szrfc2833_pt) ? atoi(szrfc2833_pt) : 0, rate = !zstr(szrate) ? atoi(szrate) : 8000, pt = !zstr(szpt) ? atoi(szpt) : 0; @@ -196,7 +196,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi rate, ptime, 1, - SWITCH_CODEC_FLAG_ENCODE /*| SWITCH_CODEC_FLAG_DECODE*/, + SWITCH_CODEC_FLAG_ENCODE /*| SWITCH_CODEC_FLAG_DECODE*/, NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); goto fail; @@ -304,7 +304,6 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch goto cng; } -done: *frame = &tech_pvt->read_frame; return SWITCH_STATUS_SUCCESS; From 6acde3a86996afffa64c96492b37f21a51e33fe3 Mon Sep 17 00:00:00 2001 From: Kapil Date: Tue, 17 Jul 2012 13:07:32 -0400 Subject: [PATCH 311/822] adding validation of megaco commands code and modification in handling ADD message --- .../mod_media_gateway/media_gateway.c | 57 +++++++++ .../media_gateway_cmd_handler.c | 68 +++++++++- .../mod_media_gateway/media_gateway_stack.h | 4 +- .../mod_media_gateway/media_gateway_utils.c | 57 +++++++++ .../mod_media_gateway/mod_media_gateway.c | 117 +++++++++++++++--- .../mod_media_gateway/mod_media_gateway.h | 3 + 6 files changed, 282 insertions(+), 24 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 0c43adab6b..769bdc5465 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -46,6 +46,63 @@ void megaco_peer_profile_release(mg_peer_profile_t *profile) switch_thread_rwlock_unlock(profile->rwlock); } +megaco_profile_t* megaco_get_profile_by_suId(SuId suId) +{ + megaco_profile_t* profile = NULL; + void *val = NULL; + switch_hash_index_t *hi = NULL; + int found = 0x00; + const void *var; + + /*iterate through profile list to get requested suID profile */ + for (hi = switch_hash_first(NULL, megaco_globals.profile_hash); hi; hi = switch_hash_next(hi)) { + switch_hash_this(hi, &var, NULL, &val); + profile = (megaco_profile_t *) val; + if (profile->idx == suId) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got profile[%s] associated with suId[%d]\n",profile->name, suId); + found = 0x01; + break; + } + } + + if(!found){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " Not able to find profile associated with suId[%d]\n",suId); + return NULL; + } + + return profile; +} + +mg_context_t *megaco_find_context_by_suid(SuId suId, uint32_t context_id) +{ + mg_context_t *result = NULL; + megaco_profile_t* profile = NULL; + + if(NULL == (profile = megaco_get_profile_by_suId(suId))){ + return NULL; + } + + + if (context_id > MG_MAX_CONTEXTS) { + return NULL; + } + + switch_thread_rwlock_rdlock(profile->contexts_rwlock); + + /* Context exists */ + if (profile->contexts_bitmap[context_id % 8] & (1 << (context_id / 8))) { + for (result = profile->contexts[context_id % MG_CONTEXT_MODULO]; result; result = result->next) { + if (result->context_id == context_id) { + break; + } + } + } + + switch_thread_rwlock_unlock(profile->contexts_rwlock); + + return result; +} + mg_context_t *megaco_get_context(megaco_profile_t *profile, uint32_t context_id) { mg_context_t *result = NULL; diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 7855bcd9d9..b19d799a9d 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -29,16 +29,65 @@ const char *mg_service_change_reason[] = { * * */ -switch_status_t handle_mg_add_cmd(MgMgcoAmmReq *addReq) +switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd) { - int descId; - for (descId = 0; descId < addReq->dl.num.val; descId++) { - switch (addReq->dl.descs[descId]->type.val) { + MgMgcoContextId *ctxtId; + int descId; + MgStr errTxt; + MgMgcoInd *mgErr; + MgMgcoTermId *termId; + MgMgcoTermIdLst* termLst; + int err_code; + MgMgcoAmmReq *cmd = &inc_cmd->u.mgCmdInd[0]->cmd.u.add; + U32 txn_id = inc_cmd->transId.val; + + /********************************************************************/ + ctxtId = &inc_cmd->contextId; + termLst = mg_get_term_id_list(inc_cmd); + termId = termLst->terms[0]; + + /********************************************************************/ + /* Validating ADD request *******************************************/ + + /*-- NULL Context & ALL Context not applicable for ADD request --*/ + if ((NOTPRSNT != ctxtId->type.pres) && + ((MGT_CXTID_ALL == ctxtId->type.val) || + (MGT_CXTID_NULL == ctxtId->type.val))) { + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," ADD Request processing failed, Context ALL/NULL not allowed\n"); + + mg_util_set_ctxt_string(&errTxt, ctxtId); + err_code = MGT_MGCO_RSP_CODE_PROT_ERROR; + goto error; + } + + /********************************************************************/ + /* Allocate context - if context type is CHOOSE */ + if ((NOTPRSNT != ctxtId->type.pres) && + (MGT_CXTID_CHOOSE == ctxtId->type.val)){ + + /* TODO - Matt */ + } + + /********************************************************************/ + /* Allocate new RTP termination - If term type is CHOOSE */ + if ((NOTPRSNT != termId->type.pres) && + (MGT_TERMID_CHOOSE == termId->type.val)){ + + /* TODO - Matt */ + /* allocate rtp term and associated the same to context */ + } + + /********************************************************************/ + + + for (descId = 0; descId < cmd->dl.num.val; descId++) { + switch (cmd->dl.descs[descId]->type.val) { case MGT_MEDIADESC: { int mediaId; - for (mediaId = 0; mediaId < addReq->dl.descs[descId]->u.media.num.val; mediaId++) { - MgMgcoMediaPar *mediaPar = addReq->dl.descs[descId]->u.media.parms[mediaId]; + for (mediaId = 0; mediaId < cmd->dl.descs[descId]->u.media.num.val; mediaId++) { + MgMgcoMediaPar *mediaPar = cmd->dl.descs[descId]->u.media.parms[mediaId]; switch (mediaPar->type.val) { case MGT_MEDIAPAR_LOCAL: { @@ -94,6 +143,13 @@ switch_status_t handle_mg_add_cmd(MgMgcoAmmReq *addReq) return SWITCH_STATUS_SUCCESS; +error: + if (SWITCH_STATUS_SUCCESS == + mg_build_mgco_err_request(&mgErr, txn_id, ctxtId, err_code, &errTxt)) { + sng_mgco_send_err(mg_profile->idx, mgErr); + } + mg_free_cmd(cmd); + return SWITCH_STATUS_FALSE; } /*****************************************************************************************************************************/ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index cdbde20c13..8225ee9570 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -133,7 +133,7 @@ int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, megaco_profile_t* mg_cfg, m switch_status_t mg_send_end_of_axn(SuId suId, MgMgcoTransId* transId, MgMgcoContextId* ctxtId, TknU32* peerId); void mgco_print_sdp(CmSdpInfoSet *sdp); void mg_util_set_ctxt_string ( MgStr *errTxt, MgMgcoContextId *ctxtId); -switch_status_t handle_mg_add_cmd(MgMgcoAmmReq *addReq); +switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *addReq); switch_status_t mg_stack_free_mem(void* msg); switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ); MgMgcoMediaDesc* get_default_media_desc(void); @@ -144,6 +144,8 @@ void mg_util_set_txn_string(MgStr *errTxt, U32 *txnId); switch_status_t mg_build_mgco_err_request(MgMgcoInd **errcmd,U32 trans_id, MgMgcoContextId *ctxt_id, U32 err, MgStr *errTxt); switch_status_t mg_send_audit_rsp(SuId suId, MgMgcoCommand *req); switch_status_t handle_mg_audit_cmd(SuId suId, MgMgcoCommand *auditReq); +switch_status_t mg_stack_termination_is_in_service(char* term_str, int len); +void mg_util_set_cmd_name_string (MgStr *errTxt, MgMgcoCommand *cmd); switch_status_t mg_send_modify_rsp(SuId suId, MgMgcoCommand *req); switch_status_t mg_send_subtract_rsp(SuId suId, MgMgcoCommand *req); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index ed70b74173..e536fd83bf 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -78,6 +78,14 @@ switch_status_t mg_stack_free_mem(void* msg) } +/*****************************************************************************************************************************/ + +/* TODO - Matt - to see if term is in service or not */ +switch_status_t mg_stack_termination_is_in_service(char* term_str,int len) +{ + return SWITCH_STATUS_SUCCESS; +} + /*****************************************************************************************************************************/ S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, char* term_str, int term_len, CmMemListCp *memCp) @@ -351,6 +359,55 @@ void mg_util_set_ctxt_string ( MgStr *errTxt, MgMgcoContextId *ctxtId) "info, error-text is: %s\n", __PRETTY_FUNCTION__,errTxt->val); } +/*****************************************************************************************************************************/ + +void mg_util_set_cmd_name_string (MgStr *errTxt, MgMgcoCommand *cmd) +{ + MG_ZERO((errTxt->val), sizeof(errTxt->val)); + errTxt->len = 0; + + if ((!cmd) && (!cmd->u.mgCmdInd[0])) { + switch(cmd->u.mgCmdInd[0]->cmd.type.val) + { + case MGT_AUDITCAP: + errTxt->val[0]='\"'; + errTxt->val[1]='A'; + errTxt->val[2]='u'; + errTxt->val[3]='d'; + errTxt->val[4]='i'; + errTxt->val[5]='t'; + errTxt->val[6]='C'; + errTxt->val[7]='a'; + errTxt->val[8]='p'; + errTxt->val[9]='a'; + errTxt->val[10]='b'; + errTxt->val[11]='i'; + errTxt->val[12]='l'; + errTxt->val[13]='i'; + errTxt->val[14]='t'; + errTxt->val[15]='y'; + errTxt->val[16]='\"'; + errTxt->len = 17; + break; + + case MGT_MOVE: + errTxt->val[0]='\"'; + errTxt->val[1]='M'; + errTxt->val[2]='o'; + errTxt->val[3]='v'; + errTxt->val[4]='e'; + errTxt->val[5]='\"'; + errTxt->len = 6; + break; + + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: Not expected command Type[%d]\n", + __PRETTY_FUNCTION__,cmd->u.mgCmdInd[0]->cmd.type.val); + + break; + } + } +} /*****************************************************************************************************************************/ void mgco_print_sdp(CmSdpInfoSet *sdp) diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 7e4be231ca..a6202295fd 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -233,6 +233,9 @@ static switch_status_t mgco_parse_local_sdp(mg_termination_t *term, CmSdpInfoSet } #endif +/* KAPIL- NOTE : We are using Command mode operation of MEGACO stack, so we will always get command indication instead of transaction */ +/* Below API is not useful ... just leaving as it is...*/ + void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) { size_t txnIter; @@ -425,8 +428,12 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) MgMgcoInd *mgErr; MgStr errTxt; MgMgcoContextId ctxtId; + MgMgcoContextId *inc_context; MgMgcoTermIdLst* termLst; - + MgMgcoTermId *termId; + int count; + int err_code; + megaco_profile_t* mg_profile; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: Received Command Type[%s] \n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(cmd->cmdType.val)); @@ -442,15 +449,8 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) ctxtId.val.pres = NOTPRSNT; mg_util_set_txn_string(&errTxt, &txn_id); - - if (SWITCH_STATUS_SUCCESS == mg_build_mgco_err_request(&mgErr, txn_id, &ctxtId, - MGT_MGCO_RSP_CODE_INVLD_IDENTIFIER, &errTxt)) { - sng_mgco_send_err(suId, mgErr); - } - - /* deallocate the msg */ - mg_free_cmd(cmd); - return ; + err_code = MGT_MGCO_RSP_CODE_INVLD_IDENTIFIER; + goto error; } /* Get the termination Id list from the command(Note: GCP_2_1 has termination list , else it will be termination Id) */ @@ -458,12 +458,80 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) if ((NULL == termLst) || (NOTPRSNT == termLst->num.pres)) { /* termination-id not present , error */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Termination-Id Not received..rejecting command \n"); - mg_free_cmd(cmd); - return ; + + /*-- Send Error to MG Stack --*/ + MG_ZERO(&ctxtId, sizeof(MgMgcoContextId)); + ctxtId.type.pres = NOTPRSNT; + ctxtId.val.pres = NOTPRSNT; + mg_util_set_txn_string(&errTxt, &txn_id); + err_code = MGT_MGCO_RSP_CODE_INVLD_IDENTIFIER; + goto error; } + termId = termLst->terms[0]; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Termination-Id received..value[%s] type[%d] \n", termId->name.lcl.val, termId->type.val); + + /* Not sure - IF Stack fills term type properly..but adding code just to be sure ...*/ + if ((PRSNT_NODEF == termId->type.pres) && + (MGT_TERMID_OTHER == termId->type.val)) { + /* Checking the $ in the pathname */ + if ((PRSNT_NODEF == termId->name.pres.pres) && + (PRSNT_NODEF == termId->name.lcl.pres)) { + for (count = 0; count < termId->name.lcl.len; count++) { + if (termId->name.lcl.val[count] == '$') { + termId->type.val = MGT_TERMID_CHOOSE; + break; + } + + if (termId->name.lcl.val[count] == '*') { + termId->type.val = MGT_TERMID_ALL; + break; + } + } + } + } + + /*If term type is other then check if that term is configured with us..for term type CHOOSE/ALL , no need to check */ + if (MGT_TERMID_OTHER == termId->type.val){ + if(SWITCH_STATUS_FALSE != mg_stack_termination_is_in_service((char*)termId->name.lcl.val, termId->name.lcl.len)){ + mg_util_set_term_string(&errTxt, termId); + err_code = MGT_MGCO_RSP_CODE_UNKNOWN_TERM_ID; + goto error; + } + } + + + /* Validate Context - if context is specified then check if its present with us */ + inc_context = &cmd->contextId; + MG_ZERO(&ctxtId, sizeof(MgMgcoContextId)); + memcpy(&ctxtId, inc_context, sizeof(MgMgcoContextId)); + + if(NOTPRSNT == inc_context->type.pres){ + goto ctxt_error; + + }else if(MGT_CXTID_OTHER == inc_context->type.pres){ + + if(NOTPRSNT != inc_context->val.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"Context specific request for contextId[%d]\n",inc_context->val.val); + /* check if context present with us */ + if(NULL == megaco_find_context_by_suid(suId, inc_context->val.val)){ + goto ctxt_error; + } + }else{ + /* context id value not present - in case of type OTHER we should have context value */ + goto ctxt_error; + } + } + + /*mgAccEvntPrntMgMgcoCommand(cmd, stdout);*/ + /*get mg profile associated with SuId */ + if(NULL == (mg_profile = megaco_get_profile_by_suId(suId))){ + goto error1; + } + switch(cmd->cmdType.val) { case CH_CMD_TYPE_IND: @@ -475,7 +543,7 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) { case MGT_ADD: { - handle_mg_add_cmd(&cmd->u.mgCmdInd[0]->cmd.u.add); + handle_mg_add_cmd(mg_profile, cmd); mg_send_add_rsp(suId, cmd); break; } @@ -488,9 +556,10 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) } case MGT_MOVE: { - /*MgMgcoAmmReq *addReq = &cmdReq->cmd.u.move;*/ - break; - + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MOVE Method Not Yet Supported\n"); + err_code = MGT_MGCO_RSP_CODE_UNSUPPORTED_CMD; + mg_util_set_cmd_name_string(&errTxt, cmd); + goto error; } case MGT_SUB: { @@ -511,7 +580,9 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) case MGT_AUDITCAP: { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Audit-Capability Method Not Yet Supported\n"); - break; + err_code = MGT_MGCO_RSP_CODE_UNSUPPORTED_CMD; + mg_util_set_cmd_name_string(&errTxt, cmd); + goto error; } case MGT_AUDITVAL: { @@ -542,6 +613,18 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) } return; + +ctxt_error: + err_code = MGT_MGCO_RSP_CODE_UNKNOWN_CTXT; + +error: + if (SWITCH_STATUS_SUCCESS == + mg_build_mgco_err_request(&mgErr, txn_id, &ctxtId, err_code, &errTxt)) { + sng_mgco_send_err(suId, mgErr); + } +error1: + mg_free_cmd(cmd); + return; } /*****************************************************************************************************************************/ diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index 91dc74210c..f1da14a4f2 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -139,6 +139,9 @@ mg_context_t *megaco_get_context(megaco_profile_t *profile, uint32_t context_id) mg_context_t *megaco_choose_context(megaco_profile_t *profile); void megaco_release_context(mg_context_t *ctx); +megaco_profile_t* megaco_get_profile_by_suId(SuId suId); +mg_context_t *megaco_find_context_by_suid(SuId suId, uint32_t context_id); + switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload); switch_status_t sng_mgco_start(megaco_profile_t* profile); switch_status_t sng_mgco_stop(megaco_profile_t* profile); From 4c4a7b7486f810804b988f61a11683bf445f0b97 Mon Sep 17 00:00:00 2001 From: Kapil Date: Tue, 17 Jul 2012 16:12:54 -0400 Subject: [PATCH 312/822] adding MEGACO Media Descriptors prints --- .../media_gateway_cmd_handler.c | 133 +++++++++++++++++- 1 file changed, 130 insertions(+), 3 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index b19d799a9d..3e1aeb462d 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -38,13 +38,27 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i MgMgcoTermId *termId; MgMgcoTermIdLst* termLst; int err_code; + int i; + int j; + int fmtCnt; MgMgcoAmmReq *cmd = &inc_cmd->u.mgCmdInd[0]->cmd.u.add; U32 txn_id = inc_cmd->transId.val; + MgMgcoLocalDesc *local; + MgMgcoRemoteDesc *remote; + MgMgcoLclCtlDesc *locCtl; + CmSdpInfo *sdp; + MgMgcoLocalParm *lclParm; + MgMgcoTermStateDesc *tstate; + CmSdpMedFmtRtpList *fmt_list; + MgMgcoTermStateParm *tsp; + TknU8 *fmt; + CmSdpMedProtoFmts *format; /********************************************************************/ ctxtId = &inc_cmd->contextId; termLst = mg_get_term_id_list(inc_cmd); termId = termLst->terms[0]; + /* For Matt - termId->name.lcl.val - to get the termination id name */ /********************************************************************/ /* Validating ADD request *******************************************/ @@ -76,10 +90,11 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i /* TODO - Matt */ /* allocate rtp term and associated the same to context */ - } - /********************************************************************/ - + }else{ /* Physical termination */ + /* TODO - Matt - associate physical termination to context */ + } + /********************************************************************/ for (descId = 0; descId < cmd->dl.num.val; descId++) { switch (cmd->dl.descs[descId]->type.val) { @@ -92,22 +107,126 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i case MGT_MEDIAPAR_LOCAL: { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCAL"); + /* Matt - check local descriptor processing */ + local = &mediaPar->u.local; + sdp = local->sdp.info[0]; + for (i = 0; i < sdp->mediaDescSet.numComp.val; i++) { + /* sdp formats */ + for (j = 0; j < + sdp->mediaDescSet.mediaDesc[i]->field.par.numProtFmts.val; j++) + { + format = sdp->mediaDescSet.mediaDesc[i]->field.par.pflst[j]; + /* Matt - format has field for T38 also */ + if ((format->protType.pres != NOTPRSNT) && + (format->protType.val == CM_SDP_MEDIA_PROTO_RTP)) { + + /* protocol type RTP */ + fmt_list = &format->u.rtp; + + /* print format */ + for(fmtCnt = 0; fmtCnt < fmt_list->num.val; fmtCnt++){ + fmt = &fmt_list->fmts[i]->val; + if(fmt->pres == NOTPRSNT) continue; + printf("Format [%d]\n", fmt->val); + } + } + } + } + break; } + case MGT_MEDIAPAR_REMOTE: { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_REMOTE"); + /* Matt - check remote descriptor processing */ + remote = &mediaPar->u.remote; + sdp = remote->sdp.info[0]; + /* for Matt - same like local descriptor */ break; } case MGT_MEDIAPAR_LOCCTL: { + /* Matt - check Local Control descriptor processing */ + locCtl = &mediaPar->u.locCtl; + for (i = 0; i < locCtl->num.val; i++){ + lclParm = locCtl->parms[i]; + if (PRSNT_NODEF == lclParm->type.pres){ + switch(lclParm->type.val) + { + case MGT_LCLCTL_MODE: + { + /* Mode Property */ + printf("MGT_LCLCTL_MODE - Mode value [%d]\n", lclParm->u.mode.val); + break; + } + case MGT_LCLCTL_RESVAL: + { + /* Reserve Value */ + printf("MGT_LCLCTL_RESVAL: Reserve Value[%d] \n", lclParm->u.resVal.val); + break; + } + case MGT_LCLCTL_RESGRP: + { + /* Reserve group */ + printf("MGT_LCLCTL_RESGRP: Reserve Group[%d]\n", lclParm->u.resGrp.val); + break; + } + case MGT_LCLCTL_PROPPARM: + { + /* Properties (of a termination) */ + /* Matt - See how we can apply this to a termination */ + printf("MGT_LCLCTL_PROPPARM: \n"); + break; + } + default: + printf("Invalid local control descriptor type[%d]\n",lclParm->type.val); + break; + } + } + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCCTL"); break; } case MGT_MEDIAPAR_TERMST: { + /* Matt - apply termination state descriptor */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_TERMST"); + tstate = &mediaPar->u.tstate; + for (i = 0; i < tstate->numComp.val; i++) + { + /* Matt to see how to apply below descriptors to a termination */ + tsp = tstate->trmStPar[i]; + if (PRSNT_NODEF == tsp->type.pres) { + switch(tsp->type.val) + { + case MGT_TERMST_PROPLST: + { + /* Matt to see how to apply properties to a termination */ + /* Properties of a termination */ + printf("MGT_TERMST_PROPLST:\n"); + break; + } + case MGT_TERMST_EVTBUFCTL: + { + /* Event /buffer Control Properties */ + printf(" MGT_TERMST_EVTBUFCTL: value[%d]\n", tsp->u.evtBufCtl.val); + break; + } + case MGT_TERMST_SVCST: + { + /* Service State Properties */ + printf(" MGT_TERMST_SVCST: value[%d]\n", tsp->u.svcState.val); + break; + } + default: + printf("Invalid termination state descriptor type[%d]\n",tsp->type.val); + break; + } + } + } break; } case MGT_MEDIAPAR_STRPAR: @@ -141,6 +260,14 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i } } + /* Matt - to provide the response SDP structure which needs to fill in ADD command response */ + + /* Matt - to indicate if there is any failure while processing add message */ + + /* Kapil - to return error if there is any failure based on Matt's indication */ + + /* Kapil - to fill the response structure and call the response API to send ADD response */ + return SWITCH_STATUS_SUCCESS; error: From 62787362ce075ba665ee05197c4f4439079660b0 Mon Sep 17 00:00:00 2001 From: Kapil Date: Wed, 18 Jul 2012 10:11:51 -0400 Subject: [PATCH 313/822] adding service change wrapper APIs --- .../media_gateway_cmd_handler.c | 32 +++++++++++++++++++ .../mod_media_gateway/media_gateway_stack.h | 3 ++ 2 files changed, 35 insertions(+) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 3e1aeb462d..8c86389e96 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -521,6 +521,7 @@ switch_status_t handle_mg_audit_cmd( SuId suId, MgMgcoCommand *auditReq) (MGT_TERMID_ROOT == termId->type.val)) && ((NOTPRSNT != ctxtId->type.pres) && (MGT_CXTID_OTHER == ctxtId->type.val))) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "failed, Term: Invalid combination, ROOT Term with OTHER CONTEXT\n"); @@ -1199,6 +1200,37 @@ U32 get_txn_id(){ return outgoing_txn_id; } /*****************************************************************************************************************************/ +/* Note : API to send Service Change when termination is coming up(in-service) */ +/* INPUT : MG Profile structure and termination name */ +/* wild flag will tell if service change request needs to be in W-SC format as we can have W-SC=A01* or SC=A01* */ +switch_status_t mg_send_ins_service_change(megaco_profile_t* mg_profile, const char* term_name, int wild) +{ + switch_assert(term_name); + switch_assert(mg_profile); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + "Sending In-Service Service Change for termination[%s] configured in mg profile[%s], suId[%d]\n", + term_name, mg_profile->name, mg_profile->idx); + + return mg_send_service_change(mg_profile->idx, term_name, MGT_SVCCHGMETH_RESTART, MG_SVC_REASON_900_RESTORED, wild); +} + +/*****************************************************************************************************************************/ +/* Note : API to send Service Change when termination is going down (out-of-service) */ +/* INPUT : MG Profile structure and termination name */ +/* wild flag will tell if service change request needs to be in W-SC format as we can have W-SC=A01* or SC=A01* */ +switch_status_t mg_send_oos_service_change(megaco_profile_t* mg_profile, const char* term_name, int wild) +{ + switch_assert(term_name); + switch_assert(mg_profile); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + "Sending Out-Of-Service Service Change for termination[%s] configured in mg profile[%s], suId[%d]\n", + term_name, mg_profile->name, mg_profile->idx); + + return mg_send_service_change(mg_profile->idx, term_name, MGT_SVCCHGMETH_FORCED, MG_SVC_REASON_905_TERM_OOS, wild); +} +/*****************************************************************************************************************************/ /* Note : API to send Service Change */ /* INPUT : * method - Service change method type (can be MGT_SVCCHGMETH_RESTART/MGT_SVCCHGMETH_FORCED (please refer to sng_ss7/cm/mgt.h for more values)) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index 8225ee9570..bbc3141d37 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -160,6 +160,9 @@ void mg_fill_null_context(MgMgcoContextId* ctxt); switch_status_t mg_send_service_change(SuId suId, const char* term_name, uint8_t method, MgServiceChangeReason_e reason,uint8_t wild); switch_status_t mg_create_mgco_command(MgMgcoCommand *cmd, uint8_t apiType, uint8_t cmdType); +switch_status_t mg_send_oos_service_change(megaco_profile_t* mg_profile, const char* term_name, int wild); +switch_status_t mg_send_ins_service_change(megaco_profile_t* mg_profile, const char* term_name, int wild); + /****************************************************************************************************************/ From 9b73c8087e520836d414e178e5912ab4e44f1b8e Mon Sep 17 00:00:00 2001 From: Kapil Date: Wed, 18 Jul 2012 12:05:15 -0400 Subject: [PATCH 314/822] adding MODIFY command handler API --- .../media_gateway_cmd_handler.c | 265 ++++++++++++++++++ .../mod_media_gateway/media_gateway_stack.h | 3 +- .../mod_media_gateway/mod_media_gateway.c | 1 + 3 files changed, 268 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 8c86389e96..7da367155a 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -279,6 +279,271 @@ error: return SWITCH_STATUS_FALSE; } +/*****************************************************************************************************************************/ + +/* +* +* Fun: handle_mg_modify_cmd +* +* Desc: this api will handle the Modify request received from MG stack +* +* +*/ +switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd) +{ + MgMgcoContextId *ctxtId; + int descId; + MgStr errTxt; + MgMgcoInd *mgErr; + MgMgcoTermId *termId; + MgMgcoTermIdLst* termLst; + int err_code; + int i; + int j; + int fmtCnt; + MgMgcoAmmReq *cmd = &inc_cmd->u.mgCmdInd[0]->cmd.u.mod; + U32 txn_id = inc_cmd->transId.val; + MgMgcoLocalDesc *local; + MgMgcoRemoteDesc *remote; + MgMgcoLclCtlDesc *locCtl; + CmSdpInfo *sdp; + MgMgcoLocalParm *lclParm; + MgMgcoTermStateDesc *tstate; + CmSdpMedFmtRtpList *fmt_list; + MgMgcoTermStateParm *tsp; + TknU8 *fmt; + CmSdpMedProtoFmts *format; + + /********************************************************************/ + ctxtId = &inc_cmd->contextId; + termLst = mg_get_term_id_list(inc_cmd); + termId = termLst->terms[0]; + /* For Matt - termId->name.lcl.val - to get the termination id name */ + + /********************************************************************/ + /* Validation *******************************************/ + /********************************************************************/ + + /*** CHOOSE Context NOT ALLOWED ***/ + if ((NOTPRSNT != ctxtId->type.pres) && + (MGT_CXTID_CHOOSE == ctxtId->type.val)) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, + "Modify request processing failure, CHOOSE Context should not present in Modify\n"); + + err_code = MGT_MGCO_RSP_CODE_INVLD_IDENTIFIER; + mg_util_set_ctxt_string(&errTxt, ctxtId); + goto error; + } + /*** CHOOSE Termination NOT ALLOWED **/ + else if ((NOTPRSNT != termId->type.pres) && + (MGT_TERMID_CHOOSE == termId->type.val)) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, + "Modify request processing failure, CHOOSE Termination should not present in Modify\n"); + + err_code = MGT_MGCO_RSP_CODE_INVLD_IDENTIFIER; + mg_util_set_term_string(&errTxt,termId); + goto error; + } + + /********************************************************************/ + /* context id presence check is already being done, we are here it means context-id requested in megaco message is present */ + + /* Matt - to check if we have terminations in the context */ + + /* TODO - Matt */ + + /* Matt to indicate ERROR - If there is no terminations in requested context */ + + /* Kapil - If there is an error - send response back to MG stack with MGT_MGCO_RSP_CODE_NO_TERM_CTXT error code*/ + + /********************************************************************/ + + + for (descId = 0; descId < cmd->dl.num.val; descId++) { + switch (cmd->dl.descs[descId]->type.val) { + case MGT_MEDIADESC: + { + int mediaId; + for (mediaId = 0; mediaId < cmd->dl.descs[descId]->u.media.num.val; mediaId++) { + MgMgcoMediaPar *mediaPar = cmd->dl.descs[descId]->u.media.parms[mediaId]; + switch (mediaPar->type.val) { + case MGT_MEDIAPAR_LOCAL: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCAL"); + /* Matt - check local descriptor processing */ + local = &mediaPar->u.local; + sdp = local->sdp.info[0]; + for (i = 0; i < sdp->mediaDescSet.numComp.val; i++) { + /* sdp formats */ + for (j = 0; j < + sdp->mediaDescSet.mediaDesc[i]->field.par.numProtFmts.val; j++) + { + format = sdp->mediaDescSet.mediaDesc[i]->field.par.pflst[j]; + /* Matt - format has field for T38 also */ + if ((format->protType.pres != NOTPRSNT) && + (format->protType.val == CM_SDP_MEDIA_PROTO_RTP)) { + + /* protocol type RTP */ + fmt_list = &format->u.rtp; + + /* print format */ + for(fmtCnt = 0; fmtCnt < fmt_list->num.val; fmtCnt++){ + fmt = &fmt_list->fmts[i]->val; + if(fmt->pres == NOTPRSNT) continue; + printf("Format [%d]\n", fmt->val); + } + } + } + } + + break; + } + + case MGT_MEDIAPAR_REMOTE: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_REMOTE"); + /* Matt - check remote descriptor processing */ + remote = &mediaPar->u.remote; + sdp = remote->sdp.info[0]; + /* for Matt - same like local descriptor */ + break; + } + + case MGT_MEDIAPAR_LOCCTL: + { + /* Matt - check Local Control descriptor processing */ + locCtl = &mediaPar->u.locCtl; + for (i = 0; i < locCtl->num.val; i++){ + lclParm = locCtl->parms[i]; + if (PRSNT_NODEF == lclParm->type.pres){ + switch(lclParm->type.val) + { + case MGT_LCLCTL_MODE: + { + /* Mode Property */ + printf("MGT_LCLCTL_MODE - Mode value [%d]\n", lclParm->u.mode.val); + break; + } + case MGT_LCLCTL_RESVAL: + { + /* Reserve Value */ + printf("MGT_LCLCTL_RESVAL: Reserve Value[%d] \n", lclParm->u.resVal.val); + break; + } + case MGT_LCLCTL_RESGRP: + { + /* Reserve group */ + printf("MGT_LCLCTL_RESGRP: Reserve Group[%d]\n", lclParm->u.resGrp.val); + break; + } + case MGT_LCLCTL_PROPPARM: + { + /* Properties (of a termination) */ + /* Matt - See how we can apply this to a termination */ + printf("MGT_LCLCTL_PROPPARM: \n"); + break; + } + default: + printf("Invalid local control descriptor type[%d]\n",lclParm->type.val); + break; + } + } + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCCTL"); + break; + } + case MGT_MEDIAPAR_TERMST: + { + /* Matt - apply termination state descriptor */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_TERMST"); + tstate = &mediaPar->u.tstate; + for (i = 0; i < tstate->numComp.val; i++) + { + /* Matt to see how to apply below descriptors to a termination */ + tsp = tstate->trmStPar[i]; + if (PRSNT_NODEF == tsp->type.pres) { + switch(tsp->type.val) + { + case MGT_TERMST_PROPLST: + { + /* Matt to see how to apply properties to a termination */ + /* Properties of a termination */ + printf("MGT_TERMST_PROPLST:\n"); + break; + } + case MGT_TERMST_EVTBUFCTL: + { + /* Event /buffer Control Properties */ + printf(" MGT_TERMST_EVTBUFCTL: value[%d]\n", tsp->u.evtBufCtl.val); + break; + } + case MGT_TERMST_SVCST: + { + /* Service State Properties */ + printf(" MGT_TERMST_SVCST: value[%d]\n", tsp->u.svcState.val); + break; + } + default: + printf("Invalid termination state descriptor type[%d]\n",tsp->type.val); + break; + } + } + } + break; + } + case MGT_MEDIAPAR_STRPAR: + { + MgMgcoStreamDesc *mgStream = &mediaPar->u.stream; + + if (mgStream->sl.remote.pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got remote stream media description:\n"); + mgco_print_sdp(&mgStream->sl.remote.sdp); + } + + if (mgStream->sl.local.pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got local stream media description:\n"); + mgco_print_sdp(&mgStream->sl.local.sdp); + } + + break; + } + } + } + } + case MGT_MODEMDESC: + case MGT_MUXDESC: + case MGT_REQEVTDESC: + case MGT_EVBUFDESC: + case MGT_SIGNALSDESC: + case MGT_DIGMAPDESC: + case MGT_AUDITDESC: + case MGT_STATSDESC: + break; + } + } + + /* Matt - to provide the response SDP structure which needs to fill in Modify command response */ + + /* Matt - to indicate if there is any failure while processing add message */ + + /* Kapil - to return error if there is any failure based on Matt's indication */ + + /* Kapil - to fill the response structure and call the response API to send Modify response */ + + + return SWITCH_STATUS_SUCCESS; +error: + if (SWITCH_STATUS_SUCCESS == + mg_build_mgco_err_request(&mgErr, txn_id, ctxtId, err_code, &errTxt)) { + sng_mgco_send_err(mg_profile->idx, mgErr); + } + mg_free_cmd(cmd); + return SWITCH_STATUS_FALSE; +} + /*****************************************************************************************************************************/ /* * diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index bbc3141d37..d06fd727a1 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -133,7 +133,8 @@ int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, megaco_profile_t* mg_cfg, m switch_status_t mg_send_end_of_axn(SuId suId, MgMgcoTransId* transId, MgMgcoContextId* ctxtId, TknU32* peerId); void mgco_print_sdp(CmSdpInfoSet *sdp); void mg_util_set_ctxt_string ( MgStr *errTxt, MgMgcoContextId *ctxtId); -switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *addReq); +switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *cmd); +switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *cmd); switch_status_t mg_stack_free_mem(void* msg); switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ); MgMgcoMediaDesc* get_default_media_desc(void); diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index a6202295fd..4336b90982 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -551,6 +551,7 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) case MGT_MODIFY: { /*MgMgcoAmmReq *addReq = &cmdReq->cmd.u.mod;*/ + handle_mg_modify_cmd(mg_profile, cmd); mg_send_modify_rsp(suId, cmd); break; } From 909d464abd35d9988b686104f908598f68ac4c37 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Thu, 19 Jul 2012 17:51:25 -0400 Subject: [PATCH 315/822] add/sub done but untested, mod remains. this commit also adds a message handler inside the rtp endpoint so it can properly flush streams, setup jitter buffering, and honor uuid_debug_audio requests --- libs/freetdm/mod_freetdm/tdm.c | 2 +- .../mod_media_gateway/media_gateway.c | 183 ++++++++++++++++-- .../mod_media_gateway/mod_media_gateway.h | 49 +++-- src/mod/endpoints/mod_sofia/rtp.c | 156 ++++++++++++++- 4 files changed, 353 insertions(+), 37 deletions(-) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index 61a145ed3b..a3369f1f7b 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -112,7 +112,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi ctdm_private_t *tech_pvt = NULL; if (zstr(szchanid) || zstr(szspanid)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Both "kSPAN_ID" and "kCHAN_ID" have to be set.\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Both ["kSPAN_ID"] and ["kCHAN_ID"] have to be set.\n"); goto fail; } diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 769bdc5465..b596cdb819 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -55,6 +55,8 @@ megaco_profile_t* megaco_get_profile_by_suId(SuId suId) const void *var; /*iterate through profile list to get requested suID profile */ + + switch_thread_rwlock_rdlock(megaco_globals.profile_rwlock); for (hi = switch_hash_first(NULL, megaco_globals.profile_hash); hi; hi = switch_hash_next(hi)) { switch_hash_this(hi, &var, NULL, &val); profile = (megaco_profile_t *) val; @@ -66,13 +68,172 @@ megaco_profile_t* megaco_get_profile_by_suId(SuId suId) } if(!found){ + profile = NULL; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " Not able to find profile associated with suId[%d]\n",suId); - return NULL; } + + switch_thread_rwlock_unlock(megaco_globals.profile_rwlock); return profile; } +/* + * Creates a freeswitch channel for the specified termination. + * The channel will be parked until future actions are taken + */ +switch_status_t megaco_activate_termination(mg_termination_t *term) +{ + switch_event_t *var_event = NULL; + switch_core_session_t *session = NULL; + switch_status_t status = SWITCH_STATUS_SUCCESS; + char dialstring[100]; + switch_call_cause_t cause; + + if (!zstr(term->uuid)) { + /* A UUID is present, check if the channel still exists */ + switch_core_session_t *session; + if ((session = switch_core_session_locate(term->uuid))) { + switch_core_session_rwunlock(session); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel [%s] already exists for termination [%s]\n", term->uuid, term->name); + return SWITCH_STATUS_SUCCESS; + } + + /* The referenced channel doesn't exist anymore, clear it */ + term->uuid = NULL; + } + + switch_event_create(&var_event, SWITCH_EVENT_CLONE); + + if (term->type == MG_TERM_RTP) { + switch_snprintf(dialstring, sizeof dialstring, "rtp/%s", term->name); + + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, kLOCALADDR, term->u.rtp.local_addr); + switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, kLOCALPORT, "%d", term->u.rtp.local_port); + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, kREMOTEADDR, term->u.rtp.remote_addr); + switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, kREMOTEPORT, "%d", term->u.rtp.remote_port); + + switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, kPTIME, "%d", term->u.rtp.ptime); + switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, kPT, "%d", term->u.rtp.pt); + switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, kRFC2833PT, "%d", term->u.rtp.rfc2833_pt); + switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, kRATE, "%d", term->u.rtp.rate); + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, kCODEC, term->u.rtp.codec); + } else if (term->type == MG_TERM_TDM) { + switch_snprintf(dialstring, sizeof dialstring, "tdm/%s", term->name); + + switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, kSPAN_ID, "%d", term->u.tdm.span); + switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, kCHAN_ID, "%d", term->u.tdm.channel); + } + + /* Set common variables on the channel */ + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, SWITCH_PARK_AFTER_BRIDGE_VARIABLE, "true"); + + if (switch_ivr_originate(NULL, &session, &cause, dialstring, 0, NULL, NULL, NULL, NULL, var_event, 0, NULL) != SWITCH_CAUSE_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to instanciate termination [%s]: %s\n", term->name, switch_channel_cause2str(cause)); + status = SWITCH_STATUS_FALSE; + goto done; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Termination [%s] successfully instanciated as [%s] [%s]\n", term->name, dialstring, switch_core_session_get_uuid(session)); + +done: + if (session) { + switch_core_session_rwunlock(session); + } + switch_event_destroy(&var_event); +} + +mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const char *prefix) +{ + mg_termination_type_t termtype; + + /* Check the termination type by prefix */ + if (strncasecmp(prefix, profile->rtp_termination_id_prefix, strlen(profile->rtp_termination_id_prefix)) == 0) { + termtype = MG_TERM_RTP; + } else { + /* TODO Math: look through TDM channels */ + return NULL; + } + + +} + +mg_termination_t *megaco_find_termination(megaco_profile_t *profile, const char *name) +{ + mg_termination_t *term = switch_core_hash_find_rdlock(profile->terminations, name, profile->terminations_rwlock); + return term; + +} + +void megaco_termination_destroy(mg_termination_t *term) +{ + /* Lookup the FS session and hang it up */ + switch_core_session_t *session; + switch_channel_t *channel; + + if ((session = switch_core_session_locate(term->uuid))) { + channel = switch_core_session_get_channel(session); + switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + switch_core_session_rwunlock(session); + term->uuid = NULL; + } + + switch_core_hash_delete_wrlock(term->profile->terminations, term->name, term->profile->terminations_rwlock); +} + +switch_status_t megaco_context_add_termination(mg_context_t *ctx, mg_termination_t *term) +{ + + switch_assert(ctx != NULL); + switch_assert(term != NULL); + + /* Check if the current context has existing terminations */ + if (ctx->terminations[0] && ctx->terminations[1]) { + /* Context is full */ + return SWITCH_STATUS_FALSE; + } + + if (ctx->terminations[0]) { + ctx->terminations[1] = term; + } else if (ctx->terminations[1]) { + ctx->terminations[0] = term; + } else { + ctx->terminations[0] = term; + } + + if (ctx->terminations[0] && ctx->terminations[1]) { + if (zstr(ctx->terminations[0]->uuid)) { + megaco_activate_termination(ctx->terminations[0]); + } + if (zstr(ctx->terminations[1]->uuid)) { + megaco_activate_termination(ctx->terminations[1]); + } + + switch_ivr_uuid_bridge(ctx->terminations[0]->uuid, ctx->terminations[1]->uuid); + } +} + + +switch_status_t megaco_context_sub_termination(mg_context_t *ctx, mg_termination_t *term) +{ + switch_assert(ctx != NULL); + switch_assert(term != NULL); + + /* Channels will automatically go to park once the bridge ends */ + if (ctx->terminations[0] == term) { + ctx->terminations[0] = NULL; + } else if (ctx->terminations[1] == term) { + ctx->terminations[1] = NULL; + } + + megaco_termination_destroy(term); +} + + +switch_status_t megaco_context_move_termination(mg_context_t *dst, mg_termination_t *term) +{ + +} + mg_context_t *megaco_find_context_by_suid(SuId suId, uint32_t context_id) { mg_context_t *result = NULL; @@ -87,20 +248,7 @@ mg_context_t *megaco_find_context_by_suid(SuId suId, uint32_t context_id) return NULL; } - switch_thread_rwlock_rdlock(profile->contexts_rwlock); - - /* Context exists */ - if (profile->contexts_bitmap[context_id % 8] & (1 << (context_id / 8))) { - for (result = profile->contexts[context_id % MG_CONTEXT_MODULO]; result; result = result->next) { - if (result->context_id == context_id) { - break; - } - } - } - - switch_thread_rwlock_unlock(profile->contexts_rwlock); - - return result; + return megaco_get_context(profile, context_id); } mg_context_t *megaco_get_context(megaco_profile_t *profile, uint32_t context_id) @@ -213,8 +361,9 @@ switch_status_t megaco_profile_start(const char *profilename) switch_thread_rwlock_create(&profile->rwlock, pool); switch_thread_rwlock_create(&profile->contexts_rwlock, pool); + switch_thread_rwlock_create(&profile->terminations_rwlock, pool); -// switch_core_hash_init(&profile->contexts_hash, pool); + switch_core_hash_init(&profile->terminations, pool); if (SWITCH_STATUS_SUCCESS != config_profile(profile, SWITCH_FALSE)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error configuring profile %s\n", profile->name); @@ -235,7 +384,7 @@ switch_status_t megaco_profile_start(const char *profilename) fail: switch_core_destroy_memory_pool(&pool); return SWITCH_STATUS_FALSE; -} +} switch_status_t megaco_profile_destroy(megaco_profile_t **profile) diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index f1da14a4f2..1fe81c8825 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -64,25 +64,46 @@ typedef enum { typedef struct megaco_profile_s megaco_profile_t; typedef struct mg_context_s mg_context_t; +/* RTP parameters understood by the controllable channel */ +#define kLOCALADDR "local_addr" +#define kLOCALPORT "local_port" +#define kREMOTEADDR "remote_addr" +#define kREMOTEPORT "remote_port" +#define kCODEC "codec" +#define kPTIME "ptime" +#define kPT "pt" +#define kRFC2833PT "rfc2833_pt" +#define kMODE "mode" +#define kRATE "rate" + +/* TDM parameters understood by the controllable channel */ +#define kSPAN_ID "span" +#define kCHAN_ID "chan" + typedef struct mg_termination_s { mg_termination_type_t type; - const char *uuid; - mg_context_t *context; + const char *name; /*!< Megaco Name */ + const char *uuid; /*!< UUID of the associated FS channel, or NULL if it's not activated */ + mg_context_t *context; /*!< Context in which this termination is connected, or NULL */ + megaco_profile_t *profile; /*!< Parent MG profile */ union { struct { - const char *codec; - int ptime; - const char *remote_address; - switch_port_t remote_port; + /* The RTP termination will automatically operate as "sendonly" or "recvonly" as soon as + * one of the network addresses are NULL */ + const char *local_addr; switch_port_t local_port; - CmSdpInfoSet *local_sdp; - CmSdpInfoSet *remote_sdp; - - unsigned mode:2; - unsigned :0; + const char *remote_addr; + switch_port_t remote_port; + + int ptime; + int pt; + int rfc2833_pt; + int rate; + const char *codec; } rtp; + struct { int span; int channel; @@ -93,7 +114,7 @@ typedef struct mg_termination_s { struct mg_context_s { uint32_t context_id; - mg_termination_t terminations[MG_CONTEXT_MAX_TERMS]; + mg_termination_t *terminations[MG_CONTEXT_MAX_TERMS]; megaco_profile_t *profile; mg_context_t *next; switch_memory_pool_t *pool; @@ -102,6 +123,7 @@ struct mg_context_s { #define MG_CONTEXT_MODULO 16 #define MG_MAX_CONTEXTS 32768 + struct megaco_profile_s { char *name; switch_memory_pool_t *pool; @@ -125,6 +147,9 @@ struct megaco_profile_s { uint32_t next_context_id; uint8_t contexts_bitmap[MG_MAX_CONTEXTS/8]; /* Availability matrix, enough bits for a 32768 bitmap */ mg_context_t *contexts[MG_CONTEXT_MODULO]; + + switch_hash_t *terminations; + switch_thread_rwlock_t *terminations_rwlock; }; diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 679a9a0e22..a464beb1be 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -75,7 +75,11 @@ typedef struct { switch_port_t remote_port; switch_payload_t agreed_pt; /*XXX*/ sofia_dtmf_t dtmf_type; - + enum { + RTP_SENDONLY, + RTP_RECVONLY, + RTP_SENDRECV + } mode; } crtp_private_t; static switch_status_t channel_on_init(switch_core_session_t *session); @@ -128,8 +132,10 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi switch_channel_t *channel; char name[128]; crtp_private_t *tech_pvt = NULL; + switch_caller_profile_t *caller_profile; const char *err; + const char *local_addr = switch_event_get_header_nil(var_event, kLOCALADDR), *szlocal_port = switch_event_get_header_nil(var_event, kLOCALPORT), @@ -150,8 +156,16 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi //rfc2833_pt = !zstr(szrfc2833_pt) ? atoi(szrfc2833_pt) : 0, rate = !zstr(szrate) ? atoi(szrate) : 8000, pt = !zstr(szpt) ? atoi(szpt) : 0; - - + + if ( + ((zstr(remote_addr) || remote_port == 0) && (zstr(local_addr) || local_port == 0)) || + zstr(codec) || + zstr(szpt)) { + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing required arguments\n"); + goto fail; + } + if (!(*new_session = switch_core_session_request(crtp.endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, 0, pool))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't request session.\n"); @@ -171,10 +185,21 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi tech_pvt->agreed_pt = pt; tech_pvt->dtmf_type = DTMF_2833; /* XXX */ + if (zstr(local_addr) || local_port == 0) { + tech_pvt->mode = RTP_SENDONLY; + } else if (zstr(remote_addr) || remote_port == 0) { + tech_pvt->mode = RTP_SENDRECV; + } else { + + } + switch_core_session_set_private(*new_session, tech_pvt); + caller_profile = switch_caller_profile_clone(*new_session, outbound_profile); + switch_channel_set_caller_profile(channel, caller_profile); - snprintf(name, sizeof(name), "rtp/ctrl"); + + snprintf(name, sizeof(name), "rtp/%s", outbound_profile->destination_number); switch_channel_set_name(channel, name); switch_channel_set_state(channel, CS_INIT); @@ -251,7 +276,7 @@ static switch_status_t channel_on_init(switch_core_session_t *session) switch_channel_t *channel = switch_core_session_get_channel(session); - switch_channel_set_state(channel, CS_ROUTING); + switch_channel_set_state(channel, CS_CONSUME_MEDIA); return SWITCH_STATUS_SUCCESS; } @@ -290,7 +315,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch if (!tech_pvt->rtp_session) { goto cng; } - + if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) { switch_dtmf_t dtmf = { 0 }; switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, &dtmf); @@ -319,7 +344,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc { crtp_private_t *tech_pvt; switch_channel_t *channel; - int frames = 0, bytes = 0, samples = 0; + //int frames = 0, bytes = 0, samples = 0; channel = switch_core_session_get_channel(session); assert(channel != NULL); @@ -328,6 +353,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc assert(tech_pvt != NULL); +#if 0 if (!switch_test_flag(frame, SFF_CNG) && !switch_test_flag(frame, SFF_PROXY_PACKET)) { if (tech_pvt->read_codec.implementation->encoded_bytes_per_packet) { bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_packet; @@ -339,6 +365,8 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc } tech_pvt->timestamp_send += samples; +#endif + switch_rtp_write_frame(tech_pvt->rtp_session, frame); return SWITCH_STATUS_SUCCESS; @@ -369,6 +397,120 @@ static switch_status_t channel_send_dtmf(switch_core_session_t *session, const s static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) { + crtp_private_t *tech_pvt = NULL; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + switch (msg->message_id) { + case SWITCH_MESSAGE_INDICATE_DEBUG_AUDIO: + { + if (switch_rtp_ready(tech_pvt->rtp_session) && !zstr(msg->string_array_arg[0]) && !zstr(msg->string_array_arg[1])) { + int32_t flags = 0; + if (!strcasecmp(msg->string_array_arg[0], "read")) { + flags |= SWITCH_RTP_FLAG_DEBUG_RTP_READ; + } else if (!strcasecmp(msg->string_array_arg[0], "write")) { + flags |= SWITCH_RTP_FLAG_DEBUG_RTP_WRITE; + } else if (!strcasecmp(msg->string_array_arg[0], "both")) { + flags |= SWITCH_RTP_FLAG_DEBUG_RTP_READ | SWITCH_RTP_FLAG_DEBUG_RTP_WRITE; + } + + if (flags) { + if (switch_true(msg->string_array_arg[1])) { + switch_rtp_set_flag(tech_pvt->rtp_session, flags); + } else { + switch_rtp_clear_flag(tech_pvt->rtp_session, flags); + } + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid Options\n"); + } + } + break; + } + case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC: + if (switch_rtp_ready(tech_pvt->rtp_session)) { + rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_ONCE); + } + break; + case SWITCH_MESSAGE_INDICATE_JITTER_BUFFER: + { + if (switch_rtp_ready(tech_pvt->rtp_session)) { + int len = 0, maxlen = 0, qlen = 0, maxqlen = 50, max_drift = 0; + + if (msg->string_arg) { + char *p, *q; + const char *s; + + if (!strcasecmp(msg->string_arg, "pause")) { + switch_rtp_pause_jitter_buffer(tech_pvt->rtp_session, SWITCH_TRUE); + goto end; + } else if (!strcasecmp(msg->string_arg, "resume")) { + switch_rtp_pause_jitter_buffer(tech_pvt->rtp_session, SWITCH_FALSE); + goto end; + } else if (!strncasecmp(msg->string_arg, "debug:", 6)) { + s = msg->string_arg + 6; + if (s && !strcmp(s, "off")) { + s = NULL; + } + switch_rtp_debug_jitter_buffer(tech_pvt->rtp_session, s); + goto end; + } + + + if ((len = atoi(msg->string_arg))) { + qlen = len / (tech_pvt->read_codec.implementation->microseconds_per_packet / 1000); + if (qlen < 1) { + qlen = 3; + } + } + + if (qlen) { + if ((p = strchr(msg->string_arg, ':'))) { + p++; + maxlen = atol(p); + if ((q = strchr(p, ':'))) { + q++; + max_drift = abs(atol(q)); + } + } + } + + + if (maxlen) { + maxqlen = maxlen / (tech_pvt->read_codec.implementation->microseconds_per_packet / 1000); + } + } + + if (qlen) { + if (maxqlen < qlen) { + maxqlen = qlen * 5; + } + if (switch_rtp_activate_jitter_buffer(tech_pvt->rtp_session, qlen, maxqlen, + tech_pvt->read_codec.implementation->samples_per_packet, + tech_pvt->read_codec.implementation->samples_per_second, max_drift) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), + SWITCH_LOG_DEBUG, "Setting Jitterbuffer to %dms (%d frames) (%d max frames) (%d max drift)\n", + len, qlen, maxqlen, max_drift); + switch_channel_set_flag(tech_pvt->channel, CF_JITTERBUFFER); + if (!switch_false(switch_channel_get_variable(tech_pvt->channel, "sip_jitter_buffer_plc"))) { + switch_channel_set_flag(tech_pvt->channel, CF_JITTERBUFFER_PLC); + } + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), + SWITCH_LOG_WARNING, "Error Setting Jitterbuffer to %dms (%d frames)\n", len, qlen); + } + + } else { + switch_rtp_deactivate_jitter_buffer(tech_pvt->rtp_session); + } + } + } + break; + + default: + break; + } +end: return SWITCH_STATUS_SUCCESS; } From d6d136505365420cb3f23458e66b47dc5724a334 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Thu, 19 Jul 2012 18:06:13 -0400 Subject: [PATCH 316/822] add comments --- .../mod_media_gateway/mod_media_gateway.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index 1fe81c8825..1c9ff91b0d 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -91,17 +91,17 @@ typedef struct mg_termination_s { struct { /* The RTP termination will automatically operate as "sendonly" or "recvonly" as soon as * one of the network addresses are NULL */ - const char *local_addr; - switch_port_t local_port; + const char *local_addr; /*!< RTP Session's Local IP address */ + switch_port_t local_port; /*!< RTP Session's Local IP address */ - const char *remote_addr; - switch_port_t remote_port; + const char *remote_addr; /*!< RTP Session's Remote IP address */ + switch_port_t remote_port; /*!< RTP Session's Remote IP address */ - int ptime; - int pt; - int rfc2833_pt; - int rate; - const char *codec; + int ptime; /*!< Packetization Interval, in miliseconds. The default is 20, but it has to be set */ + int pt; /*!< Payload type */ + int rfc2833_pt; /*!< If the stream is using rfc2833 for dtmf events, this has to be set to its negotiated payload type */ + int rate; /*!< Sampling rate */ + const char *codec; /*!< Codec to use, using the freeswitch nomenclature. This could be "PCMU" for G711.U, "PCMA" for G711.A, or "G729" for g729 */ } rtp; struct { From 96fd063ae3cb9e264fdc2bd6d669078f88567ea3 Mon Sep 17 00:00:00 2001 From: Kapil Date: Fri, 20 Jul 2012 09:58:43 -0400 Subject: [PATCH 317/822] adding add/mod/sub api and alloc context during add and release context while processing subtract code --- .../mod_media_gateway/media_gateway.c | 12 +- .../media_gateway_cmd_handler.c | 786 +++++++++++++----- .../media_gateway_packages.c | 34 +- .../mod_media_gateway/media_gateway_stack.h | 3 +- .../mod_media_gateway/mod_media_gateway.c | 18 +- 5 files changed, 615 insertions(+), 238 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index b596cdb819..8ed5590e54 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -140,6 +140,8 @@ done: switch_core_session_rwunlock(session); } switch_event_destroy(&var_event); + + return SWITCH_STATUS_SUCCESS; } mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const char *prefix) @@ -154,7 +156,7 @@ mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const cha return NULL; } - + return SWITCH_STATUS_SUCCESS; } mg_termination_t *megaco_find_termination(megaco_profile_t *profile, const char *name) @@ -210,6 +212,8 @@ switch_status_t megaco_context_add_termination(mg_context_t *ctx, mg_termination switch_ivr_uuid_bridge(ctx->terminations[0]->uuid, ctx->terminations[1]->uuid); } + + return SWITCH_STATUS_SUCCESS; } @@ -226,17 +230,19 @@ switch_status_t megaco_context_sub_termination(mg_context_t *ctx, mg_termination } megaco_termination_destroy(term); + + return SWITCH_STATUS_SUCCESS; } switch_status_t megaco_context_move_termination(mg_context_t *dst, mg_termination_t *term) { - + + return SWITCH_STATUS_SUCCESS; } mg_context_t *megaco_find_context_by_suid(SuId suId, uint32_t context_id) { - mg_context_t *result = NULL; megaco_profile_t* profile = NULL; if(NULL == (profile = megaco_get_profile_by_suId(suId))){ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 7da367155a..8cc0e41268 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -29,254 +29,441 @@ const char *mg_service_change_reason[] = { * * */ -switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd) +switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd, MgMgcoContextId* new_ctxtId) { - MgMgcoContextId *ctxtId; - int descId; - MgStr errTxt; - MgMgcoInd *mgErr; - MgMgcoTermId *termId; - MgMgcoTermIdLst* termLst; - int err_code; - int i; - int j; - int fmtCnt; - MgMgcoAmmReq *cmd = &inc_cmd->u.mgCmdInd[0]->cmd.u.add; - U32 txn_id = inc_cmd->transId.val; - MgMgcoLocalDesc *local; - MgMgcoRemoteDesc *remote; - MgMgcoLclCtlDesc *locCtl; - CmSdpInfo *sdp; - MgMgcoLocalParm *lclParm; - MgMgcoTermStateDesc *tstate; - CmSdpMedFmtRtpList *fmt_list; - MgMgcoTermStateParm *tsp; - TknU8 *fmt; - CmSdpMedProtoFmts *format; + MgMgcoContextId *ctxtId; + int descId; + MgStr errTxt; + MgMgcoInd *mgErr; + MgMgcoTermId *termId; + MgMgcoTermIdLst* termLst; + int err_code; + int i; + int j; + int is_rtp = 0x00; + char rtp_term_name[32]; + int fmtCnt; + MgMgcoAmmReq *cmd = &inc_cmd->u.mgCmdInd[0]->cmd.u.add; + U32 txn_id = inc_cmd->transId.val; + MgMgcoLocalDesc *local; + MgMgcoRemoteDesc *remote; + MgMgcoLclCtlDesc *locCtl; + CmSdpInfo *sdp; + MgMgcoLocalParm *lclParm; + MgMgcoTermStateDesc *tstate; + CmSdpMedFmtRtpList *fmt_list; + MgMgcoTermStateParm *tsp; + TknU8 *fmt; + CmSdpMedProtoFmts *format; + MgMgcoMediaDesc* inc_med_desc; + MgMgcoAudRetParm *desc; + mg_context_t* mg_ctxt; - /********************************************************************/ - ctxtId = &inc_cmd->contextId; - termLst = mg_get_term_id_list(inc_cmd); - termId = termLst->terms[0]; - /* For Matt - termId->name.lcl.val - to get the termination id name */ + memset(&rtp_term_name[0], 0, 32); - /********************************************************************/ - /* Validating ADD request *******************************************/ - /*-- NULL Context & ALL Context not applicable for ADD request --*/ - if ((NOTPRSNT != ctxtId->type.pres) && - ((MGT_CXTID_ALL == ctxtId->type.val) || - (MGT_CXTID_NULL == ctxtId->type.val))) { + /********************************************************************/ + ctxtId = &inc_cmd->contextId; + termLst = mg_get_term_id_list(inc_cmd); + termId = termLst->terms[0]; + /* For Matt - termId->name.lcl.val - to get the termination id name */ - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," ADD Request processing failed, Context ALL/NULL not allowed\n"); + /********************************************************************/ + /* Validating ADD request *******************************************/ - mg_util_set_ctxt_string(&errTxt, ctxtId); - err_code = MGT_MGCO_RSP_CODE_PROT_ERROR; - goto error; - } + /*-- NULL Context & ALL Context not applicable for ADD request --*/ + if ((NOTPRSNT != ctxtId->type.pres) && + ((MGT_CXTID_ALL == ctxtId->type.val) || + (MGT_CXTID_NULL == ctxtId->type.val))) { - /********************************************************************/ - /* Allocate context - if context type is CHOOSE */ - if ((NOTPRSNT != ctxtId->type.pres) && - (MGT_CXTID_CHOOSE == ctxtId->type.val)){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," ADD Request processing failed, Context ALL/NULL not allowed\n"); - /* TODO - Matt */ - } + mg_util_set_ctxt_string(&errTxt, ctxtId); + err_code = MGT_MGCO_RSP_CODE_PROT_ERROR; + goto error; + } - /********************************************************************/ - /* Allocate new RTP termination - If term type is CHOOSE */ - if ((NOTPRSNT != termId->type.pres) && - (MGT_TERMID_CHOOSE == termId->type.val)){ + /********************************************************************/ + /* Allocate context - if context type is CHOOSE */ + if ((NOTPRSNT != ctxtId->type.pres) && + (MGT_CXTID_CHOOSE == ctxtId->type.val)){ - /* TODO - Matt */ - /* allocate rtp term and associated the same to context */ - /********************************************************************/ - }else{ /* Physical termination */ - /* TODO - Matt - associate physical termination to context */ - } - /********************************************************************/ + mg_ctxt = megaco_choose_context(mg_profile); - for (descId = 0; descId < cmd->dl.num.val; descId++) { - switch (cmd->dl.descs[descId]->type.val) { - case MGT_MEDIADESC: - { - int mediaId; - for (mediaId = 0; mediaId < cmd->dl.descs[descId]->u.media.num.val; mediaId++) { - MgMgcoMediaPar *mediaPar = cmd->dl.descs[descId]->u.media.parms[mediaId]; - switch (mediaPar->type.val) { - case MGT_MEDIAPAR_LOCAL: - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCAL"); - /* Matt - check local descriptor processing */ - local = &mediaPar->u.local; - sdp = local->sdp.info[0]; - for (i = 0; i < sdp->mediaDescSet.numComp.val; i++) { - /* sdp formats */ - for (j = 0; j < - sdp->mediaDescSet.mediaDesc[i]->field.par.numProtFmts.val; j++) - { - format = sdp->mediaDescSet.mediaDesc[i]->field.par.pflst[j]; - /* Matt - format has field for T38 also */ - if ((format->protType.pres != NOTPRSNT) && - (format->protType.val == CM_SDP_MEDIA_PROTO_RTP)) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Allocated Context[%p] with context_id[%d]\n", (void*)mg_ctxt, mg_ctxt->context_id); - /* protocol type RTP */ - fmt_list = &format->u.rtp; + /* fill Trillium Context structure with allocated context */ + MG_SET_VAL_PRES(new_ctxtId->type, MGT_CXTID_OTHER); + MG_SET_VAL_PRES(new_ctxtId->val, mg_ctxt->context_id); + } + else { + /* context already present */ + memcpy(new_ctxtId, &inc_cmd->contextId,sizeof(MgMgcoContextId)); + } - /* print format */ - for(fmtCnt = 0; fmtCnt < fmt_list->num.val; fmtCnt++){ - fmt = &fmt_list->fmts[i]->val; - if(fmt->pres == NOTPRSNT) continue; - printf("Format [%d]\n", fmt->val); - } - } - } - } + /********************************************************************/ + /* Allocate new RTP termination - If term type is CHOOSE */ + if ((NOTPRSNT != termId->type.pres) && + (MGT_TERMID_CHOOSE == termId->type.val)){ - break; - } + is_rtp = 0x01; + strcpy(rtp_term_name,"rtp/1"); - case MGT_MEDIAPAR_REMOTE: - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_REMOTE"); - /* Matt - check remote descriptor processing */ - remote = &mediaPar->u.remote; - sdp = remote->sdp.info[0]; - /* for Matt - same like local descriptor */ - break; - } + /* TODO - Matt */ + /* allocate rtp term and associated the same to context */ + /********************************************************************/ + }else{ /* Physical termination */ + /* TODO - Matt - associate physical termination to context */ + } + /********************************************************************/ - case MGT_MEDIAPAR_LOCCTL: - { - /* Matt - check Local Control descriptor processing */ - locCtl = &mediaPar->u.locCtl; - for (i = 0; i < locCtl->num.val; i++){ - lclParm = locCtl->parms[i]; - if (PRSNT_NODEF == lclParm->type.pres){ - switch(lclParm->type.val) - { - case MGT_LCLCTL_MODE: - { - /* Mode Property */ - printf("MGT_LCLCTL_MODE - Mode value [%d]\n", lclParm->u.mode.val); - break; - } - case MGT_LCLCTL_RESVAL: - { - /* Reserve Value */ - printf("MGT_LCLCTL_RESVAL: Reserve Value[%d] \n", lclParm->u.resVal.val); - break; - } - case MGT_LCLCTL_RESGRP: - { - /* Reserve group */ - printf("MGT_LCLCTL_RESGRP: Reserve Group[%d]\n", lclParm->u.resGrp.val); - break; - } - case MGT_LCLCTL_PROPPARM: - { - /* Properties (of a termination) */ - /* Matt - See how we can apply this to a termination */ - printf("MGT_LCLCTL_PROPPARM: \n"); - break; - } - default: - printf("Invalid local control descriptor type[%d]\n",lclParm->type.val); - break; - } - } - } + for (descId = 0; descId < cmd->dl.num.val; descId++) { + switch (cmd->dl.descs[descId]->type.val) { + case MGT_MEDIADESC: + { + int mediaId; + inc_med_desc = &cmd->dl.descs[descId]->u.media; + for (mediaId = 0; mediaId < cmd->dl.descs[descId]->u.media.num.val; mediaId++) { + MgMgcoMediaPar *mediaPar = cmd->dl.descs[descId]->u.media.parms[mediaId]; + switch (mediaPar->type.val) { + case MGT_MEDIAPAR_LOCAL: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCAL"); + /* Matt - check local descriptor processing */ + local = &mediaPar->u.local; + sdp = local->sdp.info[0]; + for (i = 0; i < sdp->mediaDescSet.numComp.val; i++) { + /* sdp formats */ + for (j = 0; j < + sdp->mediaDescSet.mediaDesc[i]->field.par.numProtFmts.val; j++) + { + format = sdp->mediaDescSet.mediaDesc[i]->field.par.pflst[j]; + /* Matt - format has field for T38 also */ + if ((format->protType.pres != NOTPRSNT) && + (format->protType.val == CM_SDP_MEDIA_PROTO_RTP)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCCTL"); - break; - } - case MGT_MEDIAPAR_TERMST: - { - /* Matt - apply termination state descriptor */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_TERMST"); - tstate = &mediaPar->u.tstate; - for (i = 0; i < tstate->numComp.val; i++) - { - /* Matt to see how to apply below descriptors to a termination */ - tsp = tstate->trmStPar[i]; - if (PRSNT_NODEF == tsp->type.pres) { - switch(tsp->type.val) - { - case MGT_TERMST_PROPLST: - { - /* Matt to see how to apply properties to a termination */ - /* Properties of a termination */ - printf("MGT_TERMST_PROPLST:\n"); - break; - } - case MGT_TERMST_EVTBUFCTL: - { - /* Event /buffer Control Properties */ - printf(" MGT_TERMST_EVTBUFCTL: value[%d]\n", tsp->u.evtBufCtl.val); - break; - } - case MGT_TERMST_SVCST: - { - /* Service State Properties */ - printf(" MGT_TERMST_SVCST: value[%d]\n", tsp->u.svcState.val); - break; - } - default: - printf("Invalid termination state descriptor type[%d]\n",tsp->type.val); - break; - } - } - } - break; - } - case MGT_MEDIAPAR_STRPAR: - { - MgMgcoStreamDesc *mgStream = &mediaPar->u.stream; + /* protocol type RTP */ + fmt_list = &format->u.rtp; - if (mgStream->sl.remote.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got remote stream media description:\n"); - mgco_print_sdp(&mgStream->sl.remote.sdp); - } + /* print format */ + for(fmtCnt = 0; fmtCnt < fmt_list->num.val; fmtCnt++){ + fmt = &fmt_list->fmts[i]->val; + if(fmt->pres == NOTPRSNT) continue; + printf("Format [%d]\n", fmt->val); + } + } + } + } - if (mgStream->sl.local.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got local stream media description:\n"); - mgco_print_sdp(&mgStream->sl.local.sdp); - } + break; + } - break; - } - } - } - } - case MGT_MODEMDESC: - case MGT_MUXDESC: - case MGT_REQEVTDESC: - case MGT_EVBUFDESC: - case MGT_SIGNALSDESC: - case MGT_DIGMAPDESC: - case MGT_AUDITDESC: - case MGT_STATSDESC: - break; - } - } + case MGT_MEDIAPAR_REMOTE: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_REMOTE"); + /* Matt - check remote descriptor processing */ + remote = &mediaPar->u.remote; + sdp = remote->sdp.info[0]; + /* for Matt - same like local descriptor */ + break; + } - /* Matt - to provide the response SDP structure which needs to fill in ADD command response */ + case MGT_MEDIAPAR_LOCCTL: + { + /* Matt - check Local Control descriptor processing */ + locCtl = &mediaPar->u.locCtl; + for (i = 0; i < locCtl->num.val; i++){ + lclParm = locCtl->parms[i]; + if (PRSNT_NODEF == lclParm->type.pres){ + switch(lclParm->type.val) + { + case MGT_LCLCTL_MODE: + { + /* Mode Property */ + printf("MGT_LCLCTL_MODE - Mode value [%d]\n", lclParm->u.mode.val); + break; + } + case MGT_LCLCTL_RESVAL: + { + /* Reserve Value */ + printf("MGT_LCLCTL_RESVAL: Reserve Value[%d] \n", lclParm->u.resVal.val); + break; + } + case MGT_LCLCTL_RESGRP: + { + /* Reserve group */ + printf("MGT_LCLCTL_RESGRP: Reserve Group[%d]\n", lclParm->u.resGrp.val); + break; + } + case MGT_LCLCTL_PROPPARM: + { + /* Properties (of a termination) */ + /* Matt - See how we can apply this to a termination */ + printf("MGT_LCLCTL_PROPPARM: \n"); + break; + } + default: + printf("Invalid local control descriptor type[%d]\n",lclParm->type.val); + break; + } + } + } - /* Matt - to indicate if there is any failure while processing add message */ - - /* Kapil - to return error if there is any failure based on Matt's indication */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCCTL"); + break; + } + case MGT_MEDIAPAR_TERMST: + { + /* Matt - apply termination state descriptor */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_TERMST"); + tstate = &mediaPar->u.tstate; + for (i = 0; i < tstate->numComp.val; i++) + { + /* Matt to see how to apply below descriptors to a termination */ + tsp = tstate->trmStPar[i]; + if (PRSNT_NODEF == tsp->type.pres) { + switch(tsp->type.val) + { + case MGT_TERMST_PROPLST: + { + /* Matt to see how to apply properties to a termination */ + /* Properties of a termination */ + printf("MGT_TERMST_PROPLST:\n"); + break; + } + case MGT_TERMST_EVTBUFCTL: + { + /* Event /buffer Control Properties */ + printf(" MGT_TERMST_EVTBUFCTL: value[%d]\n", tsp->u.evtBufCtl.val); + break; + } + case MGT_TERMST_SVCST: + { + /* Service State Properties */ + printf(" MGT_TERMST_SVCST: value[%d]\n", tsp->u.svcState.val); + break; + } + default: + printf("Invalid termination state descriptor type[%d]\n",tsp->type.val); + break; + } + } + } + break; + } + case MGT_MEDIAPAR_STRPAR: + { + MgMgcoStreamDesc *mgStream = &mediaPar->u.stream; - /* Kapil - to fill the response structure and call the response API to send ADD response */ - + if (mgStream->sl.remote.pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got remote stream media description:\n"); + mgco_print_sdp(&mgStream->sl.remote.sdp); + } - return SWITCH_STATUS_SUCCESS; + if (mgStream->sl.local.pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got local stream media description:\n"); + mgco_print_sdp(&mgStream->sl.local.sdp); + } + + break; + } + } + } + } + case MGT_MODEMDESC: + case MGT_MUXDESC: + case MGT_REQEVTDESC: + case MGT_EVBUFDESC: + case MGT_SIGNALSDESC: + case MGT_DIGMAPDESC: + case MGT_AUDITDESC: + case MGT_STATSDESC: + break; + } + } + + /* Matt - to provide the response SDP structure which needs to fill in ADD command response */ + + /* Matt - to indicate if there is any failure while processing add message */ + + /* Kapil - to return error if there is any failure based on Matt's indication */ + + /* Kapil - to fill the response structure and call the response API to send ADD response */ + + /*************************************************************************************************************************/ + /* sample resp code -- begin */ + { + MgMgcoCommand rsp; + int ret = 0x00; + MgMgcoTermId *out_termId; + + memset(&rsp,0, sizeof(rsp)); + + /*copy transaction-id*/ + memcpy(&rsp.transId, &inc_cmd->transId,sizeof(MgMgcoTransId)); + + /*copy context-id*/ + memcpy(&rsp.contextId, new_ctxtId,sizeof(MgMgcoContextId)); + + /*copy peer identifier */ + memcpy(&rsp.peerId, &inc_cmd->peerId,sizeof(TknU32)); + + /*fill response structue */ + if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&rsp.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ + return ret; + } + + rsp.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; + rsp.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; + rsp.u.mgCmdRsp[0]->type.val = MGT_ADD; + rsp.u.mgCmdRsp[0]->u.add.pres.pres = PRSNT_NODEF; + + if(!is_rtp){ + /* IF ADD request is for Physical term then we can simply copy incoming + * termination */ + mgUtlAllocMgMgcoTermIdLst(&rsp.u.mgCmdRsp[0]->u.add.termIdLst, &inc_cmd->u.mgCmdReq[0]->cmd.u.add.termIdLst); + +#ifdef GCP_VER_2_1 + out_termId = rsp.u.mgCmdRsp[0]->u.add.termIdLst.terms[0]; +#else + out_termId = &(rsp.u.mgCmdRsp[0]->u.add.termId); +#endif + }else{ + /* ADD request is for RTP term we need to create termination */ + + /* Grow the list of reply parameters */ + if (mgUtlGrowList((void ***)&rsp.u.mgCmdRsp[0]->u.add.termIdLst.terms, sizeof(MgMgcoTermId), + &rsp.u.mgCmdRsp[0]->u.add.termIdLst.num, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + out_termId = rsp.u.mgCmdRsp[0]->u.add.termIdLst.terms[rsp.u.mgCmdRsp[0]->u.add.termIdLst.num.val-1]; + mg_fill_mgco_termid(out_termId, (char*)rtp_term_name, strlen((char*)rtp_term_name), &rsp.u.mgCmdRsp[0]->memCp); + } + + /* Whatever Media descriptor we have received, we can copy that and then + * whatever we want we can modify the fields */ + /* Kapil - TODO - will see if there is any problem of coping the + * descriptor */ + + if (mgUtlGrowList((void ***)&rsp.u.mgCmdRsp[0]->u.add.audit.parms, sizeof(MgMgcoAudRetParm), + &rsp.u.mgCmdRsp[0]->u.add.audit.num, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + /* copy media descriptor */ + + desc = rsp.u.mgCmdRsp[0]->u.add.audit.parms[rsp.u.mgCmdRsp[0]->u.add.audit.num.val-1]; + desc->type.pres = PRSNT_NODEF; + desc->type.val = MGT_MEDIADESC; + mgUtlCpyMgMgcoMediaDesc(&desc->u.media, inc_med_desc, &rsp.u.mgCmdRsp[0]->memCp); + +#if 0 + + /* Most probably we need to add local descriptor */ + { + MgMgcoStreamDesc *stream; + MgMgcoLocalDesc *local; + MgMgcoRemoteDesc* remote; + CmSdpInfoSet *psdp; + CmSdpInfoSet *prsdp; + char* ipAddress = "192.168.1.1"; + + /* TODO - considering only one descriptor*/ + stream = &desc->u.media.parms[0]->u.stream; + local = &stream->sl.local; + remote = &stream->sl.remote; + + if(!local->pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " Local stream media not present adding it \n"); + local->pres.pres = PRSNT_NODEF; + psdp = &(local->sdp); + prsdp = &(remote->sdp); + + if (mgUtlGrowList((void ***)&psdp->info, sizeof(CmSdpInfo), + &psdp->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + psdp->info[0]->pres.pres = PRSNT_NODEF; + + /* fill version */ + memcpy(&psdp->info[0]->ver, &prsdp->info[0]->ver, sizeof(TknU16)); + + /* fill orig */ + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[0]), ipAddress[0]); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[1]), ipAddress[1]); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[2]), ipAddress[2]); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[3]), ipAddress[3]); + + /* fill session name */ + memcpy(&psdp->info[0]->sessName, &prsdp->info[0]->sessName, sizeof(TknStrOSXL)); + + /* fill info */ + MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[0]), ipAddress[0]); + MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[1]), ipAddress[1]); + MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[2]), ipAddress[2]); + MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[3]), ipAddress[3]); + + /* Fill the SDP Connection Info */ + /* "c=" line - ipaddress */ + memcpy(&psdp->info[0]->conn, &prsdp->info[0]->conn, sizeof(CmSdpConn)); + + /* fill media descriptors */ + { + CmSdpMediaDescSet* med = &psdp->mediaDescSet; + CmSdpMediaDesc* m; + + if (mgUtlGrowList((void ***)&med->mediaDesc, sizeof(CmSdpMediaDesc), + &med->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + } + + m = med->mediaDesc[0]; + + m->pres.pres = PRSNT_NODEF; + } + else { + printf("!local->pres.pres false \n"); + } + } +#endif + + + + /* We will always send one command at a time..*/ + rsp.cmdStatus.pres = PRSNT_NODEF; + rsp.cmdStatus.val = CH_CMD_STATUS_END_OF_CMD; + + rsp.cmdType.pres = PRSNT_NODEF; + rsp.cmdType.val = CH_CMD_TYPE_RSP; + + ret = sng_mgco_send_cmd( mg_profile->idx, &rsp); + + return ret; + + } + /* sample resp code -- end */ + /*************************************************************************************************************************/ + + + return SWITCH_STATUS_SUCCESS; error: - if (SWITCH_STATUS_SUCCESS == - mg_build_mgco_err_request(&mgErr, txn_id, ctxtId, err_code, &errTxt)) { - sng_mgco_send_err(mg_profile->idx, mgErr); - } - mg_free_cmd(cmd); - return SWITCH_STATUS_FALSE; + if (SWITCH_STATUS_SUCCESS == + mg_build_mgco_err_request(&mgErr, txn_id, ctxtId, err_code, &errTxt)) { + sng_mgco_send_err(mg_profile->idx, mgErr); + } + mg_free_cmd(cmd); + return SWITCH_STATUS_FALSE; } /*****************************************************************************************************************************/ @@ -341,7 +528,7 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand { switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "Modify request processing failure, CHOOSE Termination should not present in Modify\n"); - + err_code = MGT_MGCO_RSP_CODE_INVLD_IDENTIFIER; mg_util_set_term_string(&errTxt,termId); goto error; @@ -359,7 +546,11 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand /* Kapil - If there is an error - send response back to MG stack with MGT_MGCO_RSP_CODE_NO_TERM_CTXT error code*/ /********************************************************************/ - + + + /* Media Descriptor processing same as ADD command */ + + /* TODO - Will see If we can have common media_descriptor processing API which we can use for both ADD/MODIFY */ for (descId = 0; descId < cmd->dl.num.val; descId++) { switch (cmd->dl.descs[descId]->type.val) { @@ -528,11 +719,11 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand /* Matt - to provide the response SDP structure which needs to fill in Modify command response */ /* Matt - to indicate if there is any failure while processing add message */ - + /* Kapil - to return error if there is any failure based on Matt's indication */ /* Kapil - to fill the response structure and call the response API to send Modify response */ - + return SWITCH_STATUS_SUCCESS; error: @@ -544,6 +735,147 @@ error: return SWITCH_STATUS_FALSE; } +/*****************************************************************************************************************************/ + +/* +* +* Fun: handle_mg_subtract_cmd +* +* Desc: this api will handle the Subtract request received from MG stack +* +* +*/ +switch_status_t handle_mg_subtract_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd) +{ + MgMgcoContextId *ctxtId; + MgStr errTxt; + MgMgcoInd *mgErr; + MgMgcoTermId *termId; + MgMgcoTermIdLst* termLst; + int err_code; + MgMgcoAmmReq *cmd = &inc_cmd->u.mgCmdInd[0]->cmd.u.add; + U32 txn_id = inc_cmd->transId.val; + mg_context_t* mg_ctxt; + uint8_t wild = 0x00; + + wild = inc_cmd->u.mgCmdReq[0]->wild.pres; + + + /********************************************************************/ + ctxtId = &inc_cmd->contextId; + termLst = mg_get_term_id_list(inc_cmd); + termId = termLst->terms[0]; + + /********************************************************************/ + /* Validating Subtract request *******************************************/ + + /*-- NULL Context & CHOOSE Context not applicable for SUB request --*/ + if ((NOTPRSNT != ctxtId->type.pres) && + ((MGT_CXTID_CHOOSE == ctxtId->type.val) || + (MGT_CXTID_NULL == ctxtId->type.val))) { + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," SUB Request processing failed, Context CHOOSE/NULL not allowed\n"); + + mg_util_set_ctxt_string(&errTxt, ctxtId); + err_code = MGT_MGCO_RSP_CODE_PROT_ERROR; + goto error; + } + /* ROOT Termination & CHOOSE Termination not allowed */ + else if ((NOTPRSNT != termId->type.pres) && + ((MGT_TERMID_ROOT == termId->type.val) || + (MGT_TERMID_CHOOSE == termId->type.val))) { + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," SUB Request processing failed, Termination ROOT/CHOOSE not allowed\n"); + + mg_util_set_term_string(&errTxt,termId); + err_code = MGT_MGCO_RSP_CODE_INVLD_IDENTIFIER; + goto error; + } + + + /********************************************************************/ + /* Matt - TODO - check if we have terminations in the context */ + + /* Matt to indicate ERROR - If there is no terminations in requested context */ + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Received context_id[%d]\n", ctxtId->val.val); + + /*find context based on received context-id */ + mg_ctxt = megaco_get_context(mg_profile, ctxtId->val.val); + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Found Context[%p] for context_id[%d]\n", (void*)mg_ctxt, mg_ctxt->context_id); + + /* TODO - remove terminations from context....as if now there is no termination associated with Context */ + + /* release context*/ + megaco_release_context(mg_ctxt); + + /*************************************************************************************************************************/ + /* resp code -- begin */ + { + MgMgcoCommand rsp; + int ret = 0x00; + MgMgcoTermId *out_termId; + + memset(&rsp,0, sizeof(rsp)); + + /*copy transaction-id*/ + memcpy(&rsp.transId, &inc_cmd->transId, sizeof(MgMgcoTransId)); + + /*copy context-id*/ + memcpy(&rsp.contextId, &inc_cmd->contextId, sizeof(MgMgcoContextId)); + + /*copy peer identifier */ + memcpy(&rsp.peerId, &inc_cmd->peerId,sizeof(TknU32)); + + /*fill response structue */ + if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&rsp.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ + return ret; + } + + rsp.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; + rsp.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; + rsp.u.mgCmdRsp[0]->type.val = MGT_SUB; + rsp.u.mgCmdRsp[0]->u.sub.pres.pres = PRSNT_NODEF; + + if(wild){ + rsp.u.mgCmdRsp[0]->wild.pres = PRSNT_NODEF; + } + + mgUtlAllocMgMgcoTermIdLst(&rsp.u.mgCmdRsp[0]->u.add.termIdLst, &inc_cmd->u.mgCmdReq[0]->cmd.u.add.termIdLst); + +#ifdef GCP_VER_2_1 + out_termId = rsp.u.mgCmdRsp[0]->u.add.termIdLst.terms[0]; +#else + out_termId = &(rsp.u.mgCmdRsp[0]->u.add.termId); +#endif + + /* We will always send one command at a time..*/ + rsp.cmdStatus.pres = PRSNT_NODEF; + rsp.cmdStatus.val = CH_CMD_STATUS_END_OF_CMD; + + rsp.cmdType.pres = PRSNT_NODEF; + rsp.cmdType.val = CH_CMD_TYPE_RSP; + + ret = sng_mgco_send_cmd( mg_profile->idx, &rsp); + + return ret; + + } + /* sample resp code -- end */ + /*************************************************************************************************************************/ + + + return SWITCH_STATUS_SUCCESS; +error: + if (SWITCH_STATUS_SUCCESS == + mg_build_mgco_err_request(&mgErr, txn_id, ctxtId, err_code, &errTxt)) { + sng_mgco_send_err(mg_profile->idx, mgErr); + } + mg_free_cmd(cmd); + return SWITCH_STATUS_FALSE; +} + /*****************************************************************************************************************************/ /* * diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_packages.c b/src/mod/endpoints/mod_media_gateway/media_gateway_packages.c index 19c1b1dae7..0c6f17b0df 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_packages.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_packages.c @@ -47,10 +47,11 @@ MgPackage_t mg_pkg_list [] = 1, /* Version 1 */ "tdmc", /* Package name */ }, + /* TODO - not sure IF we need this */ { /* INDEX : 7 */ - MGT_PKG_QTY_ALT, /*55*/ + MGT_PKG_SEGMENTATION, 1, /* Version 1 */ - "qac", /* Package name */ + "seg", /* Package name */ }, { /* INDEX : 8 */ MGT_PKG_EN_ALERT, /*59*/ @@ -58,9 +59,9 @@ MgPackage_t mg_pkg_list [] = "alert", /* Package name */ }, { /* INDEX : 9 */ - MGT_PKG_AN_DISP, /*60*/ + MGT_PKG_CONTINUITY, /*60*/ 2, /* Version 1 */ - "andisp", /* Package name */ + "ct", /* Package name */ }, { /* INDEX : 10 */ MGT_PKG_INACTTIMER, /*69*/ @@ -97,6 +98,31 @@ MgPackage_t mg_pkg_list [] = 1, /* Version 1 */ "etsi_nr", /* Package name */ }, + { /* INDEX : 17 */ + MGT_PKG_TONEGEN, + 1, /* Version 1 */ + "tonegen", /* Package name */ + }, + { /* INDEX : 18 */ + MGT_PKG_DTMFGEN, + 1, /* Version 1 */ + "tonegen", /* Package name */ + }, + { /* INDEX : 19 */ + MGT_PKG_CALLPROGGEN, + 1, /* Version 1 */ + "tonegen", /* Package name */ + }, + { /* INDEX : 20 */ + MGT_PKG_CALLPROGDET, + 1, /* Version 1 */ + "tonedet", /* Package name */ + }, + { /* INDEX : 21 */ + MGT_PKG_ANALOG, + 1, /* Version 1 */ + "analog", /* Package name */ + }, /* Add more packages */ }; diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index d06fd727a1..b207f2e75a 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -133,7 +133,8 @@ int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, megaco_profile_t* mg_cfg, m switch_status_t mg_send_end_of_axn(SuId suId, MgMgcoTransId* transId, MgMgcoContextId* ctxtId, TknU32* peerId); void mgco_print_sdp(CmSdpInfoSet *sdp); void mg_util_set_ctxt_string ( MgStr *errTxt, MgMgcoContextId *ctxtId); -switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *cmd); +switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd, MgMgcoContextId* new_ctxtId); +switch_status_t handle_mg_subtract_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd); switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *cmd); switch_status_t mg_stack_free_mem(void* msg); switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ); diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 4336b90982..cbdf144a6a 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -424,6 +424,7 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) /*****************************************************************************************************************************/ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) { + MgMgcoContextId out_ctxt; U32 txn_id = 0x00; MgMgcoInd *mgErr; MgStr errTxt; @@ -435,6 +436,8 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) int err_code; megaco_profile_t* mg_profile; + memset(&out_ctxt,0,sizeof(out_ctxt)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: Received Command Type[%s] \n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(cmd->cmdType.val)); /* validate Transaction Id */ @@ -532,6 +535,8 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) goto error1; } + memcpy(&out_ctxt, inc_context,sizeof(MgMgcoContextId)); + switch(cmd->cmdType.val) { case CH_CMD_TYPE_IND: @@ -543,8 +548,8 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) { case MGT_ADD: { - handle_mg_add_cmd(mg_profile, cmd); - mg_send_add_rsp(suId, cmd); + handle_mg_add_cmd(mg_profile, cmd, &out_ctxt); + /*mg_send_add_rsp(suId, cmd);*/ break; } @@ -565,7 +570,8 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) case MGT_SUB: { /*MgMgcoSubAudReq *addReq = &cmdReq->cmd.u.sub;*/ - mg_send_subtract_rsp(suId, cmd); + handle_mg_subtract_cmd(mg_profile, cmd); + /*mg_send_subtract_rsp(suId, cmd);*/ break; } case MGT_SVCCHG: @@ -613,6 +619,12 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) return; } + /* END OF TXN received - means last command in txn to process. + * Send response to peer */ + if(CH_CMD_STATUS_END_OF_TXN == cmd->cmdStatus.val){ + mg_send_end_of_axn(suId, &cmd->transId, &out_ctxt, &cmd->peerId); + } + return; ctxt_error: From fffc9d4eec85964a6fa1c439b5322bc99ef0ec15 Mon Sep 17 00:00:00 2001 From: Kapil Date: Fri, 20 Jul 2012 13:25:16 -0400 Subject: [PATCH 318/822] Adding code to print SDP structure --- .../mod_media_gateway/media_gateway_utils.c | 673 +++++++++++++++++- 1 file changed, 637 insertions(+), 36 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index e536fd83bf..b4728a2bc0 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -410,55 +410,656 @@ void mg_util_set_cmd_name_string (MgStr *errTxt, MgMgcoCommand *cmd) } /*****************************************************************************************************************************/ +void mgco_print_sdp_attr_set(CmSdpAttrSet *s) +{ + int i=0x00; + if (s->numComp.pres) { + for (i = 0; i < s->numComp.val; i++) { + CmSdpAttr *a = s->attr[i]; + + if(NOTPRSNT == a->type.pres) continue; + + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Attribute Type[%d]\n",a->type.val); + + switch(a->type.val) + { + case CM_SDP_ATTR_GENERIC: + { + break; + } + case CM_SDP_ATTR_CAT: + { + break; + } + + case CM_SDP_ATTR_KEYWDS: + { + break; + } + case CM_SDP_ATTR_TOOL: + { + break; + } + case CM_SDP_ATTR_PTIME: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t PTIME = %d \n", + (NOTPRSNT != a->u.ptime.pres)?a->u.ptime.val:-1); + break; + } + case CM_SDP_ATTR_RECVONLY: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_ATTR_RECVONLY: \n"); + break; + } + case CM_SDP_ATTR_SENDRECV: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_ATTR_SENDRECV: \n"); + break; + } + case CM_SDP_ATTR_SENDONLY: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_ATTR_SENDONLY: \n"); + break; + } + case CM_SDP_ATTR_ORIENT: + { + break; + } + case CM_SDP_ATTR_TYPE: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_ATTR_TYPE: \n"); + break; + } + case CM_SDP_ATTR_CHARSET: + { + break; + } + + case CM_SDP_ATTR_SDPLANG: + { + break; + } + + case CM_SDP_ATTR_LANG: + { + break; + } + case CM_SDP_ATTR_FRAMERATE: + { + break; + } + case CM_SDP_ATTR_QUALITY: + { + break; + } + case CM_SDP_ATTR_FMTP: + { + CmSdpAttrFmtp* f = &a->u.fmtp; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_ATTR_FMTP: \n"); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Format Type = %d \n",(NOTPRSNT == f->type.pres)?f->type.val:-1); + + break; + } + case CM_SDP_ATTR_RTPMAP: + { + CmSdpAttrRtpMap* r = &a->u.rtpmap; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_ATTR_RTPMAP: \n"); + + if(NOTPRSNT != r->pres.pres){ + + /* payload type */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Payload Type = %d \n", + (NOTPRSNT != r->pay.type.pres)?r->pay.type.val:-1); + + /* payload value */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Payload Value = %d \n", + (NOTPRSNT != r->pay.val.pres)?r->pay.val.val:-1); + + /* encoding name */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Encoding Name value = %d \n", + (NOTPRSNT != r->enc.val.pres)?r->enc.val.val:-1); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Encoding Name name = %s \n", + (NOTPRSNT != r->enc.name.pres)?(char*)r->enc.name.val:"Not Present"); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Clock Rate = %d \n", + (NOTPRSNT != r->clk.pres)?r->clk.val:-1); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Encoding Parameters = %s \n", + (NOTPRSNT != r->parms.pres)?(char*)r->parms.val:"Not Present"); + } + break; + } + case CM_SDP_ATTR_INACTIVE: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_ATTR_INACTIVE: \n"); + break; + } + case CM_SDP_ATTR_CONTROL: + { + break; + } + case CM_SDP_ATTR_RANGE: + { + break; + } + case CM_SDP_ATTR_ETAG: + { + break; + } + case CM_SDP_ATTR_ATMMAP: + { + break; + } + case CM_SDP_ATTR_EECID: + { + break; + } + case CM_SDP_ATTR_AALTYPE: + { + break; + } + case CM_SDP_ATTR_SILENCESUPP: + { + break; + } + case CM_SDP_ATTR_ECAN: + { + break; + } + case CM_SDP_ATTR_GC: + { + break; + } + case CM_SDP_ATTR_PROFILEDESC: + { + break; + } + case CM_SDP_ATTR_VSEL: + { + break; + } + case CM_SDP_ATTR_DSEL: + { + break; + } + case CM_SDP_ATTR_FSEL: + { + break; + } + case CM_SDP_ATTR_CAPABILITY: + { + break; + } + case CM_SDP_ATTR_QOSCLASS: + { + break; + } + case CM_SDP_ATTR_BCOB: + { + break; + } + case CM_SDP_ATTR_STC: + { + break; + } + case CM_SDP_ATTR_UPCC: + { + break; + } + case CM_SDP_ATTR_ATMQOSPARMS: + { + break; + } + case CM_SDP_ATTR_AAL2QOSFPARMS: + { + break; + } + case CM_SDP_ATTR_AAL2QOSBPARMS: + { + break; + } + case CM_SDP_ATTR_ATMTRFCDESC: + { + break; + } + case CM_SDP_ATTR_AAL2FTRFCDESC: + { + break; + } + case CM_SDP_ATTR_AAL2BTRFCDESC: + { + break; + } + case CM_SDP_ATTR_ABRPARMS: + { + break; + } + case CM_SDP_ATTR_CLKREC: + { + break; + } + case CM_SDP_ATTR_FEC: + { + break; + } + case CM_SDP_ATTR_PRTFL: + { + break; + } + case CM_SDP_ATTR_BEARERTYPE: + { + break; + } + case CM_SDP_ATTR_STRUCTURE: + { + break; + } + case CM_SDP_ATTR_SBC: + { + break; + } + case CM_SDP_ATTR_CPSSDUSIZE: + { + break; + } + case CM_SDP_ATTR_AAL2CPS: + { + break; + } + case CM_SDP_ATTR_ANYCAST: + { + break; + } + case CM_SDP_ATTR_WTP: + { + break; + } + case CM_SDP_ATTR_CACHE: + { + break; + } + case CM_SDP_ATTR_CHAIN: + { + break; + } + case CM_SDP_ATTR_PHONECONTEXT: + { + break; + } + case CM_SDP_ATTR_CLIR: + { + break; + } + case CM_SDP_ATTR_DIRECTION: + { + break; + } + case CM_SDP_ATTR_MAXPTIME: + { + break; + } + case CM_SDP_ATTR_T38_FAX: + { + break; + } + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Not supported Type[%d]\n",a->type.val); + break; + } + } + }else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "a-line not present \n"); + } + + +} + +void mgco_print_sdp_c_line(CmSdpConn *s) +{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "********** SDP connection line ****** \n"); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Net Type = %d \n", + (NOTPRSNT != s->netType.type.pres)?s->netType.type.val:-1); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Address Type = %d \n", + (NOTPRSNT != s->addrType.pres)?s->addrType.val:-1); + + if (s->addrType.pres && s->addrType.val == CM_SDP_ADDR_TYPE_IPV4 && + s->netType.type.val == CM_SDP_NET_TYPE_IN && + s->u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) { + + if (s->u.ip4.addrType.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Address: %d.%d.%d.%d\n", + s->u.ip4.u.uniIp.b[0].val, + s->u.ip4.u.uniIp.b[1].val, + s->u.ip4.u.uniIp.b[2].val, + s->u.ip4.u.uniIp.b[3].val); + } + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "**************** \n"); +} + +void mgco_print_CmSdpU8OrNil(CmSdpU8OrNil* p) +{ + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,"CmSdpU8OrNil: Type = %d \n", (NOTPRSNT != p->type.pres)?p->type.val:-1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,"CmSdpU8OrNil: Value = %d \n", (NOTPRSNT != p->val.pres)?p->val.val:-1); +} + +void mgco_print_sdp_media_param(CmSdpMedPar *s) +{ + int i=0x00; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "***** Media Parameter *********** \n"); + if (s->numProtFmts.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Media Formats = %d \n", s->numProtFmts.val); + for (i = 0; i < s->numProtFmts.val; i++) { + CmSdpMedProtoFmts *a = s->pflst[i]; + + /*Prot*/ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " Proto Type = %d \n", (NOTPRSNT != a->prot.type.pres)?a->prot.type.val:-1); + switch(a->prot.type.val) + { + case CM_SDP_MEDIA_PROTO_UNKNOWN: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " Proto Type Unknown , name = %s \n", + (NOTPRSNT != a->prot.u.name.pres)?(char*)a->prot.u.name.val:"Not Present "); + break; + } + case CM_SDP_MEDIA_PROTO_RTP: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " Proto Type RTP , subtype = %d \n", + (NOTPRSNT != a->prot.u.subtype.type.pres)?a->prot.u.subtype.type.val: -1); + break; + } + } + + /*repeated from "prot" field */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " Proto Type = %d \n", + (NOTPRSNT != a->protType.pres)?a->protType.val: -1); + + switch(a->protType.val) + { + case CM_SDP_MEDIA_PROTO_RTP: + { + CmSdpMedFmtRtpList* r = &a->u.rtp; + int i = 0x00; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " CM_SDP_MEDIA_PROTO_RTP: \n"); + if(NOTPRSNT != r->num.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " Number of Formats[%d] \n", r->num.val); + + for(i=0;inum.val;i++){ + mgco_print_CmSdpU8OrNil(r->fmts[i]); + } + } + break; + } + + case CM_SDP_UDPTL_FMT_T38: + { + /*CmSdpMedFmtUdptlList* t = &a->u.t38;*/ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " CM_SDP_UDPTL_FMT_T38: \n"); + break; + } + default: + break; + } + } + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "**************** \n"); +} + void mgco_print_sdp(CmSdpInfoSet *sdp) { - int i; + int i; - if (sdp->numComp.pres == NOTPRSNT) { - return; - } + if (sdp->numComp.pres == NOTPRSNT) { + return; + } - for (i = 0; i < sdp->numComp.val; i++) { - CmSdpInfo *s = sdp->info[i]; - int mediaId; + for (i = 0; i < sdp->numComp.val; i++) { + CmSdpInfo *s = sdp->info[i]; + int mediaId; - if (s->conn.addrType.pres && s->conn.addrType.val == CM_SDP_ADDR_TYPE_IPV4 && - s->conn.netType.type.val == CM_SDP_NET_TYPE_IN && - s->conn.u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) { + /************************************************************************************************************************/ + /* info presence check */ + if(NOTPRSNT == s->pres.pres) continue; - if (s->conn.u.ip4.addrType.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Address: %d.%d.%d.%d\n", - s->conn.u.ip4.u.uniIp.b[0].val, - s->conn.u.ip4.u.uniIp.b[1].val, - s->conn.u.ip4.u.uniIp.b[2].val, - s->conn.u.ip4.u.uniIp.b[3].val); - } - if (s->attrSet.numComp.pres) { - for (mediaId = 0; mediaId < s->attrSet.numComp.val; mediaId++) { - /*CmSdpAttr *a = s->attrSet.attr[mediaId];*/ + /************************************************************************************************************************/ + /* Version */ + if(NOTPRSNT != s->ver.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " SDP Version = %d \n", s->ver.val); + } + + /************************************************************************************************************************/ + /* Orig */ + if(NOTPRSNT != s->orig.pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "********** SDP orig line ****** \n \t Type = %d \n", s->orig.type.val); + + if(NOTPRSNT != s->orig.orig.pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t User Name = %s \n", + (NOTPRSNT != s->orig.orig.usrName.pres)?(char*)s->orig.orig.usrName.val:"Not Present"); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Id = %s \n", + (NOTPRSNT != s->orig.orig.sessId.pres)?(char*)s->orig.orig.sessId.val:"Not Present"); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Version = %s \n", + (NOTPRSNT != s->orig.orig.sessVer.pres)?(char*)s->orig.orig.sessVer.val:"Not Present"); + + /* sdpAddr */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Net Type = %d \n", + (NOTPRSNT != s->orig.orig.sdpAddr.netType.type.pres)?s->orig.orig.sdpAddr.netType.type.val:-1); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Address Type = %d \n", + (NOTPRSNT != s->orig.orig.sdpAddr.addrType.pres)?s->orig.orig.sdpAddr.addrType.val:-1); + + /* print IPV4 address */ + if (s->orig.orig.sdpAddr.addrType.pres && s->orig.orig.sdpAddr.addrType.val == CM_SDP_ADDR_TYPE_IPV4 && + s->orig.orig.sdpAddr.netType.type.val == CM_SDP_NET_TYPE_IN && + s->orig.orig.sdpAddr.u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) { + + if (s->orig.orig.sdpAddr.u.ip4.addrType.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Address: %d.%d.%d.%d\n", + s->orig.orig.sdpAddr.u.ip4.u.ip.b[0].val, + s->orig.orig.sdpAddr.u.ip4.u.ip.b[1].val, + s->orig.orig.sdpAddr.u.ip4.u.ip.b[2].val, + s->orig.orig.sdpAddr.u.ip4.u.ip.b[3].val); + } + + }else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t O-line not present \n"); + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "********** ****** \n"); + } + } else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t O-line not present \n"); + } + /************************************************************************************************************************/ + /* Session Name (s = line) */ + + if(NOTPRSNT != s->sessName.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Name = %s \n", s->sessName.val); + } else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t s-line not present \n"); + } + + /************************************************************************************************************************/ + /* Session Info(i= line) */ + + if(NOTPRSNT != s->info.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Info = %s \n", s->info.val); + } else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t i-line not present \n"); + } + + /************************************************************************************************************************/ + /* Session Uri */ + + if(NOTPRSNT != s->uri.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Uri = %s \n", s->uri.val); + } else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t uri not present \n"); + } + + /************************************************************************************************************************/ + /* E-Mail */ + /* TODO */ - } - } + /************************************************************************************************************************/ + /* Phone */ + /* TODO */ - if (s->mediaDescSet.numComp.pres) { - for (mediaId = 0; mediaId < s->mediaDescSet.numComp.val; mediaId++) { - CmSdpMediaDesc *desc = s->mediaDescSet.mediaDesc[mediaId]; - if (desc->field.mediaType.val == CM_SDP_MEDIA_AUDIO && - desc->field.id.type.val == CM_SDP_VCID_PORT && - desc->field.id.u.port.type.val == CM_SDP_PORT_INT && - desc->field.id.u.port.u.portInt.port.type.val == CM_SDP_SPEC) { - int port = desc->field.id.u.port.u.portInt.port.val.val; + /************************************************************************************************************************/ + /* connection line */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Port: %d\n", port); + mgco_print_sdp_c_line(&s->conn); + /************************************************************************************************************************/ + /* Bandwidth */ + /* TODO */ - } - } - } - } - } + /************************************************************************************************************************/ + /* SDP Time (t= line)*/ + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "*** t-line **************** \n"); + if(NOTPRSNT != s->sdpTime.pres.pres) { + if(NOTPRSNT != s->sdpTime.sdpOpTimeSet.numComp.pres) { + int i = 0x00; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "SDP op time present with total component[%d]\n", s->sdpTime.sdpOpTimeSet.numComp.val); + for (i = 0;isdpTime.sdpOpTimeSet.numComp.val;i++){ + CmSdpOpTime* t = s->sdpTime.sdpOpTimeSet.sdpOpTime[i]; + if(NOTPRSNT == t->pres.pres) continue; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Start Time = %s \n", + (NOTPRSNT != t->startTime.pres)?(char*)t->startTime.val:"Not Present"); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Stop Time = %s \n", + (NOTPRSNT != t->stopTime.pres)?(char*)t->stopTime.val:"Not Present"); + + /*repeat time repFieldSet */ + + if(NOTPRSNT != t->repFieldSet.numComp.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "SDP repeat time present with total component[%d]\n", + t->repFieldSet.numComp.val); + + /*TODO - print repeat fields */ + }else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "SDP repeat time not present \n"); + } + } /* sdpOpTimeSet.numComp for loop -- end */ + }else{/*sdpOpTimeSet.numComp.pres if -- end */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "SDP op time not present \n"); + } + + /*TODO - zoneAdjSet */ + }else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "t-line not present \n"); + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "**************** \n"); + + + /************************************************************************************************************************/ + /* key type (k= line)*/ + + if(NOTPRSNT != s->keyType.pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Key Type = %d \n", + (NOTPRSNT != s->keyType.keyType.pres)?s->keyType.keyType.val:-1); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Key Data = %s \n", + (NOTPRSNT != s->keyType.key_data.pres)?(char*)s->keyType.key_data.val:"Not Present"); + }else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "k-line not present \n"); + } + + /************************************************************************************************************************/ + /* Attribute Set */ + + mgco_print_sdp_attr_set(&s->attrSet); + + /************************************************************************************************************************/ + /* Media Descriptor Set */ + + if (s->mediaDescSet.numComp.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "****** Media Descriptor Set present with numComp[%d]\n", s->mediaDescSet.numComp.val); + for (mediaId = 0; mediaId < s->mediaDescSet.numComp.val; mediaId++) { + CmSdpMediaDesc *desc = s->mediaDescSet.mediaDesc[mediaId]; + + if(NOTPRSNT == desc->pres.pres) continue; + + /* Media Field */ + { + CmSdpMediaField* f = &desc->field; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Media Type = %d \n",(NOTPRSNT == f->mediaType.pres)?f->mediaType.val:-1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Media = %s \n",(NOTPRSNT == f->media.pres)?(char*)f->media.val:"Not Present"); + /* Channel ID */ + if(NOTPRSNT != f->id.type.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t VcId Type = %d \n", f->id.type.val); + switch(f->id.type.val){ + case CM_SDP_VCID_PORT: + { + CmSdpPort *p = &f->id.u.port; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "CM_SDP_VCID_PORT:\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t SDP port type = %d \n", (NOTPRSNT == p->type.pres)?p->type.val:-1); + switch(p->type.val) + { + case CM_SDP_PORT_INT: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_PORT_INT: SDP port = %d type = %d \n", p->u.portInt.port.val.val, p->u.portInt.port.type.val); + break; + } + case CM_SDP_PORT_VPCID: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_PORT_VPCID: \n"); + break; + } + default: + break; + } + break; + } + default: + break; + } + } + mgco_print_sdp_media_param(&f->par); + } + + /*info */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Info = %s \n",(NOTPRSNT == desc->info.pres)?(char*)desc->info.val:"Not Present"); + + /*connection set */ + { + int cnt=0x00; + if(NOTPRSNT != desc->connSet.numComp.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Number of Connection component[%d]\n",desc->connSet.numComp.val); + for(cnt=0;cntconnSet.numComp.val;cnt++){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "************************\n"); + mgco_print_sdp_c_line(desc->connSet.connSet[cnt]); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "************************\n"); + } + } + } + + /* attribute set */ + mgco_print_sdp_attr_set(&desc->attrSet); + + + if (desc->field.mediaType.val == CM_SDP_MEDIA_AUDIO && + desc->field.id.type.val == CM_SDP_VCID_PORT && + desc->field.id.u.port.type.val == CM_SDP_PORT_INT && + desc->field.id.u.port.u.portInt.port.type.val == CM_SDP_SPEC) { + int port = desc->field.id.u.port.u.portInt.port.val.val; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Port: %d\n", port); + + } + } + } + } } /*****************************************************************************************************************************/ From dd633cfbfd47f9afcdc0206fdc3a41a8c4024762 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Fri, 20 Jul 2012 14:33:36 -0400 Subject: [PATCH 319/822] Pre-fill values for rtp terms (local address + reserved rtp port). Add functions to pick rtp term ids, add a memory pool in the termination struct. --- .../mod_media_gateway/media_gateway.c | 54 +++++++++++++++++++ .../mod_media_gateway/mod_media_gateway.h | 50 +++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index b596cdb819..3a5e7bbb8c 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -145,16 +145,40 @@ done: mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const char *prefix) { mg_termination_type_t termtype; + switch_memory_pool_t *pool; + mg_termination_t *term = NULL; + char name[100]; + int term_id; /* Check the termination type by prefix */ if (strncasecmp(prefix, profile->rtp_termination_id_prefix, strlen(profile->rtp_termination_id_prefix)) == 0) { termtype = MG_TERM_RTP; + term_id = mg_rtp_request_id(profile); + switch_snprintf(name, sizeof name, "%s/%d", profile->rtp_termination_id_prefix, term_id); } else { /* TODO Math: look through TDM channels */ return NULL; } + switch_core_new_memory_pool(&pool); + term = switch_core_alloc(pool, sizeof *term); + term->pool = pool; + term->type = termtype; + if (termtype == MG_TERM_RTP) { + /* Fill in local address and reserve an rtp port */ + term->u.rtp.local_addr = profile->my_ipaddr; + term->u.rtp.local_port = switch_rtp_request_port(term->u.rtp.local_addr); + term->u.rtp.codec = megaco_codec_str(profile->default_codec); + term->u.rtp.term_id = term_id; + term->name = switch_core_strdup(term->pool, name); + } else if (termtype == MG_TERM_TDM) { + /* XXX initialize tdm-specific fields */ + } + + switch_core_hash_insert_wrlock(profile->terminations, term->name, term, profile->terminations_rwlock); + + return term; } mg_termination_t *megaco_find_termination(megaco_profile_t *profile, const char *name) @@ -177,7 +201,12 @@ void megaco_termination_destroy(mg_termination_t *term) term->uuid = NULL; } + if (term->type == MG_TERM_RTP && term->u.rtp.local_port != 0) { + switch_rtp_release_port(term->u.rtp.local_addr, term->u.rtp.local_port); + } + switch_core_hash_delete_wrlock(term->profile->terminations, term->name, term->profile->terminations_rwlock); + switch_core_destroy_memory_pool(&term->pool); } switch_status_t megaco_context_add_termination(mg_context_t *ctx, mg_termination_t *term) @@ -210,6 +239,8 @@ switch_status_t megaco_context_add_termination(mg_context_t *ctx, mg_termination switch_ivr_uuid_bridge(ctx->terminations[0]->uuid, ctx->terminations[1]->uuid); } + + return SWITCH_STATUS_SUCCESS; } @@ -226,6 +257,8 @@ switch_status_t megaco_context_sub_termination(mg_context_t *ctx, mg_termination } megaco_termination_destroy(term); + + return SWITCH_STATUS_SUCCESS; } @@ -343,6 +376,27 @@ void megaco_release_context(mg_context_t *ctx) switch_thread_rwlock_unlock(profile->contexts_rwlock); } +uint32_t mg_rtp_request_id(megaco_profile_t *profile) +{ + if (profile->rtpid_next >= MG_MAX_RTPID || profile->rtpid_next == 0) { + profile->rtpid_next = 1; + } + + for (; profile->rtpid_next < MG_MAX_RTPID; profile->rtpid_next++) { + if ((profile->rtpid_bitmap[profile->rtpid_next % 8] & (1 << (profile->rtpid_next / 8))) == 0) { + profile->rtpid_bitmap[profile->rtpid_next % 8] |= 1 << (profile->rtpid_next / 8); + return profile->rtpid_next; + } + } + + return 0; +} + +void mg_rtp_release_id(megaco_profile_t *profile, uint32_t id) +{ + profile->rtpid_bitmap[id % 8] &= ~(1 << (id / 8)); +} + switch_status_t megaco_profile_start(const char *profilename) { switch_memory_pool_t *pool; diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index 1c9ff91b0d..e62f59bf09 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -40,6 +40,9 @@ typedef enum { MEGACO_CODEC_G729, MEGACO_CODEC_G723_1, MEGACO_CODEC_ILBC, + + /* Nothing below this line */ + MEGACO_CODEC_INVALID = 0xFFFFFFFF } megaco_codec_t; typedef struct mg_peer_profile_s{ @@ -81,6 +84,7 @@ typedef struct mg_context_s mg_context_t; #define kCHAN_ID "chan" typedef struct mg_termination_s { + switch_memory_pool_t *pool; mg_termination_type_t type; const char *name; /*!< Megaco Name */ const char *uuid; /*!< UUID of the associated FS channel, or NULL if it's not activated */ @@ -102,6 +106,7 @@ typedef struct mg_termination_s { int rfc2833_pt; /*!< If the stream is using rfc2833 for dtmf events, this has to be set to its negotiated payload type */ int rate; /*!< Sampling rate */ const char *codec; /*!< Codec to use, using the freeswitch nomenclature. This could be "PCMU" for G711.U, "PCMA" for G711.A, or "G729" for g729 */ + int term_id; } rtp; struct { @@ -122,6 +127,7 @@ struct mg_context_s { #define MG_CONTEXT_MODULO 16 #define MG_MAX_CONTEXTS 32768 +#define MG_MAX_RTPID 32768 struct megaco_profile_s { @@ -148,10 +154,47 @@ struct megaco_profile_s { uint8_t contexts_bitmap[MG_MAX_CONTEXTS/8]; /* Availability matrix, enough bits for a 32768 bitmap */ mg_context_t *contexts[MG_CONTEXT_MODULO]; + uint8_t rtpid_bitmap[MG_MAX_CONTEXTS/8]; + uint32_t rtpid_next; switch_hash_t *terminations; switch_thread_rwlock_t *terminations_rwlock; }; +static inline const char *megaco_codec_str(megaco_codec_t codec) +{ + switch (codec) { + case MEGACO_CODEC_PCMU: + return "PCMU"; + case MEGACO_CODEC_PCMA: + return "PCMA"; + case MEGACO_CODEC_G729: + return "G729"; + case MEGACO_CODEC_G723_1: + return "G723"; /* XXX double check this */ + case MEGACO_CODEC_ILBC: + return "ILBC"; + case MEGACO_CODEC_INVALID: + default: + return NULL; + } +} + +static inline megaco_codec_t megaco_codec_parse(const char *codec) { + if (!strcasecmp(codec, "PCMU")) { + return MEGACO_CODEC_PCMU; + } else if (!strcasecmp(codec, "PCMA")) { + return MEGACO_CODEC_PCMA; + } else if (!strcasecmp(codec, "G729")) { + return MEGACO_CODEC_G729; + } else if (!strcasecmp(codec, "G723")) { + return MEGACO_CODEC_G723_1; + } else if (!strcasecmp(codec, "ILBC")) { + return MEGACO_CODEC_ILBC; + } else { + return MEGACO_CODEC_INVALID; + } +} + megaco_profile_t *megaco_profile_locate(const char *name); mg_peer_profile_t *megaco_peer_profile_locate(const char *name); @@ -160,10 +203,17 @@ void megaco_profile_release(megaco_profile_t *profile); switch_status_t megaco_profile_start(const char *profilename); switch_status_t megaco_profile_destroy(megaco_profile_t **profile); +uint32_t mg_rtp_request_id(megaco_profile_t *profile); +void mg_rtp_release_id(megaco_profile_t *profile, uint32_t id); + mg_context_t *megaco_get_context(megaco_profile_t *profile, uint32_t context_id); mg_context_t *megaco_choose_context(megaco_profile_t *profile); void megaco_release_context(mg_context_t *ctx); +mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const char *prefix); +mg_termination_t *megaco_find_termination(megaco_profile_t *profile, const char *name); +void megaco_termination_destroy(mg_termination_t *term); + megaco_profile_t* megaco_get_profile_by_suId(SuId suId); mg_context_t *megaco_find_context_by_suid(SuId suId, uint32_t context_id); From 63c53a858b5e5fb0247b500a1c1f3ebd2b62c0d6 Mon Sep 17 00:00:00 2001 From: Kapil Date: Mon, 23 Jul 2012 12:18:14 -0400 Subject: [PATCH 320/822] fixing issues found during seagull testing and add single common descriptors api --- .../mod_media_gateway/media_gateway.c | 1 + .../media_gateway_cmd_handler.c | 736 ++++++++++-------- .../mod_media_gateway/media_gateway_stack.h | 9 + .../mod_media_gateway/mod_media_gateway.c | 15 +- .../mod_media_gateway/mod_media_gateway.h | 3 +- 5 files changed, 434 insertions(+), 330 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 75687c2cf6..b0db09c6ab 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -166,6 +166,7 @@ mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const cha term = switch_core_alloc(pool, sizeof *term); term->pool = pool; term->type = termtype; + term->active_events = NULL; if (termtype == MG_TERM_RTP) { /* Fill in local address and reserve an rtp port */ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 8cc0e41268..b544f853f7 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -23,108 +23,85 @@ const char *mg_service_change_reason[] = { /* * -* Fun: handle_mg_add_cmd +* Fun: mg_prc_descriptors * -* Desc: this api will handle the ADD request received from MG stack +* Desc: this api will process the descriptors received from MG stack * * */ -switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd, MgMgcoContextId* new_ctxtId) +switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand *cmd, mg_termination_t* term) { - MgMgcoContextId *ctxtId; - int descId; - MgStr errTxt; - MgMgcoInd *mgErr; - MgMgcoTermId *termId; - MgMgcoTermIdLst* termLst; - int err_code; - int i; - int j; - int is_rtp = 0x00; - char rtp_term_name[32]; - int fmtCnt; - MgMgcoAmmReq *cmd = &inc_cmd->u.mgCmdInd[0]->cmd.u.add; - U32 txn_id = inc_cmd->transId.val; - MgMgcoLocalDesc *local; - MgMgcoRemoteDesc *remote; - MgMgcoLclCtlDesc *locCtl; - CmSdpInfo *sdp; - MgMgcoLocalParm *lclParm; - MgMgcoTermStateDesc *tstate; - CmSdpMedFmtRtpList *fmt_list; - MgMgcoTermStateParm *tsp; - TknU8 *fmt; CmSdpMedProtoFmts *format; - MgMgcoMediaDesc* inc_med_desc; - MgMgcoAudRetParm *desc; - mg_context_t* mg_ctxt; + TknU8 *fmt; + CmSdpMedFmtRtpList *fmt_list; + MgMgcoTermStateDesc *tstate; + int fmtCnt; + int i; + int descId = 0x00; + int j; + MgMgcoLocalParm *lclParm; + CmSdpInfo *sdp; + MgMgcoLclCtlDesc *locCtl; + MgMgcoTermStateParm *tsp; + MgMgcoAmmReq* desc = NULL; + MgMgcoLocalDesc *local; + MgMgcoRemoteDesc* remote; - memset(&rtp_term_name[0], 0, 32); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"cmd->cmdType.val[%d]\n",cmd->cmdType.val); - - /********************************************************************/ - ctxtId = &inc_cmd->contextId; - termLst = mg_get_term_id_list(inc_cmd); - termId = termLst->terms[0]; - /* For Matt - termId->name.lcl.val - to get the termination id name */ - - /********************************************************************/ - /* Validating ADD request *******************************************/ - - /*-- NULL Context & ALL Context not applicable for ADD request --*/ - if ((NOTPRSNT != ctxtId->type.pres) && - ((MGT_CXTID_ALL == ctxtId->type.val) || - (MGT_CXTID_NULL == ctxtId->type.val))) { - - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," ADD Request processing failed, Context ALL/NULL not allowed\n"); - - mg_util_set_ctxt_string(&errTxt, ctxtId); - err_code = MGT_MGCO_RSP_CODE_PROT_ERROR; - goto error; + switch (cmd->cmdType.val) + { + case CH_CMD_TYPE_IND: + switch(cmd->u.mgCmdInd[0]->cmd.type.val) + { + case MGT_ADD: + { + desc = &cmd->u.mgCmdInd[0]->cmd.u.add; + break; + } + case MGT_MOVE: + { + desc = &cmd->u.mgCmdInd[0]->cmd.u.move; + break; + } + case MGT_MODIFY: + { + desc = &cmd->u.mgCmdInd[0]->cmd.u.mod; + break; + } + default: + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Invalid cmd.type[%d] for descriptor processing \n", + cmd->u.mgCmdInd[0]->cmd.type.val); + return SWITCH_STATUS_FALSE; + } + break; + default: + { + return SWITCH_STATUS_FALSE; + } } - /********************************************************************/ - /* Allocate context - if context type is CHOOSE */ - if ((NOTPRSNT != ctxtId->type.pres) && - (MGT_CXTID_CHOOSE == ctxtId->type.val)){ - - mg_ctxt = megaco_choose_context(mg_profile); - - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Allocated Context[%p] with context_id[%d]\n", (void*)mg_ctxt, mg_ctxt->context_id); - - /* fill Trillium Context structure with allocated context */ - MG_SET_VAL_PRES(new_ctxtId->type, MGT_CXTID_OTHER); - MG_SET_VAL_PRES(new_ctxtId->val, mg_ctxt->context_id); - } - else { - /* context already present */ - memcpy(new_ctxtId, &inc_cmd->contextId,sizeof(MgMgcoContextId)); + if(NULL == desc){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"No Valid descriptor found \n"); + return SWITCH_STATUS_FALSE; } - /********************************************************************/ - /* Allocate new RTP termination - If term type is CHOOSE */ - if ((NOTPRSNT != termId->type.pres) && - (MGT_TERMID_CHOOSE == termId->type.val)){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"descriptors[%d] found in-coming megaco request \n", desc->dl.num.val); - is_rtp = 0x01; - strcpy(rtp_term_name,"rtp/1"); - - /* TODO - Matt */ - /* allocate rtp term and associated the same to context */ - /********************************************************************/ - }else{ /* Physical termination */ - /* TODO - Matt - associate physical termination to context */ + if(NOTPRSNT == desc->dl.num.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"No descriptor found in-coming megaco request \n"); + return SWITCH_STATUS_SUCCESS; } - /********************************************************************/ - for (descId = 0; descId < cmd->dl.num.val; descId++) { - switch (cmd->dl.descs[descId]->type.val) { + + for (descId = 0; descId < desc->dl.num.val; descId++) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"descriptors[%d] type in-coming megaco request \n", desc->dl.descs[descId]->type.val); + switch (desc->dl.descs[descId]->type.val) { case MGT_MEDIADESC: { int mediaId; - inc_med_desc = &cmd->dl.descs[descId]->u.media; - for (mediaId = 0; mediaId < cmd->dl.descs[descId]->u.media.num.val; mediaId++) { - MgMgcoMediaPar *mediaPar = cmd->dl.descs[descId]->u.media.parms[mediaId]; + for (mediaId = 0; mediaId < desc->dl.descs[descId]->u.media.num.val; mediaId++) { + MgMgcoMediaPar *mediaPar = desc->dl.descs[descId]->u.media.parms[mediaId]; switch (mediaPar->type.val) { case MGT_MEDIAPAR_LOCAL: { @@ -269,19 +246,160 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i } } } + break; + } + case MGT_REQEVTDESC: + { + MgMgcoReqEvtDesc* evt = &desc->dl.descs[descId]->u.evts; + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," Requested Event descriptor\n"); + + /* If we receive events from MGC , means clear any ongoing events */ + /* as such we dont apply any events to term, so for us (as of now) clear events means clear active_events structure*/ + + if(NULL != term->active_events){ + mgUtlDelMgMgcoReqEvtDesc(term->active_events); + free(term->active_events); + term->active_events = NULL; + } + + term->active_events = malloc(sizeof(*term->active_events)); + + /* copy requested event */ + if(RFAILED == mgUtlCpyMgMgcoReqEvtDesc(term->active_events, evt, NULLP)){ + free(term->active_events); + term->active_events = NULL; + return SWITCH_STATUS_FALSE; + } + + /* print Requested event descriptor */ + mgAccEvntPrntMgMgcoReqEvtDesc(term->active_events, stdout); + + /* TODO - We can check for it/ito package*/ + + break; + } + case MGT_SIGNALSDESC: + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," Requested Signal descriptor\n"); + break; } case MGT_MODEMDESC: case MGT_MUXDESC: - case MGT_REQEVTDESC: case MGT_EVBUFDESC: - case MGT_SIGNALSDESC: case MGT_DIGMAPDESC: case MGT_AUDITDESC: case MGT_STATSDESC: break; + } } + return SWITCH_STATUS_SUCCESS; +} + + +/*****************************************************************************************************************************/ + +/* +* +* Fun: handle_mg_add_cmd +* +* Desc: this api will handle the ADD request received from MG stack +* +* +*/ +switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd, MgMgcoContextId* new_ctxtId) +{ + switch_status_t ret; + MgMgcoContextId *ctxtId; + MgStr errTxt; + MgMgcoInd *mgErr; + MgMgcoTermId *termId; + MgMgcoTermIdLst* termLst; + int err_code; + int is_rtp = 0x00; + char rtp_term_name[32]; + MgMgcoAmmReq *cmd = &inc_cmd->u.mgCmdInd[0]->cmd.u.add; + U32 txn_id = inc_cmd->transId.val; + mg_termination_t* term = NULL; + MgMgcoMediaDesc* inc_med_desc; + MgMgcoAudRetParm *desc; + mg_context_t* mg_ctxt; + MgMgcoStreamDesc *stream; + MgMgcoLocalDesc *local; + MgMgcoRemoteDesc* remote; + CmSdpInfoSet *psdp; + CmSdpInfoSet *prsdp; + char* ipAddress = "192.168.1.1"; + + /* TODO - Kapil dummy line , will need to add with proper code */ + inc_med_desc = &cmd->dl.descs[0]->u.media; + + memset(&rtp_term_name[0], 0, 32); + + + /********************************************************************/ + ctxtId = &inc_cmd->contextId; + termLst = mg_get_term_id_list(inc_cmd); + termId = termLst->terms[0]; + /* For Matt - termId->name.lcl.val - to get the termination id name */ + + /********************************************************************/ + /* Validating ADD request *******************************************/ + + /*-- NULL Context & ALL Context not applicable for ADD request --*/ + if ((NOTPRSNT != ctxtId->type.pres) && + ((MGT_CXTID_ALL == ctxtId->type.val) || + (MGT_CXTID_NULL == ctxtId->type.val))) { + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," ADD Request processing failed, Context ALL/NULL not allowed\n"); + + mg_util_set_ctxt_string(&errTxt, ctxtId); + err_code = MGT_MGCO_RSP_CODE_PROT_ERROR; + goto error; + } + + /********************************************************************/ + /* Allocate context - if context type is CHOOSE */ + if ((NOTPRSNT != ctxtId->type.pres) && + (MGT_CXTID_CHOOSE == ctxtId->type.val)){ + + mg_ctxt = megaco_choose_context(mg_profile); + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Allocated Context[%p] with context_id[%d]\n", (void*)mg_ctxt, mg_ctxt->context_id); + + /* fill Trillium Context structure with allocated context */ + MG_SET_VAL_PRES(new_ctxtId->type, MGT_CXTID_OTHER); + MG_SET_VAL_PRES(new_ctxtId->val, mg_ctxt->context_id); + } + else { + /* context already present */ + memcpy(new_ctxtId, &inc_cmd->contextId,sizeof(MgMgcoContextId)); + } + + /********************************************************************/ + /* Allocate new RTP termination - If term type is CHOOSE */ + if ((NOTPRSNT != termId->type.pres) && + (MGT_TERMID_CHOOSE == termId->type.val)){ + + is_rtp = 0x01; + strcpy(rtp_term_name,"rtp/1"); + + /* TODO - Matt */ + /* allocate rtp term and associated the same to context */ + /********************************************************************/ + }else{ /* Physical termination */ + /* TODO - Matt - associate physical termination to context */ + } + /********************************************************************/ + + ret = mg_prc_descriptors(mg_profile, inc_cmd, term); + + /* TODO - locally assigned SDP must be the part of termination...which we can use to fill responses*/ + + /********************************************************************/ + /* Matt - to provide the response SDP structure which needs to fill in ADD command response */ /* Matt - to indicate if there is any failure while processing add message */ @@ -362,81 +480,168 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i desc->type.val = MGT_MEDIADESC; mgUtlCpyMgMgcoMediaDesc(&desc->u.media, inc_med_desc, &rsp.u.mgCmdRsp[0]->memCp); -#if 0 /* Most probably we need to add local descriptor */ - { - MgMgcoStreamDesc *stream; - MgMgcoLocalDesc *local; - MgMgcoRemoteDesc* remote; - CmSdpInfoSet *psdp; - CmSdpInfoSet *prsdp; - char* ipAddress = "192.168.1.1"; - /* TODO - considering only one descriptor*/ - stream = &desc->u.media.parms[0]->u.stream; + /* TODO - considering only one descriptor*/ + stream = &desc->u.media.parms[0]->u.stream; + stream->pres.pres = PRSNT_NODEF; + stream->sl.pres.pres = PRSNT_NODEF; + local = &stream->sl.local; + remote = &stream->sl.remote; + + if(!local->pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " Local stream media not present adding it \n"); + + /* allocating mem for local descriptor */ + if (mgUtlGrowList((void ***)&desc->u.media.parms, sizeof(MgMgcoMediaPar), + &desc->u.media.num, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + desc->u.media.parms[desc->u.media.num.val-1]->type.pres = PRSNT_NODEF; + desc->u.media.parms[desc->u.media.num.val-1]->type.val = MGT_MEDIAPAR_STRPAR; + + + stream = &desc->u.media.parms[desc->u.media.num.val-1]->u.stream; + stream->pres.pres = PRSNT_NODEF; + stream->pres.val = 0x01; + stream->sl.pres.pres = PRSNT_NODEF; + stream->sl.pres.val = 0x01; local = &stream->sl.local; remote = &stream->sl.remote; - if(!local->pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " Local stream media not present adding it \n"); - local->pres.pres = PRSNT_NODEF; - psdp = &(local->sdp); - prsdp = &(remote->sdp); + memcpy(&stream->streamId, &desc->u.media.parms[0]->u.stream.streamId, sizeof(MgMgcoStreamId)); - if (mgUtlGrowList((void ***)&psdp->info, sizeof(CmSdpInfo), - &psdp->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + local->pres.pres = PRSNT_NODEF; + psdp = &(local->sdp); + prsdp = &(remote->sdp); + + if (mgUtlGrowList((void ***)&psdp->info, sizeof(CmSdpInfo), + &psdp->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + psdp->info[0]->pres.pres = PRSNT_NODEF; + + /* fill version */ + /*memcpy(&psdp->info[0]->ver, &prsdp->info[0]->ver, sizeof(TknU16)); */ + MG_INIT_TOKEN_VALUE(&(psdp->info[0]->ver),1); + + /* fill orig */ + MG_SET_TKNSTROSXL(psdp->info[0]->orig.orig.usrName, 1, "-", + &rsp.u.mgCmdRsp[0]->memCp); + MG_SET_TKNSTROSXL(psdp->info[0]->orig.orig.sessId, 1, "0", + &rsp.u.mgCmdRsp[0]->memCp); + MG_SET_TKNSTROSXL(psdp->info[0]->orig.orig.sessVer, 1, "0", + &rsp.u.mgCmdRsp[0]->memCp); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.netType.type), + CM_SDP_NET_TYPE_IN); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.addrType), + CM_SDP_ADDR_TYPE_IPV4); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.addrType), + CM_SDP_IPV4_IP_UNI); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.addrType), + CM_SDP_IPV4_IP_UNI); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[0]), + ipAddress[0]); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[1]), + ipAddress[1]); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[2]), + ipAddress[2]); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[3]), + ipAddress[3]); + + /* fill session name */ + /*memcpy(&psdp->info[0]->sessName, &prsdp->info[0]->sessName, sizeof(TknStrOSXL));*/ + MG_SET_TKNSTROSXL(psdp->info[0]->sessName, 1, "-",&rsp.u.mgCmdRsp[0]->memCp); + + + /* fill info */ + MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[0]), ipAddress[0]); + MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[1]), ipAddress[1]); + MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[2]), ipAddress[2]); + MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[3]), ipAddress[3]); + + /* Fill the SDP Connection Info */ + /* "c=" line - ipaddress */ + /*memcpy(&psdp->info[0]->conn, &prsdp->info[0]->conn, sizeof(CmSdpConn));*/ + + /* fill media descriptors */ + { + CmSdpMediaDescSet* med = &psdp->info[0]->mediaDescSet; + CmSdpMediaDesc* media; + + if (mgUtlGrowList((void ***)&med->mediaDesc, sizeof(CmSdpMediaDesc), + &med->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) { switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); return SWITCH_STATUS_FALSE; } - psdp->info[0]->pres.pres = PRSNT_NODEF; + media = med->mediaDesc[0]; - /* fill version */ - memcpy(&psdp->info[0]->ver, &prsdp->info[0]->ver, sizeof(TknU16)); + MG_INIT_TOKEN_VALUE(&(media->pres),1); - /* fill orig */ - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[0]), ipAddress[0]); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[1]), ipAddress[1]); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[2]), ipAddress[2]); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[3]), ipAddress[3]); + /* Fill CmSdpMediaField */ + MG_INIT_TOKEN_VALUE(&(media->field.pres),1); + MG_INIT_TOKEN_VALUE(&(media->field.mediaType),CM_SDP_MEDIA_AUDIO); - /* fill session name */ - memcpy(&psdp->info[0]->sessName, &prsdp->info[0]->sessName, sizeof(TknStrOSXL)); + MG_INIT_TOKEN_VALUE(&(media->field.id.type),CM_SDP_VCID_PORT); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.type),CM_SDP_PORT_INT); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.pres),1); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.type), + CM_SDP_SPEC); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.val), 2904); - /* fill info */ - MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[0]), ipAddress[0]); - MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[1]), ipAddress[1]); - MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[2]), ipAddress[2]); - MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[3]), ipAddress[3]); - /* Fill the SDP Connection Info */ - /* "c=" line - ipaddress */ - memcpy(&psdp->info[0]->conn, &prsdp->info[0]->conn, sizeof(CmSdpConn)); + MG_INIT_TOKEN_VALUE(&(media->field.par.numProtFmts),1); + MG_GETMEM((media->field.par.pflst),1*sizeof(CmSdpMedProtoFmts*),&rsp.u.mgCmdRsp[0]->memCp, ret); + MG_GETMEM((media->field.par.pflst[0]),sizeof(CmSdpMedProtoFmts),&rsp.u.mgCmdRsp[0]->memCp, ret); + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->prot.type), + CM_SDP_MEDIA_PROTO_RTP) + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->prot.u.subtype.type), + CM_SDP_PROTO_RTP_AVP); + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->protType), + CM_SDP_MEDIA_PROTO_RTP); - /* fill media descriptors */ + + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->u.rtp.num),1); + + MG_GETMEM((media->field.par.pflst[0]->u.rtp.fmts), + 1*sizeof(CmSdpU8OrNil *), &rsp.u.mgCmdRsp[0]->memCp, ret); + + MG_GETMEM((media->field.par.pflst[0]->u.rtp.fmts[0]), + sizeof(CmSdpU8OrNil), &rsp.u.mgCmdRsp[0]->memCp, ret); + + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->u.rtp.fmts[0]->type), + CM_SDP_SPEC); + + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->u.rtp.fmts[0]->val), + 4); + + /* Fill attribute if reqd */ { - CmSdpMediaDescSet* med = &psdp->mediaDescSet; - CmSdpMediaDesc* m; - - if (mgUtlGrowList((void ***)&med->mediaDesc, sizeof(CmSdpMediaDesc), - &med->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); - return SWITCH_STATUS_FALSE; - } + MG_INIT_TOKEN_VALUE(&(media->attrSet.numComp),1); + MG_GETMEM((media->attrSet.attr),sizeof(CmSdpAttr*),&rsp.u.mgCmdRsp[0]->memCp, ret); + MG_GETMEM((media->attrSet.attr[0]),sizeof(CmSdpAttr),&rsp.u.mgCmdRsp[0]->memCp, ret); + MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[0]->type),CM_SDP_ATTR_PTIME); + media->attrSet.attr[0]->u.ptime.pres = PRSNT_NODEF; + media->attrSet.attr[0]->u.ptime.val = 30; } - m = med->mediaDesc[0]; + } + + printf("ret[%d]\n",ret); - m->pres.pres = PRSNT_NODEF; - } - else { - printf("!local->pres.pres false \n"); - } } -#endif + else { + printf("!local->pres.pres false \n"); + } @@ -479,27 +684,15 @@ error: switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd) { MgMgcoContextId *ctxtId; - int descId; MgStr errTxt; MgMgcoInd *mgErr; MgMgcoTermId *termId; MgMgcoTermIdLst* termLst; + mg_termination_t* term = NULL; + switch_status_t ret; int err_code; - int i; - int j; - int fmtCnt; MgMgcoAmmReq *cmd = &inc_cmd->u.mgCmdInd[0]->cmd.u.mod; U32 txn_id = inc_cmd->transId.val; - MgMgcoLocalDesc *local; - MgMgcoRemoteDesc *remote; - MgMgcoLclCtlDesc *locCtl; - CmSdpInfo *sdp; - MgMgcoLocalParm *lclParm; - MgMgcoTermStateDesc *tstate; - CmSdpMedFmtRtpList *fmt_list; - MgMgcoTermStateParm *tsp; - TknU8 *fmt; - CmSdpMedProtoFmts *format; /********************************************************************/ ctxtId = &inc_cmd->contextId; @@ -546,175 +739,14 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand /* Kapil - If there is an error - send response back to MG stack with MGT_MGCO_RSP_CODE_NO_TERM_CTXT error code*/ /********************************************************************/ + + /* TODO - dummy code will replace with proper choose_termination api */ + term = malloc(sizeof(*term)); + term->active_events = NULL; + ret = mg_prc_descriptors(mg_profile, inc_cmd, term); - /* Media Descriptor processing same as ADD command */ - - /* TODO - Will see If we can have common media_descriptor processing API which we can use for both ADD/MODIFY */ - - for (descId = 0; descId < cmd->dl.num.val; descId++) { - switch (cmd->dl.descs[descId]->type.val) { - case MGT_MEDIADESC: - { - int mediaId; - for (mediaId = 0; mediaId < cmd->dl.descs[descId]->u.media.num.val; mediaId++) { - MgMgcoMediaPar *mediaPar = cmd->dl.descs[descId]->u.media.parms[mediaId]; - switch (mediaPar->type.val) { - case MGT_MEDIAPAR_LOCAL: - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCAL"); - /* Matt - check local descriptor processing */ - local = &mediaPar->u.local; - sdp = local->sdp.info[0]; - for (i = 0; i < sdp->mediaDescSet.numComp.val; i++) { - /* sdp formats */ - for (j = 0; j < - sdp->mediaDescSet.mediaDesc[i]->field.par.numProtFmts.val; j++) - { - format = sdp->mediaDescSet.mediaDesc[i]->field.par.pflst[j]; - /* Matt - format has field for T38 also */ - if ((format->protType.pres != NOTPRSNT) && - (format->protType.val == CM_SDP_MEDIA_PROTO_RTP)) { - - /* protocol type RTP */ - fmt_list = &format->u.rtp; - - /* print format */ - for(fmtCnt = 0; fmtCnt < fmt_list->num.val; fmtCnt++){ - fmt = &fmt_list->fmts[i]->val; - if(fmt->pres == NOTPRSNT) continue; - printf("Format [%d]\n", fmt->val); - } - } - } - } - - break; - } - - case MGT_MEDIAPAR_REMOTE: - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_REMOTE"); - /* Matt - check remote descriptor processing */ - remote = &mediaPar->u.remote; - sdp = remote->sdp.info[0]; - /* for Matt - same like local descriptor */ - break; - } - - case MGT_MEDIAPAR_LOCCTL: - { - /* Matt - check Local Control descriptor processing */ - locCtl = &mediaPar->u.locCtl; - for (i = 0; i < locCtl->num.val; i++){ - lclParm = locCtl->parms[i]; - if (PRSNT_NODEF == lclParm->type.pres){ - switch(lclParm->type.val) - { - case MGT_LCLCTL_MODE: - { - /* Mode Property */ - printf("MGT_LCLCTL_MODE - Mode value [%d]\n", lclParm->u.mode.val); - break; - } - case MGT_LCLCTL_RESVAL: - { - /* Reserve Value */ - printf("MGT_LCLCTL_RESVAL: Reserve Value[%d] \n", lclParm->u.resVal.val); - break; - } - case MGT_LCLCTL_RESGRP: - { - /* Reserve group */ - printf("MGT_LCLCTL_RESGRP: Reserve Group[%d]\n", lclParm->u.resGrp.val); - break; - } - case MGT_LCLCTL_PROPPARM: - { - /* Properties (of a termination) */ - /* Matt - See how we can apply this to a termination */ - printf("MGT_LCLCTL_PROPPARM: \n"); - break; - } - default: - printf("Invalid local control descriptor type[%d]\n",lclParm->type.val); - break; - } - } - } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCCTL"); - break; - } - case MGT_MEDIAPAR_TERMST: - { - /* Matt - apply termination state descriptor */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_TERMST"); - tstate = &mediaPar->u.tstate; - for (i = 0; i < tstate->numComp.val; i++) - { - /* Matt to see how to apply below descriptors to a termination */ - tsp = tstate->trmStPar[i]; - if (PRSNT_NODEF == tsp->type.pres) { - switch(tsp->type.val) - { - case MGT_TERMST_PROPLST: - { - /* Matt to see how to apply properties to a termination */ - /* Properties of a termination */ - printf("MGT_TERMST_PROPLST:\n"); - break; - } - case MGT_TERMST_EVTBUFCTL: - { - /* Event /buffer Control Properties */ - printf(" MGT_TERMST_EVTBUFCTL: value[%d]\n", tsp->u.evtBufCtl.val); - break; - } - case MGT_TERMST_SVCST: - { - /* Service State Properties */ - printf(" MGT_TERMST_SVCST: value[%d]\n", tsp->u.svcState.val); - break; - } - default: - printf("Invalid termination state descriptor type[%d]\n",tsp->type.val); - break; - } - } - } - break; - } - case MGT_MEDIAPAR_STRPAR: - { - MgMgcoStreamDesc *mgStream = &mediaPar->u.stream; - - if (mgStream->sl.remote.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got remote stream media description:\n"); - mgco_print_sdp(&mgStream->sl.remote.sdp); - } - - if (mgStream->sl.local.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got local stream media description:\n"); - mgco_print_sdp(&mgStream->sl.local.sdp); - } - - break; - } - } - } - } - case MGT_MODEMDESC: - case MGT_MUXDESC: - case MGT_REQEVTDESC: - case MGT_EVBUFDESC: - case MGT_SIGNALSDESC: - case MGT_DIGMAPDESC: - case MGT_AUDITDESC: - case MGT_STATSDESC: - break; - } - } + /********************************************************************/ /* Matt - to provide the response SDP structure which needs to fill in Modify command response */ @@ -724,6 +756,55 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand /* Kapil - to fill the response structure and call the response API to send Modify response */ + { /* send response */ + + MgMgcoCommand rsp; + int ret = 0x00; + + memset(&rsp,0, sizeof(rsp)); + + /*copy transaction-id*/ + memcpy(&rsp.transId, &inc_cmd->transId,sizeof(MgMgcoTransId)); + + /*copy context-id*/ /*TODO - in case of $ context should be generated by app, we should not simply copy incoming structure */ + memcpy(&rsp.contextId, &inc_cmd->contextId,sizeof(MgMgcoContextId)); + + /*copy peer identifier */ + memcpy(&rsp.peerId, &inc_cmd->peerId,sizeof(TknU32)); + + /*fill response structue */ + if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&rsp.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ + return ret; + } + + rsp.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; + rsp.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; + rsp.u.mgCmdRsp[0]->type.val = MGT_MODIFY; + rsp.u.mgCmdRsp[0]->u.mod.pres.pres = PRSNT_NODEF; + rsp.u.mgCmdRsp[0]->u.mod.termIdLst.num.pres = PRSNT_NODEF; + rsp.u.mgCmdRsp[0]->u.mod.termIdLst.num.val = 1; + + mgUtlAllocMgMgcoTermIdLst(&rsp.u.mgCmdRsp[0]->u.mod.termIdLst, &inc_cmd->u.mgCmdReq[0]->cmd.u.mod.termIdLst); + +#ifdef GCP_VER_2_1 + termId = rsp.u.mgCmdRsp[0]->u.mod.termIdLst.terms[0]; +#else + termId = &(rsp.u.mgCmdRsp[0]->u.mod.termId); +#endif + /*mg_fill_mgco_termid(termId, (char*)"term1",&req->u.mgCmdRsp[0]->memCp);*/ + + /* We will always send one command at a time..*/ + rsp.cmdStatus.pres = PRSNT_NODEF; + rsp.cmdStatus.val = CH_CMD_STATUS_END_OF_CMD; + + rsp.cmdType.pres = PRSNT_NODEF; + rsp.cmdType.val = CH_CMD_TYPE_RSP; + + + ret = sng_mgco_send_cmd(mg_profile->idx, &rsp); + + } + return SWITCH_STATUS_SUCCESS; error: @@ -755,7 +836,7 @@ switch_status_t handle_mg_subtract_cmd(megaco_profile_t* mg_profile, MgMgcoComma int err_code; MgMgcoAmmReq *cmd = &inc_cmd->u.mgCmdInd[0]->cmd.u.add; U32 txn_id = inc_cmd->transId.val; - mg_context_t* mg_ctxt; + mg_context_t* mg_ctxt = NULL; uint8_t wild = 0x00; wild = inc_cmd->u.mgCmdReq[0]->wild.pres; @@ -792,6 +873,8 @@ switch_status_t handle_mg_subtract_cmd(megaco_profile_t* mg_profile, MgMgcoComma goto error; } + /********************************************************************/ + /* TODO - see if we receive wild card SUB for ALL context */ /********************************************************************/ /* Matt - TODO - check if we have terminations in the context */ @@ -800,15 +883,20 @@ switch_status_t handle_mg_subtract_cmd(megaco_profile_t* mg_profile, MgMgcoComma switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Received context_id[%d]\n", ctxtId->val.val); +#if 0 /*find context based on received context-id */ mg_ctxt = megaco_get_context(mg_profile, ctxtId->val.val); +#endif - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Found Context[%p] for context_id[%d]\n", (void*)mg_ctxt, mg_ctxt->context_id); + if(mg_ctxt){ - /* TODO - remove terminations from context....as if now there is no termination associated with Context */ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Found Context[%p] for context_id[%d]\n", (void*)mg_ctxt, mg_ctxt->context_id); - /* release context*/ - megaco_release_context(mg_ctxt); + /* TODO - remove terminations from context....as if now there is no termination associated with Context */ + + /* release context*/ + megaco_release_context(mg_ctxt); + } /*************************************************************************************************************************/ /* resp code -- begin */ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index b207f2e75a..3d872898be 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -112,6 +112,15 @@ typedef enum { cmMemcpy((U8 *)(_tkn)->val, (CONSTANT U8 *)(_val), (_len)); \ } +#define MG_SET_TKNSTROSXL(_tkn, _len, _val, _mem)\ +{\ + (_tkn).pres = PRSNT_NODEF;\ + (_tkn).len = (_len);\ + cmGetMem((Ptr)_mem, (Size)((_len)*sizeof(U8)), (Ptr*)&((_tkn).val));\ + cmMemcpy((U8*)((_tkn).val), (U8*)(_val), _len);\ +} + +switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd, mg_termination_t* term); void handle_sng_log(uint8_t level, char *fmt, ...); void handle_mgco_sta_ind(Pst *pst, SuId suId, MgMgtSta* msg); void handle_mgco_txn_sta_ind(Pst *pst, SuId suId, MgMgcoInd* msg); diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index cbdf144a6a..c2dddc1c6e 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -438,6 +438,9 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) memset(&out_ctxt,0,sizeof(out_ctxt)); + inc_context = &cmd->contextId; + memcpy(&out_ctxt, inc_context,sizeof(MgMgcoContextId)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: Received Command Type[%s] \n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(cmd->cmdType.val)); /* validate Transaction Id */ @@ -506,7 +509,6 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) /* Validate Context - if context is specified then check if its present with us */ - inc_context = &cmd->contextId; MG_ZERO(&ctxtId, sizeof(MgMgcoContextId)); memcpy(&ctxtId, inc_context, sizeof(MgMgcoContextId)); @@ -535,7 +537,6 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) goto error1; } - memcpy(&out_ctxt, inc_context,sizeof(MgMgcoContextId)); switch(cmd->cmdType.val) { @@ -557,7 +558,7 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) { /*MgMgcoAmmReq *addReq = &cmdReq->cmd.u.mod;*/ handle_mg_modify_cmd(mg_profile, cmd); - mg_send_modify_rsp(suId, cmd); + /*mg_send_modify_rsp(suId, cmd);*/ break; } case MGT_MOVE: @@ -619,9 +620,10 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) return; } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "cmd->cmdStatus.val[%d]\n",cmd->cmdStatus.val); /* END OF TXN received - means last command in txn to process. * Send response to peer */ - if(CH_CMD_STATUS_END_OF_TXN == cmd->cmdStatus.val){ + /*if(CH_CMD_STATUS_END_OF_TXN == cmd->cmdStatus.val)*/{ mg_send_end_of_axn(suId, &cmd->transId, &out_ctxt, &cmd->peerId); } @@ -635,6 +637,9 @@ error: mg_build_mgco_err_request(&mgErr, txn_id, &ctxtId, err_code, &errTxt)) { sng_mgco_send_err(suId, mgErr); } + if(CH_CMD_STATUS_END_OF_TXN == cmd->cmdStatus.val){ + mg_send_end_of_axn(suId, &cmd->transId, &out_ctxt, &cmd->peerId); + } error1: mg_free_cmd(cmd); return; @@ -654,7 +659,7 @@ void handle_mgco_txn_sta_ind(Pst *pst, SuId suId, MgMgcoInd* txn_sta_ind) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s\n", __PRETTY_FUNCTION__); /*dump information*/ - /*mgAccEvntPrntMgMgcoInd(txn_sta_ind, stdout);*/ + mgAccEvntPrntMgMgcoInd(txn_sta_ind, stdout); } /*****************************************************************************************************************************/ diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index e62f59bf09..1dded04d7b 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -42,7 +42,7 @@ typedef enum { MEGACO_CODEC_ILBC, /* Nothing below this line */ - MEGACO_CODEC_INVALID = 0xFFFFFFFF + MEGACO_CODEC_INVALID = 0xFFFFFF } megaco_codec_t; typedef struct mg_peer_profile_s{ @@ -90,6 +90,7 @@ typedef struct mg_termination_s { const char *uuid; /*!< UUID of the associated FS channel, or NULL if it's not activated */ mg_context_t *context; /*!< Context in which this termination is connected, or NULL */ megaco_profile_t *profile; /*!< Parent MG profile */ + MgMgcoReqEvtDesc *active_events; /* !< active megaco events */ union { struct { From d7e4b509b6838654d920da649f29b3ff21653aa4 Mon Sep 17 00:00:00 2001 From: Kapil Date: Mon, 23 Jul 2012 15:24:43 -0400 Subject: [PATCH 321/822] integrating term/context alloc/delete api to megaco command handler code --- .../mod_media_gateway/media_gateway.c | 41 +- .../media_gateway_cmd_handler.c | 517 +++++++++++------- .../mod_media_gateway/media_gateway_stack.h | 1 + .../mod_media_gateway/media_gateway_utils.c | 7 + .../mod_media_gateway/mod_media_gateway.c | 2 +- .../mod_media_gateway/mod_media_gateway.h | 4 + 6 files changed, 377 insertions(+), 195 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index b0db09c6ab..6c0bfd4092 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -167,6 +167,7 @@ mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const cha term->pool = pool; term->type = termtype; term->active_events = NULL; + term->profile = profile; if (termtype == MG_TERM_RTP) { /* Fill in local address and reserve an rtp port */ @@ -212,6 +213,23 @@ void megaco_termination_destroy(mg_termination_t *term) switch_core_destroy_memory_pool(&term->pool); } +switch_status_t megaco_context_is_term_present(mg_context_t *ctx, mg_termination_t *term) +{ + + switch_assert(ctx != NULL); + switch_assert(term != NULL); + + if (ctx->terminations[0] && (term == ctx->terminations[0])) { + return SWITCH_STATUS_SUCCESS; + } + + if (ctx->terminations[1] && (term == ctx->terminations[1])) { + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_FALSE; +} + switch_status_t megaco_context_add_termination(mg_context_t *ctx, mg_termination_t *term) { @@ -247,6 +265,21 @@ switch_status_t megaco_context_add_termination(mg_context_t *ctx, mg_termination } +switch_status_t megaco_context_sub_all_termination(mg_context_t *ctx) +{ + switch_assert(ctx != NULL); + + /* Channels will automatically go to park once the bridge ends */ + if (ctx->terminations[0]) { + megaco_termination_destroy(ctx->terminations[0]); + ctx->terminations[0] = NULL; + } else if (ctx->terminations[1]) { + megaco_termination_destroy(ctx->terminations[1]); + } + + return SWITCH_STATUS_SUCCESS; +} + switch_status_t megaco_context_sub_termination(mg_context_t *ctx, mg_termination_t *term) { switch_assert(ctx != NULL); @@ -315,7 +348,8 @@ mg_context_t *megaco_get_context(megaco_profile_t *profile, uint32_t context_id) mg_context_t *megaco_choose_context(megaco_profile_t *profile) { mg_context_t *ctx; - int i = 0x0;; + int i = 0x0; + int j = 0x0; switch_thread_rwlock_wrlock(profile->contexts_rwlock); /* Try the next one */ @@ -332,7 +366,10 @@ mg_context_t *megaco_choose_context(megaco_profile_t *profile) ctx = malloc(sizeof *ctx); ctx->context_id = profile->next_context_id; ctx->profile = profile; - + for(j = 0; j< MG_CONTEXT_MAX_TERMS; j++){ + ctx->terminations[j] = NULL; + } + if (!profile->contexts[i]) { profile->contexts[i] = ctx; } else { diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index b544f853f7..bee845a8c1 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -319,26 +319,16 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i MgMgcoTermIdLst* termLst; int err_code; int is_rtp = 0x00; - char rtp_term_name[32]; MgMgcoAmmReq *cmd = &inc_cmd->u.mgCmdInd[0]->cmd.u.add; U32 txn_id = inc_cmd->transId.val; mg_termination_t* term = NULL; MgMgcoMediaDesc* inc_med_desc; MgMgcoAudRetParm *desc; mg_context_t* mg_ctxt; - MgMgcoStreamDesc *stream; - MgMgcoLocalDesc *local; - MgMgcoRemoteDesc* remote; - CmSdpInfoSet *psdp; - CmSdpInfoSet *prsdp; - char* ipAddress = "192.168.1.1"; /* TODO - Kapil dummy line , will need to add with proper code */ inc_med_desc = &cmd->dl.descs[0]->u.media; - memset(&rtp_term_name[0], 0, 32); - - /********************************************************************/ ctxtId = &inc_cmd->contextId; termLst = mg_get_term_id_list(inc_cmd); @@ -367,6 +357,12 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i mg_ctxt = megaco_choose_context(mg_profile); + if(NULL == mg_ctxt){ + mg_util_set_err_string(&errTxt, " Resource Failure "); + err_code = MGT_MGCO_RSP_CODE_RSRC_ERROR; + goto error; + } + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Allocated Context[%p] with context_id[%d]\n", (void*)mg_ctxt, mg_ctxt->context_id); /* fill Trillium Context structure with allocated context */ @@ -383,15 +379,34 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i if ((NOTPRSNT != termId->type.pres) && (MGT_TERMID_CHOOSE == termId->type.val)){ + term = megaco_choose_termination(mg_profile, "RTP"); /* TODO - RTP string has be configured one */ + + if(NULL == term){ + mg_util_set_err_string(&errTxt, " Resource Failure "); + err_code = MGT_MGCO_RSP_CODE_RSRC_ERROR; + goto error; + } + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Allocated Termination[%p] with term name[%s]\n", (void*)term, term->name); + is_rtp = 0x01; - strcpy(rtp_term_name,"rtp/1"); /* TODO - Matt */ /* allocate rtp term and associated the same to context */ /********************************************************************/ }else{ /* Physical termination */ - /* TODO - Matt - associate physical termination to context */ + + /* get physical termination */ } + /********************************************************************/ + /* associate physical termination to context */ + + if(SWITCH_STATUS_FALSE == megaco_context_add_termination(mg_ctxt, term)){ + mg_util_set_err_string(&errTxt, " Resource Failure "); + err_code = MGT_MGCO_RSP_CODE_RSRC_ERROR; + goto error; + } + /********************************************************************/ ret = mg_prc_descriptors(mg_profile, inc_cmd, term); @@ -458,7 +473,7 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i } out_termId = rsp.u.mgCmdRsp[0]->u.add.termIdLst.terms[rsp.u.mgCmdRsp[0]->u.add.termIdLst.num.val-1]; - mg_fill_mgco_termid(out_termId, (char*)rtp_term_name, strlen((char*)rtp_term_name), &rsp.u.mgCmdRsp[0]->memCp); + mg_fill_mgco_termid(out_termId, (char*)term->name, strlen((char*)term->name), &rsp.u.mgCmdRsp[0]->memCp); } /* Whatever Media descriptor we have received, we can copy that and then @@ -480,168 +495,179 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i desc->type.val = MGT_MEDIADESC; mgUtlCpyMgMgcoMediaDesc(&desc->u.media, inc_med_desc, &rsp.u.mgCmdRsp[0]->memCp); +#if 0 + { - /* Most probably we need to add local descriptor */ + MgMgcoStreamDesc *stream; + MgMgcoLocalDesc *local; + MgMgcoRemoteDesc* remote; + CmSdpInfoSet *psdp; + CmSdpInfoSet *prsdp; + char* ipAddress = "192.168.1.1"; - /* TODO - considering only one descriptor*/ - stream = &desc->u.media.parms[0]->u.stream; - stream->pres.pres = PRSNT_NODEF; - stream->sl.pres.pres = PRSNT_NODEF; - local = &stream->sl.local; - remote = &stream->sl.remote; + /* Most probably we need to add local descriptor */ - if(!local->pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " Local stream media not present adding it \n"); - - /* allocating mem for local descriptor */ - if (mgUtlGrowList((void ***)&desc->u.media.parms, sizeof(MgMgcoMediaPar), - &desc->u.media.num, &rsp.u.mgCmdRsp[0]->memCp) != ROK) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); - return SWITCH_STATUS_FALSE; - } - - desc->u.media.parms[desc->u.media.num.val-1]->type.pres = PRSNT_NODEF; - desc->u.media.parms[desc->u.media.num.val-1]->type.val = MGT_MEDIAPAR_STRPAR; - - - stream = &desc->u.media.parms[desc->u.media.num.val-1]->u.stream; + /* TODO - considering only one descriptor*/ + stream = &desc->u.media.parms[0]->u.stream; stream->pres.pres = PRSNT_NODEF; - stream->pres.val = 0x01; stream->sl.pres.pres = PRSNT_NODEF; - stream->sl.pres.val = 0x01; local = &stream->sl.local; remote = &stream->sl.remote; - memcpy(&stream->streamId, &desc->u.media.parms[0]->u.stream.streamId, sizeof(MgMgcoStreamId)); + if(!local->pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " Local stream media not present adding it \n"); - local->pres.pres = PRSNT_NODEF; - psdp = &(local->sdp); - prsdp = &(remote->sdp); - - if (mgUtlGrowList((void ***)&psdp->info, sizeof(CmSdpInfo), - &psdp->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); - return SWITCH_STATUS_FALSE; - } - - psdp->info[0]->pres.pres = PRSNT_NODEF; - - /* fill version */ - /*memcpy(&psdp->info[0]->ver, &prsdp->info[0]->ver, sizeof(TknU16)); */ - MG_INIT_TOKEN_VALUE(&(psdp->info[0]->ver),1); - - /* fill orig */ - MG_SET_TKNSTROSXL(psdp->info[0]->orig.orig.usrName, 1, "-", - &rsp.u.mgCmdRsp[0]->memCp); - MG_SET_TKNSTROSXL(psdp->info[0]->orig.orig.sessId, 1, "0", - &rsp.u.mgCmdRsp[0]->memCp); - MG_SET_TKNSTROSXL(psdp->info[0]->orig.orig.sessVer, 1, "0", - &rsp.u.mgCmdRsp[0]->memCp); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.netType.type), - CM_SDP_NET_TYPE_IN); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.addrType), - CM_SDP_ADDR_TYPE_IPV4); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.addrType), - CM_SDP_IPV4_IP_UNI); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.addrType), - CM_SDP_IPV4_IP_UNI); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[0]), - ipAddress[0]); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[1]), - ipAddress[1]); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[2]), - ipAddress[2]); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[3]), - ipAddress[3]); - - /* fill session name */ - /*memcpy(&psdp->info[0]->sessName, &prsdp->info[0]->sessName, sizeof(TknStrOSXL));*/ - MG_SET_TKNSTROSXL(psdp->info[0]->sessName, 1, "-",&rsp.u.mgCmdRsp[0]->memCp); - - - /* fill info */ - MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[0]), ipAddress[0]); - MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[1]), ipAddress[1]); - MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[2]), ipAddress[2]); - MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[3]), ipAddress[3]); - - /* Fill the SDP Connection Info */ - /* "c=" line - ipaddress */ - /*memcpy(&psdp->info[0]->conn, &prsdp->info[0]->conn, sizeof(CmSdpConn));*/ - - /* fill media descriptors */ - { - CmSdpMediaDescSet* med = &psdp->info[0]->mediaDescSet; - CmSdpMediaDesc* media; - - if (mgUtlGrowList((void ***)&med->mediaDesc, sizeof(CmSdpMediaDesc), - &med->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + /* allocating mem for local descriptor */ + if (mgUtlGrowList((void ***)&desc->u.media.parms, sizeof(MgMgcoMediaPar), + &desc->u.media.num, &rsp.u.mgCmdRsp[0]->memCp) != ROK) { switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); return SWITCH_STATUS_FALSE; } - media = med->mediaDesc[0]; - - MG_INIT_TOKEN_VALUE(&(media->pres),1); - - /* Fill CmSdpMediaField */ - MG_INIT_TOKEN_VALUE(&(media->field.pres),1); - MG_INIT_TOKEN_VALUE(&(media->field.mediaType),CM_SDP_MEDIA_AUDIO); - - MG_INIT_TOKEN_VALUE(&(media->field.id.type),CM_SDP_VCID_PORT); - MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.type),CM_SDP_PORT_INT); - MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.pres),1); - MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.type), - CM_SDP_SPEC); - MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.val), 2904); + desc->u.media.parms[desc->u.media.num.val-1]->type.pres = PRSNT_NODEF; + desc->u.media.parms[desc->u.media.num.val-1]->type.val = MGT_MEDIAPAR_STRPAR; - MG_INIT_TOKEN_VALUE(&(media->field.par.numProtFmts),1); - MG_GETMEM((media->field.par.pflst),1*sizeof(CmSdpMedProtoFmts*),&rsp.u.mgCmdRsp[0]->memCp, ret); - MG_GETMEM((media->field.par.pflst[0]),sizeof(CmSdpMedProtoFmts),&rsp.u.mgCmdRsp[0]->memCp, ret); - MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->prot.type), - CM_SDP_MEDIA_PROTO_RTP) - MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->prot.u.subtype.type), - CM_SDP_PROTO_RTP_AVP); - MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->protType), - CM_SDP_MEDIA_PROTO_RTP); + stream = &desc->u.media.parms[desc->u.media.num.val-1]->u.stream; + stream->pres.pres = PRSNT_NODEF; + stream->pres.val = 0x01; + stream->sl.pres.pres = PRSNT_NODEF; + stream->sl.pres.val = 0x01; + local = &stream->sl.local; + remote = &stream->sl.remote; + memcpy(&stream->streamId, &desc->u.media.parms[0]->u.stream.streamId, sizeof(MgMgcoStreamId)); - MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->u.rtp.num),1); + local->pres.pres = PRSNT_NODEF; + psdp = &(local->sdp); + prsdp = &(remote->sdp); - MG_GETMEM((media->field.par.pflst[0]->u.rtp.fmts), - 1*sizeof(CmSdpU8OrNil *), &rsp.u.mgCmdRsp[0]->memCp, ret); - - MG_GETMEM((media->field.par.pflst[0]->u.rtp.fmts[0]), - sizeof(CmSdpU8OrNil), &rsp.u.mgCmdRsp[0]->memCp, ret); - - MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->u.rtp.fmts[0]->type), - CM_SDP_SPEC); - - MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->u.rtp.fmts[0]->val), - 4); - - /* Fill attribute if reqd */ + if (mgUtlGrowList((void ***)&psdp->info, sizeof(CmSdpInfo), + &psdp->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) { - MG_INIT_TOKEN_VALUE(&(media->attrSet.numComp),1); - MG_GETMEM((media->attrSet.attr),sizeof(CmSdpAttr*),&rsp.u.mgCmdRsp[0]->memCp, ret); - MG_GETMEM((media->attrSet.attr[0]),sizeof(CmSdpAttr),&rsp.u.mgCmdRsp[0]->memCp, ret); - MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[0]->type),CM_SDP_ATTR_PTIME); - media->attrSet.attr[0]->u.ptime.pres = PRSNT_NODEF; - media->attrSet.attr[0]->u.ptime.val = 30; + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; } + psdp->info[0]->pres.pres = PRSNT_NODEF; + + /* fill version */ + /*memcpy(&psdp->info[0]->ver, &prsdp->info[0]->ver, sizeof(TknU16)); */ + MG_INIT_TOKEN_VALUE(&(psdp->info[0]->ver),1); + + /* fill orig */ + MG_SET_TKNSTROSXL(psdp->info[0]->orig.orig.usrName, 1, "-", + &rsp.u.mgCmdRsp[0]->memCp); + MG_SET_TKNSTROSXL(psdp->info[0]->orig.orig.sessId, 1, "0", + &rsp.u.mgCmdRsp[0]->memCp); + MG_SET_TKNSTROSXL(psdp->info[0]->orig.orig.sessVer, 1, "0", + &rsp.u.mgCmdRsp[0]->memCp); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.netType.type), + CM_SDP_NET_TYPE_IN); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.addrType), + CM_SDP_ADDR_TYPE_IPV4); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.addrType), + CM_SDP_IPV4_IP_UNI); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.addrType), + CM_SDP_IPV4_IP_UNI); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[0]), + ipAddress[0]); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[1]), + ipAddress[1]); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[2]), + ipAddress[2]); + MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[3]), + ipAddress[3]); + + /* fill session name */ + /*memcpy(&psdp->info[0]->sessName, &prsdp->info[0]->sessName, sizeof(TknStrOSXL));*/ + MG_SET_TKNSTROSXL(psdp->info[0]->sessName, 1, "-",&rsp.u.mgCmdRsp[0]->memCp); + + + /* fill info */ + MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[0]), ipAddress[0]); + MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[1]), ipAddress[1]); + MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[2]), ipAddress[2]); + MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[3]), ipAddress[3]); + + /* Fill the SDP Connection Info */ + /* "c=" line - ipaddress */ + /*memcpy(&psdp->info[0]->conn, &prsdp->info[0]->conn, sizeof(CmSdpConn));*/ + + /* fill media descriptors */ + { + CmSdpMediaDescSet* med = &psdp->info[0]->mediaDescSet; + CmSdpMediaDesc* media; + + if (mgUtlGrowList((void ***)&med->mediaDesc, sizeof(CmSdpMediaDesc), + &med->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + media = med->mediaDesc[0]; + + MG_INIT_TOKEN_VALUE(&(media->pres),1); + + /* Fill CmSdpMediaField */ + MG_INIT_TOKEN_VALUE(&(media->field.pres),1); + MG_INIT_TOKEN_VALUE(&(media->field.mediaType),CM_SDP_MEDIA_AUDIO); + + MG_INIT_TOKEN_VALUE(&(media->field.id.type),CM_SDP_VCID_PORT); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.type),CM_SDP_PORT_INT); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.pres),1); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.type), + CM_SDP_SPEC); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.val), 2904); + + + MG_INIT_TOKEN_VALUE(&(media->field.par.numProtFmts),1); + MG_GETMEM((media->field.par.pflst),1*sizeof(CmSdpMedProtoFmts*),&rsp.u.mgCmdRsp[0]->memCp, ret); + MG_GETMEM((media->field.par.pflst[0]),sizeof(CmSdpMedProtoFmts),&rsp.u.mgCmdRsp[0]->memCp, ret); + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->prot.type), + CM_SDP_MEDIA_PROTO_RTP) + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->prot.u.subtype.type), + CM_SDP_PROTO_RTP_AVP); + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->protType), + CM_SDP_MEDIA_PROTO_RTP); + + + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->u.rtp.num),1); + + MG_GETMEM((media->field.par.pflst[0]->u.rtp.fmts), + 1*sizeof(CmSdpU8OrNil *), &rsp.u.mgCmdRsp[0]->memCp, ret); + + MG_GETMEM((media->field.par.pflst[0]->u.rtp.fmts[0]), + sizeof(CmSdpU8OrNil), &rsp.u.mgCmdRsp[0]->memCp, ret); + + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->u.rtp.fmts[0]->type), + CM_SDP_SPEC); + + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->u.rtp.fmts[0]->val), + 4); + + /* Fill attribute if reqd */ + { + MG_INIT_TOKEN_VALUE(&(media->attrSet.numComp),1); + MG_GETMEM((media->attrSet.attr),sizeof(CmSdpAttr*),&rsp.u.mgCmdRsp[0]->memCp, ret); + MG_GETMEM((media->attrSet.attr[0]),sizeof(CmSdpAttr),&rsp.u.mgCmdRsp[0]->memCp, ret); + MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[0]->type),CM_SDP_ATTR_PTIME); + media->attrSet.attr[0]->u.ptime.pres = PRSNT_NODEF; + media->attrSet.attr[0]->u.ptime.val = 30; + } + + } + + printf("ret[%d]\n",ret); + + } + else { + printf("!local->pres.pres false \n"); } - - printf("ret[%d]\n",ret); - - } - else { - printf("!local->pres.pres false \n"); } +#endif @@ -667,7 +693,7 @@ error: mg_build_mgco_err_request(&mgErr, txn_id, ctxtId, err_code, &errTxt)) { sng_mgco_send_err(mg_profile->idx, mgErr); } - mg_free_cmd(cmd); + mg_free_cmd(inc_cmd); return SWITCH_STATUS_FALSE; } @@ -683,6 +709,7 @@ error: */ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd) { + mg_context_t* mg_ctxt = NULL; MgMgcoContextId *ctxtId; MgStr errTxt; MgMgcoInd *mgErr; @@ -691,7 +718,7 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand mg_termination_t* term = NULL; switch_status_t ret; int err_code; - MgMgcoAmmReq *cmd = &inc_cmd->u.mgCmdInd[0]->cmd.u.mod; + /*MgMgcoAmmReq *cmd = &inc_cmd->u.mgCmdInd[0]->cmd.u.mod;*/ U32 txn_id = inc_cmd->transId.val; /********************************************************************/ @@ -729,22 +756,71 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand /********************************************************************/ /* context id presence check is already being done, we are here it means context-id requested in megaco message is present */ + /********************************************************************/ - /* Matt - to check if we have terminations in the context */ + /* MGT_TERMID_ROOT = If ROOT term then there will not be any conext */ - /* TODO - Matt */ - - /* Matt to indicate ERROR - If there is no terminations in requested context */ - - /* Kapil - If there is an error - send response back to MG stack with MGT_MGCO_RSP_CODE_NO_TERM_CTXT error code*/ + if(MGT_TERMID_ROOT == termId->type.val){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + "Modify request is for ROOT termination \n"); + /* TODO */ /********************************************************************/ - - /* TODO - dummy code will replace with proper choose_termination api */ - term = malloc(sizeof(*term)); - term->active_events = NULL; + } else if(MGT_TERMID_OTHER == termId->type.val){ + /********************************************************************/ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + "Modify request is for termination[%s] and context: type[%d], value[%d] \n", + termId->name.lcl.val, ctxtId->type.val, ctxtId->val.val); - ret = mg_prc_descriptors(mg_profile, inc_cmd, term); + term = megaco_find_termination(mg_profile, (char*)termId->name.lcl.val); + + if(NULL == term){ + mg_util_set_term_string(&errTxt,termId); + err_code = MGT_MGCO_RSP_CODE_UNKNOWN_TERM_ID; + goto error; + } + + /* termination specified...context should also be specified */ + + /* check if we have terminations in the context */ + + if (NOTPRSNT != ctxtId->type.pres) { + if(MGT_CXTID_OTHER == ctxtId->type.val) { + /*find context based on received context-id */ + mg_ctxt = megaco_get_context(mg_profile, ctxtId->val.val); + if(NULL == mg_ctxt){ + mg_util_set_ctxt_string(&errTxt, ctxtId); + err_code = MGT_MGCO_RSP_CODE_UNKNOWN_CTXT; + goto error; + } + + if(SWITCH_STATUS_FALSE == megaco_context_is_term_present(mg_ctxt, term)){ + /* ERROR - termination didnt bind with requested context */ + mg_util_set_term_string(&errTxt,termId); + err_code = MGT_MGCO_RSP_CODE_NO_TERM_CTXT; + goto error; + } + + }else if(MGT_CXTID_NULL == ctxtId->type.val) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + "Modify request is for NULL Context \n"); + /*TODO - NULL context...nothing to do now...jump to response to send +ve response */ + goto response; + }else if(MGT_CXTID_ALL == ctxtId->type.val) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + "Modify request is for ALL Context \n"); + /*TODO - ALL context...nothing to do now...jump to response to send +ve response */ + goto response; + } + } + + /* Not sure if MODIFY can come with Context ALL with specified term */ + + /********************************************************************/ + + ret = mg_prc_descriptors(mg_profile, inc_cmd, term); + + } /********************************************************************/ @@ -756,6 +832,7 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand /* Kapil - to fill the response structure and call the response API to send Modify response */ +response: { /* send response */ MgMgcoCommand rsp; @@ -812,7 +889,7 @@ error: mg_build_mgco_err_request(&mgErr, txn_id, ctxtId, err_code, &errTxt)) { sng_mgco_send_err(mg_profile->idx, mgErr); } - mg_free_cmd(cmd); + mg_free_cmd(inc_cmd); return SWITCH_STATUS_FALSE; } @@ -834,26 +911,40 @@ switch_status_t handle_mg_subtract_cmd(megaco_profile_t* mg_profile, MgMgcoComma MgMgcoTermId *termId; MgMgcoTermIdLst* termLst; int err_code; - MgMgcoAmmReq *cmd = &inc_cmd->u.mgCmdInd[0]->cmd.u.add; + /*MgMgcoAmmReq *cmd = &inc_cmd->u.mgCmdInd[0]->cmd.u.add;*/ U32 txn_id = inc_cmd->transId.val; mg_context_t* mg_ctxt = NULL; + mg_termination_t* term = NULL; uint8_t wild = 0x00; wild = inc_cmd->u.mgCmdReq[0]->wild.pres; - /********************************************************************/ + /************************************************************************************************************************************************************/ ctxtId = &inc_cmd->contextId; termLst = mg_get_term_id_list(inc_cmd); termId = termLst->terms[0]; - /********************************************************************/ + /************************************************************************************************************************************************************/ /* Validating Subtract request *******************************************/ + if(NOTPRSNT == ctxtId->type.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," SUB Request processing failed, Context Not Present\n"); + mg_util_set_ctxt_string(&errTxt, ctxtId); + err_code = MGT_MGCO_RSP_CODE_PROT_ERROR; + goto error; + } + + if(NOTPRSNT == termId->type.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," SUB Request processing failed, Termination Not Present\n"); + mg_util_set_term_string(&errTxt,termId); + err_code = MGT_MGCO_RSP_CODE_PROT_ERROR; + goto error; + } + /*-- NULL Context & CHOOSE Context not applicable for SUB request --*/ - if ((NOTPRSNT != ctxtId->type.pres) && - ((MGT_CXTID_CHOOSE == ctxtId->type.val) || - (MGT_CXTID_NULL == ctxtId->type.val))) { + if ((MGT_CXTID_CHOOSE == ctxtId->type.val) || + (MGT_CXTID_NULL == ctxtId->type.val)) { switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," SUB Request processing failed, Context CHOOSE/NULL not allowed\n"); @@ -862,9 +953,8 @@ switch_status_t handle_mg_subtract_cmd(megaco_profile_t* mg_profile, MgMgcoComma goto error; } /* ROOT Termination & CHOOSE Termination not allowed */ - else if ((NOTPRSNT != termId->type.pres) && - ((MGT_TERMID_ROOT == termId->type.val) || - (MGT_TERMID_CHOOSE == termId->type.val))) { + else if ((MGT_TERMID_ROOT == termId->type.val) || + (MGT_TERMID_CHOOSE == termId->type.val)) { switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," SUB Request processing failed, Termination ROOT/CHOOSE not allowed\n"); @@ -872,33 +962,76 @@ switch_status_t handle_mg_subtract_cmd(megaco_profile_t* mg_profile, MgMgcoComma err_code = MGT_MGCO_RSP_CODE_INVLD_IDENTIFIER; goto error; } + /************************************************************************************************************************************************************/ - /********************************************************************/ - /* TODO - see if we receive wild card SUB for ALL context */ + if (MGT_CXTID_OTHER == ctxtId->type.val){ - /********************************************************************/ - /* Matt - TODO - check if we have terminations in the context */ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," SUB Request for Context[%d] \n", ctxtId->val.val); - /* Matt to indicate ERROR - If there is no terminations in requested context */ - - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Received context_id[%d]\n", ctxtId->val.val); - -#if 0 - /*find context based on received context-id */ - mg_ctxt = megaco_get_context(mg_profile, ctxtId->val.val); -#endif - - if(mg_ctxt){ + /*find context based on received context-id */ + mg_ctxt = megaco_get_context(mg_profile, ctxtId->val.val); + if(NULL == mg_ctxt){ + mg_util_set_ctxt_string(&errTxt, ctxtId); + err_code = MGT_MGCO_RSP_CODE_UNKNOWN_CTXT; + goto error; + } switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Found Context[%p] for context_id[%d]\n", (void*)mg_ctxt, mg_ctxt->context_id); - /* TODO - remove terminations from context....as if now there is no termination associated with Context */ + + if(MGT_TERMID_ALL == termId->type.val){ + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," SUB Request for context[%d] with ALL termination \n", mg_ctxt->context_id); + + /* remove terminations from context */ + megaco_context_sub_all_termination(mg_ctxt); + + }else if(MGT_TERMID_OTHER == termId->type.val){ + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," SUB Request for termination[%s] \n", (char*)termId->name.lcl.val); + + term = megaco_find_termination(mg_profile, (char*)termId->name.lcl.val); + + if(SWITCH_STATUS_FALSE == megaco_context_is_term_present(mg_ctxt, term)){ + /* ERROR - termination didnt bind with requested context */ + mg_util_set_term_string(&errTxt,termId); + err_code = MGT_MGCO_RSP_CODE_NO_TERM_CTXT; + goto error; + } + + if(NULL == term){ + mg_util_set_term_string(&errTxt,termId); + err_code = MGT_MGCO_RSP_CODE_UNKNOWN_TERM_ID; + goto error; + } + + /* remove termination from context */ + megaco_context_sub_termination(mg_ctxt, term); + } /* release context*/ megaco_release_context(mg_ctxt); } - /*************************************************************************************************************************/ + /************************************************************************************************************************************************************/ + /* CONTEXT = ALL */ + + if (MGT_CXTID_ALL == ctxtId->type.val){ + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," SUB Request for ALL context \n"); + + /* TODO */ + + /* As of now sending +ve response */ + goto response; + } + + + /************************************************************************************************************************************************************/ + + +response: + /************************************************************************************************************************************************************/ /* resp code -- begin */ { MgMgcoCommand rsp; @@ -951,7 +1084,7 @@ switch_status_t handle_mg_subtract_cmd(megaco_profile_t* mg_profile, MgMgcoComma } /* sample resp code -- end */ - /*************************************************************************************************************************/ + /************************************************************************************************************************************************************/ return SWITCH_STATUS_SUCCESS; @@ -960,7 +1093,7 @@ error: mg_build_mgco_err_request(&mgErr, txn_id, ctxtId, err_code, &errTxt)) { sng_mgco_send_err(mg_profile->idx, mgErr); } - mg_free_cmd(cmd); + mg_free_cmd(inc_cmd); return SWITCH_STATUS_FALSE; } diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index 3d872898be..fc27386d9a 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -132,6 +132,7 @@ void handle_mg_alarm(Pst *pst, MgMngmt *sta); void handle_tucl_alarm(Pst *pst, HiMngmt *sta); int mg_enable_logging(void); int mg_disable_logging(void); +void mg_util_set_err_string ( MgStr *errTxt, char* str); switch_status_t sng_mgco_cfg(megaco_profile_t* profile); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index b4728a2bc0..73d467f8de 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -318,6 +318,13 @@ void mg_util_set_txn_string(MgStr *errTxt, U32 *txnId) } +/*****************************************************************************************************************************/ +void mg_util_set_err_string ( MgStr *errTxt, char* str) +{ + MG_ZERO((errTxt->val), sizeof(errTxt->val)); + errTxt->len = strlen(str); + strcpy((char*)&errTxt->val, str); +} /*****************************************************************************************************************************/ void mg_util_set_ctxt_string ( MgStr *errTxt, MgMgcoContextId *ctxtId) { diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index c2dddc1c6e..03a61104ec 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -500,7 +500,7 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) /*If term type is other then check if that term is configured with us..for term type CHOOSE/ALL , no need to check */ if (MGT_TERMID_OTHER == termId->type.val){ - if(SWITCH_STATUS_FALSE != mg_stack_termination_is_in_service((char*)termId->name.lcl.val, termId->name.lcl.len)){ + if(SWITCH_STATUS_FALSE == mg_stack_termination_is_in_service((char*)termId->name.lcl.val, termId->name.lcl.len)){ mg_util_set_term_string(&errTxt, termId); err_code = MGT_MGCO_RSP_CODE_UNKNOWN_TERM_ID; goto error; diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index 1dded04d7b..f5f83c6dd6 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -210,6 +210,8 @@ void mg_rtp_release_id(megaco_profile_t *profile, uint32_t id); mg_context_t *megaco_get_context(megaco_profile_t *profile, uint32_t context_id); mg_context_t *megaco_choose_context(megaco_profile_t *profile); void megaco_release_context(mg_context_t *ctx); +switch_status_t megaco_context_sub_termination(mg_context_t *ctx, mg_termination_t *term); +switch_status_t megaco_context_sub_all_termination(mg_context_t *ctx); mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const char *prefix); mg_termination_t *megaco_find_termination(megaco_profile_t *profile, const char *name); @@ -225,6 +227,8 @@ switch_status_t mg_config_cleanup(megaco_profile_t* profile); switch_status_t mg_peer_config_cleanup(mg_peer_profile_t* profile); switch_status_t megaco_peer_profile_destroy(mg_peer_profile_t **profile); switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stream); +switch_status_t megaco_context_add_termination(mg_context_t *ctx, mg_termination_t *term); +switch_status_t megaco_context_is_term_present(mg_context_t *ctx, mg_termination_t *term); #endif /* MOD_MEGACO_H */ From fc4b7bb8da58944dfe0986789bf35d921784b273 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Mon, 23 Jul 2012 16:57:33 -0400 Subject: [PATCH 322/822] stash fix --- .../endpoints/mod_media_gateway/media_gateway_cmd_handler.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index bee845a8c1..1974403cda 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -976,9 +976,7 @@ switch_status_t handle_mg_subtract_cmd(megaco_profile_t* mg_profile, MgMgcoComma goto error; } - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Found Context[%p] for context_id[%d]\n", (void*)mg_ctxt, mg_ctxt->context_id); - - + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Found Context[%p] for context_id[%d]\n", (void*)mg_ctxt, mg_ctxt->context_id); if(MGT_TERMID_ALL == termId->type.val){ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," SUB Request for context[%d] with ALL termination \n", mg_ctxt->context_id); From 390dabb3518f170336eb2795ca3f5b8f5522b5a5 Mon Sep 17 00:00:00 2001 From: Kapil Date: Tue, 24 Jul 2012 11:46:50 -0400 Subject: [PATCH 323/822] Adding code to 1) build NOTIFY command and send to MGC 2) CLI command to send DTMF NOTIFY Megaco command to MGC --- .../mod_media_gateway/media_gateway.c | 5 + .../mod_media_gateway/media_gateway_cli.c | 71 +++++-- .../media_gateway_cmd_handler.c | 197 ++++++++++++++++++ .../mod_media_gateway/media_gateway_stack.h | 10 + .../mod_media_gateway/media_gateway_utils.c | 36 ++++ 5 files changed, 300 insertions(+), 19 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 6c0bfd4092..5d58674a0c 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -208,6 +208,11 @@ void megaco_termination_destroy(mg_termination_t *term) if (term->type == MG_TERM_RTP && term->u.rtp.local_port != 0) { switch_rtp_release_port(term->u.rtp.local_addr, term->u.rtp.local_port); } + + if(term->active_events){ + free(term->active_events); + term->active_events = NULL; + } switch_core_hash_delete_wrlock(term->profile->terminations, term->name, term->profile->terminations_rwlock); switch_core_destroy_memory_pool(&term->pool); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c index 3e3b034df5..f249d012f4 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c @@ -98,29 +98,61 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre /**********************************************************************************/ }else if(!strcmp(argv[2], "send")) { /**********************************************************************************/ - /* mg profile send sc */ printf("count = %d \n",argc); - if(argc < 7){ - goto usage; - } - if(zstr(argv[3]) || zstr(argv[4]) || zstr(argv[5]) || zstr(argv[6])){ - goto usage; - } - if (profile) { - if(!zstr(argv[7]) && !strcasecmp(argv[7],"wild")){ - wild = 0x01; - } + if (profile) { - printf("Input to Send Service Change command : " - "Profile Name[%s], term-id[%s] method[%s] reason[%s] \n", - profile->name, argv[4], argv[5], argv[6]); + switch(argc) + { + case 7: + { + /* mg profile send sc */ + printf("ARGC = 7 \n"); + if(zstr(argv[3]) || zstr(argv[4]) || zstr(argv[5]) || zstr(argv[6])){ + goto usage; + } + + if(!zstr(argv[7]) && !strcasecmp(argv[7],"wild")){ + wild = 0x01; + } + + printf("Input to Send Service Change command : " + "Profile Name[%s], term-id[%s] method[%s] reason[%s] \n", + profile->name, argv[4], argv[5], argv[6]); + + megaco_profile_release(profile); + mg_send_service_change(profile->idx, argv[4], atoi(argv[5]), atoi(argv[6]),wild); + + break; + } + case 6: + { + /* mg profile send notify */ + if(zstr(argv[3]) || zstr(argv[4]) || zstr(argv[5])){ + goto usage; + } + + if(strcasecmp(argv[3],"notify")){ + stream->write_function(stream, "-ERR wrong input \n"); + goto usage; + } + + printf("Sending DTMF digits[%s] NOTIFY for termination[%s]\n", argv[5], argv[4]); + + megaco_profile_release(profile); + mg_send_dtmf_notify(profile, argv[4], (char*)argv[5], (int)strlen(argv[5])); + + break; + } + default: + { + goto usage; + } + } + }else{ + stream->write_function(stream, "-ERR No such profile\n"); + } - megaco_profile_release(profile); - mg_send_service_change(profile->idx, argv[4], atoi(argv[5]), atoi(argv[6]),wild); - } else { - stream->write_function(stream, "-ERR No such profile\n"); - } /**********************************************************************************/ }else { /**********************************************************************************/ @@ -154,6 +186,7 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre goto done; usage: + megaco_profile_release(profile); stream->write_function(stream, "-ERR Usage: \n""\t"MEGACO_CLI_SYNTAX" \n \t"MEGACO_FUNCTION_SYNTAX"\n \t" MEGACO_LOGGING_CLI_SYNTAX "\n"); done: diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index bee845a8c1..12174639ae 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -2135,3 +2135,200 @@ err: return ret; } /*****************************************************************************************************************************/ +/* API to send DTMF Digits Notification */ + +switch_status_t mg_send_dtmf_notify(megaco_profile_t* mg_profile, const char* term_name, char* digits, int num_of_collected_digits ) +{ + MgMgcoObsEvt *oevt; + MgMgcoEvtPar* param; + int ascii = 0x00; + int cnt = 0x00; + + switch_assert(term_name); + switch_assert(mg_profile); + switch_assert(digits); + + if(0 == num_of_collected_digits ){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"num_of_collected_digits cannt be ZERO \n"); + return SWITCH_STATUS_FALSE; + } + + mg_stack_alloc_mem((Ptr*)&oevt, sizeof(MgMgcoObsEvt)); + + oevt->pres.pres = PRSNT_NODEF; + + mg_get_time_stamp(&oevt->time); + + MG_INIT_TOKEN_VALUE(&(oevt->pkg.pkgType), MGT_PKG_KNOWN); + + MG_INIT_TOKEN_VALUE(&(oevt->pkg.valType), MGT_PKG_KNOWN); + + MG_INIT_TOKEN_VALUE(&(oevt->pkg.u.val), MGT_PKG_EXT_DTMF); + + MG_INIT_TOKEN_VALUE(&(oevt->name.type),MGT_GEN_TYPE_KNOWN); + + MG_INIT_TOKEN_VALUE(&(oevt->name.u.val),(U8)MGT_PKG_ENUM_REQEVT_EXT_DTMF_EXT_CE); + + if (mgUtlGrowList((void ***)&oevt->pl.parms, sizeof(MgMgcoEvtPar), &oevt->pl.num, NULL) != ROK) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + param = oevt->pl.parms[0]; + + MG_INIT_TOKEN_VALUE(&(param->type),(U8)MGT_EVTPAR_OTHER); + + MG_INIT_TOKEN_VALUE(&(param->u.other.name.type),MGT_GEN_TYPE_KNOWN); + MG_INIT_TOKEN_VALUE(&(param->u.other.name.u.val),MGT_PKG_ENUM_OBSEVTOTHER_EXT_DTMF_EXT_CE_DGT_STR); + + MG_INIT_TOKEN_VALUE(&(param->u.other.val.type),MGT_VALUE_EQUAL); + MG_INIT_TOKEN_VALUE(&(param->u.other.val.u.eq.type),MGT_VALTYPE_OCTSTRXL); + + mg_stack_alloc_mem((Ptr*)¶m->u.other.val.u.eq.u.osxl.val, num_of_collected_digits+2); + + param->u.other.val.u.eq.u.osxl.pres = 0x01; + param->u.other.val.u.eq.u.osxl.len = num_of_collected_digits+2; + + param->u.other.val.u.eq.u.osxl.val[0] = '\"'; + + /* copy collected DTMF digits */ + if(ascii) + { + for(cnt = 1; cnt< num_of_collected_digits; cnt++){ + /* convert values to ascii */ + if(digits[cnt-1] <= 9){ + param->u.other.val.u.eq.u.osxl.val[cnt] = digits[cnt-1] + '0'; + }else{ + /* 10 for decimal equivalent of A */ + param->u.other.val.u.eq.u.osxl.val[cnt] = digits[cnt-1] + 'A' - 10; + } + } + } else { + /* If incoming digits are already in ascii format .. simply copy */ + for(cnt = 1; cnt< num_of_collected_digits; cnt++){ + param->u.other.val.u.eq.u.osxl.val[cnt] = digits[cnt-1]; + } + } + + + param->u.other.val.u.eq.u.osxl.val[num_of_collected_digits+1] = '\"'; + + if (mgUtlGrowList((void ***)&oevt->pl.parms, sizeof(MgMgcoEvtPar), &oevt->pl.num, NULL) != ROK) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + param = oevt->pl.parms[1]; + + + /* Set method */ + MG_INIT_TOKEN_VALUE(&(param->type),MGT_EVTPAR_OTHER); + MG_INIT_TOKEN_VALUE(&(param->u.other.name.type),MGT_GEN_TYPE_KNOWN); + MG_INIT_TOKEN_VALUE(&(param->u.other.name.u.val),MGT_PKG_ENUM_OBSEVTOTHER_EXT_DTMF_EXT_CE_TERM_METH); + + MG_INIT_TOKEN_VALUE(&(param->u.other.val.type),MGT_VALUE_EQUAL); + MG_INIT_TOKEN_VALUE(&(param->u.other.val.u.eq.type),MGT_VALTYPE_ENUM); + MG_INIT_TOKEN_VALUE(&(param->u.other.val.u.eq.u.enume),MGT_PKG_ENUM_OBSEVTOTHER_EXT_DTMF_EXT_CE_TERM_METHFM); + + return mg_send_notify(mg_profile, term_name, oevt); +} + +/*****************************************************************************************************************************/ + +/* Note : API to send NOTIFY Message */ +/* INPUT : +* mg_profile - MG profile structure pointer +* term_name - Termination Name(as specified for MEGACO ) +* oevt - Observed Event structure pointer +*/ +switch_status_t mg_send_notify(megaco_profile_t* mg_profile, const char* term_name, MgMgcoObsEvt* oevt) +{ + switch_status_t ret; + MgMgcoCommand request; + MgMgcoTermId* termId; + mg_termination_t* term = NULL; + MgMgcoObsEvtDesc *obs_desc = NULL; + MgMgcoRequestId reqId; + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "Sending Notify Message for termination[%s] !\n", term_name); + + MG_ZERO(&request, sizeof(request)); + MG_ZERO(&reqId, sizeof(reqId)); + + term = megaco_find_termination(mg_profile, (char*)term_name); + + if(!term){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "No termination configured for given name[%s] !\n", term_name); + return SWITCH_STATUS_FALSE; + } + + if(NULL == term->active_events){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "No Active events observed on given termination[%s] !\n", term_name); + /* return SWITCH_STATUS_FALSE; */ + /*TODO - ideally we should return ... + * as of now not returning .. if we dont have active signals then + * setting default request id and sending notification to MGC */ + MG_SET_DEF_REQID(&reqId); + }else{ + MG_MEM_COPY(&reqId, &term->active_events->reqId, sizeof(MgMgcoRequestId)); + } + + + if(SWITCH_STATUS_FALSE == (ret = mg_create_mgco_command(&request, CH_CMD_TYPE_REQ, MGT_NTFY))){ + return SWITCH_STATUS_FALSE; + } + + if (mgUtlGrowList((void ***)&request.u.mgCmdReq[0]->cmd.u.ntfy.obs.el.evts, sizeof(MgMgcoObsEvtLst), + &request.u.mgCmdReq[0]->cmd.u.ntfy.obs.el.num, &request.u.mgCmdReq[0]->memCp) != ROK) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + obs_desc = &request.u.mgCmdReq[0]->cmd.u.ntfy.obs; + + MG_INIT_TOKEN_VALUE(&(obs_desc->pres), PRSNT_NODEF); + + /* copy request id */ + MG_MEM_COPY(&obs_desc->reqId, &reqId, sizeof(MgMgcoRequestId)); + + /* copy observe event */ + /*MG_MEM_COPY(obs_desc->el.evts[0], oevt, sizeof(MgMgcoObsEvt));*/ + + obs_desc->el.evts[0] = oevt; + + + /*fill txn id */ + request.transId.pres = PRSNT_NODEF; + request.transId.val = get_txn_id(); + + request.contextId.type.pres = PRSNT_NODEF; + request.contextId.type.val = MGT_CXTID_NULL; + + request.cmdStatus.pres = PRSNT_NODEF; + request.cmdStatus.val = CH_CMD_STATUS_END_OF_TXN; + + request.cmdType.pres = PRSNT_NODEF; + request.cmdType.val = CH_CMD_TYPE_REQ; + + /* fill termination */ + if (mgUtlGrowList((void ***)&request.u.mgCmdReq[0]->cmd.u.ntfy.termIdLst.terms, sizeof(MgMgcoTermIdLst), + &request.u.mgCmdReq[0]->cmd.u.ntfy.termIdLst.num, &request.u.mgCmdReq[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + +#ifdef GCP_VER_2_1 + termId = request.u.mgCmdReq[0]->cmd.u.ntfy.termIdLst.terms[0]; +#else + termId = &(request.u.mgCmdReq[0]->cmd.u.ntfy.termId); +#endif + + mg_fill_mgco_termid(termId, (char*)term_name ,strlen(term_name), &request.u.mgCmdReq[0]->memCp); + + sng_mgco_send_cmd(mg_profile->idx, &request); + + return SWITCH_STATUS_SUCCESS; +} +/*****************************************************************************************************************************/ + diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index fc27386d9a..f308496b1e 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -120,6 +120,13 @@ typedef enum { cmMemcpy((U8*)((_tkn).val), (U8*)(_val), _len);\ } +#define MG_SET_DEF_REQID(_reqId) \ + (_reqId)->type.pres = PRSNT_NODEF; \ + (_reqId)->type.val = MGT_REQID_OTHER; \ + (_reqId)->id.pres = PRSNT_NODEF; \ + (_reqId)->id.val = 0xFFFFFFFF; + + switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd, mg_termination_t* term); void handle_sng_log(uint8_t level, char *fmt, ...); void handle_mgco_sta_ind(Pst *pst, SuId suId, MgMgtSta* msg); @@ -174,6 +181,9 @@ switch_status_t mg_create_mgco_command(MgMgcoCommand *cmd, uint8_t apiType, ui switch_status_t mg_send_oos_service_change(megaco_profile_t* mg_profile, const char* term_name, int wild); switch_status_t mg_send_ins_service_change(megaco_profile_t* mg_profile, const char* term_name, int wild); +switch_status_t mg_send_notify(megaco_profile_t* mg_profile, const char* term_name, MgMgcoObsEvt* oevt); +switch_status_t mg_send_dtmf_notify(megaco_profile_t* mg_profile, const char* term_name, char* digits, int num_of_collected_digits); +switch_status_t mg_util_build_obs_evt_desc (MgMgcoObsEvt *obs_event, MgMgcoRequestId *request_id, MgMgcoObsEvtDesc **ptr_obs_desc); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index 73d467f8de..b6751c6eea 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -1353,3 +1353,39 @@ void mg_fill_null_context(MgMgcoContextId* ctxt) MG_SET_TKN_VAL_PRES(&ctxt->type, MGT_CXTID_NULL, PRSNT_NODEF); } /*****************************************************************************************************************************/ +switch_status_t mg_util_build_obs_evt_desc (MgMgcoObsEvt *obs_event, MgMgcoRequestId *request_id, MgMgcoObsEvtDesc **ptr_obs_desc) +{ + MgMgcoObsEvtDesc *obs_desc = NULL; + + /* Check for valid request Id, if not then fill default value */ + if (NOTPRSNT == request_id->type.pres) + { + MG_SET_DEF_REQID(request_id); + } + + mg_stack_alloc_mem((Ptr*)&obs_desc, sizeof(MgMgcoObsEvtDesc)); + if (NULL == obs_desc) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "Failed to allocate MgMgcoObsEvtDesc!\n"); + return SWITCH_STATUS_FALSE; + } + + obs_desc->pres.pres = PRSNT_NODEF; + MG_MEM_COPY(&obs_desc->reqId, request_id, sizeof(MgMgcoRequestId)); + obs_desc->el.num.pres = PRSNT_NODEF; + obs_desc->el.num.val = 1; + + mg_stack_alloc_mem((Ptr*)&obs_desc->el.evts, sizeof(MgMgcoObsEvt*)); + if (NULL == obs_desc->el.evts) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "Failed to allocate MgMgcoObsEvt!\n"); + return SWITCH_STATUS_FALSE; + } + + MG_MEM_COPY(obs_desc->el.evts[0], obs_event, sizeof(obs_event)); + + *ptr_obs_desc = obs_desc; + + return SWITCH_STATUS_SUCCESS; +} +/*****************************************************************************************************************************/ From 12e8e481b5789c73b60202e193967274a067f9e7 Mon Sep 17 00:00:00 2001 From: Kapil Date: Tue, 24 Jul 2012 13:34:02 -0400 Subject: [PATCH 324/822] adding API to send "In-Activity" timer expiry NOTIFY to MGC for IT/ITO package --- .../mod_media_gateway/media_gateway_cli.c | 19 ++++++ .../media_gateway_cmd_handler.c | 62 +++++++++++++++---- .../mod_media_gateway/media_gateway_stack.h | 1 + .../mod_media_gateway/media_gateway_utils.c | 36 ++++++----- .../mod_media_gateway/mod_media_gateway.c | 4 +- 5 files changed, 93 insertions(+), 29 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c index f249d012f4..9b575c5384 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c @@ -142,6 +142,25 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre megaco_profile_release(profile); mg_send_dtmf_notify(profile, argv[4], (char*)argv[5], (int)strlen(argv[5])); + break; + } + case 5: + { + /* mg profile send ito notify */ + if(zstr(argv[3])){ + goto usage; + } + + if(strcasecmp(argv[3],"ito")){ + stream->write_function(stream, "-ERR wrong input \n"); + goto usage; + } + + printf("Sending In-Activity NOTIFY \n"); + + megaco_profile_release(profile); + mg_send_ito_notify(profile); + break; } default: diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 12174639ae..290b21efe8 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -2134,6 +2134,36 @@ err: mgUtlDelMgMgcoSvcChgPar(&srvPar); return ret; } + +/*****************************************************************************************************************************/ +/* API to send In-Activity Timeout NOTIFY to MGC */ +switch_status_t mg_send_ito_notify(megaco_profile_t* mg_profile ) +{ + MgMgcoObsEvt *oevt; + + switch_assert(mg_profile); + + mg_stack_alloc_mem((Ptr*)&oevt, sizeof(MgMgcoObsEvt)); + + oevt->pres.pres = PRSNT_NODEF; + + mg_get_time_stamp(&oevt->time); + + MG_INIT_TOKEN_VALUE(&(oevt->pkg.pkgType), MGT_PKG_KNOWN); + + MG_INIT_TOKEN_VALUE(&(oevt->pkg.valType), MGT_PKG_KNOWN); + + MG_INIT_TOKEN_VALUE(&(oevt->pkg.u.val), MGT_PKG_INACTTIMER); + + MG_INIT_TOKEN_VALUE(&(oevt->name.type),MGT_GEN_TYPE_KNOWN); + + MG_INIT_TOKEN_VALUE(&(oevt->name.u.val),(U8)MGT_PKG_ENUM_REQEVT_INACTTIMER_INACT_TIMOUT); + + oevt->pl.num.pres = PRSNT_NODEF; + oevt->pl.num.val = 0x00; + + return mg_send_notify(mg_profile, "ROOT", oevt); +} /*****************************************************************************************************************************/ /* API to send DTMF Digits Notification */ @@ -2255,23 +2285,29 @@ switch_status_t mg_send_notify(megaco_profile_t* mg_profile, const char* term_n MG_ZERO(&request, sizeof(request)); MG_ZERO(&reqId, sizeof(reqId)); - term = megaco_find_termination(mg_profile, (char*)term_name); + if(strcmp(term_name, "ROOT")){ + /* Not ROOT term then --- */ + term = megaco_find_termination(mg_profile, (char*)term_name); - if(!term){ - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "No termination configured for given name[%s] !\n", term_name); - return SWITCH_STATUS_FALSE; - } + if(!term){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "No termination configured for given name[%s] !\n", term_name); + return SWITCH_STATUS_FALSE; + } - if(NULL == term->active_events){ - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "No Active events observed on given termination[%s] !\n", term_name); - /* return SWITCH_STATUS_FALSE; */ - /*TODO - ideally we should return ... - * as of now not returning .. if we dont have active signals then - * setting default request id and sending notification to MGC */ - MG_SET_DEF_REQID(&reqId); + if(NULL == term->active_events){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "No Active events observed on given termination[%s] !\n", term_name); + /* return SWITCH_STATUS_FALSE; */ + /*TODO - ideally we should return ... + * as of now not returning .. if we dont have active signals then + * setting default request id and sending notification to MGC */ + MG_SET_DEF_REQID(&reqId); + }else{ + MG_MEM_COPY(&reqId, &term->active_events->reqId, sizeof(MgMgcoRequestId)); + } }else{ - MG_MEM_COPY(&reqId, &term->active_events->reqId, sizeof(MgMgcoRequestId)); + MG_SET_DEF_REQID(&reqId); } + if(SWITCH_STATUS_FALSE == (ret = mg_create_mgco_command(&request, CH_CMD_TYPE_REQ, MGT_NTFY))){ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index f308496b1e..d5b82a5b54 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -183,6 +183,7 @@ switch_status_t mg_send_oos_service_change(megaco_profile_t* mg_profile, const c switch_status_t mg_send_ins_service_change(megaco_profile_t* mg_profile, const char* term_name, int wild); switch_status_t mg_send_notify(megaco_profile_t* mg_profile, const char* term_name, MgMgcoObsEvt* oevt); switch_status_t mg_send_dtmf_notify(megaco_profile_t* mg_profile, const char* term_name, char* digits, int num_of_collected_digits); +switch_status_t mg_send_ito_notify(megaco_profile_t* mg_profile); switch_status_t mg_util_build_obs_evt_desc (MgMgcoObsEvt *obs_event, MgMgcoRequestId *request_id, MgMgcoObsEvtDesc **ptr_obs_desc); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index b6751c6eea..d521823005 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -96,27 +96,33 @@ S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, char* term_str, int term_len, C S16 ret = ROK; termId->type.pres = PRSNT_NODEF; - termId->type.val = MGT_TERMID_OTHER; - termId->name.dom.pres = NOTPRSNT; - termId->name.dom.len = 0x00; + if(!strcmp(term_str,"ROOT")){ + /* ROOT Termination */ + termId->type.val = MGT_TERMID_ROOT; + } else { + termId->type.val = MGT_TERMID_OTHER; - termId->name.pres.pres = PRSNT_NODEF; - termId->name.lcl.pres = PRSNT_NODEF; - termId->name.lcl.len = term_len; - /*MG_GETMEM(termId->name.lcl.val, termId->name.lcl.len , memCp, ret);*/ - ret = mg_stack_alloc_mem((Ptr*)&termId->name.lcl.val,term_len); + termId->name.dom.pres = NOTPRSNT; + termId->name.dom.len = 0x00; - printf("termId->name.lcl.val[%p]\n",termId->name.lcl.val); + termId->name.pres.pres = PRSNT_NODEF; + termId->name.lcl.pres = PRSNT_NODEF; + termId->name.lcl.len = term_len; + /*MG_GETMEM(termId->name.lcl.val, termId->name.lcl.len , memCp, ret);*/ + ret = mg_stack_alloc_mem((Ptr*)&termId->name.lcl.val,term_len); - if( ret != ROK) - RETVALUE(ret); + printf("termId->name.lcl.val[%p]\n",termId->name.lcl.val); - /*cmMemcpy((U8*)(termId->name.lcl.val), (CONSTANT U8*)term_str,termId->name.lcl.len);*/ - strncpy((char*)(termId->name.lcl.val), term_str, termId->name.lcl.len); - termId->name.lcl.val[termId->name.lcl.len] = '\0'; + if( ret != ROK) + RETVALUE(ret); - printf("mg_fill_mgco_termid: name.lcl.val[%s], len[%d], term_str[%s], term_len[%d]\n",termId->name.lcl.val, termId->name.lcl.len, term_str,term_len); + /*cmMemcpy((U8*)(termId->name.lcl.val), (CONSTANT U8*)term_str,termId->name.lcl.len);*/ + strncpy((char*)(termId->name.lcl.val), term_str, termId->name.lcl.len); + termId->name.lcl.val[termId->name.lcl.len] = '\0'; + + printf("mg_fill_mgco_termid: name.lcl.val[%s], len[%d], term_str[%s], term_len[%d]\n",termId->name.lcl.val, termId->name.lcl.len, term_str,term_len); + } #ifdef GCP_ASN diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 03a61104ec..4394a86184 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -613,6 +613,7 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) } case CH_CMD_TYPE_CFM: { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Received Command txn[%d] Response/Confirmation \n",txn_id); break; } default: @@ -623,7 +624,8 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "cmd->cmdStatus.val[%d]\n",cmd->cmdStatus.val); /* END OF TXN received - means last command in txn to process. * Send response to peer */ - /*if(CH_CMD_STATUS_END_OF_TXN == cmd->cmdStatus.val)*/{ + if(CH_CMD_TYPE_IND == cmd->cmdType.val){ + /*if(CH_CMD_STATUS_END_OF_TXN == cmd->cmdStatus.val)*/ mg_send_end_of_axn(suId, &cmd->transId, &out_ctxt, &cmd->peerId); } From e5821eeb7961ffdb693b9475f2949dae523715fc Mon Sep 17 00:00:00 2001 From: Kapil Date: Tue, 24 Jul 2012 16:57:09 -0400 Subject: [PATCH 325/822] adding code to fill dummy local descriptor sdp to add response --- .../media_gateway_cmd_handler.c | 280 +++++++++--------- 1 file changed, 145 insertions(+), 135 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 290b21efe8..55da9a3757 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -323,6 +323,7 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i U32 txn_id = inc_cmd->transId.val; mg_termination_t* term = NULL; MgMgcoMediaDesc* inc_med_desc; + /*MgMgcoStreamDesc* inc_strm_desc;*/ MgMgcoAudRetParm *desc; mg_context_t* mg_ctxt; @@ -495,180 +496,189 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i desc->type.val = MGT_MEDIADESC; mgUtlCpyMgMgcoMediaDesc(&desc->u.media, inc_med_desc, &rsp.u.mgCmdRsp[0]->memCp); -#if 0 { - - MgMgcoStreamDesc *stream; + /* build local descriptors */ + /*MgMgcoStreamDesc *stream;*/ MgMgcoLocalDesc *local; - MgMgcoRemoteDesc* remote; CmSdpInfoSet *psdp; - CmSdpInfoSet *prsdp; char* ipAddress = "192.168.1.1"; + MgMgcoMediaDesc* media = &desc->u.media; /* Most probably we need to add local descriptor */ - /* TODO - considering only one descriptor*/ - stream = &desc->u.media.parms[0]->u.stream; + /* allocating mem for local descriptor */ + if (mgUtlGrowList((void ***)&media->parms, sizeof(MgMgcoMediaPar), + &media->num, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + +#if 0 + /* Kapil - NOT REQUIRED..keeping now just for ref..will delete asap */ + media->parms[media->num.val-1]->type.pres = PRSNT_NODEF; + /*media->parms[media->num.val-1]->type.val = MGT_MEDIAPAR_STRPAR;*/ + + printf("media->num.val[%d]\n",media->num.val); + + stream = &media->parms[media->num.val-1]->u.stream; stream->pres.pres = PRSNT_NODEF; + stream->pres.val = 0x01; +#if 0 + if(inc_med_desc->num.pres && inc_med_desc->num.val){ + /* TODO - check stream descriptor type for all medias */ + inc_strm_desc = &inc_med_desc->parms[0]->u.stream; + memcpy(&stream->streamId, &inc_strm_desc->streamId, sizeof(MgMgcoStreamId)); + } +#endif + + MG_INIT_TOKEN_VALUE(&(stream->streamId), 1); + + stream->sl.pres.pres = PRSNT_NODEF; + stream->sl.pres.val = 0x01; + local = &stream->sl.local; - remote = &stream->sl.remote; +#endif + media->parms[media->num.val-1]->type.pres = PRSNT_NODEF; + media->parms[media->num.val-1]->type.val = MGT_MEDIAPAR_LOCAL; - if(!local->pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " Local stream media not present adding it \n"); + local = &media->parms[media->num.val-1]->u.local; - /* allocating mem for local descriptor */ - if (mgUtlGrowList((void ***)&desc->u.media.parms, sizeof(MgMgcoMediaPar), - &desc->u.media.num, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + local->pres.pres = PRSNT_NODEF; + + psdp = &(local->sdp); + + if (mgUtlGrowList((void ***)&psdp->info, sizeof(CmSdpInfo), + &psdp->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + psdp->info[psdp->numComp.val-1]->pres.pres = PRSNT_NODEF; + + /* fill version */ + /*memcpy(&psdp->info[0]->ver, &prsdp->info[0]->ver, sizeof(TknU16)); */ + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->ver),1); + + /* fill orig */ + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.pres), 1); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.type), CM_SDP_SPEC); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.orig.pres), 1); + + MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.usrName, 1, "-", + &rsp.u.mgCmdRsp[0]->memCp); + MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.sessId, 1, "0", + &rsp.u.mgCmdRsp[0]->memCp); + MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.sessVer, 1, "0", + &rsp.u.mgCmdRsp[0]->memCp); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.netType.type), + CM_SDP_NET_TYPE_IN); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.addrType), + CM_SDP_ADDR_TYPE_IPV4); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.addrType), + CM_SDP_IPV4_IP_UNI); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.addrType), + CM_SDP_IPV4_IP_UNI); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[0]), + ipAddress[0]); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[1]), + ipAddress[1]); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[2]), + ipAddress[2]); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[3]), + ipAddress[3]); + + /* fill session name */ + /* TODO - need to fill proper session name or skip it..*/ + MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->sessName, 8, "SANGOMA",&rsp.u.mgCmdRsp[0]->memCp); + + + /* Fill the SDP Connection Info */ + /* "c=" line - ipaddress */ + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.netType.type),CM_SDP_NET_TYPE_IN); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.addrType), CM_SDP_ADDR_TYPE_IPV4); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.u.ip4.addrType), CM_SDP_IPV4_IP_UNI); + + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[0]), ipAddress[0]); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[1]), ipAddress[1]); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[2]), ipAddress[2]); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[3]), ipAddress[3]); + + /* t= line */ + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->sdpTime.pres),1); +#if 0 + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->sdpTime.sdpOpTimeSet.numComp),0); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->sdpTime.zoneAdjSet.numComp),0); +#endif + + /* fill media descriptors */ + { + CmSdpMediaDescSet* med = &psdp->info[psdp->numComp.val-1]->mediaDescSet; + CmSdpMediaDesc* media; + + if (mgUtlGrowList((void ***)&med->mediaDesc, sizeof(CmSdpMediaDesc), + &med->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) { switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); return SWITCH_STATUS_FALSE; } - desc->u.media.parms[desc->u.media.num.val-1]->type.pres = PRSNT_NODEF; - desc->u.media.parms[desc->u.media.num.val-1]->type.val = MGT_MEDIAPAR_STRPAR; + media = med->mediaDesc[med->numComp.val-1]; + MG_INIT_TOKEN_VALUE(&(media->pres),1); - stream = &desc->u.media.parms[desc->u.media.num.val-1]->u.stream; - stream->pres.pres = PRSNT_NODEF; - stream->pres.val = 0x01; - stream->sl.pres.pres = PRSNT_NODEF; - stream->sl.pres.val = 0x01; - local = &stream->sl.local; - remote = &stream->sl.remote; + /* Fill CmSdpMediaField */ + MG_INIT_TOKEN_VALUE(&(media->field.pres),1); + MG_INIT_TOKEN_VALUE(&(media->field.mediaType),CM_SDP_MEDIA_AUDIO); - memcpy(&stream->streamId, &desc->u.media.parms[0]->u.stream.streamId, sizeof(MgMgcoStreamId)); + MG_INIT_TOKEN_VALUE(&(media->field.id.type),CM_SDP_VCID_PORT); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.type),CM_SDP_PORT_INT); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.pres),1); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.type), CM_SDP_SPEC); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.val), 2904); - local->pres.pres = PRSNT_NODEF; - psdp = &(local->sdp); - prsdp = &(remote->sdp); - - if (mgUtlGrowList((void ***)&psdp->info, sizeof(CmSdpInfo), - &psdp->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + if (mgUtlGrowList((void ***)&media->field.par.pflst, sizeof(CmSdpMedProtoFmts), + &media->field.par.numProtFmts, &rsp.u.mgCmdRsp[0]->memCp) != ROK) { switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); return SWITCH_STATUS_FALSE; } - psdp->info[0]->pres.pres = PRSNT_NODEF; - - /* fill version */ - /*memcpy(&psdp->info[0]->ver, &prsdp->info[0]->ver, sizeof(TknU16)); */ - MG_INIT_TOKEN_VALUE(&(psdp->info[0]->ver),1); - - /* fill orig */ - MG_SET_TKNSTROSXL(psdp->info[0]->orig.orig.usrName, 1, "-", - &rsp.u.mgCmdRsp[0]->memCp); - MG_SET_TKNSTROSXL(psdp->info[0]->orig.orig.sessId, 1, "0", - &rsp.u.mgCmdRsp[0]->memCp); - MG_SET_TKNSTROSXL(psdp->info[0]->orig.orig.sessVer, 1, "0", - &rsp.u.mgCmdRsp[0]->memCp); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.netType.type), - CM_SDP_NET_TYPE_IN); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.addrType), - CM_SDP_ADDR_TYPE_IPV4); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.addrType), - CM_SDP_IPV4_IP_UNI); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.addrType), - CM_SDP_IPV4_IP_UNI); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[0]), - ipAddress[0]); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[1]), - ipAddress[1]); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[2]), - ipAddress[2]); - MG_SET_VAL_PRES( (psdp->info[0]->orig.orig.sdpAddr.u.ip4.u.ip.b[3]), - ipAddress[3]); - - /* fill session name */ - /*memcpy(&psdp->info[0]->sessName, &prsdp->info[0]->sessName, sizeof(TknStrOSXL));*/ - MG_SET_TKNSTROSXL(psdp->info[0]->sessName, 1, "-",&rsp.u.mgCmdRsp[0]->memCp); + /* CmSdpMedProtoFmts */ + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->prot.type), CM_SDP_MEDIA_PROTO_RTP) + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->prot.u.subtype.type), CM_SDP_PROTO_RTP_AVP); + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->protType), CM_SDP_MEDIA_PROTO_RTP); - /* fill info */ - MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[0]), ipAddress[0]); - MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[1]), ipAddress[1]); - MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[2]), ipAddress[2]); - MG_SET_VAL_PRES( (psdp->info[0]->conn.u.ip4.u.uniIp.b[3]), ipAddress[3]); - - /* Fill the SDP Connection Info */ - /* "c=" line - ipaddress */ - /*memcpy(&psdp->info[0]->conn, &prsdp->info[0]->conn, sizeof(CmSdpConn));*/ - - /* fill media descriptors */ + if (mgUtlGrowList((void ***)&media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.fmts, sizeof(CmSdpU8OrNil), + &media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.num, &rsp.u.mgCmdRsp[0]->memCp) != ROK) { - CmSdpMediaDescSet* med = &psdp->info[0]->mediaDescSet; - CmSdpMediaDesc* media; + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } - if (mgUtlGrowList((void ***)&med->mediaDesc, sizeof(CmSdpMediaDesc), - &med->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.fmts[0]->type), CM_SDP_SPEC); + + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.fmts[0]->val), 4); + + /* Fill attribute if reqd */ + { + if (mgUtlGrowList((void ***)&media->attrSet.attr, sizeof(CmSdpAttr), + &media->attrSet.numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) { switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); return SWITCH_STATUS_FALSE; } - media = med->mediaDesc[0]; - - MG_INIT_TOKEN_VALUE(&(media->pres),1); - - /* Fill CmSdpMediaField */ - MG_INIT_TOKEN_VALUE(&(media->field.pres),1); - MG_INIT_TOKEN_VALUE(&(media->field.mediaType),CM_SDP_MEDIA_AUDIO); - - MG_INIT_TOKEN_VALUE(&(media->field.id.type),CM_SDP_VCID_PORT); - MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.type),CM_SDP_PORT_INT); - MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.pres),1); - MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.type), - CM_SDP_SPEC); - MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.val), 2904); - - - MG_INIT_TOKEN_VALUE(&(media->field.par.numProtFmts),1); - MG_GETMEM((media->field.par.pflst),1*sizeof(CmSdpMedProtoFmts*),&rsp.u.mgCmdRsp[0]->memCp, ret); - MG_GETMEM((media->field.par.pflst[0]),sizeof(CmSdpMedProtoFmts),&rsp.u.mgCmdRsp[0]->memCp, ret); - MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->prot.type), - CM_SDP_MEDIA_PROTO_RTP) - MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->prot.u.subtype.type), - CM_SDP_PROTO_RTP_AVP); - MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->protType), - CM_SDP_MEDIA_PROTO_RTP); - - - MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->u.rtp.num),1); - - MG_GETMEM((media->field.par.pflst[0]->u.rtp.fmts), - 1*sizeof(CmSdpU8OrNil *), &rsp.u.mgCmdRsp[0]->memCp, ret); - - MG_GETMEM((media->field.par.pflst[0]->u.rtp.fmts[0]), - sizeof(CmSdpU8OrNil), &rsp.u.mgCmdRsp[0]->memCp, ret); - - MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->u.rtp.fmts[0]->type), - CM_SDP_SPEC); - - MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[0]->u.rtp.fmts[0]->val), - 4); - - /* Fill attribute if reqd */ - { - MG_INIT_TOKEN_VALUE(&(media->attrSet.numComp),1); - MG_GETMEM((media->attrSet.attr),sizeof(CmSdpAttr*),&rsp.u.mgCmdRsp[0]->memCp, ret); - MG_GETMEM((media->attrSet.attr[0]),sizeof(CmSdpAttr),&rsp.u.mgCmdRsp[0]->memCp, ret); - MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[0]->type),CM_SDP_ATTR_PTIME); - media->attrSet.attr[0]->u.ptime.pres = PRSNT_NODEF; - media->attrSet.attr[0]->u.ptime.val = 30; - } - + MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[0]->type),CM_SDP_ATTR_PTIME); + MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[0]->u.ptime),30); } - printf("ret[%d]\n",ret); + } - } - else { - printf("!local->pres.pres false \n"); - } } -#endif - /* We will always send one command at a time..*/ From dd0b5147410de6915ecfc108d8b694dbc39dfcc0 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 25 Jul 2012 10:53:07 -0400 Subject: [PATCH 326/822] fixing 32bit specific print warnings --- .../mod_media_gateway/media_gateway_cmd_handler.c | 10 ++++++++++ .../mod_media_gateway/media_gateway_utils.c | 10 ++++++++++ .../mod_media_gateway/mod_media_gateway.c | 14 +++++++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 55da9a3757..37effcbe95 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -778,9 +778,15 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand /********************************************************************/ } else if(MGT_TERMID_OTHER == termId->type.val){ /********************************************************************/ +#ifdef BIT_64 switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "Modify request is for termination[%s] and context: type[%d], value[%d] \n", termId->name.lcl.val, ctxtId->type.val, ctxtId->val.val); +#else + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + "Modify request is for termination[%s] and context: type[%d], value[%ld] \n", + termId->name.lcl.val, ctxtId->type.val, ctxtId->val.val); +#endif term = megaco_find_termination(mg_profile, (char*)termId->name.lcl.val); @@ -976,7 +982,11 @@ switch_status_t handle_mg_subtract_cmd(megaco_profile_t* mg_profile, MgMgcoComma if (MGT_CXTID_OTHER == ctxtId->type.val){ +#ifdef BIT_64 switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," SUB Request for Context[%d] \n", ctxtId->val.val); +#else + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," SUB Request for Context[%ld] \n", ctxtId->val.val); +#endif /*find context based on received context-id */ mg_ctxt = megaco_get_context(mg_profile, ctxtId->val.val); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index d521823005..e8788ea6f2 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -456,8 +456,13 @@ void mgco_print_sdp_attr_set(CmSdpAttrSet *s) } case CM_SDP_ATTR_PTIME: { +#ifdef BIT_64 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t PTIME = %d \n", (NOTPRSNT != a->u.ptime.pres)?a->u.ptime.val:-1); +#else + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t PTIME = %ld \n", + (NOTPRSNT != a->u.ptime.pres)?a->u.ptime.val:-1); +#endif break; } case CM_SDP_ATTR_RECVONLY: @@ -537,8 +542,13 @@ void mgco_print_sdp_attr_set(CmSdpAttrSet *s) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Encoding Name name = %s \n", (NOTPRSNT != r->enc.name.pres)?(char*)r->enc.name.val:"Not Present"); +#ifdef BIT_64 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Clock Rate = %d \n", (NOTPRSNT != r->clk.pres)?r->clk.val:-1); +#else + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Clock Rate = %ld \n", + (NOTPRSNT != r->clk.pres)?r->clk.val:-1); +#endif switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Encoding Parameters = %s \n", (NOTPRSNT != r->parms.pres)?(char*)r->parms.val:"Not Present"); diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 4394a86184..2cd68716be 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -518,7 +518,11 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) }else if(MGT_CXTID_OTHER == inc_context->type.pres){ if(NOTPRSNT != inc_context->val.pres){ +#ifdef BIT_64 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"Context specific request for contextId[%d]\n",inc_context->val.val); +#else + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"Context specific request for contextId[%ld]\n",inc_context->val.val); +#endif /* check if context present with us */ if(NULL == megaco_find_context_by_suid(suId, inc_context->val.val)){ goto ctxt_error; @@ -613,11 +617,19 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) } case CH_CMD_TYPE_CFM: { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Received Command txn[%d] Response/Confirmation \n",txn_id); +#ifdef BIT_64 + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Received Command txn[%d] Response/Confirmation \n",txn_id); +#else + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Received Command txn[%ld] Response/Confirmation \n",txn_id); +#endif break; } default: +#ifdef BIT_64 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Invalid command type[%d]\n",cmd->cmdType.val); +#else + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Invalid command type[%d]\n",cmd->cmdType.val); +#endif return; } From 4585dbffbbdd210cbe5c56a1f90a5236cc50a042 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 25 Jul 2012 11:27:01 -0400 Subject: [PATCH 327/822] Fixed conflict from previous merge --- conf/vanilla/autoload_configs/modules.conf.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/conf/vanilla/autoload_configs/modules.conf.xml b/conf/vanilla/autoload_configs/modules.conf.xml index ef40fd1992..f88bb7b7c0 100644 --- a/conf/vanilla/autoload_configs/modules.conf.xml +++ b/conf/vanilla/autoload_configs/modules.conf.xml @@ -82,11 +82,7 @@ -<<<<<<< HEAD - -======= ->>>>>>> eb0404d0256dee4696b3ae1b62c4b1cef9327a0d From 2d9ed21007cc309380fb0af99bc15d20e957fcac Mon Sep 17 00:00:00 2001 From: Kapil Date: Wed, 25 Jul 2012 12:57:42 -0400 Subject: [PATCH 328/822] adding code to 1) parse incoming MODIFY request for ITO package , 2) starting timer based on MGC requested time 3) on expiry generate Inactivity Notify to MGC --- .../media_gateway_cmd_handler.c | 157 ++++++++++++++++++ .../mod_media_gateway/media_gateway_stack.h | 5 + .../mod_media_gateway/media_gateway_utils.c | 8 + .../mod_media_gateway/mod_media_gateway.h | 2 + 4 files changed, 172 insertions(+) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 37effcbe95..ec760398e7 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -19,6 +19,159 @@ const char *mg_service_change_reason[] = { 0 }; + +/*****************************************************************************************************************************/ +switch_status_t mg_activate_ito_timer(megaco_profile_t* profile) +{ + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Starting IT/ITO Timer \n"); + mg_print_time(); + + switch_scheduler_add_task(switch_epoch_time_now(NULL)+profile->inact_tmr, mg_inactivity_timer_exp,"","media_gateway",0,profile,0); + return SWITCH_STATUS_SUCCESS; +} + +/*****************************************************************************************************************************/ +static void mg_inactivity_timer_exp(switch_scheduler_task_t *task) +{ + megaco_profile_t* profile = (megaco_profile_t*) task->cmd_arg; + /* TODO */ + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," mg_inactivity_timer_exp for profile[%s]\n", profile->name); + mg_print_time(); + + mg_send_ito_notify(profile); + + /*task->runtime = switch_epoch_time_now(NULL)+100; */ /* interval in seconds */ +} + +/*****************************************************************************************************************************/ +switch_status_t mg_is_ito_pkg_req(megaco_profile_t* mg_profile, MgMgcoCommand *cmd) +{ + int descId = 0x00; + MgMgcoAmmReq* desc = NULL; + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"cmd->cmdType.val[%d]\n",cmd->cmdType.val); + + if(CH_CMD_TYPE_IND != cmd->cmdType.val) + return SWITCH_STATUS_FALSE; + + if(MGT_MODIFY != cmd->u.mgCmdInd[0]->cmd.type.val) + return SWITCH_STATUS_FALSE; + + desc = &cmd->u.mgCmdInd[0]->cmd.u.mod; + + if(NULL == desc){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"No Valid descriptor found \n"); + return SWITCH_STATUS_FALSE; + } + + if(NOTPRSNT == desc->dl.num.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"No descriptor found in-coming megaco request \n"); + return SWITCH_STATUS_SUCCESS; + } + + + for (descId = 0; descId < desc->dl.num.val; descId++) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"descriptors[%d] type in-coming megaco request \n", desc->dl.descs[descId]->type.val); + switch (desc->dl.descs[descId]->type.val) { + case MGT_MEDIADESC: + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," Media descriptor on ROOT termination..Not Supporting now\n"); + break; + } + + case MGT_REQEVTDESC: + { + MgMgcoReqEvtDesc* evts = &desc->dl.descs[descId]->u.evts; + MgMgcoEvtPar *reqEvtPar; + MgMgcoReqEvt *evt; + int numEvts = 0; + int i; + + /* As of now only handling ito package */ + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," Requested Event descriptor\n"); + + if (evts->el.num.pres) + numEvts = evts->el.num.val; + + for (i = 0; i < numEvts; i++) + { + evt = evts->el.revts[i]; + if (evt->pl.num.pres) + { + /* Check for the package */ + if((MGT_PKG_KNOWN == evt->pkg.valType.val) && + (MGT_PKG_INACTTIMER != evt->pkg.u.val.val)) + { + continue; + } + else + { + if((MGT_GEN_TYPE_KNOWN == evt->name.type.val) && + (MGT_PKG_ENUM_REQEVT_INACTTIMER_INACT_TIMOUT == + evt->name.u.val.val)){ + + if((evt->pl.num.pres != NOTPRSNT) && + (evt->pl.num.val != 0)) { + + reqEvtPar = evt->pl.parms[0]; + + if((NULL != reqEvtPar) && + (reqEvtPar->type.val == MGT_EVTPAR_OTHER) && + (reqEvtPar->u.other.name.type.pres == PRSNT_NODEF) && + (reqEvtPar->u.other.name.type.val == MGT_GEN_TYPE_KNOWN) && + (reqEvtPar->u.other.name.u.val.pres == PRSNT_NODEF) && + (reqEvtPar->u.other.name.u.val.val == + MGT_PKG_ENUM_REQEVTOTHER_INACTTIMER_INACT_TIMOUT_MAX_IATIME)&& + (reqEvtPar->u.other.val.type.pres == PRSNT_NODEF) && + (reqEvtPar->u.other.val.type.val == MGT_VALUE_EQUAL) && + (reqEvtPar->u.other.val.u.eq.type.pres == PRSNT_NODEF) && + (reqEvtPar->u.other.val.u.eq.type.val == MGT_VALTYPE_UINT32)) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Received Inactivity timer value [%d]\n", + reqEvtPar->u.other.val.u.eq.u.decInt.val); + + mg_profile->inact_tmr = reqEvtPar->u.other.val.u.eq.u.decInt.val/MG_INACTIVITY_TMR_RESOLUTION; + + if(0 == mg_profile->inact_tmr){ + /* value ZERO means MGC wantes to disable ito timer */ + + /* TODO - check and stop currently running ito timer */ + } else { + mg_activate_ito_timer(mg_profile); + } + break; + } + } + } + } + } + } + + break; + } + case MGT_SIGNALSDESC: + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," Signal descriptor on ROOT termination..Not Supporting now\n"); + break; + } + case MGT_MODEMDESC: + case MGT_MUXDESC: + case MGT_EVBUFDESC: + case MGT_DIGMAPDESC: + case MGT_AUDITDESC: + case MGT_STATSDESC: + break; + + } + } + + return SWITCH_STATUS_SUCCESS; +} + + /*****************************************************************************************************************************/ /* @@ -773,6 +926,10 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand if(MGT_TERMID_ROOT == termId->type.val){ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "Modify request is for ROOT termination \n"); + + /* check if we have ito packg request */ + mg_is_ito_pkg_req(mg_profile, inc_cmd); + /* TODO */ /********************************************************************/ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index d5b82a5b54..37c1c321eb 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -13,6 +13,8 @@ #define MAX_MID_LEN 30 +#define MG_INACTIVITY_TMR_RESOLUTION 100 /* mit in ito package is experessed in 10ms steps */ + typedef enum{ SNG_MG_TPT_NONE, SNG_MG_TPT_UDP, @@ -147,6 +149,7 @@ switch_status_t sng_mgco_init(sng_mg_event_interface_t* event); switch_status_t sng_mgco_stack_shutdown(void); int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, megaco_profile_t* mg_cfg, mg_peer_profile_t* mg_peer); +switch_status_t mg_is_ito_pkg_req(megaco_profile_t* mg_profile, MgMgcoCommand *cmd); switch_status_t mg_send_end_of_axn(SuId suId, MgMgcoTransId* transId, MgMgcoContextId* ctxtId, TknU32* peerId); void mgco_print_sdp(CmSdpInfoSet *sdp); void mg_util_set_ctxt_string ( MgStr *errTxt, MgMgcoContextId *ctxtId); @@ -185,6 +188,8 @@ switch_status_t mg_send_notify(megaco_profile_t* mg_profile, const char* term_n switch_status_t mg_send_dtmf_notify(megaco_profile_t* mg_profile, const char* term_name, char* digits, int num_of_collected_digits); switch_status_t mg_send_ito_notify(megaco_profile_t* mg_profile); switch_status_t mg_util_build_obs_evt_desc (MgMgcoObsEvt *obs_event, MgMgcoRequestId *request_id, MgMgcoObsEvtDesc **ptr_obs_desc); +void mg_print_time(); +switch_status_t mg_activate_ito_timer(megaco_profile_t* profile); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index e8788ea6f2..4e4d34b736 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -1405,3 +1405,11 @@ switch_status_t mg_util_build_obs_evt_desc (MgMgcoObsEvt *obs_event, MgMgcoRequ return SWITCH_STATUS_SUCCESS; } /*****************************************************************************************************************************/ +void mg_print_time() +{ + time_t now; + time(&now); + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"Current Time = %s", ctime(&now)); +} +/*****************************************************************************************************************************/ diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index f5f83c6dd6..050ffcbad3 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -15,6 +15,7 @@ #define MG_MAX_PEERS 5 + #define MG_CONTEXT_MAX_TERMS 3 #define MEGACO_CLI_SYNTAX "profile|logging" @@ -149,6 +150,7 @@ struct megaco_profile_s { char* rtp_termination_id_prefix; int rtp_termination_id_len; char* peer_list[MG_MAX_PEERS]; /* MGC Peer ID LIST */ + int inact_tmr; /* inactivity timer value */ switch_thread_rwlock_t *contexts_rwlock; uint32_t next_context_id; From 061e082b62bb92b6dc2acfedf122daa57def5bfb Mon Sep 17 00:00:00 2001 From: Kapil Date: Wed, 25 Jul 2012 13:05:54 -0400 Subject: [PATCH 329/822] adding "MGC_FAIL" alarm --- .../media_gateway_cmd_handler.c | 22 +++++++++---------- .../media_gateway_stack_alarms.c | 10 +++++++++ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index ec760398e7..9a15871ff8 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -20,17 +20,6 @@ const char *mg_service_change_reason[] = { }; -/*****************************************************************************************************************************/ -switch_status_t mg_activate_ito_timer(megaco_profile_t* profile) -{ - - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Starting IT/ITO Timer \n"); - mg_print_time(); - - switch_scheduler_add_task(switch_epoch_time_now(NULL)+profile->inact_tmr, mg_inactivity_timer_exp,"","media_gateway",0,profile,0); - return SWITCH_STATUS_SUCCESS; -} - /*****************************************************************************************************************************/ static void mg_inactivity_timer_exp(switch_scheduler_task_t *task) { @@ -45,6 +34,17 @@ static void mg_inactivity_timer_exp(switch_scheduler_task_t *task) /*task->runtime = switch_epoch_time_now(NULL)+100; */ /* interval in seconds */ } +/*****************************************************************************************************************************/ +switch_status_t mg_activate_ito_timer(megaco_profile_t* profile) +{ + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Starting IT/ITO Timer \n"); + mg_print_time(); + + switch_scheduler_add_task(switch_epoch_time_now(NULL)+profile->inact_tmr, mg_inactivity_timer_exp,"","media_gateway",0,profile,0); + return SWITCH_STATUS_SUCCESS; +} + /*****************************************************************************************************************************/ switch_status_t mg_is_ito_pkg_req(megaco_profile_t* mg_profile, MgMgcoCommand *cmd) { diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack_alarms.c b/src/mod/endpoints/mod_media_gateway/media_gateway_stack_alarms.c index 5281a7942a..4564468e96 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack_alarms.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack_alarms.c @@ -74,6 +74,16 @@ void handle_mg_alarm(Pst *pst, MgMngmt *usta) len = len + sprintf(prBuf+len, " Event ( "); switch (usta->t.usta.alarm.event) { + case LMG_EVENT_ALL_MGC_FAILED: + { + len = len + sprintf(prBuf+len, "ALL MGC Failed "); + break; + } + case LMG_EVENT_MGC_FAILED: + { + len = len + sprintf(prBuf+len, "MGC Failed "); + break; + } case LMG_EVENT_TSAP_RECVRY_SUCCESS: { len = len + sprintf(prBuf+len, "TSAP recovery success"); From 245dfc1fd81926c15d7080de40691dcb658c2984 Mon Sep 17 00:00:00 2001 From: Kapil Date: Wed, 25 Jul 2012 15:02:00 -0400 Subject: [PATCH 330/822] adding code to print the Notify/Service-Change response --- .../mod_media_gateway/media_gateway.c | 2 + .../mod_media_gateway/media_gateway_cli.c | 3 +- .../media_gateway_cmd_handler.c | 23 ++- .../mod_media_gateway/media_gateway_stack.h | 1 + .../mod_media_gateway/mod_media_gateway.c | 176 ++++++++++++++---- .../mod_media_gateway/mod_media_gateway.h | 1 + 6 files changed, 165 insertions(+), 41 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 5d58674a0c..cc4351799b 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -456,6 +456,8 @@ switch_status_t megaco_profile_start(const char *profilename) profile->pool = pool; profile->name = switch_core_strdup(pool, profilename); profile->next_context_id++; + profile->inact_tmr = 0x00; + profile->inact_tmr_task_id = 0x00; switch_thread_rwlock_create(&profile->rwlock, pool); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c index 9b575c5384..e8cb79097b 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c @@ -205,7 +205,8 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre goto done; usage: - megaco_profile_release(profile); + if(profile) + megaco_profile_release(profile); stream->write_function(stream, "-ERR Usage: \n""\t"MEGACO_CLI_SYNTAX" \n \t"MEGACO_FUNCTION_SYNTAX"\n \t" MEGACO_LOGGING_CLI_SYNTAX "\n"); done: diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 9a15871ff8..b801e3fa67 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -20,28 +20,40 @@ const char *mg_service_change_reason[] = { }; +/*****************************************************************************************************************************/ +void mg_restart_inactivity_timer(megaco_profile_t* profile) +{ + /* NOTE - For Restart - we are deleting existing task and adding it again */ + if(profile->inact_tmr_task_id) + switch_scheduler_del_task_id(profile->inact_tmr_task_id); + + if(profile->inact_tmr) { + mg_activate_ito_timer(profile); + } +} + /*****************************************************************************************************************************/ static void mg_inactivity_timer_exp(switch_scheduler_task_t *task) { megaco_profile_t* profile = (megaco_profile_t*) task->cmd_arg; - /* TODO */ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," mg_inactivity_timer_exp for profile[%s]\n", profile->name); mg_print_time(); mg_send_ito_notify(profile); - /*task->runtime = switch_epoch_time_now(NULL)+100; */ /* interval in seconds */ + /* resetting task_id */ + profile->inact_tmr_task_id = 0x00; } /*****************************************************************************************************************************/ switch_status_t mg_activate_ito_timer(megaco_profile_t* profile) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Starting IT/ITO Timer \n"); mg_print_time(); - switch_scheduler_add_task(switch_epoch_time_now(NULL)+profile->inact_tmr, mg_inactivity_timer_exp,"","media_gateway",0,profile,0); + profile->inact_tmr_task_id = switch_scheduler_add_task(switch_epoch_time_now(NULL)+profile->inact_tmr, mg_inactivity_timer_exp,"","media_gateway",0,profile,0); + return SWITCH_STATUS_SUCCESS; } @@ -137,8 +149,7 @@ switch_status_t mg_is_ito_pkg_req(megaco_profile_t* mg_profile, MgMgcoCommand *c if(0 == mg_profile->inact_tmr){ /* value ZERO means MGC wantes to disable ito timer */ - - /* TODO - check and stop currently running ito timer */ + switch_scheduler_del_task_id(mg_profile->inact_tmr_task_id) ; } else { mg_activate_ito_timer(mg_profile); } diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index 37c1c321eb..8c429ef620 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -191,6 +191,7 @@ switch_status_t mg_util_build_obs_evt_desc (MgMgcoObsEvt *obs_event, MgMgcoRequ void mg_print_time(); switch_status_t mg_activate_ito_timer(megaco_profile_t* profile); +void mg_restart_inactivity_timer(megaco_profile_t* profile); /****************************************************************************************************************/ diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 2cd68716be..1533ca7d15 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -102,35 +102,40 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load) SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_media_gateway_shutdown) { - void *val = NULL; - const void *key = NULL; - switch_ssize_t keylen; - switch_hash_index_t *hi = NULL; - megaco_profile_t* profile = NULL; - mg_peer_profile_t* peer_profile = NULL; + void *val = NULL; + const void *key = NULL; + switch_ssize_t keylen; + switch_hash_index_t *hi = NULL; + megaco_profile_t* profile = NULL; + mg_peer_profile_t* peer_profile = NULL; - /* destroy all the mg profiles */ - while ((hi = switch_hash_first(NULL, megaco_globals.profile_hash))) { - switch_hash_this(hi, &key, &keylen, &val); - profile = (megaco_profile_t *) val; - megaco_profile_destroy(&profile); - profile = NULL; - } + /* destroy all the mg profiles */ + while ((hi = switch_hash_first(NULL, megaco_globals.profile_hash))) { + switch_hash_this(hi, &key, &keylen, &val); + profile = (megaco_profile_t *) val; + if(profile->inact_tmr_task_id){ + switch_scheduler_del_task_id(profile->inact_tmr_task_id); + profile->inact_tmr_task_id = 0x00; + } + megaco_profile_destroy(&profile); + profile = NULL; + } - hi = NULL; - key = NULL; - val = NULL; - /* destroy all the mg peer profiles */ - while ((hi = switch_hash_first(NULL, megaco_globals.peer_profile_hash))) { - switch_hash_this(hi, &key, &keylen, &val); - peer_profile = (mg_peer_profile_t *) val; - megaco_peer_profile_destroy(&peer_profile); - peer_profile = NULL; - } + hi = NULL; + key = NULL; + val = NULL; + /* destroy all the mg peer profiles */ + while ((hi = switch_hash_first(NULL, megaco_globals.peer_profile_hash))) { + switch_hash_this(hi, &key, &keylen, &val); + peer_profile = (mg_peer_profile_t *) val; + megaco_peer_profile_destroy(&peer_profile); + peer_profile = NULL; + } - sng_mgco_stack_shutdown(); + sng_mgco_stack_shutdown(); - return SWITCH_STATUS_SUCCESS; + + return SWITCH_STATUS_SUCCESS; } /*****************************************************************************************************************************/ @@ -443,6 +448,14 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: Received Command Type[%s] \n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(cmd->cmdType.val)); + /*get mg profile associated with SuId */ + if(NULL == (mg_profile = megaco_get_profile_by_suId(suId))){ + goto error1; + } + + /* first thing - restart ito timer */ + mg_restart_inactivity_timer(mg_profile); + /* validate Transaction Id */ if (NOTPRSNT != cmd->transId.pres){ txn_id = cmd->transId.val; @@ -536,12 +549,7 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) /*mgAccEvntPrntMgMgcoCommand(cmd, stdout);*/ - /*get mg profile associated with SuId */ - if(NULL == (mg_profile = megaco_get_profile_by_suId(suId))){ - goto error1; - } - - + switch(cmd->cmdType.val) { case CH_CMD_TYPE_IND: @@ -618,11 +626,111 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) case CH_CMD_TYPE_CFM: { #ifdef BIT_64 - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Received Command txn[%d] Response/Confirmation \n",txn_id); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Received Command[%s] txn[%d] Response/Confirmation \n", + PRNT_MG_CMD(cmd->u.mgCmdCfm[0]->type.val), txn_id); #else - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Received Command txn[%ld] Response/Confirmation \n",txn_id); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Received Command[%s] txn[%ld] Response/Confirmation \n", + PRNT_MG_CMD(cmd->u.mgCmdCfm[0]->type.val), txn_id); #endif - break; + switch(cmd->u.mgCmdCfm[0]->type.val) + { + case MGT_NTFY: + { + MgMgcoNtfyReply* ntfy = &cmd->u.mgCmdCfm[0]->u.ntfy; + MgMgcoTermId* term = NULL; + char term_name[32]; + memset(&term_name[0], 32, 0x00); + + strcpy(&term_name[0], "Invalid"); + +#ifdef GCP_VER_2_1 + if((NOTPRSNT != ntfy->termIdLst.num.pres) && + (0 != ntfy->termIdLst.num.val)){ + term = ntfy->termIdLst.terms[0]; + } +#else + term = &ntfy->termId; + +#endif + if(NOTPRSNT != term->type.pres){ + if(MGT_TERMID_ROOT == term->type.val){ + strcpy(&term_name[0],"ROOT"); + } + else if(MGT_TERMID_OTHER == term->type.val){ + strcpy(&term_name[0], (char*)term->name.lcl.val); + }else if(MGT_TERMID_ALL == term->type.val){ + strcpy(&term_name[0],"ALL Termination"); + }else if(MGT_TERMID_CHOOSE == term->type.val){ + strcpy(&term_name[0],"CHOOSE Termination"); + } + } + + if(NOTPRSNT != ntfy->pres.pres){ + if((NOTPRSNT != ntfy->err.pres.pres) && + (NOTPRSNT != ntfy->err.code.pres)){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, + "Received NOTIFY command response with ErroCode[%d] for Termination[%s] \n", + ntfy->err.code.val, &term_name[0]); + } + else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, + "Received Successful NOTIFY command response for Termination[%s] \n", &term_name[0]); + } + } + + break; + } + case MGT_SVCCHG: + { + MgMgcoSvcChgReply* svc = &cmd->u.mgCmdCfm[0]->u.svc; + MgMgcoTermId* term = NULL; + char term_name[32]; + memset(&term_name[0], 32, 0x00); + + strcpy(&term_name[0], "Invalid"); + +#ifdef GCP_VER_2_1 + if((NOTPRSNT != svc->termIdLst.num.pres) && + (0 != svc->termIdLst.num.val)){ + term = svc->termIdLst.terms[0]; + } +#else + term = &svc->termId; + +#endif + if(NOTPRSNT != term->type.pres){ + if(MGT_TERMID_ROOT == term->type.val){ + strcpy(&term_name[0],"ROOT"); + } + else if(MGT_TERMID_OTHER == term->type.val){ + strcpy(&term_name[0], (char*)term->name.lcl.val); + }else if(MGT_TERMID_ALL == term->type.val){ + strcpy(&term_name[0],"ALL Termination"); + }else if(MGT_TERMID_CHOOSE == term->type.val){ + strcpy(&term_name[0],"CHOOSE Termination"); + } + } + + if(NOTPRSNT != svc->pres.pres){ + + if((NOTPRSNT != svc->res.type.pres) && + (MGT_ERRDESC == svc->res.type.val)){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, + "Received Service-Change command response with ErroCode[%d] for Termination[%s] \n", + svc->res.u.err.code.val, &term_name[0]); + } + else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, + "Received Successful Service-Change command response for Termination[%s] \n", &term_name[0]); + } + } + + break; + } + default: + break; + } + break; } default: #ifdef BIT_64 diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index 050ffcbad3..03f03b5c2d 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -151,6 +151,7 @@ struct megaco_profile_s { int rtp_termination_id_len; char* peer_list[MG_MAX_PEERS]; /* MGC Peer ID LIST */ int inact_tmr; /* inactivity timer value */ + uint32_t inact_tmr_task_id; /* FS timer scheduler task-id */ switch_thread_rwlock_t *contexts_rwlock; uint32_t next_context_id; From bc4c2d9fab831f19086f1958149ce7c53eb22fa2 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 15:10:47 -0400 Subject: [PATCH 331/822] map physical terms --- .../mod_media_gateway/media_gateway.c | 34 ++++------- .../mod_media_gateway/media_gateway_xml.c | 60 ++++++++++++++++++- .../mod_media_gateway/mod_media_gateway.h | 9 ++- 3 files changed, 78 insertions(+), 25 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 5d58674a0c..7670478644 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -158,8 +158,8 @@ mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const cha term_id = mg_rtp_request_id(profile); switch_snprintf(name, sizeof name, "%s/%d", profile->rtp_termination_id_prefix, term_id); } else { - /* TODO Math: look through TDM channels */ - return NULL; + + return term; } switch_core_new_memory_pool(&pool); @@ -176,8 +176,6 @@ mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const cha term->u.rtp.codec = megaco_codec_str(profile->default_codec); term->u.rtp.term_id = term_id; term->name = switch_core_strdup(term->pool, name); - } else if (termtype == MG_TERM_TDM) { - /* XXX initialize tdm-specific fields */ } switch_core_hash_insert_wrlock(profile->terminations, term->name, term, profile->terminations_rwlock); @@ -214,8 +212,10 @@ void megaco_termination_destroy(mg_termination_t *term) term->active_events = NULL; } - switch_core_hash_delete_wrlock(term->profile->terminations, term->name, term->profile->terminations_rwlock); - switch_core_destroy_memory_pool(&term->pool); + if (term->type == MG_TERM_RTP) { + switch_core_hash_delete_wrlock(term->profile->terminations, term->name, term->profile->terminations_rwlock); + switch_core_destroy_memory_pool(&term->pool); + } } switch_status_t megaco_context_is_term_present(mg_context_t *ctx, mg_termination_t *term) @@ -276,10 +276,11 @@ switch_status_t megaco_context_sub_all_termination(mg_context_t *ctx) /* Channels will automatically go to park once the bridge ends */ if (ctx->terminations[0]) { - megaco_termination_destroy(ctx->terminations[0]); - ctx->terminations[0] = NULL; - } else if (ctx->terminations[1]) { - megaco_termination_destroy(ctx->terminations[1]); + megaco_context_sub_termination(ctx, ctx->terminations[0]); + } + + if (ctx->terminations[1]) { + megaco_context_sub_termination(ctx, ctx->terminations[1]); } return SWITCH_STATUS_SUCCESS; @@ -316,11 +317,6 @@ mg_context_t *megaco_find_context_by_suid(SuId suId, uint32_t context_id) if(NULL == (profile = megaco_get_profile_by_suId(suId))){ return NULL; } - - - if (context_id > MG_MAX_CONTEXTS) { - return NULL; - } return megaco_get_context(profile, context_id); } @@ -353,8 +349,6 @@ mg_context_t *megaco_get_context(megaco_profile_t *profile, uint32_t context_id) mg_context_t *megaco_choose_context(megaco_profile_t *profile) { mg_context_t *ctx; - int i = 0x0; - int j = 0x0; switch_thread_rwlock_wrlock(profile->contexts_rwlock); /* Try the next one */ @@ -366,14 +360,12 @@ mg_context_t *megaco_choose_context(megaco_profile_t *profile) for (; profile->next_context_id < MG_MAX_CONTEXTS; profile->next_context_id++) { if ((profile->contexts_bitmap[profile->next_context_id % 8] & (1 << (profile->next_context_id / 8))) == 0) { /* Found! */ + int i = profile->next_context_id % MG_CONTEXT_MODULO; profile->contexts_bitmap[profile->next_context_id % 8] |= 1 << (profile->next_context_id / 8); - i = profile->next_context_id % MG_CONTEXT_MODULO; ctx = malloc(sizeof *ctx); + memset(ctx, 0, sizeof *ctx); ctx->context_id = profile->next_context_id; ctx->profile = profile; - for(j = 0; j< MG_CONTEXT_MAX_TERMS; j++){ - ctx->terminations[j] = NULL; - } if (!profile->contexts[i]) { profile->contexts[i] = ctx; diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index fe588df34a..ca2e20d10d 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -17,7 +17,7 @@ static switch_status_t modify_mid(char** pmid); /****************************************************************************************************************************/ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) { - switch_xml_t cfg, xml, param, mg_interfaces, mg_interface, mg_peers, mg_peer, peer_interfaces ; + switch_xml_t cfg, xml, param, mg_interfaces, mg_interface, mg_peers, mg_peer, mg_phys_terms, mg_term, peer_interfaces ; switch_status_t status = SWITCH_STATUS_FALSE; switch_event_t *event = NULL; const char *file = "media_gateway.conf"; @@ -101,7 +101,7 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) goto done; } - if(SWITCH_STATUS_FALSE == (status = modify_mid(&peer_profile->mid))){ + if (SWITCH_STATUS_FALSE == (status = modify_mid(&peer_profile->mid))) { goto done; } @@ -112,6 +112,62 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) } } } + + + if ((mg_phys_terms = switch_xml_child(cfg, "physical_terminations"))) { + + for (mg_term = switch_xml_child(mg_phys_terms, "map"); mg_term; mg_term = mg_term->next) { + switch_memory_pool_t *pool; + mg_termination_t *term; + // + const char *prefix = switch_xml_attr(mg_term, "termination-id-prefix"); + const char *sztermination_id_base = switch_xml_attr(mg_term, "termination-id-base"); + const char *tech = switch_xml_attr(mg_term, "tech"); + const char *channel_prefix = switch_xml_attr(mg_term, "channel-prefix"); + const char *channel_map = switch_xml_attr(mg_term, "channel-map"); + const char *szspan_id = switch_xml_attr(mg_term, "span-id"); + const int span_id = !zstr(szspan_id) ? atoi(szspan_id) : 0; + + int term_id = 1; + int chan_id = 1; + + + if (!zstr(channel_map)) { + /* Split channel-map */ + char *channel_map_dup = strdup(channel_map); + char *chanmap[24]; + int chanmap_count, i; + chanmap_count = switch_split(channel_map_dup, ' ', chanmap); + for (i = 0; i < chanmap_count; i++) { + char *p = strchr(chanmap[i], '-'); + if (p) { + int startchan, endchan, j; + *p++ = '\0'; + startchan = atoi(chanmap[i]); + endchan = atoi(p); + + for (j = startchan; j < endchan; j++) { + switch_core_new_memory_pool(&pool); + term = switch_core_alloc(profile->pool, sizeof *term); + term->pool = pool; + term->type = MG_TERM_TDM; + term->profile = profile; + term->name = switch_core_sprintf(pool, "%s%d", prefix, j); + term->u.tdm.span = span_id; + term->u.tdm.channel = j; + + switch_core_hash_insert_wrlock(profile->terminations, term->name, term, profile->terminations_rwlock); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Mapped termination [%s] to freetdm span: %d chan: %d\n", term->name, term->u.tdm.span, term->u.tdm.channel); + } + } + } + + free(channel_map_dup); + } + + } + } /* configure the MEGACO stack */ status = sng_mgco_cfg(profile); diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index f5f83c6dd6..f2ecbe002b 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -83,7 +83,10 @@ typedef struct mg_context_s mg_context_t; #define kSPAN_ID "span" #define kCHAN_ID "chan" -typedef struct mg_termination_s { + +typedef struct mg_termination_s mg_termination_t; + +struct mg_termination_s { switch_memory_pool_t *pool; mg_termination_type_t type; const char *name; /*!< Megaco Name */ @@ -91,6 +94,7 @@ typedef struct mg_termination_s { mg_context_t *context; /*!< Context in which this termination is connected, or NULL */ megaco_profile_t *profile; /*!< Parent MG profile */ MgMgcoReqEvtDesc *active_events; /* !< active megaco events */ + mg_termination_t *next; /*!< List for physical terminations */ union { struct { @@ -115,7 +119,7 @@ typedef struct mg_termination_s { int channel; } tdm; } u; -} mg_termination_t; +}; struct mg_context_s { @@ -149,6 +153,7 @@ struct megaco_profile_s { char* rtp_termination_id_prefix; int rtp_termination_id_len; char* peer_list[MG_MAX_PEERS]; /* MGC Peer ID LIST */ + char* codec_prefs; switch_thread_rwlock_t *contexts_rwlock; uint32_t next_context_id; From 0a000613e203e3ef1053e1ab563be16622802873 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 15:13:04 -0400 Subject: [PATCH 332/822] fix warnings --- src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c | 2 +- src/mod/endpoints/mod_media_gateway/media_gateway_xml.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 6a6ef5c4d9..4307a8e91b 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -143,7 +143,7 @@ switch_status_t mg_is_ito_pkg_req(megaco_profile_t* mg_profile, MgMgcoCommand *c (reqEvtPar->u.other.val.u.eq.type.val == MGT_VALTYPE_UINT32)) { switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Received Inactivity timer value [%d]\n", - reqEvtPar->u.other.val.u.eq.u.decInt.val); + (int)reqEvtPar->u.other.val.u.eq.u.decInt.val); mg_profile->inact_tmr = reqEvtPar->u.other.val.u.eq.u.decInt.val/MG_INACTIVITY_TMR_RESOLUTION; diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index b52d4da0f1..0d6390a173 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -123,7 +123,7 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) const char *prefix = switch_xml_attr(mg_term, "termination-id-prefix"); //const char *sztermination_id_base = switch_xml_attr(mg_term, "termination-id-base"); //const char *tech = switch_xml_attr(mg_term, "tech"); - const char *channel_prefix = switch_xml_attr(mg_term, "channel-prefix"); + //const char *channel_prefix = switch_xml_attr(mg_term, "channel-prefix"); const char *channel_map = switch_xml_attr(mg_term, "channel-map"); const char *szspan_id = switch_xml_attr(mg_term, "span-id"); const int span_id = !zstr(szspan_id) ? atoi(szspan_id) : 0; From 457f98686c11fd4264b9fc234a42f0783e840f5e Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 15:22:01 -0400 Subject: [PATCH 333/822] fix warnings --- src/mod/endpoints/mod_media_gateway/media_gateway_xml.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index ca2e20d10d..b52d4da0f1 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -121,16 +121,13 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) mg_termination_t *term; // const char *prefix = switch_xml_attr(mg_term, "termination-id-prefix"); - const char *sztermination_id_base = switch_xml_attr(mg_term, "termination-id-base"); - const char *tech = switch_xml_attr(mg_term, "tech"); + //const char *sztermination_id_base = switch_xml_attr(mg_term, "termination-id-base"); + //const char *tech = switch_xml_attr(mg_term, "tech"); const char *channel_prefix = switch_xml_attr(mg_term, "channel-prefix"); const char *channel_map = switch_xml_attr(mg_term, "channel-map"); const char *szspan_id = switch_xml_attr(mg_term, "span-id"); const int span_id = !zstr(szspan_id) ? atoi(szspan_id) : 0; - int term_id = 1; - int chan_id = 1; - if (!zstr(channel_map)) { /* Split channel-map */ From 828a13733b812a6138427aba7d75b3994f48dacc Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 15:45:20 -0400 Subject: [PATCH 334/822] oops --- .../mod_media_gateway/media_gateway_xml.c | 105 +++++++++--------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index b52d4da0f1..68d546985d 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -65,6 +65,58 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) profile->idx = ++mg_sap_id; + + + if ((mg_phys_terms = switch_xml_child(mg_interface, "physical_terminations"))) { + for (mg_term = switch_xml_child(mg_phys_terms, "map"); mg_term; mg_term = mg_term->next) { + switch_memory_pool_t *pool; + mg_termination_t *term; + // + const char *prefix = switch_xml_attr(mg_term, "termination-id-prefix"); + //const char *sztermination_id_base = switch_xml_attr(mg_term, "termination-id-base"); + //const char *tech = switch_xml_attr(mg_term, "tech"); + const char *channel_prefix = switch_xml_attr(mg_term, "channel-prefix"); + const char *channel_map = switch_xml_attr(mg_term, "channel-map"); + const char *szspan_id = switch_xml_attr(mg_term, "span-id"); + const int span_id = !zstr(szspan_id) ? atoi(szspan_id) : 0; + + + if (!zstr(channel_map)) { + /* Split channel-map */ + char *channel_map_dup = strdup(channel_map); + char *chanmap[24]; + int chanmap_count, i; + chanmap_count = switch_split(channel_map_dup, ' ', chanmap); + for (i = 0; i < chanmap_count; i++) { + char *p = strchr(chanmap[i], '-'); + if (p) { + int startchan, endchan, j; + *p++ = '\0'; + startchan = atoi(chanmap[i]); + endchan = atoi(p); + + for (j = startchan; j < endchan; j++) { + switch_core_new_memory_pool(&pool); + term = switch_core_alloc(profile->pool, sizeof *term); + term->pool = pool; + term->type = MG_TERM_TDM; + term->profile = profile; + term->name = switch_core_sprintf(pool, "%s%d", prefix, j); + term->u.tdm.span = span_id; + term->u.tdm.channel = j; + + switch_core_hash_insert_wrlock(profile->terminations, term->name, term, profile->terminations_rwlock); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Mapped termination [%s] to freetdm span: %d chan: %d\n", term->name, term->u.tdm.span, term->u.tdm.channel); + } + } + } + + free(channel_map_dup); + } + } + } + /* we should break from here , profile name should be unique */ break; @@ -113,59 +165,6 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) } } - - if ((mg_phys_terms = switch_xml_child(cfg, "physical_terminations"))) { - - for (mg_term = switch_xml_child(mg_phys_terms, "map"); mg_term; mg_term = mg_term->next) { - switch_memory_pool_t *pool; - mg_termination_t *term; - // - const char *prefix = switch_xml_attr(mg_term, "termination-id-prefix"); - //const char *sztermination_id_base = switch_xml_attr(mg_term, "termination-id-base"); - //const char *tech = switch_xml_attr(mg_term, "tech"); - const char *channel_prefix = switch_xml_attr(mg_term, "channel-prefix"); - const char *channel_map = switch_xml_attr(mg_term, "channel-map"); - const char *szspan_id = switch_xml_attr(mg_term, "span-id"); - const int span_id = !zstr(szspan_id) ? atoi(szspan_id) : 0; - - - if (!zstr(channel_map)) { - /* Split channel-map */ - char *channel_map_dup = strdup(channel_map); - char *chanmap[24]; - int chanmap_count, i; - chanmap_count = switch_split(channel_map_dup, ' ', chanmap); - for (i = 0; i < chanmap_count; i++) { - char *p = strchr(chanmap[i], '-'); - if (p) { - int startchan, endchan, j; - *p++ = '\0'; - startchan = atoi(chanmap[i]); - endchan = atoi(p); - - for (j = startchan; j < endchan; j++) { - switch_core_new_memory_pool(&pool); - term = switch_core_alloc(profile->pool, sizeof *term); - term->pool = pool; - term->type = MG_TERM_TDM; - term->profile = profile; - term->name = switch_core_sprintf(pool, "%s%d", prefix, j); - term->u.tdm.span = span_id; - term->u.tdm.channel = j; - - switch_core_hash_insert_wrlock(profile->terminations, term->name, term, profile->terminations_rwlock); - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Mapped termination [%s] to freetdm span: %d chan: %d\n", term->name, term->u.tdm.span, term->u.tdm.channel); - } - } - } - - free(channel_map_dup); - } - - } - } - /* configure the MEGACO stack */ status = sng_mgco_cfg(profile); From 6cf298a74631ef0baa37fd4601df3d0fad922d14 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 17:18:18 -0400 Subject: [PATCH 335/822] use span name instead of id. implement termination choose for tdm. --- libs/freetdm/mod_freetdm/tdm.c | 14 ++++++++++++-- .../endpoints/mod_media_gateway/media_gateway.c | 17 +++++++++++++++-- .../mod_media_gateway/media_gateway_xml.c | 8 ++++---- .../mod_media_gateway/mod_media_gateway.h | 13 ++++++++++++- 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index a3369f1f7b..53ee192cf0 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -38,6 +38,7 @@ void ctdm_init(switch_loadable_module_interface_t *module_interface); #define kSPAN_ID "span" #define kCHAN_ID "chan" +#define kSPAN_NAME "span_name" static struct { switch_memory_pool_t *pool; @@ -97,7 +98,8 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi switch_originate_flag_t flags, switch_call_cause_t *cancel_cause) { const char *szspanid = switch_event_get_header(var_event, kSPAN_ID), - *szchanid = switch_event_get_header(var_event, kCHAN_ID); + *szchanid = switch_event_get_header(var_event, kCHAN_ID), + *span_name = switch_event_get_header(var_event, kSPAN_NAME); int chan_id; int span_id; @@ -111,14 +113,22 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi ctdm_private_t *tech_pvt = NULL; - if (zstr(szchanid) || zstr(szspanid)) { + if (zstr(szchanid) || (zstr(szspanid) && zstr(span_name))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Both ["kSPAN_ID"] and ["kCHAN_ID"] have to be set.\n"); goto fail; } chan_id = atoi(szchanid); span_id = atoi(szspanid); + + if (!span_id) { + if (ftdm_span_find_by_name(span_name, &span) == FTDM_SUCCESS) { + span_id = ftdm_span_get_id(span); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find span [%s]\n"); + } + } if (!(*new_session = switch_core_session_request(ctdm.endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, 0, pool))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't request session.\n"); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 8580844172..8fbd08abf5 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -120,7 +120,7 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) } else if (term->type == MG_TERM_TDM) { switch_snprintf(dialstring, sizeof dialstring, "tdm/%s", term->name); - switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, kSPAN_ID, "%d", term->u.tdm.span); + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, kSPAN_NAME, term->u.tdm.span_name); switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, kCHAN_ID, "%d", term->u.tdm.channel); } @@ -135,6 +135,8 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Termination [%s] successfully instanciated as [%s] [%s]\n", term->name, dialstring, switch_core_session_get_uuid(session)); + switch_set_flag(term, MGT_ACTIVE); + done: if (session) { switch_core_session_rwunlock(session); @@ -151,6 +153,7 @@ mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const cha mg_termination_t *term = NULL; char name[100]; int term_id; + size_t prefixlen = strlen(prefix); /* Check the termination type by prefix */ if (strncasecmp(prefix, profile->rtp_termination_id_prefix, strlen(profile->rtp_termination_id_prefix)) == 0) { @@ -158,8 +161,14 @@ mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const cha term_id = mg_rtp_request_id(profile); switch_snprintf(name, sizeof name, "%s/%d", profile->rtp_termination_id_prefix, term_id); } else { + for (term = profile->physical_terminations; term; term = term->next) { + if (!strncasecmp(prefix, term->name, prefixlen) && !switch_test_flag(term, MGT_ALLOCATED)) { + switch_set_flag(term, MGT_ALLOCATED); + return term; + } + } - return term; + return NULL; } switch_core_new_memory_pool(&pool); @@ -168,6 +177,7 @@ mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const cha term->type = termtype; term->active_events = NULL; term->profile = profile; + switch_set_flag(term, MGT_ALLOCATED); if (termtype == MG_TERM_RTP) { /* Fill in local address and reserve an rtp port */ @@ -212,6 +222,9 @@ void megaco_termination_destroy(mg_termination_t *term) term->active_events = NULL; } + switch_clear_flag(term, MGT_ALLOCATED); + switch_clear_flag(term, MGT_ACTIVE); + if (term->type == MG_TERM_RTP) { switch_core_hash_delete_wrlock(term->profile->terminations, term->name, term->profile->terminations_rwlock); switch_core_destroy_memory_pool(&term->pool); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index 68d546985d..f30c1d955d 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -77,8 +77,6 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) //const char *tech = switch_xml_attr(mg_term, "tech"); const char *channel_prefix = switch_xml_attr(mg_term, "channel-prefix"); const char *channel_map = switch_xml_attr(mg_term, "channel-map"); - const char *szspan_id = switch_xml_attr(mg_term, "span-id"); - const int span_id = !zstr(szspan_id) ? atoi(szspan_id) : 0; if (!zstr(channel_map)) { @@ -102,12 +100,14 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) term->type = MG_TERM_TDM; term->profile = profile; term->name = switch_core_sprintf(pool, "%s%d", prefix, j); - term->u.tdm.span = span_id; term->u.tdm.channel = j; + term->u.tdm.span_name = switch_core_strdup(pool, channel_prefix); switch_core_hash_insert_wrlock(profile->terminations, term->name, term, profile->terminations_rwlock); + term->next = profile->physical_terminations; + profile->physical_terminations = term; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Mapped termination [%s] to freetdm span: %d chan: %d\n", term->name, term->u.tdm.span, term->u.tdm.channel); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Mapped termination [%s] to freetdm span: %s chan: %d\n", term->name, term->u.tdm.span_name, term->u.tdm.channel); } } } diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index d74fb31d1e..c1960877bd 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -83,10 +83,17 @@ typedef struct mg_context_s mg_context_t; /* TDM parameters understood by the controllable channel */ #define kSPAN_ID "span" #define kCHAN_ID "chan" +#define kSPAN_NAME "span_name" typedef struct mg_termination_s mg_termination_t; +enum { + MGT_ALLOCATED = (1 << 0), + MGT_ACTIVE = (1 << 1), + +} mg_termination_flags; + struct mg_termination_s { switch_memory_pool_t *pool; mg_termination_type_t type; @@ -96,6 +103,7 @@ struct mg_termination_s { megaco_profile_t *profile; /*!< Parent MG profile */ MgMgcoReqEvtDesc *active_events; /* !< active megaco events */ mg_termination_t *next; /*!< List for physical terminations */ + uint32_t flags; union { struct { @@ -116,8 +124,8 @@ struct mg_termination_s { } rtp; struct { - int span; int channel; + const char *span_name; } tdm; } u; }; @@ -165,6 +173,9 @@ struct megaco_profile_s { uint8_t rtpid_bitmap[MG_MAX_CONTEXTS/8]; uint32_t rtpid_next; + + mg_termination_t *physical_terminations; + switch_hash_t *terminations; switch_thread_rwlock_t *terminations_rwlock; }; From f223b9a0bb76ec5580ff84b6dc62e40fad189aa8 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 25 Jul 2012 17:28:56 -0400 Subject: [PATCH 336/822] adding add rsp sdp code --- .../media_gateway_cmd_handler.c | 294 +++++++++--------- 1 file changed, 152 insertions(+), 142 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 6a6ef5c4d9..5f756ac249 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -142,8 +142,13 @@ switch_status_t mg_is_ito_pkg_req(megaco_profile_t* mg_profile, MgMgcoCommand *c (reqEvtPar->u.other.val.u.eq.type.pres == PRSNT_NODEF) && (reqEvtPar->u.other.val.u.eq.type.val == MGT_VALTYPE_UINT32)) { +#ifdef BIT_64 switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Received Inactivity timer value [%d]\n", reqEvtPar->u.other.val.u.eq.u.decInt.val); +#else + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Received Inactivity timer value [%ld]\n", + reqEvtPar->u.other.val.u.eq.u.decInt.val); +#endif mg_profile->inact_tmr = reqEvtPar->u.other.val.u.eq.u.decInt.val/MG_INACTIVITY_TMR_RESOLUTION; @@ -544,7 +549,7 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i if ((NOTPRSNT != termId->type.pres) && (MGT_TERMID_CHOOSE == termId->type.val)){ - term = megaco_choose_termination(mg_profile, "RTP"); /* TODO - RTP string has be configured one */ + term = megaco_choose_termination(mg_profile, mg_profile->rtp_termination_id_prefix); if(NULL == term){ mg_util_set_err_string(&errTxt, " Resource Failure "); @@ -660,189 +665,194 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i desc->type.val = MGT_MEDIADESC; mgUtlCpyMgMgcoMediaDesc(&desc->u.media, inc_med_desc, &rsp.u.mgCmdRsp[0]->memCp); - { - /* build local descriptors */ - /*MgMgcoStreamDesc *stream;*/ - MgMgcoLocalDesc *local; - CmSdpInfoSet *psdp; - char* ipAddress = "192.168.1.1"; - MgMgcoMediaDesc* media = &desc->u.media; + /* only for RTP */ + if(is_rtp){ + /* build local descriptors */ + /*MgMgcoStreamDesc *stream;*/ + MgMgcoLocalDesc *local; + CmSdpInfoSet *psdp; + char* ipAddress[4];// = "192.168.1.1"; + MgMgcoMediaDesc* media = &desc->u.media; - /* Most probably we need to add local descriptor */ + switch_split((char*)term->u.rtp.local_addr,'.',ipAddress); - /* allocating mem for local descriptor */ - if (mgUtlGrowList((void ***)&media->parms, sizeof(MgMgcoMediaPar), - &media->num, &rsp.u.mgCmdRsp[0]->memCp) != ROK) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); - return SWITCH_STATUS_FALSE; - } + printf("ipAddress[0]=%s, ipAddress[1]=%s, ipAddress[2]=%s,ipAddress[3]=%s\n",ipAddress[0],ipAddress[1],ipAddress[2],ipAddress[3]); + + /* Most probably we need to add local descriptor */ + + /* allocating mem for local descriptor */ + if (mgUtlGrowList((void ***)&media->parms, sizeof(MgMgcoMediaPar), + &media->num, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } #if 0 - /* Kapil - NOT REQUIRED..keeping now just for ref..will delete asap */ - media->parms[media->num.val-1]->type.pres = PRSNT_NODEF; - /*media->parms[media->num.val-1]->type.val = MGT_MEDIAPAR_STRPAR;*/ + /* Kapil - NOT REQUIRED..keeping now just for ref..will delete asap */ + media->parms[media->num.val-1]->type.pres = PRSNT_NODEF; + /*media->parms[media->num.val-1]->type.val = MGT_MEDIAPAR_STRPAR;*/ - printf("media->num.val[%d]\n",media->num.val); + printf("media->num.val[%d]\n",media->num.val); - stream = &media->parms[media->num.val-1]->u.stream; - stream->pres.pres = PRSNT_NODEF; - stream->pres.val = 0x01; + stream = &media->parms[media->num.val-1]->u.stream; + stream->pres.pres = PRSNT_NODEF; + stream->pres.val = 0x01; #if 0 - if(inc_med_desc->num.pres && inc_med_desc->num.val){ - /* TODO - check stream descriptor type for all medias */ - inc_strm_desc = &inc_med_desc->parms[0]->u.stream; - memcpy(&stream->streamId, &inc_strm_desc->streamId, sizeof(MgMgcoStreamId)); - } + if(inc_med_desc->num.pres && inc_med_desc->num.val){ + /* TODO - check stream descriptor type for all medias */ + inc_strm_desc = &inc_med_desc->parms[0]->u.stream; + memcpy(&stream->streamId, &inc_strm_desc->streamId, sizeof(MgMgcoStreamId)); + } #endif - MG_INIT_TOKEN_VALUE(&(stream->streamId), 1); + MG_INIT_TOKEN_VALUE(&(stream->streamId), 1); - stream->sl.pres.pres = PRSNT_NODEF; - stream->sl.pres.val = 0x01; + stream->sl.pres.pres = PRSNT_NODEF; + stream->sl.pres.val = 0x01; - local = &stream->sl.local; + local = &stream->sl.local; #endif - media->parms[media->num.val-1]->type.pres = PRSNT_NODEF; - media->parms[media->num.val-1]->type.val = MGT_MEDIAPAR_LOCAL; + media->parms[media->num.val-1]->type.pres = PRSNT_NODEF; + media->parms[media->num.val-1]->type.val = MGT_MEDIAPAR_LOCAL; - local = &media->parms[media->num.val-1]->u.local; + local = &media->parms[media->num.val-1]->u.local; - local->pres.pres = PRSNT_NODEF; + local->pres.pres = PRSNT_NODEF; - psdp = &(local->sdp); + psdp = &(local->sdp); - if (mgUtlGrowList((void ***)&psdp->info, sizeof(CmSdpInfo), - &psdp->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); - return SWITCH_STATUS_FALSE; - } + if (mgUtlGrowList((void ***)&psdp->info, sizeof(CmSdpInfo), + &psdp->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } - psdp->info[psdp->numComp.val-1]->pres.pres = PRSNT_NODEF; + psdp->info[psdp->numComp.val-1]->pres.pres = PRSNT_NODEF; - /* fill version */ - /*memcpy(&psdp->info[0]->ver, &prsdp->info[0]->ver, sizeof(TknU16)); */ - MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->ver),1); + /* fill version */ + /*memcpy(&psdp->info[0]->ver, &prsdp->info[0]->ver, sizeof(TknU16)); */ + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->ver),1); - /* fill orig */ - MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.pres), 1); - MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.type), CM_SDP_SPEC); - MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.orig.pres), 1); + /* fill orig */ + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.pres), 1); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.type), CM_SDP_SPEC); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.orig.pres), 1); - MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.usrName, 1, "-", - &rsp.u.mgCmdRsp[0]->memCp); - MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.sessId, 1, "0", - &rsp.u.mgCmdRsp[0]->memCp); - MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.sessVer, 1, "0", - &rsp.u.mgCmdRsp[0]->memCp); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.netType.type), - CM_SDP_NET_TYPE_IN); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.addrType), - CM_SDP_ADDR_TYPE_IPV4); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.addrType), - CM_SDP_IPV4_IP_UNI); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.addrType), - CM_SDP_IPV4_IP_UNI); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[0]), - ipAddress[0]); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[1]), - ipAddress[1]); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[2]), - ipAddress[2]); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[3]), - ipAddress[3]); + MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.usrName, 1, "-", + &rsp.u.mgCmdRsp[0]->memCp); + MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.sessId, 1, "0", + &rsp.u.mgCmdRsp[0]->memCp); + MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.sessVer, 1, "0", + &rsp.u.mgCmdRsp[0]->memCp); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.netType.type), + CM_SDP_NET_TYPE_IN); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.addrType), + CM_SDP_ADDR_TYPE_IPV4); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.addrType), + CM_SDP_IPV4_IP_UNI); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.addrType), + CM_SDP_IPV4_IP_UNI); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[0]), + atoi(ipAddress[0])); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[1]), + atoi(ipAddress[1])); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[2]), + atoi(ipAddress[2])); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[3]), + atoi(ipAddress[3])); - /* fill session name */ - /* TODO - need to fill proper session name or skip it..*/ - MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->sessName, 8, "SANGOMA",&rsp.u.mgCmdRsp[0]->memCp); + /* fill session name */ + /* TODO - need to fill proper session name or skip it..*/ + MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->sessName, 8, "SANGOMA",&rsp.u.mgCmdRsp[0]->memCp); - /* Fill the SDP Connection Info */ - /* "c=" line - ipaddress */ - MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.netType.type),CM_SDP_NET_TYPE_IN); - MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.addrType), CM_SDP_ADDR_TYPE_IPV4); - MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.u.ip4.addrType), CM_SDP_IPV4_IP_UNI); + /* Fill the SDP Connection Info */ + /* "c=" line - ipaddress */ + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.netType.type),CM_SDP_NET_TYPE_IN); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.addrType), CM_SDP_ADDR_TYPE_IPV4); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.u.ip4.addrType), CM_SDP_IPV4_IP_UNI); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[0]), ipAddress[0]); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[1]), ipAddress[1]); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[2]), ipAddress[2]); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[3]), ipAddress[3]); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[0]), atoi(ipAddress[0])); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[1]), atoi(ipAddress[1])); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[2]), atoi(ipAddress[2])); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[3]), atoi(ipAddress[3])); - /* t= line */ - MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->sdpTime.pres),1); + + /* t= line */ + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->sdpTime.pres),1); #if 0 - MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->sdpTime.sdpOpTimeSet.numComp),0); - MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->sdpTime.zoneAdjSet.numComp),0); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->sdpTime.sdpOpTimeSet.numComp),0); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->sdpTime.zoneAdjSet.numComp),0); #endif - /* fill media descriptors */ - { - CmSdpMediaDescSet* med = &psdp->info[psdp->numComp.val-1]->mediaDescSet; - CmSdpMediaDesc* media; + /* fill media descriptors */ + { + CmSdpMediaDescSet* med = &psdp->info[psdp->numComp.val-1]->mediaDescSet; + CmSdpMediaDesc* media; - if (mgUtlGrowList((void ***)&med->mediaDesc, sizeof(CmSdpMediaDesc), - &med->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); - return SWITCH_STATUS_FALSE; - } + if (mgUtlGrowList((void ***)&med->mediaDesc, sizeof(CmSdpMediaDesc), + &med->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } - media = med->mediaDesc[med->numComp.val-1]; + media = med->mediaDesc[med->numComp.val-1]; - MG_INIT_TOKEN_VALUE(&(media->pres),1); + MG_INIT_TOKEN_VALUE(&(media->pres),1); - /* Fill CmSdpMediaField */ - MG_INIT_TOKEN_VALUE(&(media->field.pres),1); - MG_INIT_TOKEN_VALUE(&(media->field.mediaType),CM_SDP_MEDIA_AUDIO); + /* Fill CmSdpMediaField */ + MG_INIT_TOKEN_VALUE(&(media->field.pres),1); + MG_INIT_TOKEN_VALUE(&(media->field.mediaType),CM_SDP_MEDIA_AUDIO); - MG_INIT_TOKEN_VALUE(&(media->field.id.type),CM_SDP_VCID_PORT); - MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.type),CM_SDP_PORT_INT); - MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.pres),1); - MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.type), CM_SDP_SPEC); - MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.val), 2904); + MG_INIT_TOKEN_VALUE(&(media->field.id.type),CM_SDP_VCID_PORT); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.type),CM_SDP_PORT_INT); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.pres),1); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.type), CM_SDP_SPEC); + //MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.val), term->u.rtp.local_port); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.val), 2904); - if (mgUtlGrowList((void ***)&media->field.par.pflst, sizeof(CmSdpMedProtoFmts), - &media->field.par.numProtFmts, &rsp.u.mgCmdRsp[0]->memCp) != ROK) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); - return SWITCH_STATUS_FALSE; - } + if (mgUtlGrowList((void ***)&media->field.par.pflst, sizeof(CmSdpMedProtoFmts), + &media->field.par.numProtFmts, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } - /* CmSdpMedProtoFmts */ - MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->prot.type), CM_SDP_MEDIA_PROTO_RTP) - MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->prot.u.subtype.type), CM_SDP_PROTO_RTP_AVP); - MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->protType), CM_SDP_MEDIA_PROTO_RTP); + /* CmSdpMedProtoFmts */ + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->prot.type), CM_SDP_MEDIA_PROTO_RTP) + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->prot.u.subtype.type), CM_SDP_PROTO_RTP_AVP); + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->protType), CM_SDP_MEDIA_PROTO_RTP); - if (mgUtlGrowList((void ***)&media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.fmts, sizeof(CmSdpU8OrNil), - &media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.num, &rsp.u.mgCmdRsp[0]->memCp) != ROK) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); - return SWITCH_STATUS_FALSE; - } + if (mgUtlGrowList((void ***)&media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.fmts, sizeof(CmSdpU8OrNil), + &media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.num, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } - MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.fmts[0]->type), CM_SDP_SPEC); + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.fmts[0]->type), CM_SDP_SPEC); - MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.fmts[0]->val), 4); + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.fmts[0]->val), 4); - /* Fill attribute if reqd */ - { - if (mgUtlGrowList((void ***)&media->attrSet.attr, sizeof(CmSdpAttr), - &media->attrSet.numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); - return SWITCH_STATUS_FALSE; - } + /* Fill attribute if reqd */ + { + if (mgUtlGrowList((void ***)&media->attrSet.attr, sizeof(CmSdpAttr), + &media->attrSet.numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } - MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[0]->type),CM_SDP_ATTR_PTIME); - MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[0]->u.ptime),30); - } - - } - - } + MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[0]->type),CM_SDP_ATTR_PTIME); + MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[0]->u.ptime), term->u.rtp.ptime); + } + } + } /* We will always send one command at a time..*/ From 898a183a0e59311211ee6ba86bca100ac5465d5c Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 18:57:32 -0400 Subject: [PATCH 337/822] missing crtp init in mod_freetdm.c -- start implementing media modify --- libs/freetdm/mod_freetdm/mod_freetdm.c | 3 ++ .../mod_media_gateway/media_gateway.c | 47 +++++++++++-------- src/mod/endpoints/mod_sofia/rtp.c | 38 +++++++++++++++ 3 files changed, 69 insertions(+), 19 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 16bdacdad7..34fb3f469a 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -178,6 +178,7 @@ static const char* channel_get_variable(switch_core_session_t *session, switch_e ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session_t **sp); void dump_chan(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream); void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream); +void ctdm_init(switch_loadable_module_interface_t *module_interface); static switch_core_session_t *ftdm_channel_get_session(ftdm_channel_t *channel, int32_t id) { @@ -5359,6 +5360,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load) SWITCH_ADD_APP(app_interface, "disable_dtmf", "Disable DTMF Detection", "Disable DTMF Detection", disable_dtmf_function, "", SAF_NONE); SWITCH_ADD_APP(app_interface, "enable_dtmf", "Enable DTMF Detection", "Enable DTMF Detection", enable_dtmf_function, "", SAF_NONE); + ctdm_init(*module_interface); + /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 8fbd08abf5..fe2804d212 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -88,19 +88,6 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) switch_status_t status = SWITCH_STATUS_SUCCESS; char dialstring[100]; switch_call_cause_t cause; - - if (!zstr(term->uuid)) { - /* A UUID is present, check if the channel still exists */ - switch_core_session_t *session; - if ((session = switch_core_session_locate(term->uuid))) { - switch_core_session_rwunlock(session); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel [%s] already exists for termination [%s]\n", term->uuid, term->name); - return SWITCH_STATUS_SUCCESS; - } - - /* The referenced channel doesn't exist anymore, clear it */ - term->uuid = NULL; - } switch_event_create(&var_event, SWITCH_EVENT_CLONE); @@ -126,14 +113,35 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) /* Set common variables on the channel */ switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, SWITCH_PARK_AFTER_BRIDGE_VARIABLE, "true"); + + if (!zstr(term->uuid)) { + /* A UUID is present, check if the channel still exists */ + switch_core_session_t *session; + if ((session = switch_core_session_locate(term->uuid))) { + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "command", "media_modify"); + + switch_core_session_receive_event(session, &var_event); - if (switch_ivr_originate(NULL, &session, &cause, dialstring, 0, NULL, NULL, NULL, NULL, var_event, 0, NULL) != SWITCH_CAUSE_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to instanciate termination [%s]: %s\n", term->name, switch_channel_cause2str(cause)); - status = SWITCH_STATUS_FALSE; - goto done; + switch_core_session_rwunlock(session); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sent refresh to channel [%s], for termination [%s]\n", term->uuid, term->name); + + return SWITCH_STATUS_SUCCESS; + } + + /* The referenced channel doesn't exist anymore, clear it */ + term->uuid = NULL; } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Termination [%s] successfully instanciated as [%s] [%s]\n", term->name, dialstring, switch_core_session_get_uuid(session)); + if (!zstr(term->uuid)) { + if (switch_ivr_originate(NULL, &session, &cause, dialstring, 0, NULL, NULL, NULL, NULL, var_event, 0, NULL) != SWITCH_CAUSE_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to instanciate termination [%s]: %s\n", term->name, switch_channel_cause2str(cause)); + status = SWITCH_STATUS_FALSE; + goto done; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Termination [%s] successfully instanciated as [%s] [%s]\n", term->name, dialstring, switch_core_session_get_uuid(session)); + } switch_set_flag(term, MGT_ACTIVE); @@ -162,7 +170,7 @@ mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const cha switch_snprintf(name, sizeof name, "%s/%d", profile->rtp_termination_id_prefix, term_id); } else { for (term = profile->physical_terminations; term; term = term->next) { - if (!strncasecmp(prefix, term->name, prefixlen) && !switch_test_flag(term, MGT_ALLOCATED)) { + if (!switch_test_flag(term, MGT_ALLOCATED) && !strncasecmp(prefix, term->name, prefixlen)) { switch_set_flag(term, MGT_ALLOCATED); return term; } @@ -185,6 +193,7 @@ mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const cha term->u.rtp.local_port = switch_rtp_request_port(term->u.rtp.local_addr); term->u.rtp.codec = megaco_codec_str(profile->default_codec); term->u.rtp.term_id = term_id; + term->u.rtp.ptime = 20; term->name = switch_core_strdup(term->pool, name); } diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index a464beb1be..631c8e7711 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -93,6 +93,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id); static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg); static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf); +static switch_status_t channel_receive_event(switch_core_session_t *session, switch_event_t *event); switch_state_handler_table_t crtp_state_handlers = { .on_init = channel_on_init, @@ -104,6 +105,7 @@ switch_io_routines_t crtp_io_routines = { .read_frame = channel_read_frame, .write_frame = channel_write_frame, .receive_message = channel_receive_message, + .receive_event = channel_receive_event, .send_dtmf = channel_send_dtmf }; @@ -395,6 +397,42 @@ static switch_status_t channel_send_dtmf(switch_core_session_t *session, const s return SWITCH_STATUS_SUCCESS; } +static switch_bool_t compare_var(switch_event_t *event, switch_channel_t *channel, const char *varname) +{ + const char *chan_val = switch_channel_get_variable_dup(channel, varname, SWITCH_FALSE, -1); + const char *event_val = switch_event_get_header(event, varname); + + return strcasecmp(chan_val, event_val); +} + +static switch_status_t channel_receive_event(switch_core_session_t *session, switch_event_t *event) +{ + const char *command = switch_event_get_header(event, "command"); + switch_channel_t *channel = switch_core_session_get_channel(session); + + if (!zstr(command) && !strcasecmp(command, "media_modify")) { + /* Compare parameters */ + if (compare_var(event, channel, kREMOTEADDR) || + compare_var(event, channel, kREMOTEPORT) || + compare_var(event, channel, kLOCALADDR) || + compare_var(event, channel, kLOCALPORT)) { + /* We need to reset the rtp session */ + + } + + if (compare_var(event, channel, kCODEC) || + compare_var(event, channel, kPTIME) || + compare_var(event, channel, kPT) || + compare_var(event, channel, kRATE)) { + /* Reset codec */ + + } + + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Received unknown command [%s] in event.\n", !command ? "null" : command); + } +} + static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) { crtp_private_t *tech_pvt = NULL; From 4f6f7eb4564128d7849c777348a10f623f9d4fa8 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 19:34:15 -0400 Subject: [PATCH 338/822] refactor error --- src/mod/endpoints/mod_media_gateway/media_gateway.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index fe2804d212..70d31e6f55 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -133,7 +133,7 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) term->uuid = NULL; } - if (!zstr(term->uuid)) { + if (zstr(term->uuid)) { if (switch_ivr_originate(NULL, &session, &cause, dialstring, 0, NULL, NULL, NULL, NULL, var_event, 0, NULL) != SWITCH_CAUSE_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to instanciate termination [%s]: %s\n", term->name, switch_channel_cause2str(cause)); status = SWITCH_STATUS_FALSE; From 87569c0ba9dd35fbce307369aeaeed0b5c116c91 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 19:37:16 -0400 Subject: [PATCH 339/822] properly git rid of span_id --- libs/freetdm/mod_freetdm/tdm.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index 53ee192cf0..405e4a9aad 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -97,8 +97,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause) { - const char *szspanid = switch_event_get_header(var_event, kSPAN_ID), - *szchanid = switch_event_get_header(var_event, kCHAN_ID), + const char *szchanid = switch_event_get_header(var_event, kCHAN_ID), *span_name = switch_event_get_header(var_event, kSPAN_NAME); int chan_id; int span_id; @@ -113,22 +112,20 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi ctdm_private_t *tech_pvt = NULL; - if (zstr(szchanid) || (zstr(szspanid) && zstr(span_name))) { + if (zstr(szchanid) || zstr(span_name)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Both ["kSPAN_ID"] and ["kCHAN_ID"] have to be set.\n"); goto fail; } chan_id = atoi(szchanid); - span_id = atoi(szspanid); - - if (!span_id) { - if (ftdm_span_find_by_name(span_name, &span) == FTDM_SUCCESS) { - span_id = ftdm_span_get_id(span); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find span [%s]\n"); - } + + if (ftdm_span_find_by_name(span_name, &span) == FTDM_SUCCESS) { + span_id = ftdm_span_get_id(span); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find span [%s]\n"); } + if (!(*new_session = switch_core_session_request(ctdm.endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, 0, pool))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't request session.\n"); From 4950c32dd542069e73ffac4d1eff1934af189b5a Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 19:37:47 -0400 Subject: [PATCH 340/822] properly git rid of span_id --- libs/freetdm/mod_freetdm/tdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index 405e4a9aad..5c259e0cd1 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -123,7 +123,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi if (ftdm_span_find_by_name(span_name, &span) == FTDM_SUCCESS) { span_id = ftdm_span_get_id(span); } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find span [%s]\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find span [%s]\n", span_name); } From 63b2654b54488c74b10de76a6a474ef79aa18bc5 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 25 Jul 2012 19:47:41 -0400 Subject: [PATCH 341/822] commit -- fix stash pop err --- libs/freetdm/mod_freetdm/tdm.c | 1 - .../media_gateway_cmd_handler.c | 29 +++++++++++++++---- src/mod/endpoints/mod_sofia/rtp.c | 2 ++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index 5c259e0cd1..de52934570 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -119,7 +119,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi chan_id = atoi(szchanid); - if (ftdm_span_find_by_name(span_name, &span) == FTDM_SUCCESS) { span_id = ftdm_span_get_id(span); } else { diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 5f756ac249..e040340e2c 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -540,8 +540,14 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i MG_SET_VAL_PRES(new_ctxtId->val, mg_ctxt->context_id); } else { - /* context already present */ - memcpy(new_ctxtId, &inc_cmd->contextId,sizeof(MgMgcoContextId)); + /* context already present */ + memcpy(new_ctxtId, &inc_cmd->contextId,sizeof(MgMgcoContextId)); + mg_ctxt = megaco_get_context(mg_profile, inc_cmd->contextId.val.val); + if(NULL == mg_ctxt){ + mg_util_set_err_string(&errTxt, " Resource Failure "); + err_code = MGT_MGCO_RSP_CODE_RSRC_ERROR; + goto error; + } } /********************************************************************/ @@ -565,6 +571,17 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i /* allocate rtp term and associated the same to context */ /********************************************************************/ }else{ /* Physical termination */ + printf("termId->name.lcl.val[%s]\n",termId->name.lcl.val); + term = megaco_find_termination(mg_profile, (char*)termId->name.lcl.val); + + if(NULL == term){ + mg_util_set_err_string(&errTxt, " Resource Failure "); + err_code = MGT_MGCO_RSP_CODE_RSRC_ERROR; + goto error; + } + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Allocated Termination[%p] with term name[%s]\n", (void*)term, term->name); + /* get physical termination */ } @@ -672,9 +689,10 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i MgMgcoLocalDesc *local; CmSdpInfoSet *psdp; char* ipAddress[4];// = "192.168.1.1"; + char* dup = strdup((char*)term->u.rtp.local_addr); MgMgcoMediaDesc* media = &desc->u.media; - switch_split((char*)term->u.rtp.local_addr,'.',ipAddress); + switch_split(dup,'.',ipAddress); printf("ipAddress[0]=%s, ipAddress[1]=%s, ipAddress[2]=%s,ipAddress[3]=%s\n",ipAddress[0],ipAddress[1],ipAddress[2],ipAddress[3]); @@ -812,8 +830,7 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.type),CM_SDP_PORT_INT); MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.pres),1); MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.type), CM_SDP_SPEC); - //MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.val), term->u.rtp.local_port); - MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.val), 2904); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.val), term->u.rtp.local_port); if (mgUtlGrowList((void ***)&media->field.par.pflst, sizeof(CmSdpMedProtoFmts), &media->field.par.numProtFmts, &rsp.u.mgCmdRsp[0]->memCp) != ROK) @@ -852,6 +869,8 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[0]->u.ptime), term->u.rtp.ptime); } } + + free(dup); } diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 631c8e7711..3ab784d74d 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -431,6 +431,8 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Received unknown command [%s] in event.\n", !command ? "null" : command); } + + return SWITCH_STATUS_SUCCESS; } static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) From 5284f5d134e11372eff658bd9d5a9530c33b6be3 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 19:56:25 -0400 Subject: [PATCH 342/822] missing goto fail --- libs/freetdm/mod_freetdm/tdm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index 5c259e0cd1..5b9f1486ec 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -124,6 +124,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi span_id = ftdm_span_get_id(span); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find span [%s]\n", span_name); + goto fail; } From 706c662f4b94cfc225a8de0c92e200fa8d9361cd Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 20:04:35 -0400 Subject: [PATCH 343/822] fix crash on chan open failure --- libs/freetdm/mod_freetdm/tdm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index 5b9f1486ec..9ef95a7bfc 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -270,9 +270,9 @@ static switch_status_t channel_on_destroy(switch_core_session_t *session) if (tech_pvt->write_codec.implementation) { switch_core_codec_destroy(&tech_pvt->write_codec); } + + ftdm_channel_close(&tech_pvt->ftdm_channel); } - - ftdm_channel_close(&tech_pvt->ftdm_channel); return SWITCH_STATUS_SUCCESS; } From 3c382781340922e4d440afc3cf59280c4a2a761e Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 25 Jul 2012 20:41:01 -0400 Subject: [PATCH 344/822] Added new channel type clear-channel for channels that do not have a signalling module --- libs/freetdm/src/ftdm_io.c | 30 ++++++++++++++----- .../src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c | 3 +- libs/freetdm/src/include/freetdm.h | 3 +- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index ec623ad6e6..2a5f1cb6ee 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -1470,13 +1470,23 @@ FT_DECLARE(ftdm_status_t) ftdm_group_channel_use_count(ftdm_group_t *group, uint static __inline__ int chan_is_avail(ftdm_channel_t *check) { - if (!ftdm_test_flag(check, FTDM_CHANNEL_READY) || - !ftdm_test_flag(check, FTDM_CHANNEL_SIG_UP) || - ftdm_test_flag(check, FTDM_CHANNEL_INUSE) || - ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) || - ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) || - check->state != FTDM_CHANNEL_STATE_DOWN) { - return 0; + if (check->type == FTDM_CHAN_TYPE_CLEAR) { + if (!ftdm_test_flag(check, FTDM_CHANNEL_READY) || + ftdm_test_flag(check, FTDM_CHANNEL_INUSE) || + ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) || + ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) || + check->state != FTDM_CHANNEL_STATE_DOWN) { + return 0; + } + } else { + if (!ftdm_test_flag(check, FTDM_CHANNEL_READY) || + !ftdm_test_flag(check, FTDM_CHANNEL_SIG_UP) || + ftdm_test_flag(check, FTDM_CHANNEL_INUSE) || + ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) || + ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) || + check->state != FTDM_CHANNEL_STATE_DOWN) { + return 0; + } } return 1; } @@ -5129,6 +5139,12 @@ static ftdm_status_t load_config(void) } else { ftdm_log(FTDM_LOG_WARNING, "Cannot add EM channels to a non-EM trunk!\n"); } + } else if (!strcasecmp(var, "clear-channel")) { + unsigned chans_configured = 0; + chan_config.type = FTDM_CHAN_TYPE_CLEAR; + if (ftdm_configure_span_channels(span, val, &chan_config, &chans_configured) == FTDM_SUCCESS) { + configured += chans_configured; + } } else if (!strcasecmp(var, "b-channel")) { unsigned chans_configured = 0; chan_config.type = FTDM_CHAN_TYPE_B; diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index 87ba7ed728..85ccba53bb 100755 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -306,7 +306,8 @@ static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO || type == FTDM_CHAN_TYPE_CAS - || type == FTDM_CHAN_TYPE_B) { + || type == FTDM_CHAN_TYPE_B + || type == FTDM_CHAN_TYPE_CLEAR) { int err; hwec_str = "unavailable"; diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index f7de8519b7..a45fdfe661 100755 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -181,9 +181,10 @@ typedef enum { FTDM_CHAN_TYPE_FXO, /*!< FXO analog channel */ FTDM_CHAN_TYPE_EM, /*!< E & M channel */ FTDM_CHAN_TYPE_CAS, /*!< CAS channel */ + FTDM_CHAN_TYPE_CLEAR, /* Clear channnel - no signalling module */ FTDM_CHAN_TYPE_COUNT /*!< Count of channel types */ } ftdm_chan_type_t; -#define CHAN_TYPE_STRINGS "B", "DQ921", "DQ931", "FXS", "FXO", "EM", "CAS", "INVALID" +#define CHAN_TYPE_STRINGS "B", "DQ921", "DQ931", "FXS", "FXO", "EM", "CAS", "CLEAR", "INVALID" /*! \brief transform from channel type to string and from string to channel type * ftdm_str2ftdm_chan_type transforms a channel string (ie: "FXO" to FTDM_CHAN_TYPE_FXO) * ftdm_chan_type2str transforms a channel type to string (ie: FTDM_CHAN_TYPE_B to "B") From ae84538819c9769fe2cd59472cbb6d4942514b13 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 20:49:33 -0400 Subject: [PATCH 345/822] mark tdm channel as answered immediately --- libs/freetdm/mod_freetdm/tdm.c | 2 ++ src/switch_rtp.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index 9ef95a7bfc..a01ac153b2 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -228,6 +228,8 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi goto fail; } + switch_channel_mark_answered(channel); + return SWITCH_CAUSE_SUCCESS; fail: diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 3bad17ce17..3cc5255e8b 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -34,6 +34,8 @@ //#define RTP_DEBUG_WRITE_DELTA //#define DEBUG_MISSED_SEQ +typedef unsigned long u_long; + #include #include #include @@ -1451,7 +1453,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_sess uint32_t index, switch_rtp_crypto_key_type_t type, unsigned char *key, switch_size_t keylen) { #ifndef ENABLE_SRTP - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "SRTP NOT SUPPORTED IN THIS BUILD!\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "SRTP NOT SUPPORTED IN THIS BUILD!\n"); return SWITCH_STATUS_FALSE; #else switch_rtp_crypto_key_t *crypto_key; From c6fecc1ee814939dfefdbe80a84fff6d964cddc8 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 20:50:18 -0400 Subject: [PATCH 346/822] go in consume media right away --- libs/freetdm/mod_freetdm/tdm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index a01ac153b2..6076c193fe 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -256,6 +256,9 @@ fail: static switch_status_t channel_on_init(switch_core_session_t *session) { + switch_channel_t *channel = switch_core_session_get_channel(session); + + switch_channel_set_state(channel, CS_CONSUME_MEDIA); return SWITCH_STATUS_SUCCESS; } From 3bf9fef864ceb8854734003b51880b38bee1ed47 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 20:54:47 -0400 Subject: [PATCH 347/822] originate returns a status, not a cause --- src/mod/endpoints/mod_media_gateway/media_gateway.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 70d31e6f55..3ed79ab36a 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -134,7 +134,7 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) } if (zstr(term->uuid)) { - if (switch_ivr_originate(NULL, &session, &cause, dialstring, 0, NULL, NULL, NULL, NULL, var_event, 0, NULL) != SWITCH_CAUSE_SUCCESS) { + if (switch_ivr_originate(NULL, &session, &cause, dialstring, 0, NULL, NULL, NULL, NULL, var_event, 0, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to instanciate termination [%s]: %s\n", term->name, switch_channel_cause2str(cause)); status = SWITCH_STATUS_FALSE; goto done; From b1398aaccbd6cf7aa4bde189c6006ebc099b076e Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 20:59:09 -0400 Subject: [PATCH 348/822] Im feeling bold --- src/switch_rtp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 3cc5255e8b..16e473e30f 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -1834,6 +1834,7 @@ SWITCH_DECLARE(switch_rtp_t *) switch_rtp_new(const char *rx_host, goto end; } +#if 0 if (zstr(tx_host)) { *err = "Missing remote host"; goto end; @@ -1843,6 +1844,7 @@ SWITCH_DECLARE(switch_rtp_t *) switch_rtp_new(const char *rx_host, *err = "Missing remote port"; goto end; } +#endif if (switch_rtp_create(&rtp_session, payload, samples_per_interval, ms_per_packet, flags, timer_name, err, pool) != SWITCH_STATUS_SUCCESS) { goto end; @@ -1856,7 +1858,7 @@ SWITCH_DECLARE(switch_rtp_t *) switch_rtp_new(const char *rx_host, goto end; } - if (switch_rtp_set_remote_address(rtp_session, tx_host, tx_port, 0, SWITCH_TRUE, err) != SWITCH_STATUS_SUCCESS) { + if (!zstr(tx_host) && switch_rtp_set_remote_address(rtp_session, tx_host, tx_port, 0, SWITCH_TRUE, err) != SWITCH_STATUS_SUCCESS) { switch_mutex_unlock(rtp_session->flag_mutex); rtp_session = NULL; goto end; From 051692d268e9b180ec6e50b16af18d0f398af5a3 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 21:04:15 -0400 Subject: [PATCH 349/822] save the uuid --- src/mod/endpoints/mod_media_gateway/media_gateway.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 3ed79ab36a..9805548b6f 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -140,6 +140,7 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) goto done; } + term->uuid = switch_core_strdup(term->pool, switch_core_session_get_uuid(session)); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Termination [%s] successfully instanciated as [%s] [%s]\n", term->name, dialstring, switch_core_session_get_uuid(session)); } From 0494df1ac4054e34ee6210442ba98bc50eec853d Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 21:06:47 -0400 Subject: [PATCH 350/822] give the tdm channels their caller profile so switch_ivr_uuid_bridge doesn't piss its pants off --- libs/freetdm/mod_freetdm/tdm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index 6076c193fe..6398515b72 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -101,7 +101,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi *span_name = switch_event_get_header(var_event, kSPAN_NAME); int chan_id; int span_id; - + switch_caller_profile_t *caller_profile; ftdm_span_t *span; ftdm_channel_t *chan; switch_channel_t *channel; @@ -149,6 +149,10 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi tech_pvt->session = *new_session; switch_core_session_set_private(*new_session, tech_pvt); + + caller_profile = switch_caller_profile_clone(*new_session, outbound_profile); + switch_channel_set_caller_profile(channel, caller_profile); + snprintf(name, sizeof(name), "tdm/%d:%d", span_id, chan_id); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect outbound channel %s\n", name); switch_channel_set_name(channel, name); From 4d3038c9e4e882116ca53e2fe25910caf91b7078 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 21:16:14 -0400 Subject: [PATCH 351/822] add logging before uuid_bridge, set frame->codec from tech_pvt->read_codec --- libs/freetdm/mod_freetdm/tdm.c | 1 + src/mod/endpoints/mod_media_gateway/media_gateway.c | 4 ++++ src/mod/endpoints/mod_sofia/rtp.c | 1 + 3 files changed, 6 insertions(+) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index 6398515b72..89e0d3c464 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -337,6 +337,7 @@ top: *frame = &tech_pvt->read_frame; tech_pvt->read_frame.datalen = (uint32_t)len; tech_pvt->read_frame.samples = tech_pvt->read_frame.datalen; + tech_pvt->read_frame = &tech_pvt->read_codec; if (ftdm_channel_get_codec(tech_pvt->ftdm_channel) == FTDM_CODEC_SLIN) { tech_pvt->read_frame.samples /= 2; diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 9805548b6f..3d10abf05c 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -286,6 +286,10 @@ switch_status_t megaco_context_add_termination(mg_context_t *ctx, mg_termination megaco_activate_termination(ctx->terminations[1]); } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Bridging: %s (%s) <> %s (%s)\n", + ctx->terminations[0]->name, ctx->terminations[0]->uuid, + ctx->terminations[1]->name, ctx->terminations[1]->uuid); + switch_ivr_uuid_bridge(ctx->terminations[0]->uuid, ctx->terminations[1]->uuid); } diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 631c8e7711..43e2725224 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -325,6 +325,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch } tech_pvt->read_frame.flags = SFF_NONE; + tech_pvt->read_frame.codec = &tech_pvt->read_codec; status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame, flags); if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { From f85347cf7221f6c0a5eee1a783a28f2ba71ef1d9 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 21:16:46 -0400 Subject: [PATCH 352/822] add logging before uuid_bridge, set frame->codec from tech_pvt->read_codec --- libs/freetdm/mod_freetdm/tdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index 89e0d3c464..f22ded6cb1 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -337,7 +337,7 @@ top: *frame = &tech_pvt->read_frame; tech_pvt->read_frame.datalen = (uint32_t)len; tech_pvt->read_frame.samples = tech_pvt->read_frame.datalen; - tech_pvt->read_frame = &tech_pvt->read_codec; + tech_pvt->read_frame.codec = &tech_pvt->read_codec; if (ftdm_channel_get_codec(tech_pvt->ftdm_channel) == FTDM_CODEC_SLIN) { tech_pvt->read_frame.samples /= 2; From 039c18638c16c71b7165615b34437a8e871af961 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 21:26:53 -0400 Subject: [PATCH 353/822] allocate recv buffer for tdm --- libs/freetdm/mod_freetdm/tdm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index f22ded6cb1..2e81c59c71 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -52,6 +52,8 @@ typedef struct { switch_core_session_t *session; switch_codec_t read_codec, write_codec; switch_frame_t read_frame; + + unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; } ctdm_private_t; static switch_status_t channel_on_init(switch_core_session_t *session); @@ -147,6 +149,8 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi tech_pvt->span_id = span_id; tech_pvt->ftdm_channel = chan; tech_pvt->session = *new_session; + tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf); + tech_pvt->read_frame.data = tech_pvt->databuf; switch_core_session_set_private(*new_session, tech_pvt); From c649c5b02355934e5394b3eba0d15be6a4906427 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 21:49:47 -0400 Subject: [PATCH 354/822] allow remote addr modification on rtp --- src/mod/endpoints/mod_sofia/rtp.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 43e2725224..215f545990 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -410,15 +410,25 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi { const char *command = switch_event_get_header(event, "command"); switch_channel_t *channel = switch_core_session_get_channel(session); + crtp_private_t *tech_pvt = switch_core_session_get_private(session); if (!zstr(command) && !strcasecmp(command, "media_modify")) { /* Compare parameters */ if (compare_var(event, channel, kREMOTEADDR) || - compare_var(event, channel, kREMOTEPORT) || - compare_var(event, channel, kLOCALADDR) || - compare_var(event, channel, kLOCALPORT)) { - /* We need to reset the rtp session */ + compare_var(event, channel, kREMOTEPORT)) { + char *remote_addr = switch_event_get_header(event, kREMOTEADDR); + char *szremote_port = switch_event_get_header(event, kREMOTEADDR); + switch_port_t remote_port = !zstr(szremote_port) ? atoi(szremote_port) : 0; + switch_channel_set_variable(channel, kREMOTEADDR, remote_addr); + switch_channel_set_variable(channel, kREMOTEPORT, szremote_port); + const char *err; + + if (switch_rtp_set_remote_address(tech_pvt->rtp_session, remote_addr, remote_port, 0, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error setting RTP remote address: %s\n", err); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set RTP remote: %s:%d\n", remote_addr, (int)remote_port); + } } if (compare_var(event, channel, kCODEC) || @@ -426,7 +436,7 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi compare_var(event, channel, kPT) || compare_var(event, channel, kRATE)) { /* Reset codec */ - + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Switching codec not yet implemented\n"); } } else { From 84796f84f1b2625bf85bb3d208da698ac9b87dae Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 21:58:03 -0400 Subject: [PATCH 355/822] allow remote addr modification on rtp --- src/mod/endpoints/mod_sofia/rtp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 215f545990..b24bb1653a 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -419,10 +419,11 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi char *remote_addr = switch_event_get_header(event, kREMOTEADDR); char *szremote_port = switch_event_get_header(event, kREMOTEADDR); switch_port_t remote_port = !zstr(szremote_port) ? atoi(szremote_port) : 0; + const char *err; + switch_channel_set_variable(channel, kREMOTEADDR, remote_addr); switch_channel_set_variable(channel, kREMOTEPORT, szremote_port); - const char *err; if (switch_rtp_set_remote_address(tech_pvt->rtp_session, remote_addr, remote_port, 0, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error setting RTP remote address: %s\n", err); @@ -438,7 +439,6 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi /* Reset codec */ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Switching codec not yet implemented\n"); } - } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Received unknown command [%s] in event.\n", !command ? "null" : command); } From 43e39619ae76be00bedf2f15276b04cc0fbb6ec5 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 25 Jul 2012 22:24:12 -0400 Subject: [PATCH 356/822] prevent writes if we dont have a remote addr --- src/mod/endpoints/mod_sofia/rtp.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index b24bb1653a..a12b3c6e55 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -188,11 +188,12 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi tech_pvt->dtmf_type = DTMF_2833; /* XXX */ if (zstr(local_addr) || local_port == 0) { - tech_pvt->mode = RTP_SENDONLY; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "The local address and port must be set\n"); + goto fail; } else if (zstr(remote_addr) || remote_port == 0) { - tech_pvt->mode = RTP_SENDRECV; + tech_pvt->mode = RTP_RECVONLY; } else { - + tech_pvt->mode = RTP_SENDRECV; } switch_core_session_set_private(*new_session, tech_pvt); @@ -314,7 +315,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); - if (!tech_pvt->rtp_session) { + if (!tech_pvt->rtp_session || tech_pvt->mode == RTP_RECVONLY) { goto cng; } @@ -429,6 +430,7 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error setting RTP remote address: %s\n", err); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set RTP remote: %s:%d\n", remote_addr, (int)remote_port); + tech_pvt->mode = RTP_SENDRECV; } } @@ -439,6 +441,15 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi /* Reset codec */ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Switching codec not yet implemented\n"); } + + if (compare_var(event, channel, kRFC2833PT)) { + const char *szpt = switch_channel_get_variable(channel, kRFC2833PT); + int pt = !zstr(szpt) ? atoi(szpt) : 0; + + switch_channel_set_variable(channel, kRFC2833PT, szpt); + switch_rtp_set_telephony_event(tech_pvt->rtp_session, pt); + } + } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Received unknown command [%s] in event.\n", !command ? "null" : command); } From a4bb00023c6f785a96589e8611bd02493d92ad03 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 25 Jul 2012 23:16:32 -0400 Subject: [PATCH 357/822] Reverted back clear-channel, used existing FTDM_SIGTYPE instead --- libs/freetdm/src/ftdm_io.c | 8 +------- libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c | 3 +-- libs/freetdm/src/include/freetdm.h | 3 +-- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 2a5f1cb6ee..b8b9cff527 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -1470,7 +1470,7 @@ FT_DECLARE(ftdm_status_t) ftdm_group_channel_use_count(ftdm_group_t *group, uint static __inline__ int chan_is_avail(ftdm_channel_t *check) { - if (check->type == FTDM_CHAN_TYPE_CLEAR) { + if (check->span->signal_type == FTDM_SIGTYPE_NONE) { if (!ftdm_test_flag(check, FTDM_CHANNEL_READY) || ftdm_test_flag(check, FTDM_CHANNEL_INUSE) || ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) || @@ -5139,12 +5139,6 @@ static ftdm_status_t load_config(void) } else { ftdm_log(FTDM_LOG_WARNING, "Cannot add EM channels to a non-EM trunk!\n"); } - } else if (!strcasecmp(var, "clear-channel")) { - unsigned chans_configured = 0; - chan_config.type = FTDM_CHAN_TYPE_CLEAR; - if (ftdm_configure_span_channels(span, val, &chan_config, &chans_configured) == FTDM_SUCCESS) { - configured += chans_configured; - } } else if (!strcasecmp(var, "b-channel")) { unsigned chans_configured = 0; chan_config.type = FTDM_CHAN_TYPE_B; diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index 85ccba53bb..87ba7ed728 100755 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -306,8 +306,7 @@ static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO || type == FTDM_CHAN_TYPE_CAS - || type == FTDM_CHAN_TYPE_B - || type == FTDM_CHAN_TYPE_CLEAR) { + || type == FTDM_CHAN_TYPE_B) { int err; hwec_str = "unavailable"; diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index a45fdfe661..f7de8519b7 100755 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -181,10 +181,9 @@ typedef enum { FTDM_CHAN_TYPE_FXO, /*!< FXO analog channel */ FTDM_CHAN_TYPE_EM, /*!< E & M channel */ FTDM_CHAN_TYPE_CAS, /*!< CAS channel */ - FTDM_CHAN_TYPE_CLEAR, /* Clear channnel - no signalling module */ FTDM_CHAN_TYPE_COUNT /*!< Count of channel types */ } ftdm_chan_type_t; -#define CHAN_TYPE_STRINGS "B", "DQ921", "DQ931", "FXS", "FXO", "EM", "CAS", "CLEAR", "INVALID" +#define CHAN_TYPE_STRINGS "B", "DQ921", "DQ931", "FXS", "FXO", "EM", "CAS", "INVALID" /*! \brief transform from channel type to string and from string to channel type * ftdm_str2ftdm_chan_type transforms a channel string (ie: "FXO" to FTDM_CHAN_TYPE_FXO) * ftdm_chan_type2str transforms a channel type to string (ie: FTDM_CHAN_TYPE_B to "B") From ee8047ebbf3314749712155a6775283c449fccda Mon Sep 17 00:00:00 2001 From: root Date: Thu, 26 Jul 2012 12:30:33 -0400 Subject: [PATCH 358/822] changes on test box --- .../media_gateway_cmd_handler.c | 24 +- .../mod_media_gateway/media_gateway_stack.h | 9 +- .../mod_media_gateway/media_gateway_utils.c | 489 +++++++++--------- .../mod_media_gateway/mod_media_gateway.c | 4 +- .../mod_media_gateway/mod_media_gateway.h | 1 + src/mod/endpoints/mod_sofia/rtp.c | 19 +- src/switch_channel.c | 4 +- src/switch_rtp.c | 2 +- 8 files changed, 296 insertions(+), 256 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index e040340e2c..27fe1a4a4b 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -301,6 +301,8 @@ switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand * } } + mgco_handle_sdp(&local->sdp, term, MG_SDP_LOCAL); + break; } @@ -311,6 +313,7 @@ switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand * remote = &mediaPar->u.remote; sdp = remote->sdp.info[0]; /* for Matt - same like local descriptor */ + mgco_handle_sdp(&remote->sdp, term, MG_SDP_REMOTE); break; } @@ -403,12 +406,12 @@ switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand * if (mgStream->sl.remote.pres.pres) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got remote stream media description:\n"); - mgco_print_sdp(&mgStream->sl.remote.sdp); + mgco_handle_sdp(&mgStream->sl.remote.sdp, term, MG_SDP_LOCAL); } if (mgStream->sl.local.pres.pres) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got local stream media description:\n"); - mgco_print_sdp(&mgStream->sl.local.sdp); + mgco_handle_sdp(&mgStream->sl.local.sdp, term, MG_SDP_REMOTE); } break; @@ -567,11 +570,8 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i is_rtp = 0x01; - /* TODO - Matt */ - /* allocate rtp term and associated the same to context */ - /********************************************************************/ + /********************************************************************/ }else{ /* Physical termination */ - printf("termId->name.lcl.val[%s]\n",termId->name.lcl.val); term = megaco_find_termination(mg_profile, (char*)termId->name.lcl.val); if(NULL == term){ @@ -581,9 +581,6 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i } switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Allocated Termination[%p] with term name[%s]\n", (void*)term, term->name); - - - /* get physical termination */ } /********************************************************************/ /* associate physical termination to context */ @@ -694,8 +691,6 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i switch_split(dup,'.',ipAddress); - printf("ipAddress[0]=%s, ipAddress[1]=%s, ipAddress[2]=%s,ipAddress[3]=%s\n",ipAddress[0],ipAddress[1],ipAddress[2],ipAddress[3]); - /* Most probably we need to add local descriptor */ /* allocating mem for local descriptor */ @@ -918,8 +913,8 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand MgMgcoInd *mgErr; MgMgcoTermId *termId; MgMgcoTermIdLst* termLst; - mg_termination_t* term = NULL; - switch_status_t ret; + mg_termination_t* term = NULL; + switch_status_t ret; int err_code; /*MgMgcoAmmReq *cmd = &inc_cmd->u.mgCmdInd[0]->cmd.u.mod;*/ U32 txn_id = inc_cmd->transId.val; @@ -1033,6 +1028,9 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand ret = mg_prc_descriptors(mg_profile, inc_cmd, term); + /* SDP updated to termination */ + + megaco_activate_termination(term); } /********************************************************************/ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index 8c429ef620..9401ce49ce 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -15,6 +15,13 @@ #define MG_INACTIVITY_TMR_RESOLUTION 100 /* mit in ito package is experessed in 10ms steps */ +typedef enum{ + MG_SDP_NONE, + MG_SDP_LOCAL, + MG_SDP_REMOTE, +}mgco_sdp_types_e; + + typedef enum{ SNG_MG_TPT_NONE, SNG_MG_TPT_UDP, @@ -151,7 +158,7 @@ int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, megaco_profile_t* mg_cfg, m switch_status_t mg_is_ito_pkg_req(megaco_profile_t* mg_profile, MgMgcoCommand *cmd); switch_status_t mg_send_end_of_axn(SuId suId, MgMgcoTransId* transId, MgMgcoContextId* ctxtId, TknU32* peerId); -void mgco_print_sdp(CmSdpInfoSet *sdp); +void mgco_handle_sdp(CmSdpInfoSet *sdp,mg_termination_t* term, mgco_sdp_types_e sdp_type); void mg_util_set_ctxt_string ( MgStr *errTxt, MgMgcoContextId *ctxtId); switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd, MgMgcoContextId* new_ctxtId); switch_status_t handle_mg_subtract_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index 4e4d34b736..56a1ffdc3a 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -740,8 +740,11 @@ void mgco_print_sdp_attr_set(CmSdpAttrSet *s) } -void mgco_print_sdp_c_line(CmSdpConn *s) +void mgco_handle_sdp_c_line(CmSdpConn *s, mg_termination_t* term, mgco_sdp_types_e sdp_type) { + char ipadd[12]; + memset(ipadd, 0, 12); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "********** SDP connection line ****** \n"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Net Type = %d \n", @@ -760,7 +763,21 @@ void mgco_print_sdp_c_line(CmSdpConn *s) s->u.ip4.u.uniIp.b[1].val, s->u.ip4.u.uniIp.b[2].val, s->u.ip4.u.uniIp.b[3].val); - } + + if(MG_SDP_REMOTE == sdp_type) { + sprintf(ipadd,"%d.%d.%d.%d", + s->u.ip4.u.uniIp.b[0].val, + s->u.ip4.u.uniIp.b[1].val, + s->u.ip4.u.uniIp.b[2].val, + s->u.ip4.u.uniIp.b[3].val); + printf("Remote ip = %s \n", ipadd); + /* update remote ip */ + if(MG_TERM_RTP == term->type){ + term->u.rtp.remote_addr = strdup(ipadd); + printf("Update remote ip to [%s]\n", term->u.rtp.remote_addr); + } + } + } } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "**************** \n"); } @@ -834,255 +851,263 @@ void mgco_print_sdp_media_param(CmSdpMedPar *s) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "**************** \n"); } -void mgco_print_sdp(CmSdpInfoSet *sdp) +void mgco_handle_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sdp_types_e sdp_type) { - int i; + int i; + + if (sdp->numComp.pres == NOTPRSNT) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " No %s SDP present \n", (MG_SDP_LOCAL== sdp_type)?"MG_SDP_LOCAL":"MG_SDP_REMOTE"); + return; + } + + for (i = 0; i < sdp->numComp.val; i++) { + CmSdpInfo *s = sdp->info[i]; + int mediaId; + + /************************************************************************************************************************/ + /* info presence check */ + if(NOTPRSNT == s->pres.pres) continue; + + /************************************************************************************************************************/ + /* Version */ + if(NOTPRSNT != s->ver.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " SDP Version = %d \n", s->ver.val); + } + + /************************************************************************************************************************/ + /* Orig */ + if(NOTPRSNT != s->orig.pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "********** SDP orig line ****** \n \t Type = %d \n", s->orig.type.val); + + if(NOTPRSNT != s->orig.orig.pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t User Name = %s \n", + (NOTPRSNT != s->orig.orig.usrName.pres)?(char*)s->orig.orig.usrName.val:"Not Present"); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Id = %s \n", + (NOTPRSNT != s->orig.orig.sessId.pres)?(char*)s->orig.orig.sessId.val:"Not Present"); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Version = %s \n", + (NOTPRSNT != s->orig.orig.sessVer.pres)?(char*)s->orig.orig.sessVer.val:"Not Present"); + + /* sdpAddr */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Net Type = %d \n", + (NOTPRSNT != s->orig.orig.sdpAddr.netType.type.pres)?s->orig.orig.sdpAddr.netType.type.val:-1); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Address Type = %d \n", + (NOTPRSNT != s->orig.orig.sdpAddr.addrType.pres)?s->orig.orig.sdpAddr.addrType.val:-1); + + /* print IPV4 address */ + if (s->orig.orig.sdpAddr.addrType.pres && s->orig.orig.sdpAddr.addrType.val == CM_SDP_ADDR_TYPE_IPV4 && + s->orig.orig.sdpAddr.netType.type.val == CM_SDP_NET_TYPE_IN && + s->orig.orig.sdpAddr.u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) { + + if (s->orig.orig.sdpAddr.u.ip4.addrType.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Address: %d.%d.%d.%d\n", + s->orig.orig.sdpAddr.u.ip4.u.ip.b[0].val, + s->orig.orig.sdpAddr.u.ip4.u.ip.b[1].val, + s->orig.orig.sdpAddr.u.ip4.u.ip.b[2].val, + s->orig.orig.sdpAddr.u.ip4.u.ip.b[3].val); + } + + }else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t O-line not present \n"); + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "********** ****** \n"); + } + } else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t O-line not present \n"); + } + /************************************************************************************************************************/ + /* Session Name (s = line) */ + + if(NOTPRSNT != s->sessName.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Name = %s \n", s->sessName.val); + } else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t s-line not present \n"); + } + + /************************************************************************************************************************/ + /* Session Info(i= line) */ + + if(NOTPRSNT != s->info.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Info = %s \n", s->info.val); + } else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t i-line not present \n"); + } + + /************************************************************************************************************************/ + /* Session Uri */ + + if(NOTPRSNT != s->uri.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Uri = %s \n", s->uri.val); + } else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t uri not present \n"); + } + + /************************************************************************************************************************/ + /* E-Mail */ + /* TODO */ - if (sdp->numComp.pres == NOTPRSNT) { - return; - } - - for (i = 0; i < sdp->numComp.val; i++) { - CmSdpInfo *s = sdp->info[i]; - int mediaId; - - /************************************************************************************************************************/ - /* info presence check */ - if(NOTPRSNT == s->pres.pres) continue; - - /************************************************************************************************************************/ - /* Version */ - if(NOTPRSNT != s->ver.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " SDP Version = %d \n", s->ver.val); - } - - /************************************************************************************************************************/ - /* Orig */ - if(NOTPRSNT != s->orig.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "********** SDP orig line ****** \n \t Type = %d \n", s->orig.type.val); - - if(NOTPRSNT != s->orig.orig.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t User Name = %s \n", - (NOTPRSNT != s->orig.orig.usrName.pres)?(char*)s->orig.orig.usrName.val:"Not Present"); - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Id = %s \n", - (NOTPRSNT != s->orig.orig.sessId.pres)?(char*)s->orig.orig.sessId.val:"Not Present"); - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Version = %s \n", - (NOTPRSNT != s->orig.orig.sessVer.pres)?(char*)s->orig.orig.sessVer.val:"Not Present"); - - /* sdpAddr */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Net Type = %d \n", - (NOTPRSNT != s->orig.orig.sdpAddr.netType.type.pres)?s->orig.orig.sdpAddr.netType.type.val:-1); - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Address Type = %d \n", - (NOTPRSNT != s->orig.orig.sdpAddr.addrType.pres)?s->orig.orig.sdpAddr.addrType.val:-1); - - /* print IPV4 address */ - if (s->orig.orig.sdpAddr.addrType.pres && s->orig.orig.sdpAddr.addrType.val == CM_SDP_ADDR_TYPE_IPV4 && - s->orig.orig.sdpAddr.netType.type.val == CM_SDP_NET_TYPE_IN && - s->orig.orig.sdpAddr.u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) { - - if (s->orig.orig.sdpAddr.u.ip4.addrType.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Address: %d.%d.%d.%d\n", - s->orig.orig.sdpAddr.u.ip4.u.ip.b[0].val, - s->orig.orig.sdpAddr.u.ip4.u.ip.b[1].val, - s->orig.orig.sdpAddr.u.ip4.u.ip.b[2].val, - s->orig.orig.sdpAddr.u.ip4.u.ip.b[3].val); - } - - }else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t O-line not present \n"); - } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "********** ****** \n"); - } - } else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t O-line not present \n"); - } - /************************************************************************************************************************/ - /* Session Name (s = line) */ - - if(NOTPRSNT != s->sessName.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Name = %s \n", s->sessName.val); - } else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t s-line not present \n"); - } - - /************************************************************************************************************************/ - /* Session Info(i= line) */ - - if(NOTPRSNT != s->info.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Info = %s \n", s->info.val); - } else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t i-line not present \n"); - } - - /************************************************************************************************************************/ - /* Session Uri */ - - if(NOTPRSNT != s->uri.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Uri = %s \n", s->uri.val); - } else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t uri not present \n"); - } - - /************************************************************************************************************************/ - /* E-Mail */ - /* TODO */ + /************************************************************************************************************************/ + /* Phone */ + /* TODO */ - /************************************************************************************************************************/ - /* Phone */ - /* TODO */ + /************************************************************************************************************************/ + /* connection line */ + + mgco_handle_sdp_c_line(&s->conn, term, sdp_type); + /************************************************************************************************************************/ + /* Bandwidth */ + /* TODO */ + + /************************************************************************************************************************/ + /* SDP Time (t= line)*/ + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "*** t-line **************** \n"); + if(NOTPRSNT != s->sdpTime.pres.pres) { + if(NOTPRSNT != s->sdpTime.sdpOpTimeSet.numComp.pres) { + int i = 0x00; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "SDP op time present with total component[%d]\n", s->sdpTime.sdpOpTimeSet.numComp.val); + for (i = 0;isdpTime.sdpOpTimeSet.numComp.val;i++){ + CmSdpOpTime* t = s->sdpTime.sdpOpTimeSet.sdpOpTime[i]; + if(NOTPRSNT == t->pres.pres) continue; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Start Time = %s \n", + (NOTPRSNT != t->startTime.pres)?(char*)t->startTime.val:"Not Present"); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Stop Time = %s \n", + (NOTPRSNT != t->stopTime.pres)?(char*)t->stopTime.val:"Not Present"); + + /*repeat time repFieldSet */ + + if(NOTPRSNT != t->repFieldSet.numComp.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "SDP repeat time present with total component[%d]\n", + t->repFieldSet.numComp.val); + + /*TODO - print repeat fields */ + }else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "SDP repeat time not present \n"); + } + } /* sdpOpTimeSet.numComp for loop -- end */ + }else{/*sdpOpTimeSet.numComp.pres if -- end */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "SDP op time not present \n"); + } + + /*TODO - zoneAdjSet */ + }else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "t-line not present \n"); + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "**************** \n"); - /************************************************************************************************************************/ - /* connection line */ + /************************************************************************************************************************/ + /* key type (k= line)*/ - mgco_print_sdp_c_line(&s->conn); - /************************************************************************************************************************/ - /* Bandwidth */ - /* TODO */ + if(NOTPRSNT != s->keyType.pres.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Key Type = %d \n", + (NOTPRSNT != s->keyType.keyType.pres)?s->keyType.keyType.val:-1); - /************************************************************************************************************************/ - /* SDP Time (t= line)*/ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Key Data = %s \n", + (NOTPRSNT != s->keyType.key_data.pres)?(char*)s->keyType.key_data.val:"Not Present"); + }else{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "k-line not present \n"); + } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "*** t-line **************** \n"); - if(NOTPRSNT != s->sdpTime.pres.pres) { - if(NOTPRSNT != s->sdpTime.sdpOpTimeSet.numComp.pres) { - int i = 0x00; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "SDP op time present with total component[%d]\n", s->sdpTime.sdpOpTimeSet.numComp.val); - for (i = 0;isdpTime.sdpOpTimeSet.numComp.val;i++){ - CmSdpOpTime* t = s->sdpTime.sdpOpTimeSet.sdpOpTime[i]; - if(NOTPRSNT == t->pres.pres) continue; + /************************************************************************************************************************/ + /* Attribute Set */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Start Time = %s \n", - (NOTPRSNT != t->startTime.pres)?(char*)t->startTime.val:"Not Present"); + mgco_print_sdp_attr_set(&s->attrSet); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Stop Time = %s \n", - (NOTPRSNT != t->stopTime.pres)?(char*)t->stopTime.val:"Not Present"); + /************************************************************************************************************************/ + /* Media Descriptor Set */ - /*repeat time repFieldSet */ + if (s->mediaDescSet.numComp.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "****** Media Descriptor Set present with numComp[%d]\n", s->mediaDescSet.numComp.val); + for (mediaId = 0; mediaId < s->mediaDescSet.numComp.val; mediaId++) { + CmSdpMediaDesc *desc = s->mediaDescSet.mediaDesc[mediaId]; - if(NOTPRSNT != t->repFieldSet.numComp.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "SDP repeat time present with total component[%d]\n", - t->repFieldSet.numComp.val); + if(NOTPRSNT == desc->pres.pres) continue; - /*TODO - print repeat fields */ - }else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "SDP repeat time not present \n"); - } - } /* sdpOpTimeSet.numComp for loop -- end */ - }else{/*sdpOpTimeSet.numComp.pres if -- end */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "SDP op time not present \n"); - } + /* Media Field */ + { + CmSdpMediaField* f = &desc->field; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Media Type = %d \n",(NOTPRSNT == f->mediaType.pres)?f->mediaType.val:-1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Media = %s \n",(NOTPRSNT == f->media.pres)?(char*)f->media.val:"Not Present"); + /* Channel ID */ + if(NOTPRSNT != f->id.type.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t VcId Type = %d \n", f->id.type.val); + switch(f->id.type.val){ + case CM_SDP_VCID_PORT: + { + CmSdpPort *p = &f->id.u.port; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "CM_SDP_VCID_PORT:\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t SDP port type = %d \n", (NOTPRSNT == p->type.pres)?p->type.val:-1); + switch(p->type.val) + { + case CM_SDP_PORT_INT: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, + "\t CM_SDP_PORT_INT: SDP port = %d type = %d \n", + p->u.portInt.port.val.val, p->u.portInt.port.type.val); + if(MG_SDP_REMOTE == sdp_type) { + /* update remote information */ + if(MG_TERM_RTP == term->type){ + term->u.rtp.remote_port = p->u.portInt.port.val.val; + printf("Update remote port to [%d]\n", term->u.rtp.remote_port); + } + } + break; + } + case CM_SDP_PORT_VPCID: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_PORT_VPCID: \n"); + break; + } + default: + break; + } + break; + } + default: + break; + } + } + mgco_print_sdp_media_param(&f->par); + } - /*TODO - zoneAdjSet */ - }else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "t-line not present \n"); - } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "**************** \n"); + /*info */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Info = %s \n",(NOTPRSNT == desc->info.pres)?(char*)desc->info.val:"Not Present"); + + /*connection set */ + { + int cnt=0x00; + if(NOTPRSNT != desc->connSet.numComp.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Number of Connection component[%d]\n",desc->connSet.numComp.val); + for(cnt=0;cntconnSet.numComp.val;cnt++){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "************************\n"); + mgco_handle_sdp_c_line(desc->connSet.connSet[cnt], term, sdp_type); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "************************\n"); + } + } + } + + /* attribute set */ + mgco_print_sdp_attr_set(&desc->attrSet); - /************************************************************************************************************************/ - /* key type (k= line)*/ + if (desc->field.mediaType.val == CM_SDP_MEDIA_AUDIO && + desc->field.id.type.val == CM_SDP_VCID_PORT && + desc->field.id.u.port.type.val == CM_SDP_PORT_INT && + desc->field.id.u.port.u.portInt.port.type.val == CM_SDP_SPEC) { + int port = desc->field.id.u.port.u.portInt.port.val.val; - if(NOTPRSNT != s->keyType.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Key Type = %d \n", - (NOTPRSNT != s->keyType.keyType.pres)?s->keyType.keyType.val:-1); - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Key Data = %s \n", - (NOTPRSNT != s->keyType.key_data.pres)?(char*)s->keyType.key_data.val:"Not Present"); - }else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "k-line not present \n"); - } - - /************************************************************************************************************************/ - /* Attribute Set */ - - mgco_print_sdp_attr_set(&s->attrSet); - - /************************************************************************************************************************/ - /* Media Descriptor Set */ - - if (s->mediaDescSet.numComp.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "****** Media Descriptor Set present with numComp[%d]\n", s->mediaDescSet.numComp.val); - for (mediaId = 0; mediaId < s->mediaDescSet.numComp.val; mediaId++) { - CmSdpMediaDesc *desc = s->mediaDescSet.mediaDesc[mediaId]; - - if(NOTPRSNT == desc->pres.pres) continue; - - /* Media Field */ - { - CmSdpMediaField* f = &desc->field; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Media Type = %d \n",(NOTPRSNT == f->mediaType.pres)?f->mediaType.val:-1); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Media = %s \n",(NOTPRSNT == f->media.pres)?(char*)f->media.val:"Not Present"); - /* Channel ID */ - if(NOTPRSNT != f->id.type.pres){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t VcId Type = %d \n", f->id.type.val); - switch(f->id.type.val){ - case CM_SDP_VCID_PORT: - { - CmSdpPort *p = &f->id.u.port; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "CM_SDP_VCID_PORT:\n"); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t SDP port type = %d \n", (NOTPRSNT == p->type.pres)?p->type.val:-1); - switch(p->type.val) - { - case CM_SDP_PORT_INT: - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_PORT_INT: SDP port = %d type = %d \n", p->u.portInt.port.val.val, p->u.portInt.port.type.val); - break; - } - case CM_SDP_PORT_VPCID: - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_PORT_VPCID: \n"); - break; - } - default: - break; - } - break; - } - default: - break; - } - } - mgco_print_sdp_media_param(&f->par); - } - - /*info */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Info = %s \n",(NOTPRSNT == desc->info.pres)?(char*)desc->info.val:"Not Present"); - - /*connection set */ - { - int cnt=0x00; - if(NOTPRSNT != desc->connSet.numComp.pres){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Number of Connection component[%d]\n",desc->connSet.numComp.val); - for(cnt=0;cntconnSet.numComp.val;cnt++){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "************************\n"); - mgco_print_sdp_c_line(desc->connSet.connSet[cnt]); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "************************\n"); - } - } - } - - /* attribute set */ - mgco_print_sdp_attr_set(&desc->attrSet); - - - if (desc->field.mediaType.val == CM_SDP_MEDIA_AUDIO && - desc->field.id.type.val == CM_SDP_VCID_PORT && - desc->field.id.u.port.type.val == CM_SDP_PORT_INT && - desc->field.id.u.port.u.portInt.port.type.val == CM_SDP_SPEC) { - int port = desc->field.id.u.port.u.portInt.port.val.val; - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Port: %d\n", port); - - } - } - } - } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Port: %d\n", port); + } + } + } + } } /*****************************************************************************************************************************/ diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 1533ca7d15..de315d7ae9 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -639,7 +639,7 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) MgMgcoNtfyReply* ntfy = &cmd->u.mgCmdCfm[0]->u.ntfy; MgMgcoTermId* term = NULL; char term_name[32]; - memset(&term_name[0], 32, 0x00); + memset(&term_name[0], 0x00,32); strcpy(&term_name[0], "Invalid"); @@ -685,7 +685,7 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) MgMgcoSvcChgReply* svc = &cmd->u.mgCmdCfm[0]->u.svc; MgMgcoTermId* term = NULL; char term_name[32]; - memset(&term_name[0], 32, 0x00); + memset(&term_name[0], 0x00, 32); strcpy(&term_name[0], "Invalid"); diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index c1960877bd..bf2fda7a05 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -231,6 +231,7 @@ mg_context_t *megaco_choose_context(megaco_profile_t *profile); void megaco_release_context(mg_context_t *ctx); switch_status_t megaco_context_sub_termination(mg_context_t *ctx, mg_termination_t *term); switch_status_t megaco_context_sub_all_termination(mg_context_t *ctx); +switch_status_t megaco_activate_termination(mg_termination_t *term); mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const char *prefix); mg_termination_t *megaco_find_termination(megaco_profile_t *profile, const char *name); diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index d56ca14a1f..04feb55a8a 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -315,7 +315,8 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); - if (!tech_pvt->rtp_session || tech_pvt->mode == RTP_RECVONLY) { + if (!tech_pvt->rtp_session || tech_pvt->mode == RTP_SENDONLY) { + switch_yield(20000); /* replace by local timer XXX */ goto cng; } @@ -338,6 +339,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch cng: *frame = &tech_pvt->read_frame; + tech_pvt->read_frame.codec = &tech_pvt->read_codec; tech_pvt->read_frame.flags |= SFF_CNG; tech_pvt->read_frame.datalen = 0; @@ -370,8 +372,11 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc tech_pvt->timestamp_send += samples; #endif - - switch_rtp_write_frame(tech_pvt->rtp_session, frame); + if (tech_pvt->mode == RTP_RECVONLY) { + return SWITCH_STATUS_SUCCESS; + } + + switch_rtp_write_frame(tech_pvt->rtp_session, frame); return SWITCH_STATUS_SUCCESS; } @@ -403,7 +408,11 @@ static switch_bool_t compare_var(switch_event_t *event, switch_channel_t *channe { const char *chan_val = switch_channel_get_variable_dup(channel, varname, SWITCH_FALSE, -1); const char *event_val = switch_event_get_header(event, varname); - + + if (zstr(chan_val) || zstr(event_val)) { + return 1; + } + return strcasecmp(chan_val, event_val); } @@ -418,7 +427,7 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi if (compare_var(event, channel, kREMOTEADDR) || compare_var(event, channel, kREMOTEPORT)) { char *remote_addr = switch_event_get_header(event, kREMOTEADDR); - char *szremote_port = switch_event_get_header(event, kREMOTEADDR); + char *szremote_port = switch_event_get_header(event, kREMOTEPORT); switch_port_t remote_port = !zstr(szremote_port) ? atoi(szremote_port) : 0; const char *err; diff --git a/src/switch_channel.c b/src/switch_channel.c index 138123f3eb..a563a67b1a 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -4154,8 +4154,8 @@ SWITCH_DECLARE(const char *) switch_channel_get_partner_uuid(switch_channel_t *c { const char *uuid = NULL; - if (!(uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))) { - uuid = switch_channel_get_variable(channel, SWITCH_ORIGINATE_SIGNAL_BOND_VARIABLE); + if (!(uuid = switch_channel_get_variable_dup(channel, SWITCH_SIGNAL_BOND_VARIABLE, SWITCH_FALSE, -1))) { + uuid = switch_channel_get_variable_dup(channel, SWITCH_ORIGINATE_SIGNAL_BOND_VARIABLE, SWITCH_FALSE, -1); } return uuid; diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 16e473e30f..f3234a21b2 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -2165,7 +2165,7 @@ SWITCH_DECLARE(uint8_t) switch_rtp_ready(switch_rtp_t *rtp_session) } switch_mutex_lock(rtp_session->flag_mutex); - ret = (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_IO) && rtp_session->sock_input && rtp_session->sock_output && rtp_session->remote_addr + ret = (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_IO) && rtp_session->sock_input /* && rtp_session->sock_output && rtp_session->remote_addr */ && rtp_session->ready == 2) ? 1 : 0; switch_mutex_unlock(rtp_session->flag_mutex); From 0e5ebbd984e2ca72e0badf3a357662e781c7fac0 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Thu, 26 Jul 2012 12:43:32 -0400 Subject: [PATCH 359/822] remove typedef added for code completion --- src/switch_rtp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/switch_rtp.c b/src/switch_rtp.c index f3234a21b2..341b005473 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -34,8 +34,6 @@ //#define RTP_DEBUG_WRITE_DELTA //#define DEBUG_MISSED_SEQ -typedef unsigned long u_long; - #include #include #include From a6b85b7de570399b8490ab5a6d3a14e0d6405f26 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 26 Jul 2012 13:50:43 -0400 Subject: [PATCH 360/822] fixing two add for same termination back-2-back scenario, 2nd add should reject as term already in context --- .../endpoints/mod_media_gateway/media_gateway.c | 3 +++ .../media_gateway_cmd_handler.c | 13 +++++++++++++ .../mod_media_gateway/media_gateway_stack.h | 5 +++++ .../mod_media_gateway/media_gateway_utils.c | 10 ++++++++-- .../mod_media_gateway/media_gateway_xml.c | 2 ++ .../mod_media_gateway/mod_media_gateway.h | 17 ++++++++++------- 6 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 3d10abf05c..e47055236a 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -185,6 +185,7 @@ mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const cha term->pool = pool; term->type = termtype; term->active_events = NULL; + term->mg_ctxt = NULL; term->profile = profile; switch_set_flag(term, MGT_ALLOCATED); @@ -231,6 +232,8 @@ void megaco_termination_destroy(mg_termination_t *term) free(term->active_events); term->active_events = NULL; } + + term->mg_ctxt = NULL; switch_clear_flag(term, MGT_ALLOCATED); switch_clear_flag(term, MGT_ACTIVE); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 27fe1a4a4b..57c8843aee 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -566,6 +566,10 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i goto error; } + if(!term->mg_ctxt){ + term->mg_ctxt = mg_ctxt; + } + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Allocated Termination[%p] with term name[%s]\n", (void*)term, term->name); is_rtp = 0x01; @@ -580,6 +584,15 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i goto error; } + if(!term->mg_ctxt){ + term->mg_ctxt = mg_ctxt; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Termination[%s] already in context..rejecting ADD \n", term->name); + mg_util_set_err_string(&errTxt, " Term already is in call "); + err_code = MGT_MGCP_RSP_CODE_PROT_ERROR; + goto error; + } + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Allocated Termination[%p] with term name[%s]\n", (void*)term, term->name); } /********************************************************************/ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index 9401ce49ce..e5c16df9c0 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -15,6 +15,11 @@ #define MG_INACTIVITY_TMR_RESOLUTION 100 /* mit in ito package is experessed in 10ms steps */ +/* rtp/avp profiles */ +#define MG_RTP_AVP_PROFILE_A_LAW 8 +#define MG_RTP_AVP_PROFILE_U_LAW 0 + + typedef enum{ MG_SDP_NONE, MG_SDP_LOCAL, diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index 56a1ffdc3a..908b604118 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -789,7 +789,7 @@ void mgco_print_CmSdpU8OrNil(CmSdpU8OrNil* p) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,"CmSdpU8OrNil: Value = %d \n", (NOTPRSNT != p->val.pres)?p->val.val:-1); } -void mgco_print_sdp_media_param(CmSdpMedPar *s) +void mgco_print_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sdp_types_e sdp_type) { int i=0x00; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "***** Media Parameter *********** \n"); @@ -832,6 +832,12 @@ void mgco_print_sdp_media_param(CmSdpMedPar *s) for(i=0;inum.val;i++){ mgco_print_CmSdpU8OrNil(r->fmts[i]); + + if(MG_RTP_AVP_PROFILE_A_LAW == r->fmts[i]->val.val){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " MG_RTP_AVP_PROFILE_A_LAW: \n"); + }else if(MG_RTP_AVP_PROFILE_U_LAW == r->fmts[i]->val.val){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " MG_RTP_AVP_PROFILE_U_LAW: \n"); + } } } break; @@ -1074,7 +1080,7 @@ void mgco_handle_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sdp_types_e break; } } - mgco_print_sdp_media_param(&f->par); + mgco_print_sdp_media_param(&f->par, term, sdp_type); } /*info */ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index f30c1d955d..e3c3b8c3de 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -99,6 +99,8 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) term->pool = pool; term->type = MG_TERM_TDM; term->profile = profile; + term->mg_ctxt = NULL; + term->active_events = NULL; term->name = switch_core_sprintf(pool, "%s%d", prefix, j); term->u.tdm.channel = j; term->u.tdm.span_name = switch_core_strdup(pool, channel_prefix); diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index bf2fda7a05..e0022d8ecd 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -94,6 +94,14 @@ enum { } mg_termination_flags; +struct mg_context_s { + uint32_t context_id; + mg_termination_t *terminations[MG_CONTEXT_MAX_TERMS]; + megaco_profile_t *profile; + mg_context_t *next; + switch_memory_pool_t *pool; +}; + struct mg_termination_s { switch_memory_pool_t *pool; mg_termination_type_t type; @@ -104,6 +112,7 @@ struct mg_termination_s { MgMgcoReqEvtDesc *active_events; /* !< active megaco events */ mg_termination_t *next; /*!< List for physical terminations */ uint32_t flags; + mg_context_t* mg_ctxt; union { struct { @@ -131,13 +140,7 @@ struct mg_termination_s { }; -struct mg_context_s { - uint32_t context_id; - mg_termination_t *terminations[MG_CONTEXT_MAX_TERMS]; - megaco_profile_t *profile; - mg_context_t *next; - switch_memory_pool_t *pool; -}; + #define MG_CONTEXT_MODULO 16 #define MG_MAX_CONTEXTS 32768 From b1b2bee36268834ad0d7348ed098c6ad446b75fd Mon Sep 17 00:00:00 2001 From: root Date: Thu, 26 Jul 2012 15:02:25 -0400 Subject: [PATCH 361/822] fixing local sdp issue --- .../media_gateway_cmd_handler.c | 83 +++++++++++-------- .../mod_media_gateway/media_gateway_utils.c | 13 ++- .../mod_media_gateway/mod_media_gateway.h | 2 +- 3 files changed, 54 insertions(+), 44 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 57c8843aee..185f3fb5a9 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -498,6 +498,10 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i /*MgMgcoStreamDesc* inc_strm_desc;*/ MgMgcoAudRetParm *desc; mg_context_t* mg_ctxt; + int mediaId; + MgMgcoLocalDesc *local = NULL; + CmSdpInfoSet *psdp = NULL; + /* TODO - Kapil dummy line , will need to add with proper code */ inc_med_desc = &cmd->dl.descs[0]->u.media; @@ -686,18 +690,25 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i } /* copy media descriptor */ - desc = rsp.u.mgCmdRsp[0]->u.add.audit.parms[rsp.u.mgCmdRsp[0]->u.add.audit.num.val-1]; desc->type.pres = PRSNT_NODEF; desc->type.val = MGT_MEDIADESC; mgUtlCpyMgMgcoMediaDesc(&desc->u.media, inc_med_desc, &rsp.u.mgCmdRsp[0]->memCp); + /* see if we have received local descriptor */ + if((NOTPRSNT != desc->u.media.num.pres) && + (0 != desc->u.media.num.val)) + { + for(mediaId=0; mediaIdu.media.num.val; mediaId++) { + if(MGT_MEDIAPAR_LOCAL == desc->u.media.parms[mediaId]->type.val) { + local = &desc->u.media.parms[mediaId]->u.local; + } + } + } /* only for RTP */ if(is_rtp){ /* build local descriptors */ /*MgMgcoStreamDesc *stream;*/ - MgMgcoLocalDesc *local; - CmSdpInfoSet *psdp; char* ipAddress[4];// = "192.168.1.1"; char* dup = strdup((char*)term->u.rtp.local_addr); MgMgcoMediaDesc* media = &desc->u.media; @@ -705,45 +716,47 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i switch_split(dup,'.',ipAddress); /* Most probably we need to add local descriptor */ + if(!local){ - /* allocating mem for local descriptor */ - if (mgUtlGrowList((void ***)&media->parms, sizeof(MgMgcoMediaPar), - &media->num, &rsp.u.mgCmdRsp[0]->memCp) != ROK) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); - return SWITCH_STATUS_FALSE; - } + /* allocating mem for local descriptor */ + if (mgUtlGrowList((void ***)&media->parms, sizeof(MgMgcoMediaPar), + &media->num, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } #if 0 - /* Kapil - NOT REQUIRED..keeping now just for ref..will delete asap */ - media->parms[media->num.val-1]->type.pres = PRSNT_NODEF; - /*media->parms[media->num.val-1]->type.val = MGT_MEDIAPAR_STRPAR;*/ + /* Kapil - NOT REQUIRED..keeping now just for ref..will delete asap */ + media->parms[media->num.val-1]->type.pres = PRSNT_NODEF; + /*media->parms[media->num.val-1]->type.val = MGT_MEDIAPAR_STRPAR;*/ - printf("media->num.val[%d]\n",media->num.val); + printf("media->num.val[%d]\n",media->num.val); - stream = &media->parms[media->num.val-1]->u.stream; - stream->pres.pres = PRSNT_NODEF; - stream->pres.val = 0x01; + stream = &media->parms[media->num.val-1]->u.stream; + stream->pres.pres = PRSNT_NODEF; + stream->pres.val = 0x01; #if 0 - if(inc_med_desc->num.pres && inc_med_desc->num.val){ - /* TODO - check stream descriptor type for all medias */ - inc_strm_desc = &inc_med_desc->parms[0]->u.stream; - memcpy(&stream->streamId, &inc_strm_desc->streamId, sizeof(MgMgcoStreamId)); + if(inc_med_desc->num.pres && inc_med_desc->num.val){ + /* TODO - check stream descriptor type for all medias */ + inc_strm_desc = &inc_med_desc->parms[0]->u.stream; + memcpy(&stream->streamId, &inc_strm_desc->streamId, sizeof(MgMgcoStreamId)); + } +#endif + + MG_INIT_TOKEN_VALUE(&(stream->streamId), 1); + + + stream->sl.pres.pres = PRSNT_NODEF; + stream->sl.pres.val = 0x01; + + local = &stream->sl.local; +#endif + media->parms[media->num.val-1]->type.pres = PRSNT_NODEF; + media->parms[media->num.val-1]->type.val = MGT_MEDIAPAR_LOCAL; + + local = &media->parms[media->num.val-1]->u.local; } -#endif - - MG_INIT_TOKEN_VALUE(&(stream->streamId), 1); - - - stream->sl.pres.pres = PRSNT_NODEF; - stream->sl.pres.val = 0x01; - - local = &stream->sl.local; -#endif - media->parms[media->num.val-1]->type.pres = PRSNT_NODEF; - media->parms[media->num.val-1]->type.val = MGT_MEDIAPAR_LOCAL; - - local = &media->parms[media->num.val-1]->u.local; local->pres.pres = PRSNT_NODEF; diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index 908b604118..e5d08c1d84 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -112,8 +112,6 @@ S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, char* term_str, int term_len, C /*MG_GETMEM(termId->name.lcl.val, termId->name.lcl.len , memCp, ret);*/ ret = mg_stack_alloc_mem((Ptr*)&termId->name.lcl.val,term_len); - printf("termId->name.lcl.val[%p]\n",termId->name.lcl.val); - if( ret != ROK) RETVALUE(ret); @@ -121,7 +119,7 @@ S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, char* term_str, int term_len, C strncpy((char*)(termId->name.lcl.val), term_str, termId->name.lcl.len); termId->name.lcl.val[termId->name.lcl.len] = '\0'; - printf("mg_fill_mgco_termid: name.lcl.val[%s], len[%d], term_str[%s], term_len[%d]\n",termId->name.lcl.val, termId->name.lcl.len, term_str,term_len); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,"mg_fill_mgco_termid: name.lcl.val[%s], len[%d], term_str[%s], term_len[%d]\n",termId->name.lcl.val, termId->name.lcl.len, term_str,term_len); } @@ -742,8 +740,8 @@ void mgco_print_sdp_attr_set(CmSdpAttrSet *s) void mgco_handle_sdp_c_line(CmSdpConn *s, mg_termination_t* term, mgco_sdp_types_e sdp_type) { - char ipadd[12]; - memset(ipadd, 0, 12); + char ipadd[32]; + memset(ipadd, 0, sizeof(ipadd)); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "********** SDP connection line ****** \n"); @@ -770,11 +768,10 @@ void mgco_handle_sdp_c_line(CmSdpConn *s, mg_termination_t* term, mgco_sdp_types s->u.ip4.u.uniIp.b[1].val, s->u.ip4.u.uniIp.b[2].val, s->u.ip4.u.uniIp.b[3].val); - printf("Remote ip = %s \n", ipadd); /* update remote ip */ if(MG_TERM_RTP == term->type){ - term->u.rtp.remote_addr = strdup(ipadd); - printf("Update remote ip to [%s]\n", term->u.rtp.remote_addr); + term->u.rtp.remote_addr = switch_core_strdup(term->pool,ipadd); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,"Update remote ip to [%s]\n", term->u.rtp.remote_addr); } } } diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index e0022d8ecd..af53052fbb 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -111,8 +111,8 @@ struct mg_termination_s { megaco_profile_t *profile; /*!< Parent MG profile */ MgMgcoReqEvtDesc *active_events; /* !< active megaco events */ mg_termination_t *next; /*!< List for physical terminations */ - uint32_t flags; mg_context_t* mg_ctxt; + uint32_t flags; union { struct { From 258900818a5fd7f3eb9fed91bf8ebd2659d5471a Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Thu, 26 Jul 2012 16:43:18 -0400 Subject: [PATCH 362/822] freetdm: Added thread to service events when there is no signalling module on a span --- libs/freetdm/src/ftdm_io.c | 48 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index b8b9cff527..758827c9ed 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -5618,16 +5618,61 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_signaling(ftdm_span_t *span, const return status; } +static void *ftdm_span_service_events(ftdm_thread_t *me, void *obj) +{ + int i; + unsigned waitms; + ftdm_event_t *event; + ftdm_status_t status = FTDM_SUCCESS; + ftdm_span_t *span = (ftdm_span_t*) obj; + short *poll_events = ftdm_malloc(sizeof(short) * span->chan_count); + + memset(poll_events, 0, sizeof(short) * span->chan_count); + + for(i = 1; i <= span->chan_count; i++) { + poll_events[i] |= FTDM_EVENTS; + } + + while (ftdm_running() && !(ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD))) { + waitms = 1000; + status = ftdm_span_poll_event(span, waitms, poll_events); + switch (status) { + case FTDM_FAIL: + ftdm_log(FTDM_LOG_CRIT, "%s:Failed to poll span for events\n", span->name); + break; + case FTDM_TIMEOUT: + break; + case FTDM_SUCCESS: + /* Check if there are any channels that have events available */ + while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS); + break; + default: + ftdm_log(FTDM_LOG_CRIT, "%s:Unhandled IO event\n", span->name); + } + } + return NULL; +} + FT_DECLARE(ftdm_status_t) ftdm_span_start(ftdm_span_t *span) { ftdm_status_t status = FTDM_FAIL; - ftdm_mutex_lock(span->mutex); if (ftdm_test_flag(span, FTDM_SPAN_STARTED)) { status = FTDM_EINVAL; goto done; } + if (span->signal_type == FTDM_SIGTYPE_NONE) { + /* If there is no signalling component, start a thread to poll events */ + status = ftdm_thread_create_detached(ftdm_span_service_events, span); + if (status != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_CRIT,"Failed to start span event monitor thread!\n"); + goto done; + } + + status = ftdm_report_initial_channels_alarms(span); + goto done; + } if (!span->start) { status = FTDM_ENOSYS; @@ -5643,7 +5688,6 @@ FT_DECLARE(ftdm_status_t) ftdm_span_start(ftdm_span_t *span) if (status == FTDM_SUCCESS) { ftdm_set_flag_locked(span, FTDM_SPAN_STARTED); } - done: ftdm_mutex_unlock(span->mutex); return status; From 3519ebc981eff76d7ab506f407558e93992e59b1 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Fri, 27 Jul 2012 10:59:37 -0400 Subject: [PATCH 363/822] add megaco_prepare_termination --- .../mod_media_gateway/media_gateway.c | 42 +++++++++++++++++++ .../mod_media_gateway/mod_media_gateway.h | 1 + 2 files changed, 43 insertions(+) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index e47055236a..ee5abe7d2f 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -155,6 +155,48 @@ done: return SWITCH_STATUS_SUCCESS; } + +/* + * Originate a channel so the target technology gets to run initialization code + */ +switch_status_t megaco_prepare_termination(mg_termination_t *term) +{ + switch_event_t *var_event = NULL; + switch_core_session_t *session = NULL; + switch_status_t status = SWITCH_STATUS_SUCCESS; + char dialstring[100]; + switch_call_cause_t cause; + switch_channel_t *channel; + switch_event_create(&var_event, SWITCH_EVENT_CLONE); + + if (term->type == MG_TERM_RTP) { + } else if (term->type == MG_TERM_TDM) { + switch_snprintf(dialstring, sizeof dialstring, "tdm/%s", term->name); + + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "ftdm_start_only", "true"); + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, kSPAN_NAME, term->u.tdm.span_name); + switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, kCHAN_ID, "%d", term->u.tdm.channel); + } + + /* Set common variables on the channel */ + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, SWITCH_PARK_AFTER_BRIDGE_VARIABLE, "true"); + if (switch_ivr_originate(NULL, &session, &cause, dialstring, 0, NULL, NULL, NULL, NULL, var_event, 0, NULL) != SWITCH_STATUS_SUCCESS) { + status = SWITCH_STATUS_FALSE; + goto done; + } + channel = switch_core_session_get_channel(session); + switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + +done: + if (session) { + switch_core_session_rwunlock(session); + } + switch_event_destroy(&var_event); + + return SWITCH_STATUS_SUCCESS; +} + + mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const char *prefix) { mg_termination_type_t termtype; diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index af53052fbb..4ffeaaa4e0 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -235,6 +235,7 @@ void megaco_release_context(mg_context_t *ctx); switch_status_t megaco_context_sub_termination(mg_context_t *ctx, mg_termination_t *term); switch_status_t megaco_context_sub_all_termination(mg_context_t *ctx); switch_status_t megaco_activate_termination(mg_termination_t *term); +switch_status_t megaco_prepare_termination(mg_termination_t *term); mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const char *prefix); mg_termination_t *megaco_find_termination(megaco_profile_t *profile, const char *name); From a668b9ddf65c8f58f6d4cc734e6aa7095d4bb05f Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Fri, 27 Jul 2012 11:06:23 -0400 Subject: [PATCH 364/822] automatically fail new tdm channel if ftdm_start_only is true --- libs/freetdm/mod_freetdm/tdm.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index efdf4dce3e..b2d37d47ed 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -112,7 +112,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi ftdm_codec_t codec; uint32_t interval; ftdm_status_t fstatus; - + const char *ftdm_start_only = switch_event_get_header(var_event, "ftdm_start_only"); ctdm_private_t *tech_pvt = NULL; if (zstr(szchanid) || zstr(span_name)) { @@ -129,6 +129,15 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi goto fail; } + if ((fstatus = ftdm_span_start(span)) != FTDM_SUCCESS && fstatus != FTDM_EINVAL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't start span %s.\n", span_name); + goto fail; + } + + if (!zstr(ftdm_start_only) && switch_true(ftdm_start_only)) { + goto fail; + } + if (!(*new_session = switch_core_session_request(ctdm.endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, 0, pool))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't request session.\n"); @@ -137,11 +146,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi channel = switch_core_session_get_channel(*new_session); - if ((fstatus = ftdm_span_start(span)) != FTDM_SUCCESS && fstatus != FTDM_EINVAL) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't start span %s.\n", span_name); - goto fail; - } - if (ftdm_channel_open(span_id, chan_id, &chan) != FTDM_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't open span or channel.\n"); goto fail; From 3350403d04e8dfcdb9e2548f4c9b0e4890f6a178 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 27 Jul 2012 11:22:29 -0400 Subject: [PATCH 365/822] commit from testbox --- libs/freetdm/mod_freetdm/tdm.c | 6 + .../media_gateway_cmd_handler.c | 26 +- .../mod_media_gateway/media_gateway_stack.h | 6 + .../mod_media_gateway/media_gateway_utils.c | 500 ++++++++++++++++++ .../mod_media_gateway/media_gateway_xml.c | 6 +- .../mod_media_gateway/mod_media_gateway.h | 1 + 6 files changed, 535 insertions(+), 10 deletions(-) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index c66fdbebd1..efdf4dce3e 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -111,6 +111,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi const char *dname; ftdm_codec_t codec; uint32_t interval; + ftdm_status_t fstatus; ctdm_private_t *tech_pvt = NULL; @@ -136,6 +137,11 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi channel = switch_core_session_get_channel(*new_session); + if ((fstatus = ftdm_span_start(span)) != FTDM_SUCCESS && fstatus != FTDM_EINVAL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't start span %s.\n", span_name); + goto fail; + } + if (ftdm_channel_open(span_id, chan_id, &chan) != FTDM_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't open span or channel.\n"); goto fail; diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 185f3fb5a9..ca0d286ba2 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -500,7 +500,7 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i mg_context_t* mg_ctxt; int mediaId; MgMgcoLocalDesc *local = NULL; - CmSdpInfoSet *psdp = NULL; + /*CmSdpInfoSet *psdp = NULL;*/ /* TODO - Kapil dummy line , will need to add with proper code */ @@ -707,6 +707,11 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i /* only for RTP */ if(is_rtp){ + mg_build_sdp(&desc->u.media, inc_med_desc, mg_profile, term, &rsp.u.mgCmdRsp[0]->memCp); + } +#if 0 + if(is_rtp){ + mg_build_sdp(desc, inc_med_desc, mg_profile, term, &rsp.u.mgCmdRsp[0]->memCp); /* build local descriptors */ /*MgMgcoStreamDesc *stream;*/ char* ipAddress[4];// = "192.168.1.1"; @@ -762,11 +767,14 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i psdp = &(local->sdp); - if (mgUtlGrowList((void ***)&psdp->info, sizeof(CmSdpInfo), - &psdp->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) - { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); - return SWITCH_STATUS_FALSE; + if((NOTPRSNT == local->sdp.numComp.pres) || (0 == local->sdp.numComp.val)){ + + if (mgUtlGrowList((void ***)&psdp->info, sizeof(CmSdpInfo), + &psdp->numComp, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } } psdp->info[psdp->numComp.val-1]->pres.pres = PRSNT_NODEF; @@ -875,7 +883,7 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.fmts[0]->type), CM_SDP_SPEC); - MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.fmts[0]->val), 4); + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.fmts[0]->val), 8); /* Fill attribute if reqd */ { @@ -893,6 +901,7 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i free(dup); } +#endif /* We will always send one command at a time..*/ @@ -1055,10 +1064,11 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand ret = mg_prc_descriptors(mg_profile, inc_cmd, term); /* SDP updated to termination */ - megaco_activate_termination(term); } + /* TODO - copy inc descriptor...not sure if we need to do this.. */ + /********************************************************************/ /* Matt - to provide the response SDP structure which needs to fill in Modify command response */ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index e5c16df9c0..f84bfbd5e4 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -155,6 +155,9 @@ int mg_enable_logging(void); int mg_disable_logging(void); void mg_util_set_err_string ( MgStr *errTxt, char* str); +switch_status_t mg_build_sdp(MgMgcoMediaDesc* out, MgMgcoMediaDesc* inc, megaco_profile_t* mg_profile, mg_termination_t* term, CmMemListCp *memCp); +switch_status_t mg_add_local_descriptor(MgMgcoMediaDesc* media, megaco_profile_t* mg_profile, mg_termination_t* term, CmMemListCp *memCp); + switch_status_t sng_mgco_cfg(megaco_profile_t* profile); switch_status_t sng_mgco_init(sng_mg_event_interface_t* event); @@ -193,6 +196,9 @@ switch_status_t mg_fill_svc_change(MgMgcoSvcChgPar *srvPar, uint8_t method, c void mg_fill_null_context(MgMgcoContextId* ctxt); switch_status_t mg_send_service_change(SuId suId, const char* term_name, uint8_t method, MgServiceChangeReason_e reason,uint8_t wild); switch_status_t mg_create_mgco_command(MgMgcoCommand *cmd, uint8_t apiType, uint8_t cmdType); +switch_status_t mg_add_lcl_media(CmSdpMediaDescSet* med, megaco_profile_t* mg_profile, mg_termination_t* term, CmMemListCp *memCp); +switch_status_t mg_add_supported_media_codec(CmSdpMediaDesc* media, megaco_profile_t* mg_profile, mg_termination_t* term, CmMemListCp *memCp); +switch_status_t mg_rem_unsupported_codecs (megaco_profile_t* mg_profile, mg_termination_t* term, CmSdpMedFmtRtpList *fmtList, CmSdpAttrSet *attrSet, CmMemListCp *memCp); switch_status_t mg_send_oos_service_change(megaco_profile_t* mg_profile, const char* term_name, int wild); switch_status_t mg_send_ins_service_change(megaco_profile_t* mg_profile, const char* term_name, int wild); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index e5d08c1d84..39a69f3921 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -1441,3 +1441,503 @@ void mg_print_time() switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"Current Time = %s", ctime(&now)); } /*****************************************************************************************************************************/ +switch_status_t mg_add_local_descriptor(MgMgcoMediaDesc* media, megaco_profile_t* mg_profile, mg_termination_t* term,CmMemListCp *memCp) +{ + char* ipAddress[4]; + MgMgcoLocalDesc *local; + CmSdpInfoSet *psdp = NULL; + char * dup = NULL; + switch_status_t ret = SWITCH_STATUS_SUCCESS; + CmSdpMediaDescSet* med = NULL; + + switch_assert(media); + switch_assert(mg_profile); + switch_assert(term); + + dup = strdup((char*)term->u.rtp.local_addr); + switch_split(dup,'.',ipAddress); + + /* allocating mem for local descriptor */ + if (mgUtlGrowList((void ***)&media->parms, sizeof(MgMgcoMediaPar), &media->num, memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + media->parms[media->num.val-1]->type.pres = PRSNT_NODEF; + media->parms[media->num.val-1]->type.val = MGT_MEDIAPAR_LOCAL; + + local = &media->parms[media->num.val-1]->u.local; + + local->pres.pres = PRSNT_NODEF; + + psdp = &(local->sdp); + + if (mgUtlGrowList((void ***)&psdp->info, sizeof(CmSdpInfo), &psdp->numComp, memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + psdp->info[psdp->numComp.val-1]->pres.pres = PRSNT_NODEF; + + /* fill version */ + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->ver),1); + + /* fill orig */ + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.pres), 1); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.type), CM_SDP_SPEC); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.orig.pres), 1); + + MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.usrName, 1, "-", + memCp); + MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.sessId, 1, "0", + memCp); + MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.sessVer, 1, "0", + memCp); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.netType.type), + CM_SDP_NET_TYPE_IN); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.addrType), + CM_SDP_ADDR_TYPE_IPV4); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.addrType), + CM_SDP_IPV4_IP_UNI); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.addrType), + CM_SDP_IPV4_IP_UNI); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[0]), + atoi(ipAddress[0])); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[1]), + atoi(ipAddress[1])); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[2]), + atoi(ipAddress[2])); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[3]), + atoi(ipAddress[3])); + + /* fill session name */ + MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->sessName, 8, "SANGOMA", memCp); + + + /* Fill the SDP Connection Info */ + /* "c=" line - ipaddress */ + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.netType.type),CM_SDP_NET_TYPE_IN); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.addrType), CM_SDP_ADDR_TYPE_IPV4); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.u.ip4.addrType), CM_SDP_IPV4_IP_UNI); + + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[0]), atoi(ipAddress[0])); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[1]), atoi(ipAddress[1])); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[2]), atoi(ipAddress[2])); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[3]), atoi(ipAddress[3])); + + + /* t= line */ + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->sdpTime.pres),1); +#if 0 + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->sdpTime.sdpOpTimeSet.numComp),0); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->sdpTime.zoneAdjSet.numComp),0); +#endif + + med = &psdp->info[psdp->numComp.val-1]->mediaDescSet; + ret = mg_add_lcl_media(med, mg_profile, term, memCp); + + return ret; +} +/*****************************************************************************************************************************/ +switch_status_t mg_add_supported_media_codec(CmSdpMediaDesc* media, megaco_profile_t* mg_profile, mg_termination_t* term, CmMemListCp *memCp) +{ + const switch_codec_implementation_t *codecs[16]; + char *codec_prefs[16] = { 0 }; + char *szcodec_prefs; + int codec_count; + int i; + int fmt= 0x00; + + switch_assert(media); + switch_assert(mg_profile); + switch_assert(term); + switch_assert(memCp); + + szcodec_prefs = strdup(mg_profile->codec_prefs); + codec_count = switch_split(szcodec_prefs, ',', codec_prefs); + + /* Get the list of codecs, by preference */ + switch_loadable_module_get_codecs_sorted(codecs, switch_arraylen(codecs), codec_prefs, switch_arraylen(codec_prefs)); + for (i = 0; codecs[i] && i < codec_count; i++) { + int pt = codecs[i]->ianacode; + const char *name = codecs[i]->iananame; + + printf("Preference %d is %s/%d\n", i, name, pt); + + + if (mgUtlGrowList((void ***)&media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.fmts, sizeof(CmSdpU8OrNil), + &media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.num, memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + fmt = media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.num.val-1; + + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.fmts[fmt]->type), CM_SDP_SPEC); + + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->u.rtp.fmts[fmt]->val), pt); + + /* add associated attributes */ + { + if (mgUtlGrowList((void ***)&media->attrSet.attr, sizeof(CmSdpAttr), &media->attrSet.numComp, memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[media->attrSet.numComp.val-1]->type),CM_SDP_ATTR_RTPMAP); + MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[media->attrSet.numComp.val-1]->u.rtpmap.pres), 1); + MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[media->attrSet.numComp.val-1]->u.rtpmap.pay.type), CM_SDP_SPEC); + MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[media->attrSet.numComp.val-1]->u.rtpmap.pay.val), pt); + MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[media->attrSet.numComp.val-1]->u.rtpmap.enc.val), CM_SDP_ENC_UNKNOWN); + MG_SET_TKNSTROSXL((media->attrSet.attr[media->attrSet.numComp.val-1]->u.rtpmap.enc.name), strlen(name), name, memCp); + MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[media->attrSet.numComp.val-1]->u.rtpmap.clk), codecs[i]->samples_per_second); + /* encoding parameter not required to fill */ + } + + } + free(szcodec_prefs); + return SWITCH_STATUS_SUCCESS; +} +/*****************************************************************************************************************************/ +switch_status_t mg_add_lcl_media(CmSdpMediaDescSet* med, megaco_profile_t* mg_profile, mg_termination_t* term, CmMemListCp *memCp) +{ + CmSdpMediaDesc* media; + + switch_assert(med); + switch_assert(mg_profile); + switch_assert(term); + switch_assert(memCp); + + if (mgUtlGrowList((void ***)&med->mediaDesc, sizeof(CmSdpMediaDesc), + &med->numComp, memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + media = med->mediaDesc[med->numComp.val-1]; + + MG_INIT_TOKEN_VALUE(&(media->pres),1); + + /* Fill CmSdpMediaField */ + MG_INIT_TOKEN_VALUE(&(media->field.pres),1); + MG_INIT_TOKEN_VALUE(&(media->field.mediaType),CM_SDP_MEDIA_AUDIO); + + MG_INIT_TOKEN_VALUE(&(media->field.id.type),CM_SDP_VCID_PORT); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.type),CM_SDP_PORT_INT); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.pres),1); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.type), CM_SDP_SPEC); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.val), term->u.rtp.local_port); + + if (mgUtlGrowList((void ***)&media->field.par.pflst, sizeof(CmSdpMedProtoFmts), + &media->field.par.numProtFmts, memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + /* CmSdpMedProtoFmts */ + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->prot.type), CM_SDP_MEDIA_PROTO_RTP); + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->prot.u.subtype.type), CM_SDP_PROTO_RTP_AVP); + MG_INIT_TOKEN_VALUE(&(media->field.par.pflst[media->field.par.numProtFmts.val-1]->protType), CM_SDP_MEDIA_PROTO_RTP); + + + /***************************************************************************************************************************************************************/ + /* Fill ptime attribute */ + { + if (mgUtlGrowList((void ***)&media->attrSet.attr, sizeof(CmSdpAttr), &media->attrSet.numComp, memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[media->attrSet.numComp.val-1]->type),CM_SDP_ATTR_PTIME); + MG_INIT_TOKEN_VALUE(&(media->attrSet.attr[media->attrSet.numComp.val-1]->u.ptime), term->u.rtp.ptime); + } + /***************************************************************************************************************************************************************/ + /* fill codec info */ + mg_add_supported_media_codec(media, mg_profile, term, memCp); + + return SWITCH_STATUS_SUCCESS; +} +/***************************************************************************************************************************************************************/ + +switch_status_t mg_rem_unsupported_codecs (megaco_profile_t* mg_profile, mg_termination_t* term, CmSdpMedFmtRtpList *fmtList, CmSdpAttrSet *attrSet, CmMemListCp *memCp) +{ + int i = 0x00; + int id = 0x00; + int j = 0x00; + int a = 0x00; + CmSdpU8OrNil *fmt = NULL; + int foundCodec = 0x00; + const switch_codec_implementation_t *codecs[16]; + char *codec_prefs[16] = { 0 }; + char *szcodec_prefs; + int codec_count; + CmSdpAttr *attr = NULL; + CmSdpAttrRtpMap *rtp = NULL; + + /* Check if code list is present */ + if (!fmtList || (NOTPRSNT == fmtList->num.pres)) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "codec List Not present\n"); + return SWITCH_STATUS_FALSE; + } + + szcodec_prefs = strdup(mg_profile->codec_prefs); + codec_count = switch_split(szcodec_prefs, ',', codec_prefs); + + /* Get the list of codecs, by preference */ + switch_loadable_module_get_codecs_sorted(codecs, switch_arraylen(codecs), codec_prefs, switch_arraylen(codec_prefs)); + + + /* codec type is specified one */ + + /* loop through coddec list and remove un-supported codec */ + for(i = 0; i < fmtList->num.val; i++) + { + fmt = fmtList->fmts[i]; + + if((NOTPRSNT == fmt->type.pres) || (NOTPRSNT == fmt->val.pres)) continue; + + if(CM_SDP_SPEC != fmt->type.val) continue; /* TODO - need to see for other cases like CM_SDP_NIL/CM_SDP_CHOICE etc not sure as of now */ + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "codec[%d] number \n", fmt->val.val); + + /* see if received codec is present in our codec supported list */ + for (id = 0; codecs[id] && id < codec_count; id++) { + int pt = codecs[id]->ianacode; + //const char *name = codecs[id]->iananame; + if(pt == fmt->val.val){ + foundCodec = 0x01; + break; + } + } + + /* IF codec not found in list, remove it */ + if(!foundCodec) { + + for(j = i; j < fmtList->num.val - 1; j++) + { + fmtList->fmts[j] = fmtList->fmts[j +1]; + } + mgUtlShrinkList((Void ***)&fmtList->fmts, sizeof(CmSdpU8OrNil), &fmtList->num, memCp); + i-- ; + + /* remove associated a= , if present */ + if((NOTPRSNT != attrSet->numComp.pres) && (0 != attrSet->numComp.val)){ + for(a = 0; a < attrSet->numComp.val; a++) { + attr = attrSet->attr[a]; + + if(CM_SDP_ATTR_RTPMAP != attr->type.val) continue; /* as of now only checking RTPMAP */ + + rtp = &attr->u.rtpmap; + + if((NOTPRSNT != rtp->pres.pres) && (fmt->val.val == rtp->pay.val.val)) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "a line found against codec[%d]..Removing a line \n", fmt->val.val); + + /* mgUtlShrinkList API will delete last node from list, hence suffling list nodes */ + for(j = a; j < attrSet->numComp.val - 1; j++) + { + attrSet->attr[j] = attrSet->attr[j +1]; + } + mgUtlShrinkList((Void ***)&attrSet->attr, sizeof(CmSdpAttr), &attrSet->numComp, memCp); + } + } + } + } + } + + return SWITCH_STATUS_SUCCESS; +} + + + +/*****************************************************************************************************************************/ +switch_status_t mg_build_sdp(MgMgcoMediaDesc* out, MgMgcoMediaDesc* inc, megaco_profile_t* mg_profile, mg_termination_t* term, CmMemListCp *memCp) +{ + CmSdpU8OrNil *fmt = NULL; + CmSdpInfoSet *psdp = NULL; + char* ipAddress[4]; + int i = 0x00; + int j = 0x00; + int choose_codec = 0x00; + int k = 0x00; + MgMgcoLocalDesc *local = NULL; + int fresh_sdp = 0x00; + char* dup = NULL; + CmSdpMedProtoFmts *format=NULL; + + + switch_assert(out); + switch_assert(inc); + switch_assert(mg_profile); + switch_assert(term); + + dup = strdup((char*)term->u.rtp.local_addr); + switch_split(dup,'.',ipAddress); + + + if((NOTPRSNT == inc->num.pres) || (0 == inc->num.val)){ + fresh_sdp = 0x01; + } + + /* if its fresh sdp then add only local descriptor */ + if(fresh_sdp) { + mg_add_local_descriptor(out, mg_profile, term, memCp); + } else { + /* incoming has sdp, so copy that sdp and overwrite only local sdp */ + mgUtlCpyMgMgcoMediaDesc(out, inc, memCp); + + /* now see if we have local descriptor, then pick up that and modify the fields */ + + if((NOTPRSNT != out->num.pres) && (0 != out->num.val)) + { + for(i=0; inum.val; i++) { + if(MGT_MEDIAPAR_LOCAL == out->parms[i]->type.val) { + local = &out->parms[i]->u.local; + } + } + } + } + + if(!local || (NOTPRSNT == local->sdp.numComp.pres) || (0 == local->sdp.numComp.val)){ + /* local sdp is not part of media descriptor, then add local sdp*/ + mg_add_local_descriptor(out, mg_profile, term, memCp); + }else{ + /* local sdp is present.. now go over the local descriptor and modify fields */ + psdp = &(local->sdp); + + for(i=0; i< psdp->numComp.val; i++) { +/**********************************************************************************************************************************/ + /* version - let it be same, if present else use version 1 */ + if(NOTPRSNT == psdp->info[psdp->numComp.val-1]->ver.pres) { + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->ver),1); + } +/**********************************************************************************************************************************/ + /* orig (o- line) fill with our info */ + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.pres), 1); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.type), CM_SDP_SPEC); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.orig.pres), 1); + + MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.usrName, 1, "-", + NULL); + MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.sessId, 1, "0", + NULL); + MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.sessVer, 1, "0", + NULL); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.netType.type), + CM_SDP_NET_TYPE_IN); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.addrType), + CM_SDP_ADDR_TYPE_IPV4); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.addrType), + CM_SDP_IPV4_IP_UNI); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.addrType), + CM_SDP_IPV4_IP_UNI); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[0]), + atoi(ipAddress[0])); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[1]), + atoi(ipAddress[1])); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[2]), + atoi(ipAddress[2])); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[3]), + atoi(ipAddress[3])); + +/**********************************************************************************************************************************/ + /* session-name , let it be like this if present, else skip it */ +/**********************************************************************************************************************************/ + /* "c=" line - ipaddress */ + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.netType.type),CM_SDP_NET_TYPE_IN); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.addrType), CM_SDP_ADDR_TYPE_IPV4); + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.u.ip4.addrType), CM_SDP_IPV4_IP_UNI); + + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[0]), atoi(ipAddress[0])); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[1]), atoi(ipAddress[1])); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[2]), atoi(ipAddress[2])); + MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[3]), atoi(ipAddress[3])); + +/**********************************************************************************************************************************/ + /* t= line */ + MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->sdpTime.pres),1); +/**********************************************************************************************************************************/ + /* fill media descriptors */ + { + CmSdpMediaDescSet* med = &psdp->info[psdp->numComp.val-1]->mediaDescSet; + CmSdpMediaDesc* media; + + if((NOTPRSNT == med->numComp.pres) || (0 == med->numComp.val)){ + mg_add_lcl_media(med, mg_profile, term, memCp); + }else{ + for(j =0;j < med->numComp.val; j++){ + media = med->mediaDesc[j]; + /* check for choose port and fill the port */ + if(NOTPRSNT != media->field.id.type.pres){ + if(CM_SDP_VCID_CHOOSE == media->field.id.type.val){ + MG_INIT_TOKEN_VALUE(&(media->field.id.type),CM_SDP_VCID_PORT); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.type),CM_SDP_PORT_INT); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.pres),1); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.type), CM_SDP_SPEC); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.val), term->u.rtp.local_port); + + } + } + + /* check for codec */ + if((NOTPRSNT == media->field.par.numProtFmts.pres) || + (0 == media->field.par.numProtFmts.val)){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"No codec specified in incoming local descriptor \n"); + mg_add_supported_media_codec(media, mg_profile, term, memCp ); + }else{ + /* check for media format/codec */ + for(k =0;k < media->field.par.numProtFmts.val; k++){ + format = media->field.par.pflst[k]; + if ((NOTPRSNT != format->protType.pres) && + (CM_SDP_MEDIA_PROTO_RTP == format->protType.val)) + { + if((NOTPRSNT != format->u.rtp.num.pres) + &&(0 != format->u.rtp.num.val)) + { + /* If the codec type is CHOOSE then we need to fill our list */ + for(i = 0; i < format->u.rtp.num.val; i++) + { + fmt = format->u.rtp.fmts[i]; + + if((NOTPRSNT == fmt->type.pres) || (NOTPRSNT == fmt->val.pres)) continue; + + if(CM_SDP_CHOOSE == fmt->type.val){ + choose_codec = 0x1; + } + } + if(choose_codec){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "CHOOSE codec is requested fill out supported codecs \n"); + + /* delete existing rtp format list..TODO find better way */ + for(i = 0; i < format->u.rtp.num.val; i++) + { + mgUtlShrinkList((Void ***)&format->u.rtp.fmts, sizeof(CmSdpU8OrNil), &format->u.rtp.num, memCp); + } + /* If the codec type is CHOOSE then we need to fill our list */ + mg_add_supported_media_codec(media, mg_profile, term, memCp); + } + else if (!choose_codec && (SWITCH_STATUS_FALSE == mg_rem_unsupported_codecs(mg_profile, term , &format->u.rtp, &media->attrSet, memCp))) + { + return SWITCH_STATUS_FALSE; + } + } + } + } + } + } + } +/**********************************************************************************************************************************/ + } + + } + + } + return SWITCH_STATUS_SUCCESS; +} + diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index e3c3b8c3de..011c36ce56 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -74,7 +74,7 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) // const char *prefix = switch_xml_attr(mg_term, "termination-id-prefix"); //const char *sztermination_id_base = switch_xml_attr(mg_term, "termination-id-base"); - //const char *tech = switch_xml_attr(mg_term, "tech"); + const char *tech = switch_xml_attr(mg_term, "tech"); const char *channel_prefix = switch_xml_attr(mg_term, "channel-prefix"); const char *channel_map = switch_xml_attr(mg_term, "channel-map"); @@ -100,7 +100,8 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) term->type = MG_TERM_TDM; term->profile = profile; term->mg_ctxt = NULL; - term->active_events = NULL; + term->tech = switch_core_strdup(pool, tech); + term->active_events = NULL; term->name = switch_core_sprintf(pool, "%s%d", prefix, j); term->u.tdm.channel = j; term->u.tdm.span_name = switch_core_strdup(pool, channel_prefix); @@ -260,6 +261,7 @@ static switch_xml_config_item_t *get_instructions(megaco_profile_t *profile) { SWITCH_CONFIG_ITEM("rtp-port-range", SWITCH_CONFIG_STRING, CONFIG_REQUIRED, &profile->rtp_port_range, "1-65535", &switch_config_string_strdup, "", "rtp port range"), SWITCH_CONFIG_ITEM("rtp-termination-id-prefix", SWITCH_CONFIG_STRING, CONFIG_RELOADABLE, &profile->rtp_termination_id_prefix, "", &switch_config_string_strdup, "", "rtp termination prefix"), SWITCH_CONFIG_ITEM("rtp-termination-id-len", SWITCH_CONFIG_INT, CONFIG_RELOADABLE, &profile->rtp_termination_id_len, "", &opt_termination_id_len, "", "rtp termination id"), + SWITCH_CONFIG_ITEM("codec-prefs", SWITCH_CONFIG_STRING, 0, &profile->codec_prefs, "", &switch_config_string_strdup, "", "codec preferences, coma-separated"), SWITCH_CONFIG_ITEM_END() }; diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index af53052fbb..fdecf761b9 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -113,6 +113,7 @@ struct mg_termination_s { mg_termination_t *next; /*!< List for physical terminations */ mg_context_t* mg_ctxt; uint32_t flags; + const char *tech; /* Endpoint controlling the TDM interface - only FreeTDM tested so far */ union { struct { From a4255e140b3b5de77b62213b6987a85b6dce7b1b Mon Sep 17 00:00:00 2001 From: James Zhang Date: Fri, 27 Jul 2012 11:53:00 -0400 Subject: [PATCH 366/822] freetdm: adding variables for ansi outgoing IAMs . added called party number INN variable ie. . added multiple variables to set User Service Information IE variables are : ss7_iam_usi_trans_cap ss7_iam_usi_code_standard ss7_iam_usi_trans_mode ss7_iam_usi_trans_rate_0 ss7_iam_usi_trans_rate_1 ss7_iam_usi_layer1_ident ss7_iam_usi_layer1_prot ss7_iam_usi_layer2_ident ss7_iam_usi_layer2_prot ss7_iam_usi_layer3_ident ss7_iam_usi_layer3_prot ss7_iam_usi_chan_struct ss7_iam_usi_config ss7_iam_usi_establish ss7_iam_usi_symmetry ss7_iam_usi_rate_multiplier . ss7_iam_usi_trans_cap is a string variable, the others are all integers . ss7_iam_usi_trans_cap has options of : - SPEECH - UNRESTRICTED - RESTRICTED - 31KHZ - 7KHZ - 15KHZ - VIDEO default value is SPEECH, if the parameter is wrong, set to SPEECH. If not set, this field is not present --- .../ftmod_sangoma_ss7_support.c | 229 +++++++++++++++--- 1 file changed, 199 insertions(+), 30 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 032ea8efd7..2e51ba8674 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -213,17 +213,17 @@ ftdm_status_t copy_cdPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cd ftdm_status_t copy_cdPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cdPtyNum) { - const char *cld_nadi = NULL; + char *val = NULL; ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; cdPtyNum->eh.pres = PRSNT_NODEF; cdPtyNum->natAddrInd.pres = PRSNT_NODEF; - cld_nadi = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_cld_nadi"); - if (!ftdm_strlen_zero(cld_nadi)) { - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Called NADI value \"%s\"\n", cld_nadi); - cdPtyNum->natAddrInd.val = atoi(cld_nadi); + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_cld_nadi"); + if (!ftdm_strlen_zero(val)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Called NADI value \"%s\"\n", val); + cdPtyNum->natAddrInd.val = atoi(val); } else { cdPtyNum->natAddrInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].cld_nadi; ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied NADI value found for CLD, using \"%d\"\n", cdPtyNum->natAddrInd.val); @@ -233,7 +233,14 @@ ftdm_status_t copy_cdPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cdPt cdPtyNum->numPlan.val = 0x01; cdPtyNum->innInd.pres = PRSNT_NODEF; - cdPtyNum->innInd.val = 0x01; + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_cld_inn"); + if (!ftdm_strlen_zero(val)) { + cdPtyNum->innInd.val = atoi(val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Called INN value \"%s\"\n", val); + } else { + cdPtyNum->innInd.val = 0x01; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Called INN value, set to default value 0x01\n"); + } return copy_tknStr_to_sngss7(caller_data->dnis.digits, &cdPtyNum->addrSig, &cdPtyNum->oddEven); } @@ -1240,32 +1247,194 @@ ftdm_status_t copy_txMedReq_to_sngss7(ftdm_channel_t *ftdmchan, SiTxMedReq *txMe ftdm_status_t copy_usrServInfoA_to_sngss7(ftdm_channel_t *ftdmchan, SiUsrServInfo *usrServInfoA) { - usrServInfoA->eh.pres = PRSNT_NODEF; + int bProceed = 0; + const char *val = NULL; + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_trans_cap"); + if (!ftdm_strlen_zero(val)) { + int itc_type = 0; + if (!strcasecmp(val, "SPEECH")) { + itc_type = ITC_SPEECH; + } else if (!strcasecmp(val, "UNRESTRICTED")) { + itc_type = ITC_UNRDIG; + } else if (!strcasecmp(val, "RESTRICTED")) { + itc_type = ITC_RESDIG; + } else if (!strcasecmp(val, "31KHZ")) { + itc_type = ITC_A31KHZ; + } else if (!strcasecmp(val, "7KHZ")) { + itc_type = ITC_A7KHZ; + } else if (!strcasecmp(val, "15KHZ")) { + itc_type = ITC_A15KHZ; + } else if (!strcasecmp(val, "VIDEO")) { + itc_type = ITC_VIDEO; + } else { + itc_type = ITC_SPEECH; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI transmission capability parameter is wrong : %s. Setting to default SPEECH. \n", val ); + } + + usrServInfoA->infoTranCap.pres = PRSNT_NODEF; + usrServInfoA->infoTranCap.val = get_trillium_val(bc_cap_codes, ftdmchan->caller_data.bearer_capability, itc_type); + bProceed = 1; + } else { + usrServInfoA->infoTranCap.pres = NOTPRSNT; + } - usrServInfoA->infoTranCap.pres = PRSNT_NODEF; + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_code_standard"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->cdeStand.pres = PRSNT_NODEF; + usrServInfoA->cdeStand.val = (int)atoi(val); /* default is 0x0 */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI coding standard = %d\n", usrServInfoA->cdeStand.val ); + bProceed = 1; + } else { + usrServInfoA->cdeStand.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_trans_mode"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->tranMode.pres = PRSNT_NODEF; + usrServInfoA->tranMode.val = (int)atoi(val); /* transfer mode, default is 0x0*/ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI transfer mode = %d\n", usrServInfoA->tranMode.val ); + bProceed = 1; + } else { + usrServInfoA->tranMode.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_trans_rate_0"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->infoTranRate0.pres = PRSNT_NODEF; + usrServInfoA->infoTranRate0.val = (int)atoi(val); /* default is 0x10, 64kbps origination to destination*/ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI trans rate 0 = %d\n", usrServInfoA->infoTranRate0.val ); + bProceed = 1; + } else { + usrServInfoA->infoTranRate0.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_trans_rate_1"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->infoTranRate1.pres = PRSNT_NODEF; + usrServInfoA->infoTranRate1.val = (int)atoi(val); /* 64kbps destination to origination, default is 0x10 */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI trans rate 1 = %d\n", usrServInfoA->infoTranRate1.val ); + bProceed = 1; + } else { + usrServInfoA->infoTranRate1.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_layer1_ident"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->lyr1Ident.pres = PRSNT_NODEF; + usrServInfoA->lyr1Ident.val = (int)atoi(val); /*default value is 0x01 */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI layer 1 indentification = %d\n", usrServInfoA->lyr1Ident.val ); + bProceed = 1; + } else { + usrServInfoA->lyr1Ident.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_layer1_prot"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->usrInfLyr1Prot.pres = PRSNT_NODEF; + usrServInfoA->usrInfLyr1Prot.val = (int)atoi(val); /*default value is 0x02 */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI layer 1 protocol = %d\n", usrServInfoA->usrInfLyr1Prot.val ); + bProceed = 1; + } else { + usrServInfoA->usrInfLyr1Prot.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_layer2_ident"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->lyr2Ident.pres = PRSNT_NODEF; + usrServInfoA->lyr2Ident.val = (int)atoi(val); /*default value is 0x01 */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI layer 2 indentification = %d\n", usrServInfoA->lyr2Ident.val ); + bProceed = 1; + } else { + usrServInfoA->lyr2Ident.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_layer2_prot"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->usrInfLyr2Prot.pres = PRSNT_NODEF; + usrServInfoA->usrInfLyr2Prot.val = (int)atoi(val); /*default value is 0x02 */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI layer 2 protocol = %d\n", usrServInfoA->usrInfLyr2Prot.val ); + bProceed = 1; + } else { + usrServInfoA->usrInfLyr2Prot.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_layer3_ident"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->lyr3Ident.pres = PRSNT_NODEF; + usrServInfoA->lyr3Ident.val = (int)atoi(val); /*default value is 0x01 */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI layer 3 indentification = %d\n", usrServInfoA->lyr3Ident.val ); + bProceed = 1; + } else { + usrServInfoA->lyr3Ident.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_layer3_prot"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->usrInfLyr3Prot.pres = PRSNT_NODEF; + usrServInfoA->usrInfLyr3Prot.val = (int)atoi(val); /*default value is 0x02 */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI layer 3 protocol = %d\n", usrServInfoA->usrInfLyr3Prot.val ); + bProceed = 1; + } else { + usrServInfoA->usrInfLyr3Prot.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_chan_struct"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->chanStruct.pres = PRSNT_NODEF; + usrServInfoA->chanStruct.val = (int)atoi(val); /* default value is 0x1, 8kHz integrity */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI channel structure = %d\n", usrServInfoA->chanStruct.val ); + bProceed = 1; + } else { + usrServInfoA->chanStruct.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_config"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->config.pres = PRSNT_NODEF; + usrServInfoA->config.val = (int)atoi(val); /* default value is 0x0, point to point configuration */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI configuration = %d\n", usrServInfoA->config.val ); + bProceed = 1; + } else { + usrServInfoA->config.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_establish"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->establish.pres = PRSNT_NODEF; + usrServInfoA->establish.val = (int)atoi(val); /* default value is 0x0, on demand */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI establishment = %d\n", usrServInfoA->establish.val ); + bProceed = 1; + } else { + usrServInfoA->establish.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_symmetry"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->symmetry.pres = PRSNT_NODEF; + usrServInfoA->symmetry.val = (int)atoi(val); /* default value is 0x0, bi-directional symmetric */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI symmetry = %d\n", usrServInfoA->symmetry.val ); + bProceed = 1; + } else { + usrServInfoA->symmetry.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_rate_multiplier"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->rateMultiplier.pres = PRSNT_NODEF; + usrServInfoA->rateMultiplier.val = (int)atoi(val); /* default value is 0x1, 1x rate multipler */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI rate multipier = %d\n", usrServInfoA->rateMultiplier.val ); + bProceed = 1; + } else { + usrServInfoA->rateMultiplier.pres = NOTPRSNT; + } + + if (bProceed) { + usrServInfoA->eh.pres = PRSNT_NODEF; + } else { + usrServInfoA->eh.pres = NOTPRSNT; + } - usrServInfoA->infoTranCap.val = get_trillium_val(bc_cap_codes, ftdmchan->caller_data.bearer_capability, ITC_SPEECH); - - usrServInfoA->cdeStand.pres = PRSNT_NODEF; - usrServInfoA->cdeStand.val = 0x0; /* ITU-T standardized coding */ - usrServInfoA->tranMode.pres = PRSNT_NODEF; - usrServInfoA->tranMode.val = 0x0; /* circuit mode */ - usrServInfoA->infoTranRate0.pres = PRSNT_NODEF; - usrServInfoA->infoTranRate0.val = 0x10; /* 64kbps origination to destination */ - usrServInfoA->infoTranRate1.pres = PRSNT_NODEF; - usrServInfoA->infoTranRate1.val = 0x10; /* 64kbps destination to origination */ - usrServInfoA->chanStruct.pres = PRSNT_NODEF; - usrServInfoA->chanStruct.val = 0x1; /* 8kHz integrity */ - usrServInfoA->config.pres = PRSNT_NODEF; - usrServInfoA->config.val = 0x0; /* point to point configuration */ - usrServInfoA->establish.pres = PRSNT_NODEF; - usrServInfoA->establish.val = 0x0; /* on demand */ - usrServInfoA->symmetry.pres = PRSNT_NODEF; - usrServInfoA->symmetry.val = 0x0; /* bi-directional symmetric */ - usrServInfoA->usrInfLyr1Prot.pres = PRSNT_NODEF; - usrServInfoA->usrInfLyr1Prot.val = 0x2; /* G.711 ulaw */ - usrServInfoA->rateMultiplier.pres = PRSNT_NODEF; - usrServInfoA->rateMultiplier.val = 0x1; /* 1x rate multipler */ return FTDM_SUCCESS; } From 6e54a5e9bca0eb8bbbf4f748519c0a33bc883619 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 27 Jul 2012 12:08:15 -0400 Subject: [PATCH 367/822] local descriptor codec negotiation done --- .../media_gateway_cmd_handler.c | 8 +++++- .../mod_media_gateway/media_gateway_utils.c | 26 ++++++++++++++----- .../mod_media_gateway/mod_media_gateway.h | 3 ++- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index ca0d286ba2..8940d36e66 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -707,7 +707,13 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i /* only for RTP */ if(is_rtp){ - mg_build_sdp(&desc->u.media, inc_med_desc, mg_profile, term, &rsp.u.mgCmdRsp[0]->memCp); + if(SWITCH_STATUS_FALSE == mg_build_sdp(&desc->u.media, inc_med_desc, mg_profile, term, &rsp.u.mgCmdRsp[0]->memCp)) { + if(term->mg_error_code && (*term->mg_error_code == MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT)){ + mg_util_set_err_string(&errTxt, " Unsupported Codec "); + err_code = MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT; + goto error; + } + } } #if 0 if(is_rtp){ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index 39a69f3921..ae4ec24b04 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -1699,17 +1699,18 @@ switch_status_t mg_rem_unsupported_codecs (megaco_profile_t* mg_profile, mg_term /* loop through coddec list and remove un-supported codec */ for(i = 0; i < fmtList->num.val; i++) { + foundCodec = 0x00; fmt = fmtList->fmts[i]; if((NOTPRSNT == fmt->type.pres) || (NOTPRSNT == fmt->val.pres)) continue; if(CM_SDP_SPEC != fmt->type.val) continue; /* TODO - need to see for other cases like CM_SDP_NIL/CM_SDP_CHOICE etc not sure as of now */ - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "codec[%d] number \n", fmt->val.val); /* see if received codec is present in our codec supported list */ for (id = 0; codecs[id] && id < codec_count; id++) { int pt = codecs[id]->ianacode; + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "Matching recv codec[%d] with supported codec[%d] \n", fmt->val.val, pt); //const char *name = codecs[id]->iananame; if(pt == fmt->val.val){ foundCodec = 0x01; @@ -1751,6 +1752,14 @@ switch_status_t mg_rem_unsupported_codecs (megaco_profile_t* mg_profile, mg_term } } + if(0 == fmtList->num.val) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "No Supported codec found in offer, Rejecting request \n"); + term->mg_error_code = switch_core_alloc(term->pool, sizeof(term->mg_error_code)); + *term->mg_error_code = MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT; + + return SWITCH_STATUS_FALSE; + } + return SWITCH_STATUS_SUCCESS; } @@ -1799,6 +1808,12 @@ switch_status_t mg_build_sdp(MgMgcoMediaDesc* out, MgMgcoMediaDesc* inc, megaco_ for(i=0; inum.val; i++) { if(MGT_MEDIAPAR_LOCAL == out->parms[i]->type.val) { local = &out->parms[i]->u.local; + break; + } else if(MGT_MEDIAPAR_STRPAR == out->parms[i]->type.val){ + MgMgcoStreamDesc *stream = &out->parms[i]->u.stream; + if((NOTPRSNT != stream->sl.pres.pres) && (NOTPRSNT != stream->sl.local.pres.pres)){ + local = &stream->sl.local; + } } } } @@ -1823,12 +1838,9 @@ switch_status_t mg_build_sdp(MgMgcoMediaDesc* out, MgMgcoMediaDesc* inc, megaco_ MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.type), CM_SDP_SPEC); MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.orig.pres), 1); - MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.usrName, 1, "-", - NULL); - MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.sessId, 1, "0", - NULL); - MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.sessVer, 1, "0", - NULL); + MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.usrName, 1, "-", memCp); + MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.sessId, 1, "0", memCp); + MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.sessVer, 1, "0", memCp); MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.netType.type), CM_SDP_NET_TYPE_IN); MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.addrType), diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index fdecf761b9..5c50ed9cfe 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -112,8 +112,9 @@ struct mg_termination_s { MgMgcoReqEvtDesc *active_events; /* !< active megaco events */ mg_termination_t *next; /*!< List for physical terminations */ mg_context_t* mg_ctxt; + int *mg_error_code; /* MEGACO error code */ uint32_t flags; - const char *tech; /* Endpoint controlling the TDM interface - only FreeTDM tested so far */ + const char *tech; /* Endpoint controlling the TDM interface - only FreeTDM tested so far */ union { struct { From ad5297cab71287bb48e6efe004104da34d756ace Mon Sep 17 00:00:00 2001 From: root Date: Fri, 27 Jul 2012 12:54:58 -0400 Subject: [PATCH 368/822] adding codec nogotiation code --- .../media_gateway_cmd_handler.c | 28 ++++++--- .../mod_media_gateway/media_gateway_stack.h | 4 +- .../mod_media_gateway/media_gateway_utils.c | 58 +++++++++++++++++-- 3 files changed, 75 insertions(+), 15 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 8940d36e66..18129ff975 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -198,7 +198,7 @@ switch_status_t mg_is_ito_pkg_req(megaco_profile_t* mg_profile, MgMgcoCommand *c * * */ -switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand *cmd, mg_termination_t* term) +switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand *cmd, mg_termination_t* term, CmMemListCp *memCp) { CmSdpMedProtoFmts *format; TknU8 *fmt; @@ -301,7 +301,7 @@ switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand * } } - mgco_handle_sdp(&local->sdp, term, MG_SDP_LOCAL); + mgco_handle_incoming_sdp(&local->sdp, term, MG_SDP_LOCAL, mg_profile, memCp); break; } @@ -313,7 +313,7 @@ switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand * remote = &mediaPar->u.remote; sdp = remote->sdp.info[0]; /* for Matt - same like local descriptor */ - mgco_handle_sdp(&remote->sdp, term, MG_SDP_REMOTE); + mgco_handle_incoming_sdp(&remote->sdp, term, MG_SDP_REMOTE, mg_profile, memCp); break; } @@ -406,12 +406,12 @@ switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand * if (mgStream->sl.remote.pres.pres) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got remote stream media description:\n"); - mgco_handle_sdp(&mgStream->sl.remote.sdp, term, MG_SDP_LOCAL); + mgco_handle_incoming_sdp(&mgStream->sl.remote.sdp, term, MG_SDP_LOCAL, mg_profile, memCp); } if (mgStream->sl.local.pres.pres) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got local stream media description:\n"); - mgco_handle_sdp(&mgStream->sl.local.sdp, term, MG_SDP_REMOTE); + mgco_handle_incoming_sdp(&mgStream->sl.local.sdp, term, MG_SDP_REMOTE, mg_profile, memCp); } break; @@ -610,7 +610,14 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i /********************************************************************/ - ret = mg_prc_descriptors(mg_profile, inc_cmd, term); + ret = mg_prc_descriptors(mg_profile, inc_cmd, term, &inc_cmd->u.mgCmdInd[0]->memCp); + + /* IF there is any error , return */ + if(term->mg_error_code && (*term->mg_error_code == MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT)){ + mg_util_set_err_string(&errTxt, " Unsupported Codec "); + err_code = MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT; + goto error; + } /* TODO - locally assigned SDP must be the part of termination...which we can use to fill responses*/ @@ -1067,7 +1074,14 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand /********************************************************************/ - ret = mg_prc_descriptors(mg_profile, inc_cmd, term); + ret = mg_prc_descriptors(mg_profile, inc_cmd, term, &inc_cmd->u.mgCmdInd[0]->memCp); + + /* IF there is any error , return */ + if(term->mg_error_code && (*term->mg_error_code == MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT)){ + mg_util_set_err_string(&errTxt, " Unsupported Codec "); + err_code = MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT; + goto error; + } /* SDP updated to termination */ megaco_activate_termination(term); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index f84bfbd5e4..20354b0ccb 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -141,7 +141,7 @@ typedef enum { (_reqId)->id.val = 0xFFFFFFFF; -switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd, mg_termination_t* term); +switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd, mg_termination_t* term, CmMemListCp *memCp); void handle_sng_log(uint8_t level, char *fmt, ...); void handle_mgco_sta_ind(Pst *pst, SuId suId, MgMgtSta* msg); void handle_mgco_txn_sta_ind(Pst *pst, SuId suId, MgMgcoInd* msg); @@ -166,7 +166,7 @@ int sng_mgco_mg_get_status(int elemId, MgMngmt* cfm, megaco_profile_t* mg_cfg, m switch_status_t mg_is_ito_pkg_req(megaco_profile_t* mg_profile, MgMgcoCommand *cmd); switch_status_t mg_send_end_of_axn(SuId suId, MgMgcoTransId* transId, MgMgcoContextId* ctxtId, TknU32* peerId); -void mgco_handle_sdp(CmSdpInfoSet *sdp,mg_termination_t* term, mgco_sdp_types_e sdp_type); +void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp,mg_termination_t* term, mgco_sdp_types_e sdp_type, megaco_profile_t* mg_profile, CmMemListCp *memCp); void mg_util_set_ctxt_string ( MgStr *errTxt, MgMgcoContextId *ctxtId); switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd, MgMgcoContextId* new_ctxtId); switch_status_t handle_mg_subtract_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index ae4ec24b04..019725208f 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -421,7 +421,7 @@ void mg_util_set_cmd_name_string (MgStr *errTxt, MgMgcoCommand *cmd) } /*****************************************************************************************************************************/ -void mgco_print_sdp_attr_set(CmSdpAttrSet *s) +void mgco_handle_sdp_attr_set(CmSdpAttrSet *s, mg_termination_t* term) { int i=0x00; if (s->numComp.pres) { @@ -461,6 +461,9 @@ void mgco_print_sdp_attr_set(CmSdpAttrSet *s) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t PTIME = %ld \n", (NOTPRSNT != a->u.ptime.pres)?a->u.ptime.val:-1); #endif + if(MG_TERM_RTP == term->type){ + term->u.rtp.ptime = a->u.ptime.val; + } break; } case CM_SDP_ATTR_RECVONLY: @@ -786,7 +789,30 @@ void mgco_print_CmSdpU8OrNil(CmSdpU8OrNil* p) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,"CmSdpU8OrNil: Value = %d \n", (NOTPRSNT != p->val.pres)?p->val.val:-1); } -void mgco_print_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sdp_types_e sdp_type) +const char* mg_get_codec_name(megaco_profile_t* mg_profile, int iana_code) +{ + int i = 0x00; + const switch_codec_implementation_t *codecs[16]; + char *codec_prefs[16] = { 0 }; + char *szcodec_prefs; + int codec_count; + + szcodec_prefs = strdup(mg_profile->codec_prefs); + codec_count = switch_split(szcodec_prefs, ',', codec_prefs); + + /* Get the list of codecs, by preference */ + switch_loadable_module_get_codecs_sorted(codecs, switch_arraylen(codecs), codec_prefs, switch_arraylen(codec_prefs)); + /* see if received codec is present in our codec supported list */ + for (i = 0; codecs[i] && i < codec_count; i++) { + if(iana_code == codecs[i]->ianacode){ + return codecs[i]->iananame; + } + } + + return NULL; +} + +void mgco_handle_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sdp_types_e sdp_type, megaco_profile_t* mg_profile, CmSdpAttrSet *attrSet, CmMemListCp *memCp) { int i=0x00; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "***** Media Parameter *********** \n"); @@ -837,6 +863,26 @@ void mgco_print_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sdp } } } + + /* Ideally remote descriptor should have supported codec..but just in case calling remove un-supported codecs api */ + mg_rem_unsupported_codecs(mg_profile, term , r, attrSet, memCp); + + + /* now whatever we have , that will be suported one */ + if((NOTPRSNT != r->num.pres) && (0 != r->num.val) && (NULL != r->fmts[0])){ + const char* name = mg_get_codec_name(mg_profile, r->fmts[0]->val.val); + if(name){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " Updating codec to[%d], name[%s] \n", + r->fmts[0]->val.val, name); + if(MG_TERM_RTP == term->type){ + term->u.rtp.codec = name; + } + }else{ + /* ERROR */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " NO Codec Name found against iana[%d] \n", r->fmts[0]->val.val); + } + } + break; } @@ -854,7 +900,7 @@ void mgco_print_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sdp switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "**************** \n"); } -void mgco_handle_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sdp_types_e sdp_type) +void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sdp_types_e sdp_type, megaco_profile_t* mg_profile, CmMemListCp *memCp) { int i; @@ -1021,7 +1067,7 @@ void mgco_handle_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sdp_types_e /************************************************************************************************************************/ /* Attribute Set */ - mgco_print_sdp_attr_set(&s->attrSet); + mgco_handle_sdp_attr_set(&s->attrSet, term); /************************************************************************************************************************/ /* Media Descriptor Set */ @@ -1077,7 +1123,7 @@ void mgco_handle_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sdp_types_e break; } } - mgco_print_sdp_media_param(&f->par, term, sdp_type); + mgco_handle_sdp_media_param(&f->par, term, sdp_type, mg_profile, &desc->attrSet, memCp); } /*info */ @@ -1097,7 +1143,7 @@ void mgco_handle_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sdp_types_e } /* attribute set */ - mgco_print_sdp_attr_set(&desc->attrSet); + mgco_handle_sdp_attr_set(&desc->attrSet, term); if (desc->field.mediaType.val == CM_SDP_MEDIA_AUDIO && From ed5875b54b15a7bfb9312a3dfaeb548297f6f4f0 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 27 Jul 2012 13:01:54 -0400 Subject: [PATCH 369/822] fixing issue --- src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 18129ff975..f9ae4fe90a 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -1080,6 +1080,7 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand if(term->mg_error_code && (*term->mg_error_code == MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT)){ mg_util_set_err_string(&errTxt, " Unsupported Codec "); err_code = MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT; + /* TODO delete RTP termination */ goto error; } From 6895e46983e625817d6f939f5c19c0719fbc5c55 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 27 Jul 2012 15:02:45 -0400 Subject: [PATCH 370/822] Fix compile warning --- libs/freetdm/src/ftdm_io.c | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 1c05797102..18e39a3da9 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -36,7 +36,6 @@ * David Yat Sin * */ - #define _GNU_SOURCE #include "private/ftdm_core.h" #include From 008bb4942be0a6e2d1b2f5db425c7cace04a6449 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 27 Jul 2012 16:11:46 -0400 Subject: [PATCH 371/822] adding code for updating codec types --- libs/freetdm/mod_freetdm/tdm.c | 4 +- .../mod_media_gateway/media_gateway_utils.c | 1 + src/mod/endpoints/mod_sofia/rtp.c | 82 ++++++++++++++++--- 3 files changed, 76 insertions(+), 11 deletions(-) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index b2d37d47ed..ab061a3812 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -111,7 +111,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi const char *dname; ftdm_codec_t codec; uint32_t interval; - ftdm_status_t fstatus; + /*ftdm_status_t fstatus;*/ const char *ftdm_start_only = switch_event_get_header(var_event, "ftdm_start_only"); ctdm_private_t *tech_pvt = NULL; @@ -129,10 +129,12 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi goto fail; } +#if 0 if ((fstatus = ftdm_span_start(span)) != FTDM_SUCCESS && fstatus != FTDM_EINVAL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't start span %s.\n", span_name); goto fail; } +#endif if (!zstr(ftdm_start_only) && switch_true(ftdm_start_only)) { goto fail; diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index 019725208f..f7e9dde544 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -876,6 +876,7 @@ void mgco_handle_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sd r->fmts[0]->val.val, name); if(MG_TERM_RTP == term->type){ term->u.rtp.codec = name; + term->u.rtp.pt = r->fmts[0]->val.val; } }else{ /* ERROR */ diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 04feb55a8a..bf3e36ca19 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -421,17 +421,26 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi const char *command = switch_event_get_header(event, "command"); switch_channel_t *channel = switch_core_session_get_channel(session); crtp_private_t *tech_pvt = switch_core_session_get_private(session); - + char *codec = switch_event_get_header_nil(event, kCODEC); + char *szptime = switch_event_get_header_nil(event, kPTIME); + char *szrate = switch_event_get_header_nil(event, kRATE); + char *szpt = switch_event_get_header_nil(event, kPT); + + int ptime = !zstr(szptime) ? atoi(szptime) : 0, + rate = !zstr(szrate) ? atoi(szrate) : 8000, + pt = !zstr(szpt) ? atoi(szpt) : 0; + + if (!zstr(command) && !strcasecmp(command, "media_modify")) { /* Compare parameters */ if (compare_var(event, channel, kREMOTEADDR) || compare_var(event, channel, kREMOTEPORT)) { - char *remote_addr = switch_event_get_header(event, kREMOTEADDR); - char *szremote_port = switch_event_get_header(event, kREMOTEPORT); - switch_port_t remote_port = !zstr(szremote_port) ? atoi(szremote_port) : 0; - const char *err; + char *remote_addr = switch_event_get_header(event, kREMOTEADDR); + char *szremote_port = switch_event_get_header(event, kREMOTEPORT); + switch_port_t remote_port = !zstr(szremote_port) ? atoi(szremote_port) : 0; + const char *err; + - switch_channel_set_variable(channel, kREMOTEADDR, remote_addr); switch_channel_set_variable(channel, kREMOTEPORT, szremote_port); @@ -446,10 +455,47 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi if (compare_var(event, channel, kCODEC) || compare_var(event, channel, kPTIME) || compare_var(event, channel, kPT) || - compare_var(event, channel, kRATE)) { - /* Reset codec */ - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Switching codec not yet implemented\n"); - } + compare_var(event, channel, kRATE)) { + /* Reset codec */ + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Switching codec updating \n"); + + if (switch_core_codec_init(&tech_pvt->read_codec, + codec, + NULL, + rate, + ptime, + 1, + /*SWITCH_CODEC_FLAG_ENCODE |*/ SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); + goto fail; + } else { + if (switch_core_codec_init(&tech_pvt->write_codec, + codec, + NULL, + rate, + ptime, + 1, + SWITCH_CODEC_FLAG_ENCODE /*| SWITCH_CODEC_FLAG_DECODE*/, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); + goto fail; + } + } + + if (switch_core_session_set_read_codec(session, &tech_pvt->read_codec) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set read codec?\n"); + goto fail; + } + + if (switch_core_session_set_write_codec(session, &tech_pvt->write_codec) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set write codec?\n"); + goto fail; + } + + switch_rtp_set_default_payload(tech_pvt->rtp_session, pt); + switch_rtp_set_recv_pt(tech_pvt->rtp_session, pt); + } if (compare_var(event, channel, kRFC2833PT)) { const char *szpt = switch_channel_get_variable(channel, kRFC2833PT); @@ -464,6 +510,22 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi } return SWITCH_STATUS_SUCCESS; +fail: + if (tech_pvt) { + if (tech_pvt->read_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->read_codec); + } + + if (tech_pvt->write_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->write_codec); + } + } + + if (session) { + switch_core_session_destroy(&session); + } + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + } static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) From 2dc5b322dd7cdd7a08c351805769a0a3862b9bbd Mon Sep 17 00:00:00 2001 From: root Date: Fri, 27 Jul 2012 21:31:24 -0400 Subject: [PATCH 372/822] Added event system for TDM termination alarms --- libs/freetdm/mod_freetdm/mod_freetdm.c | 6 +- libs/freetdm/mod_freetdm/tdm.c | 205 ++++++++++++++++-- libs/freetdm/src/ftdm_io.c | 15 +- libs/freetdm/src/include/freetdm.h | 12 +- .../mod_media_gateway/media_gateway.c | 61 +++--- .../mod_media_gateway/media_gateway_xml.c | 2 + .../mod_media_gateway/mod_media_gateway.c | 32 ++- .../mod_media_gateway/mod_media_gateway.h | 3 +- 8 files changed, 275 insertions(+), 61 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 34fb3f469a..a746c1877f 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -2097,7 +2097,7 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session static FIO_SIGNAL_CB_FUNCTION(on_common_signal) { uint32_t chanid, spanid; - switch_event_t *event = NULL; + switch_event_t *event = NULL; ftdm_alarm_flag_t alarmbits = FTDM_ALARM_NONE; chanid = ftdm_channel_get_id(sigmsg->channel); @@ -2200,9 +2200,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_common_signal) break; } - if (event) { - - + if (event) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", ftdm_channel_get_span_name(sigmsg->channel)); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-number", "%d", ftdm_channel_get_span_id(sigmsg->channel)); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", ftdm_channel_get_id(sigmsg->channel)); diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index ab061a3812..c5850e6f51 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -68,6 +68,9 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg); static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf); + +static ftdm_status_t ctdm_span_prepare(ftdm_span_t *span); + switch_state_handler_table_t ctdm_state_handlers = { .on_init = channel_on_init, .on_destroy = channel_on_destroy @@ -81,6 +84,115 @@ switch_io_routines_t ctdm_io_routines = { .receive_message = channel_receive_message }; +static void ctdm_report_alarms(ftdm_channel_t *channel) +{ + switch_event_t *event = NULL; + ftdm_alarm_flag_t alarmflag = 0; + + if (switch_event_create(&event, SWITCH_EVENT_TRAP) != SWITCH_STATUS_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "failed to create alarms events\n"); + return; + } + + if (ftdm_channel_get_alarms(channel, &alarmflag) != FTDM_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to retrieve alarms %s:%d\n", ftdm_channel_get_span_name(channel), ftdm_channel_get_id(channel)); + return; + } + + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", ftdm_channel_get_span_name(channel)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-number", "%d", ftdm_channel_get_span_id(channel)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", ftdm_channel_get_id(channel)); + + if (alarmflag) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-clear"); + } else { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-trap"); + } + + if (alarmflag & FTDM_ALARM_RED) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "red"); + } + if (alarmflag & FTDM_ALARM_YELLOW) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "yellow"); + } + if (alarmflag & FTDM_ALARM_RAI) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "rai"); + } + if (alarmflag & FTDM_ALARM_BLUE) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "blue"); + } + if (alarmflag & FTDM_ALARM_AIS) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "ais"); + } + if (alarmflag & FTDM_ALARM_GENERAL) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "general"); + } + + switch_event_fire(&event); + return; +} + + + +static void ctdm_event_handler(switch_event_t *event) +{ + ftdm_status_t status = FTDM_FAIL; + switch(event->event_id) { + case SWITCH_EVENT_TRAP: + { + ftdm_span_t *span = NULL; + ftdm_channel_t *channel = NULL; + const char *span_name = NULL; + const char *chan_number = NULL; + uint32_t chan_id = 0; + const char *cond = switch_event_get_header(event, "condition"); + + if (zstr(cond)) { + return; + } + + span_name = switch_event_get_header(event, "span-name"); + chan_number = switch_event_get_header(event, "chan-number"); + + if (ftdm_span_find_by_name(span_name, &span) != FTDM_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find span [%s]\n", span_name); + return; + } + + if (!strcmp(cond, "mg-tdm-prepare")) { + status = ctdm_span_prepare(span); + if (status == FTDM_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Span %s prepared successfully\n", span_name); + } else if (status != FTDM_EINVAL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to prepare span %s.\n", span_name); + } + } else if (!strcmp(cond, "mg-tdm-check")) { + if (zstr(chan_number)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No channel number specified\n"); + return; + } + chan_id = atoi(chan_number); + if (!chan_id) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid channel number:%s\n", chan_number); + return; + } + + channel = ftdm_span_get_channel(span, chan_id); + if (!channel) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find channel\n"); + return; + } + + ctdm_report_alarms(channel); + } + } + break; + default: + break; + } + return; +} + void ctdm_init(switch_loadable_module_interface_t *module_interface) { switch_endpoint_interface_t *endpoint_interface; @@ -90,7 +202,82 @@ void ctdm_init(switch_loadable_module_interface_t *module_interface) endpoint_interface->io_routines = &ctdm_io_routines; endpoint_interface->state_handler = &ctdm_state_handlers; ctdm.endpoint_interface = endpoint_interface; - + + switch_event_bind("mod_freetdm", SWITCH_EVENT_TRAP, SWITCH_EVENT_SUBCLASS_ANY, ctdm_event_handler, NULL); +} + +static FIO_SIGNAL_CB_FUNCTION(on_signal_cb) +{ + uint32_t chanid, spanid; + switch_event_t *event = NULL; + ftdm_alarm_flag_t alarmbits = FTDM_ALARM_NONE; + + chanid = ftdm_channel_get_id(sigmsg->channel); + spanid = ftdm_channel_get_span_id(sigmsg->channel); + + switch(sigmsg->event_id) { + case FTDM_SIGEVENT_ALARM_CLEAR: + case FTDM_SIGEVENT_ALARM_TRAP: + { + if (ftdm_channel_get_alarms(sigmsg->channel, &alarmbits) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "failed to retrieve alarms\n"); + return FTDM_FAIL; + } + + if (switch_event_create(&event, SWITCH_EVENT_TRAP) != SWITCH_STATUS_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "failed to create alarms events\n"); + return FTDM_FAIL; + } + if (sigmsg->event_id == FTDM_SIGEVENT_ALARM_CLEAR) { + ftdm_log(FTDM_LOG_NOTICE, "Alarm cleared on channel %d:%d\n", spanid, chanid); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-clear"); + } else { + ftdm_log(FTDM_LOG_NOTICE, "Alarm raised on channel %d:%d\n", spanid, chanid); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-trap"); + } + } + break; + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unhandled event %d\n", sigmsg->event_id); + break; + } + + if (event) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", ftdm_channel_get_span_name(sigmsg->channel)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-number", "%d", ftdm_channel_get_span_id(sigmsg->channel)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", ftdm_channel_get_id(sigmsg->channel)); + + if (alarmbits & FTDM_ALARM_RED) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "red"); + } + if (alarmbits & FTDM_ALARM_YELLOW) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "yellow"); + } + if (alarmbits & FTDM_ALARM_RAI) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "rai"); + } + if (alarmbits & FTDM_ALARM_BLUE) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "blue"); + } + if (alarmbits & FTDM_ALARM_AIS) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "ais"); + } + if (alarmbits & FTDM_ALARM_GENERAL) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "general"); + } + + switch_event_fire(&event); + } + return FTDM_SUCCESS; +} + +static ftdm_status_t ctdm_span_prepare(ftdm_span_t *span) +{ + if (ftdm_span_register_signal_cb(span, on_signal_cb) != FTDM_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register signal CB\n"); + return FTDM_FAIL; + } + return ftdm_span_start(span); } static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, @@ -111,10 +298,8 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi const char *dname; ftdm_codec_t codec; uint32_t interval; - /*ftdm_status_t fstatus;*/ - const char *ftdm_start_only = switch_event_get_header(var_event, "ftdm_start_only"); ctdm_private_t *tech_pvt = NULL; - + if (zstr(szchanid) || zstr(span_name)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Both ["kSPAN_ID"] and ["kCHAN_ID"] have to be set.\n"); goto fail; @@ -129,18 +314,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi goto fail; } -#if 0 - if ((fstatus = ftdm_span_start(span)) != FTDM_SUCCESS && fstatus != FTDM_EINVAL) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't start span %s.\n", span_name); - goto fail; - } -#endif - - if (!zstr(ftdm_start_only) && switch_true(ftdm_start_only)) { - goto fail; - } - - if (!(*new_session = switch_core_session_request(ctdm.endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, 0, pool))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't request session.\n"); goto fail; diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 758827c9ed..4e110df659 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -5653,6 +5653,12 @@ static void *ftdm_span_service_events(ftdm_thread_t *me, void *obj) return NULL; } +FT_DECLARE(ftdm_status_t) ftdm_span_register_signal_cb(ftdm_span_t *span, fio_signal_cb_t sig_cb) +{ + span->signal_cb = sig_cb; + return FTDM_SUCCESS; +} + FT_DECLARE(ftdm_status_t) ftdm_span_start(ftdm_span_t *span) { ftdm_status_t status = FTDM_FAIL; @@ -5670,7 +5676,8 @@ FT_DECLARE(ftdm_status_t) ftdm_span_start(ftdm_span_t *span) goto done; } - status = ftdm_report_initial_channels_alarms(span); + //ftdm_report_initial_channels_alarms(span); + ftdm_set_flag_locked(span, FTDM_SPAN_STARTED); goto done; } @@ -5872,8 +5879,10 @@ FT_DECLARE(ftdm_status_t) ftdm_group_create(ftdm_group_t **group, const char *na static ftdm_status_t ftdm_span_trigger_signal(const ftdm_span_t *span, ftdm_sigmsg_t *sigmsg) { - ftdm_status_t status = span->signal_cb(sigmsg); - return status; + if (!span->signal_cb) { + return FTDM_FAIL; + } + return span->signal_cb(sigmsg); } static ftdm_status_t ftdm_span_queue_signal(const ftdm_span_t *span, ftdm_sigmsg_t *sigmsg) diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index f7de8519b7..e041e1f0e7 100755 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -1611,6 +1611,17 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span(ftdm_span_t *span, const char *typ */ FT_DECLARE(ftdm_status_t) ftdm_configure_span_signaling(ftdm_span_t *span, const char *type, fio_signal_cb_t sig_cb, ftdm_conf_parameter_t *parameters); +/*! + * \brief Register callback to listen for incoming events + * \note This function should only be used when there is no signalling module + * \param span The span to register to + * \param sig_cb The callback that the signaling stack will use to notify about events + * + * \retval FTDM_SUCCESS success + * \retval FTDM_FAIL failure + */ +FT_DECLARE(ftdm_status_t) ftdm_span_register_signal_cb(ftdm_span_t *span, fio_signal_cb_t sig_cb); + /*! * \brief Start the span signaling (must call ftdm_configure_span_signaling first) * @@ -1626,7 +1637,6 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_signaling(ftdm_span_t *span, const */ FT_DECLARE(ftdm_status_t) ftdm_span_start(ftdm_span_t *span); - /*! * \brief Stop the span signaling (must call ftdm_span_start first) * \note certain signalings (boost signaling) does not support granular span start/stop diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index ee5abe7d2f..9056ee1bdc 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -155,47 +155,38 @@ done: return SWITCH_STATUS_SUCCESS; } - -/* - * Originate a channel so the target technology gets to run initialization code - */ -switch_status_t megaco_prepare_termination(mg_termination_t *term) +switch_status_t megaco_prepare_tdm_termination(mg_termination_t *term) { - switch_event_t *var_event = NULL; - switch_core_session_t *session = NULL; - switch_status_t status = SWITCH_STATUS_SUCCESS; - char dialstring[100]; - switch_call_cause_t cause; - switch_channel_t *channel; - switch_event_create(&var_event, SWITCH_EVENT_CLONE); - - if (term->type == MG_TERM_RTP) { - } else if (term->type == MG_TERM_TDM) { - switch_snprintf(dialstring, sizeof dialstring, "tdm/%s", term->name); + switch_event_t *event = NULL; + if (switch_event_create(&event, SWITCH_EVENT_TRAP) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to create NOTIFY event\n"); + return SWITCH_STATUS_FALSE; + } - switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "ftdm_start_only", "true"); - switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, kSPAN_NAME, term->u.tdm.span_name); - switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, kCHAN_ID, "%d", term->u.tdm.channel); - } - - /* Set common variables on the channel */ - switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, SWITCH_PARK_AFTER_BRIDGE_VARIABLE, "true"); - if (switch_ivr_originate(NULL, &session, &cause, dialstring, 0, NULL, NULL, NULL, NULL, var_event, 0, NULL) != SWITCH_STATUS_SUCCESS) { - status = SWITCH_STATUS_FALSE; - goto done; - } - channel = switch_core_session_get_channel(session); - switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); - -done: - if (session) { - switch_core_session_rwunlock(session); - } - switch_event_destroy(&var_event); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", term->u.tdm.span_name); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", term->u.tdm.channel); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "mg-tdm-prepare"); + switch_event_fire(&event); return SWITCH_STATUS_SUCCESS; } +/* @Kapil Call this function once H.248 link is up */ +switch_status_t megaco_check_tdm_termination(mg_termination_t *term) +{ + switch_event_t *event = NULL; + if (switch_event_create(&event, SWITCH_EVENT_TRAP) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to create NOTIFY event\n"); + return SWITCH_STATUS_FALSE; + } + + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", term->u.tdm.span_name); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", term->u.tdm.channel); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "mg-tdm-check"); + + switch_event_fire(&event); + return SWITCH_STATUS_SUCCESS; +} mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const char *prefix) { diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index 011c36ce56..1b8173aa1e 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -111,6 +111,8 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) profile->physical_terminations = term; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Mapped termination [%s] to freetdm span: %s chan: %d\n", term->name, term->u.tdm.span_name, term->u.tdm.channel); + + megaco_prepare_tdm_termination(term); } } } diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index de315d7ae9..00f5e9760f 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -56,6 +56,35 @@ static switch_status_t list_profiles(const char *line, const char *cursor, switc return status; } +static void mg_event_handler(switch_event_t *event) +{ + switch(event->event_id) { + case SWITCH_EVENT_TRAP: + { + const char *span_name = NULL; + const char *chan_number = NULL; + const char *cond = NULL; + + cond = switch_event_get_header(event, "condition"); + if (zstr(cond)) { + return; + } + + span_name = switch_event_get_header(event, "span-name"); + chan_number = switch_event_get_header(event, "chan-number"); + + if (!strcmp(cond, "ftdm-alarm-trap")) { + /* @KAPIL: TDM is in alarm, notify MGC */ + } else if (!strcmp(cond, "ftdm-alarm-clear")) { + /* @KAPIL: TDM alarm cleared, notify MGC */ + } + } + break; + default: + break; + } +} + SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load) { switch_api_interface_t *api_interface; @@ -82,7 +111,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load) switch_console_set_complete("add mg logging ::mg::list_profiles disable"); switch_console_add_complete_func("::mg::list_profiles", list_profiles); - /* Initialize MEGACO Stack */ sng_event.mg.sng_mgco_txn_ind = handle_mgco_txn_ind; sng_event.mg.sng_mgco_cmd_ind = handle_mgco_cmd_ind; @@ -96,6 +124,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load) /* Log */ sng_event.sm.sng_log = handle_sng_log; + switch_event_bind("mod_media_gateway", SWITCH_EVENT_TRAP, SWITCH_EVENT_SUBCLASS_ANY, mg_event_handler, NULL); + /* initualize MEGACO stack */ return sng_mgco_init(&sng_event); } diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index 504f147d76..86acb28861 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -256,7 +256,8 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre switch_status_t megaco_context_add_termination(mg_context_t *ctx, mg_termination_t *term); switch_status_t megaco_context_is_term_present(mg_context_t *ctx, mg_termination_t *term); - +switch_status_t megaco_prepare_tdm_termination(mg_termination_t *term); +switch_status_t megaco_check_tdm_termination(mg_termination_t *term); #endif /* MOD_MEGACO_H */ From a6503b49524e0cce8d20e5b4c31955eea24b4521 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Sat, 28 Jul 2012 09:59:47 -0400 Subject: [PATCH 373/822] Fixed compile warning --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 2e51ba8674..4e59b6ae33 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -213,7 +213,7 @@ ftdm_status_t copy_cdPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cd ftdm_status_t copy_cdPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cdPtyNum) { - char *val = NULL; + const char *val = NULL; ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; From 4bbb8c014a8dccab24439bf43905559927169f53 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Sat, 28 Jul 2012 10:41:55 -0400 Subject: [PATCH 374/822] Fixed compile error --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 2e51ba8674..105dda1f6b 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -239,7 +239,7 @@ ftdm_status_t copy_cdPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cdPt ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Called INN value \"%s\"\n", val); } else { cdPtyNum->innInd.val = 0x01; - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Called INN value, set to default value 0x01\n"); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Called INN value, set to default value 0x01\n"); } return copy_tknStr_to_sngss7(caller_data->dnis.digits, &cdPtyNum->addrSig, &cdPtyNum->oddEven); From da26b4de4122a2a6e4b6a0ca5d6ea63871b04a05 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 29 Jul 2012 10:17:13 -0400 Subject: [PATCH 375/822] adding termination service-change code --- libs/freetdm/mod_freetdm/tdm.c | 8 ++- .../mod_media_gateway/media_gateway.c | 69 +++++++++++++++++++ .../media_gateway_cmd_handler.c | 39 +++++++++++ .../mod_media_gateway/media_gateway_stack.h | 10 +++ .../media_gateway_stack_alarms.c | 9 ++- .../mod_media_gateway/media_gateway_xml.c | 2 +- .../mod_media_gateway/mod_media_gateway.c | 21 +++++- 7 files changed, 149 insertions(+), 9 deletions(-) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index c5850e6f51..790f7c17d3 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -84,7 +84,7 @@ switch_io_routines_t ctdm_io_routines = { .receive_message = channel_receive_message }; -static void ctdm_report_alarms(ftdm_channel_t *channel) +static void ctdm_report_alarms(ftdm_channel_t *channel, const char* mg_profile_name) { switch_event_t *event = NULL; ftdm_alarm_flag_t alarmflag = 0; @@ -109,6 +109,8 @@ static void ctdm_report_alarms(ftdm_channel_t *channel) switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-trap"); } + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "mg-profile-name", mg_profile_name); + if (alarmflag & FTDM_ALARM_RED) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "red"); } @@ -128,6 +130,7 @@ static void ctdm_report_alarms(ftdm_channel_t *channel) switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "general"); } + switch_event_fire(&event); return; } @@ -146,6 +149,7 @@ static void ctdm_event_handler(switch_event_t *event) const char *chan_number = NULL; uint32_t chan_id = 0; const char *cond = switch_event_get_header(event, "condition"); + const char *mg_profile_name = switch_event_get_header(event, "mg-profile-name"); if (zstr(cond)) { return; @@ -183,7 +187,7 @@ static void ctdm_event_handler(switch_event_t *event) return; } - ctdm_report_alarms(channel); + ctdm_report_alarms(channel, mg_profile_name); } } break; diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 9056ee1bdc..7e13fbaebe 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -175,6 +175,9 @@ switch_status_t megaco_prepare_tdm_termination(mg_termination_t *term) switch_status_t megaco_check_tdm_termination(mg_termination_t *term) { switch_event_t *event = NULL; + + if(!term || !term->profile) return SWITCH_STATUS_FALSE; + if (switch_event_create(&event, SWITCH_EVENT_TRAP) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to create NOTIFY event\n"); return SWITCH_STATUS_FALSE; @@ -183,6 +186,7 @@ switch_status_t megaco_check_tdm_termination(mg_termination_t *term) switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", term->u.tdm.span_name); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", term->u.tdm.channel); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "mg-tdm-check"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "mg-profile-name", term->profile->name); switch_event_fire(&event); return SWITCH_STATUS_SUCCESS; @@ -237,6 +241,42 @@ mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const cha return term; } +mg_termination_t* megaco_find_termination_by_span_chan(megaco_profile_t *profile, char *span_name, char *chan_number) +{ + void *val = NULL; + switch_hash_index_t *hi = NULL; + mg_termination_t *term = NULL; + int found = 0x00; + const void *var; + + if(!span_name || !chan_number){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"Invalid span_name/chan_number \n"); + return NULL; + } + + for (hi = switch_hash_first(NULL, profile->terminations); hi; hi = switch_hash_next(hi)) { + switch_hash_this(hi, &var, NULL, &val); + term = (mg_termination_t *) val; + if(!term) continue; + if(MG_TERM_TDM != term->type) continue; + + if ((!strcasecmp(span_name, term->u.tdm.span_name))&& (atoi(chan_number) == term->u.tdm.channel)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + "Got term[%s] associated with span[%s], channel[%s]\n",term->name, span_name, chan_number); + found = 0x01; + break; + } + } + + if(!found){ + term = NULL; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + " Not able to find termination associated with span[%s], channel[%s]\n", span_name, chan_number); + } + + return term; +} + mg_termination_t *megaco_find_termination(megaco_profile_t *profile, const char *name) { mg_termination_t *term = switch_core_hash_find_rdlock(profile->terminations, name, profile->terminations_rwlock); @@ -568,6 +608,35 @@ switch_status_t megaco_profile_destroy(megaco_profile_t **profile) return SWITCH_STATUS_SUCCESS; } + +switch_status_t mgco_init_ins_service_change(SuId suId) +{ + megaco_profile_t* profile = NULL; + void *val = NULL; + const void *key = NULL; + switch_ssize_t keylen; + switch_hash_index_t *hi = NULL; + mg_termination_t *term = NULL; + + + if(NULL == (profile = megaco_get_profile_by_suId(suId))){ + return SWITCH_STATUS_FALSE; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + "mgco_init_ins_service_change : Initiating terminations service change for profile: %s\n", profile->name); + + /* loop through all termination and post get status Event */ + for (hi = switch_hash_first(NULL, profile->terminations); hi; hi = switch_hash_next(hi)) { + switch_hash_this(hi, &key, &keylen, &val); + term = (mg_termination_t *) val; + if(!term) continue; + megaco_check_tdm_termination(term); + } + + return SWITCH_STATUS_SUCCESS; +} + switch_status_t megaco_peer_profile_destroy(mg_peer_profile_t **profile) { diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index f9ae4fe90a..ca2209b087 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -2288,6 +2288,45 @@ U32 get_txn_id(){ return outgoing_txn_id; } /*****************************************************************************************************************************/ +switch_status_t mg_send_term_service_change(char* mg_profile_name,char *span_name, char *chan_number, mg_term_states_e term_state) +{ + mg_termination_t* term = NULL; + switch_status_t ret = SWITCH_STATUS_SUCCESS; + megaco_profile_t *profile = NULL; + + switch_assert(span_name); + switch_assert(chan_number); + + profile = megaco_profile_locate(mg_profile_name); + + term = megaco_find_termination_by_span_chan(profile, span_name, chan_number); + + if(!term || !term->profile){ + return SWITCH_STATUS_FALSE; + } + + switch(term_state) + { + case MG_TERM_SERVICE_STATE_IN_SERVICE: + { + ret = mg_send_ins_service_change(term->profile, term->name, 0x00 ); + break; + } + case MG_TERM_SERVICE_STATE_OUT_OF_SERVICE: + { + ret = mg_send_oos_service_change(term->profile, term->name, 0x00 ); + break; + } + default: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," Invalid term_state[%d]\n", term_state); + return SWITCH_STATUS_FALSE; + } + } + + return ret; +} +/*****************************************************************************************************************************/ /* Note : API to send Service Change when termination is coming up(in-service) */ /* INPUT : MG Profile structure and termination name */ /* wild flag will tell if service change request needs to be in W-SC format as we can have W-SC=A01* or SC=A01* */ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index 20354b0ccb..3e2ec81bdb 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -52,6 +52,13 @@ typedef enum{ SNG_MG_ENCODING_TEXT, }sng_mg_encoding_types_e; +typedef enum{ + MG_TERM_SERVICE_STATE_UNKNOWN, + MG_TERM_SERVICE_STATE_IN_SERVICE, + MG_TERM_SERVICE_STATE_OUT_OF_SERVICE, + MG_TERM_SERVICE_STATE_INVALID, +}mg_term_states_e; + #define PRNT_ENCODING_TYPE(_val)\ ((_val == SNG_MG_ENCODING_TEXT)?"SNG_MG_ENCODING_TEXT":\ (_val == SNG_MG_ENCODING_BINARY)?"SNG_MG_ENCODING_BINARY":\ @@ -157,6 +164,8 @@ void mg_util_set_err_string ( MgStr *errTxt, char* str); switch_status_t mg_build_sdp(MgMgcoMediaDesc* out, MgMgcoMediaDesc* inc, megaco_profile_t* mg_profile, mg_termination_t* term, CmMemListCp *memCp); switch_status_t mg_add_local_descriptor(MgMgcoMediaDesc* media, megaco_profile_t* mg_profile, mg_termination_t* term, CmMemListCp *memCp); +switch_status_t mg_send_term_service_change(char* mg_profile_name, char *span_name, char *chan_number, mg_term_states_e term_state); +mg_termination_t* megaco_find_termination_by_span_chan(megaco_profile_t *profile , char *span_name, char *chan_number); switch_status_t sng_mgco_cfg(megaco_profile_t* profile); @@ -183,6 +192,7 @@ switch_status_t mg_send_audit_rsp(SuId suId, MgMgcoCommand *req); switch_status_t handle_mg_audit_cmd(SuId suId, MgMgcoCommand *auditReq); switch_status_t mg_stack_termination_is_in_service(char* term_str, int len); void mg_util_set_cmd_name_string (MgStr *errTxt, MgMgcoCommand *cmd); +switch_status_t mgco_init_ins_service_change(SuId suId); switch_status_t mg_send_modify_rsp(SuId suId, MgMgcoCommand *req); switch_status_t mg_send_subtract_rsp(SuId suId, MgMgcoCommand *req); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack_alarms.c b/src/mod/endpoints/mod_media_gateway/media_gateway_stack_alarms.c index 4564468e96..f392203db1 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack_alarms.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack_alarms.c @@ -25,8 +25,8 @@ void handle_mg_alarm(Pst *pst, MgMngmt *usta) memset(&prBuf[0], 0, sizeof(prBuf)); - len = len + sprintf(prBuf+len,"MG Status Indication: received with Category = %d, Event = %d, Cause = %d \n", - usta->t.usta.alarm.category, usta->t.usta.alarm.event, + len = len + sprintf(prBuf+len,"MG Status Indication: received for sapId[%d] with Category = %d, Event = %d, Cause = %d \n", + usta->t.usta.alarmInfo.sapId, usta->t.usta.alarm.category, usta->t.usta.alarm.event, usta->t.usta.alarm.cause); len = len + sprintf(prBuf+len, "Category ( "); @@ -218,9 +218,8 @@ void handle_mg_alarm(Pst *pst, MgMngmt *usta) case LMG_EVENT_PEER_ENABLED: { len = len + sprintf(prBuf+len, "gateway enabled"); - /* gateway enabled now we can send termination service change */ - /*TODO - probably we cannt immediate send Service change - we have to find proper place */ - /*mg_send_service_change(0x01, "A01", MGT_SVCCHGMETH_RESTART,MG_SVC_REASON_900_RESTORED );*/ + /* gateway enabled now we can send termination service change for all terminations */ + mgco_init_ins_service_change( usta->t.usta.alarmInfo.sapId ); break; } case LMG_EVENT_PEER_DISCOVERED: diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index 1b8173aa1e..6c87afa780 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -84,7 +84,7 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) char *channel_map_dup = strdup(channel_map); char *chanmap[24]; int chanmap_count, i; - chanmap_count = switch_split(channel_map_dup, ' ', chanmap); + chanmap_count = switch_split(channel_map_dup, ',', chanmap); for (i = 0; i < chanmap_count; i++) { char *p = strchr(chanmap[i], '-'); if (p) { diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 00f5e9760f..97158fdcea 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -64,9 +64,18 @@ static void mg_event_handler(switch_event_t *event) const char *span_name = NULL; const char *chan_number = NULL; const char *cond = NULL; + const char *mg_profile_name = NULL; + cond = switch_event_get_header(event, "condition"); if (zstr(cond)) { + printf("Condition NULL, returning \n"); + return; + } + + mg_profile_name = switch_event_get_header(event, "mg-profile-name"); + if (zstr(mg_profile_name)) { + printf("mg_profile_name NULL, returning \n"); return; } @@ -74,9 +83,19 @@ static void mg_event_handler(switch_event_t *event) chan_number = switch_event_get_header(event, "chan-number"); if (!strcmp(cond, "ftdm-alarm-trap")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + "ftdm-alarm-trap for span_name[%s] chan_number[%s] associated with MG profile[%s]\n", + span_name,chan_number, mg_profile_name); /* @KAPIL: TDM is in alarm, notify MGC */ + mg_send_term_service_change( + (char*)mg_profile_name, (char*)span_name, (char*)chan_number, MG_TERM_SERVICE_STATE_OUT_OF_SERVICE); } else if (!strcmp(cond, "ftdm-alarm-clear")) { - /* @KAPIL: TDM alarm cleared, notify MGC */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + "ftdm-alarm-clear for span_name[%s] chan_number[%s] associated with MG profile[%s] \n", + span_name,chan_number, mg_profile_name); + /* TDM alarm cleared, notify MGC */ + mg_send_term_service_change( + (char*)mg_profile_name, (char*)span_name, (char*)chan_number, MG_TERM_SERVICE_STATE_IN_SERVICE); } } break; From a3b4f3ad4ddd307bd72e30888cafb71026ccfeec Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Sun, 29 Jul 2012 22:28:10 -0400 Subject: [PATCH 376/822] Added mod_opal --- build/modules.conf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/build/modules.conf.in b/build/modules.conf.in index 559b06e8ea..83986b996c 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -7,6 +7,7 @@ applications/mod_hash applications/mod_spandsp dialplans/mod_dialplan_xml endpoints/mod_sofia +endpoints/mod_opal #endpoints/mod_media_gateway ../../libs/freetdm/mod_freetdm xml_int/mod_xml_cdr From 2899b4ae95051c8ce5f55ceed4ff8f0351f838bb Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Mon, 30 Jul 2012 11:07:01 -0400 Subject: [PATCH 377/822] Updated to latest code used on test machines --- src/mod/endpoints/mod_opal/mod_opal.cpp | 1318 +++++++++-------------- src/mod/endpoints/mod_opal/mod_opal.h | 330 +++--- 2 files changed, 713 insertions(+), 935 deletions(-) diff --git a/src/mod/endpoints/mod_opal/mod_opal.cpp b/src/mod/endpoints/mod_opal/mod_opal.cpp index 0760588019..8244737115 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.cpp +++ b/src/mod/endpoints/mod_opal/mod_opal.cpp @@ -4,6 +4,7 @@ * Version: MPL 1.1 * * Copyright (c) 2007 Tuyan Ozipek (tuyanozipek@gmail.com) + * Copyright (c) 2008-2012 Vox Lucida Pty. Ltd. (robertj@voxlucida.com.au) * * 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 @@ -28,29 +29,34 @@ #include #include -SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_codec_string, mod_opal_globals.codec_string); -SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_context, mod_opal_globals.context); -SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, mod_opal_globals.dialplan); + +/* FreeSWITCH does not correctly handle an H.323 subtely, that is that a + MAXIMUM audio frames per packet is nototiated, and there is no + requirement for the remote to actually send that many. So, in say GSM, we + negotiate up to 3 frames or 60ms of data and the remote actually sends one + (20ms) frame per packet. Perfectly legal but blows up the media handling + in FS. + + Eventually we will get around to bundling the packets, but not yet. This + compile flag will just force one frame/packet for all audio codecs. + */ +#define IMPLEMENT_MULTI_FAME_AUDIO 0 -#define CF_NEED_FLUSH (1 << 1) - -struct mod_opal_globals mod_opal_globals = { 0 }; - - -static switch_call_cause_t create_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, - switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session, - switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause); +static switch_call_cause_t create_outgoing_channel(switch_core_session_t *session, + switch_event_t *var_event, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, + switch_memory_pool_t **pool, + switch_originate_flag_t flags, + switch_call_cause_t *cancel_cause); static FSProcess *opal_process = NULL; -static const char ModuleName[] = "opal"; - - -static switch_status_t on_hangup(switch_core_session_t *session); -static switch_status_t on_destroy(switch_core_session_t *session); +static PConstString const ModuleName("opal"); +static char const ConfigFile[] = "opal.conf"; static switch_io_routines_t opalfs_io_routines = { @@ -70,7 +76,7 @@ static switch_state_handler_table_t opalfs_event_handlers = { /*.on_init */ FSConnection::on_init, /*.on_routing */ FSConnection::on_routing, /*.on_execute */ FSConnection::on_execute, - /*.on_hangup */ on_hangup, + /*.on_hangup */ FSConnection::on_hangup, /*.on_exchange_media */ FSConnection::on_exchange_media, /*.on_soft_execute */ FSConnection::on_soft_execute, /*.on_consume_media*/ NULL, @@ -78,7 +84,7 @@ static switch_state_handler_table_t opalfs_event_handlers = { /*.on_reset*/ NULL, /*.on_park*/ NULL, /*.on_reporting*/ NULL, - /*.on_destroy*/ on_destroy + /*.on_destroy*/ FSConnection::on_destroy }; @@ -89,7 +95,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opal_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_opal_shutdown); SWITCH_MODULE_DEFINITION(mod_opal, mod_opal_load, mod_opal_shutdown, NULL); -SWITCH_MODULE_LOAD_FUNCTION(mod_opal_load) { +SWITCH_MODULE_LOAD_FUNCTION(mod_opal_load) +{ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Starting loading mod_opal\n"); /* Prevent the loading of OPAL codecs via "plug ins", this is a directory @@ -110,8 +117,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opal_load) { if (opal_process->Initialise(*module_interface)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Opal manager initialized and running\n"); //unloading causes a seg in linux - return SWITCH_STATUS_NOUNLOAD; - //return SWITCH_STATUS_SUCCESS; + //return SWITCH_STATUS_UNLOAD; + return SWITCH_STATUS_SUCCESS; } delete opal_process; @@ -120,11 +127,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opal_load) { } -SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_opal_shutdown) { - - switch_safe_free(mod_opal_globals.context); - switch_safe_free(mod_opal_globals.dialplan); - switch_safe_free(mod_opal_globals.codec_string); +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_opal_shutdown) +{ delete opal_process; opal_process = NULL; return SWITCH_STATUS_SUCCESS; @@ -133,161 +137,79 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_opal_shutdown) { SWITCH_END_EXTERN_C /*******************************************************************************/ - - -static switch_call_cause_t create_outgoing_channel(switch_core_session_t *session, - switch_event_t *var_event, - switch_caller_profile_t *outbound_profile, - switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause) -{ - if (opal_process == NULL) { - return SWITCH_CAUSE_CRASH; - } - - PString token; - - FSManager & manager = opal_process->GetManager(); - if (!manager.SetUpCall("local:", outbound_profile->destination_number, token, outbound_profile)) { - return SWITCH_CAUSE_INVALID_NUMBER_FORMAT; - } - - PSafePtr < OpalCall > call = manager.FindCallWithLock(token); - - if (call == NULL) { - return SWITCH_CAUSE_PROTOCOL_ERROR; - } - - PSafePtr < FSConnection > connection = call->GetConnectionAs < FSConnection > (0); - - if (connection == NULL) { - return SWITCH_CAUSE_PROTOCOL_ERROR; - } - - *new_session = connection->GetSession(); - - return SWITCH_CAUSE_SUCCESS; -} - - /////////////////////////////////////////////////////////////////////// #if PTRACING -class FSTrace : public ostream { - public: - FSTrace() - : ostream(&buffer) - { - } +class FSTrace : public std::ostream +{ +private: + class Buffer : public std::stringbuf + { + virtual int sync() + { + std::string s = str(); + if (s.empty()) + return 0; - private: - class Buffer : public streambuf { - char buffer[250]; + //Due to explicit setting of flags we know exactly what we are getting + PStringArray fields(6); + static PRegularExpression logRE("^([0-9]+)\t *([^(]+)\\(([0-9]+)\\)\t(.*)", PRegularExpression::Extended); + if (!logRE.Execute(s.c_str(), fields)) { + fields[1] = "4"; + fields[2] = __FILE__; + fields[3] = __LINE__; + fields[4] = s; + } - public: - Buffer() - { - setg(buffer, buffer, &buffer[sizeof(buffer)-2]); - setp(buffer, &buffer[sizeof(buffer)-2]); - } + switch_log_level_t level; + switch (fields[1].AsUnsigned()) { + case 0 : + level = SWITCH_LOG_ALERT; + break; + case 1 : + level = SWITCH_LOG_ERROR; + break; + case 2 : + level = SWITCH_LOG_WARNING; + break; + case 3 : + level = SWITCH_LOG_INFO; + break; + default : + level = SWITCH_LOG_DEBUG; + break; + } - virtual int sync() - { - return overflow(EOF); - } + fields[4].Replace("\t", " ", true); + switch_log_printf(SWITCH_CHANNEL_ID_LOG, + fields[2], + "PTLib-OPAL", + fields[3].AsUnsigned(), + NULL, + level, + "%s", fields[4].GetPointer()); - virtual int underflow() - { - return EOF; - } + // Reset string + str(std::string()); + return 0; + } + } buffer; - virtual int overflow(int c) - { - const char *fmt = "%s"; - char *func = NULL; - - int bufSize = pptr() - pbase(); - - if (c != EOF) { - *pptr() = (char)c; - bufSize++; - } - - if (bufSize != 0) { - char *bufPtr = pbase(); - char *bufEndPtr = NULL; - setp(bufPtr, epptr()); - bufPtr[bufSize] = '\0'; - int line = 0; - char *p; - - char *file = NULL; - switch_log_level_t level; - - - switch (strtoul(bufPtr, &file, 10)) { - case 1 : - level = SWITCH_LOG_INFO; - break; - default : - level = SWITCH_LOG_DEBUG; - break; - } - - if (file) { - while (isspace(*file)) file++; - - if (file && (bufPtr = strchr(file, '(')) && (bufEndPtr = strchr(bufPtr, ')'))) { - char *e; - - for(p = bufPtr; p && *p; p++) { - if (*p == '\t') { - *p = ' '; - } - } - - *bufPtr++ = '\0'; - line = atoi(bufPtr); - while (bufEndPtr && isspace(*(++bufEndPtr))); - bufPtr = bufEndPtr; - if (bufPtr && ((e = strchr(bufPtr, ' ')) || (e = strchr(bufPtr, '\t')))) { - func = bufPtr; - bufPtr = e; - *bufPtr++ = '\0'; - } - } - } - - switch_text_channel_t tchannel = SWITCH_CHANNEL_ID_LOG; - - if (!bufPtr) { - bufPtr = pbase(); - level = SWITCH_LOG_DEBUG; - } - - if (bufPtr) { - if (end_of(bufPtr) != '\n') { - fmt = "%s\n"; - } - if (!(file && func && line)) tchannel = SWITCH_CHANNEL_ID_LOG_CLEAN; - - switch_log_printf(tchannel, file, func, line, NULL, level, fmt, bufPtr); - } - - } - - return 0; - } - } buffer; +public: + FSTrace() + : ostream(&buffer) + { + } }; -#endif +#endif // PTRACING /////////////////////////////////////////////////////////////////////// FSProcess::FSProcess() - : PLibraryProcess("Vox Lucida Pty. Ltd.", "mod_opal", 1, 0, AlphaCode, 1) + : PLibraryProcess("Vox Lucida Pty. Ltd.", MODNAME, 1, 1, BetaCode, 1) , m_manager(NULL) { } @@ -296,19 +218,24 @@ FSProcess::FSProcess() FSProcess::~FSProcess() { delete m_manager; +#if PTRACING + PTrace::SetStream(NULL); // This will delete the FSTrace object +#endif } bool FSProcess::Initialise(switch_loadable_module_interface_t *iface) { - m_manager = new FSManager(); - return m_manager != NULL && m_manager->Initialise(iface); + m_manager = new FSManager(); + return m_manager != NULL && m_manager->Initialise(iface); } /////////////////////////////////////////////////////////////////////// FSManager::FSManager() + : m_context("default") + , m_dialplan("XML") { // These are deleted by the OpalManager class, no need to have destructor m_h323ep = new H323EndPoint(*this); @@ -321,12 +248,6 @@ bool FSManager::Initialise(switch_loadable_module_interface_t *iface) { ReadConfig(false); -#if PTRACING - PTrace::SetLevel(mod_opal_globals.trace_level); //just for fun and eyecandy ;) - PTrace::SetOptions(PTrace::TraceLevel); - PTrace::SetStream(new FSTrace); -#endif - m_FreeSwitch = (switch_endpoint_interface_t *) switch_loadable_module_create_interface(iface, SWITCH_ENDPOINT_INTERFACE); m_FreeSwitch->interface_name = ModuleName; m_FreeSwitch->io_routines = &opalfs_io_routines; @@ -338,8 +259,8 @@ bool FSManager::Initialise(switch_loadable_module_interface_t *iface) m_h323ep->StartListener(""); } else { for (std::list < FSListener >::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it) { - if (!m_h323ep->StartListener(it->listenAddress)) { - PTRACE(3, "mod_opal\tCannot start listener for " << it->name); + if (!m_h323ep->StartListener(OpalTransportAddress(it->m_address, it->m_port))) { + PTRACE(2, "mod_opal\tCannot start listener for " << it->m_name); } } } @@ -363,15 +284,16 @@ bool FSManager::Initialise(switch_loadable_module_interface_t *iface) GetOpalGSMAMR(); GetOpaliLBC(); - /* For compatibility with the algorithm in FSConnection::SetCodecs() we need - to set all audio media formats to be 1 frame per packet */ +#if !IMPLEMENT_MULTI_FAME_AUDIO OpalMediaFormatList allCodecs = OpalMediaFormat::GetAllRegisteredMediaFormats(); for (OpalMediaFormatList::iterator it = allCodecs.begin(); it != allCodecs.end(); ++it) { if (it->GetMediaType() == OpalMediaType::Audio()) { it->SetOptionInteger(OpalAudioFormat::RxFramesPerPacketOption(), 1); it->SetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption(), 1); + OpalMediaFormat::SetRegisteredMediaFormat(*it); } } +#endif // IMPLEMENT_MULTI_FAME_AUDIO if (!m_gkAddress.IsEmpty()) { if (m_h323ep->UseGatekeeper(m_gkAddress, m_gkIdentifer, m_gkInterface)) @@ -391,61 +313,53 @@ bool FSManager::Initialise(switch_loadable_module_interface_t *iface) switch_status_t FSManager::ReadConfig(int reload) { - const char *cf = "opal.conf"; - switch_status_t status = SWITCH_STATUS_SUCCESS; + switch_event_t *request_params = NULL; + switch_event_create(&request_params, SWITCH_EVENT_REQUEST_PARAMS); + switch_assert(request_params); + switch_event_add_header_string(request_params, SWITCH_STACK_BOTTOM, "profile", switch_str_nil("")); - switch_memory_pool_t *pool = NULL; - if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); - return status; - } - - set_global_context("default"); - set_global_dialplan("XML"); - - switch_event_t *params = NULL; - switch_event_create(¶ms, SWITCH_EVENT_REQUEST_PARAMS); - switch_assert(params); - switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "profile", switch_str_nil("")); switch_xml_t cfg; - switch_xml_t xml = switch_xml_open_cfg(cf, &cfg, params); + switch_xml_t xml = switch_xml_open_cfg(ConfigFile, &cfg, request_params); if (xml == NULL) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", ConfigFile); return SWITCH_STATUS_FALSE; } switch_xml_t xmlSettings = switch_xml_child(cfg, "settings"); if (xmlSettings) { for (switch_xml_t xmlParam = switch_xml_child(xmlSettings, "param"); xmlParam != NULL; xmlParam = xmlParam->next) { - const char *var = switch_xml_attr_soft(xmlParam, "name"); - const char *val = switch_xml_attr_soft(xmlParam, "value"); + PConstCaselessString const var(switch_xml_attr_soft(xmlParam, "name")); + PConstString const val(switch_xml_attr_soft(xmlParam, "value")); - if (!strcasecmp(var, "trace-level")) { - int level = atoi(val); - if (level > 0) { - mod_opal_globals.trace_level = level; - } - } else if (!strcasecmp(var, "context")) { - set_global_context(val); - } else if (!strcasecmp(var, "dialplan")) { - set_global_dialplan(val); - } else if (!strcasecmp(var, "codec-prefs")) { - set_global_codec_string(val); - } else if (!strcasecmp(var, "jitter-size")) { - char * next; - unsigned minJitter = strtoul(val, &next, 10); - if (minJitter >= 10) { - unsigned maxJitter = minJitter; - if (*next == ',') - maxJitter = atoi(next+1); - SetAudioJitterDelay(minJitter, maxJitter); // In milliseconds - } - } else if (!strcasecmp(var, "gk-address")) { + if (var == "context") { + m_context = val; + } else if (var == "dialplan") { + m_dialplan = val; + } else if (var == "codec-prefs") { + m_codecPrefs = val; + } else if (var == "jitter-size") { + SetAudioJitterDelay(val.AsUnsigned(), val.Mid(val.Find(',')+1).AsUnsigned()); // In milliseconds + } else if (var == "gk-address") { m_gkAddress = val; - } else if (!strcasecmp(var, "gk-identifer")) { + } else if (var == "gk-identifer") { m_gkIdentifer = val; - } else if (!strcasecmp(var, "gk-interface")) { + } else if (var == "gk-interface") { m_gkInterface = val; +#if PTRACING + } else if (var == "trace-level") { + unsigned level = val.AsUnsigned(); + if (level > 0) { + PTrace::SetLevel(level); + PTrace::ClearOptions(0xffffffff); // Everything off + PTrace::SetOptions( // Except these + PTrace::TraceLevel|PTrace::FileAndLine +#if PTLIB_CHECK_VERSION(2,11,1) + |PTrace::ContextIdentifier +#endif + ); + PTrace::SetStream(new FSTrace); + } +#endif } } } @@ -457,196 +371,205 @@ switch_status_t FSManager::ReadConfig(int reload) m_listeners.push_back(FSListener()); FSListener & listener = m_listeners.back(); - listener.name = switch_xml_attr_soft(xmlListener, "name"); - if (listener.name.IsEmpty()) - listener.name = "unnamed"; - - PIPSocket::Address ip; - WORD port = 1720; + listener.m_name = switch_xml_attr_soft(xmlListener, "name"); + if (listener.m_name.IsEmpty()) + listener.m_name = "unnamed"; for (switch_xml_t xmlParam = switch_xml_child(xmlListener, "param"); xmlParam != NULL; xmlParam = xmlParam->next) { - const char *var = switch_xml_attr_soft(xmlParam, "name"); - const char *val = switch_xml_attr_soft(xmlParam, "value"); - //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Var - '%s' and Val - '%s' \n", var, val); - if (!strcasecmp(var, "h323-ip")) - ip = val; - else if (!strcasecmp(var, "h323-port")) - port = (WORD) atoi(val); + PConstCaselessString const var(switch_xml_attr_soft(xmlParam, "name")); + PConstString const val(switch_xml_attr_soft(xmlParam, "value")); + if (var == "h323-ip") + listener.m_address = val; + else if (var == "h323-port") + listener.m_port = (uint16_t)val.AsUnsigned(); } - listener.listenAddress = OpalTransportAddress(ip, port); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created Listener '%s'\n", (const char *) listener.name); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created Listener '%s'\n", (const char *) listener.m_name); } } - switch_event_destroy(¶ms); + switch_event_destroy(&request_params); if (xml) switch_xml_free(xml); - return status; + return SWITCH_STATUS_SUCCESS; } -OpalCall * FSManager::CreateCall(void * /*userData*/) +static switch_call_cause_t create_outgoing_channel(switch_core_session_t *session, + switch_event_t *var_event, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, + switch_memory_pool_t **pool, + switch_originate_flag_t flags, + switch_call_cause_t *cancel_cause) { - return new FSCall(*this); + if (opal_process == NULL) + return SWITCH_CAUSE_CRASH; + + FSConnection::outgoing_params params; + params.var_event = var_event; + params.outbound_profile = outbound_profile; + params.new_session = new_session; + params.pool = pool; + params.flags = flags; + params.cancel_cause = cancel_cause; + params.fail_cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT; + + if (opal_process->GetManager().SetUpCall("local:", outbound_profile->destination_number, ¶ms) != NULL) + return SWITCH_CAUSE_SUCCESS; + + if (*new_session != NULL) + switch_core_session_destroy(new_session); + return params.fail_cause; } /////////////////////////////////////////////////////////////////////// FSEndPoint::FSEndPoint(FSManager & manager) -: OpalLocalEndPoint(manager) + : OpalLocalEndPoint(manager) + , m_manager(manager) { - PTRACE(3, "mod_opal\t FSEndPoint Created!"); -} - - -bool FSEndPoint::OnIncomingCall(OpalLocalConnection & connection) -{ - return ((FSConnection &) connection).OnIncoming(); + PTRACE(4, "mod_opal\tFSEndPoint created."); } OpalLocalConnection *FSEndPoint::CreateConnection(OpalCall & call, void *userData, unsigned options, OpalConnection::StringOptions* stringOptions) { - FSManager & mgr = (FSManager &) GetManager(); - switch_core_session_t *fsSession = switch_core_session_request(mgr.GetSwitchInterface(), - (switch_caller_profile_t *)userData ? SWITCH_CALL_DIRECTION_OUTBOUND : SWITCH_CALL_DIRECTION_INBOUND, SOF_NONE, NULL); - if (fsSession == NULL) - return NULL; - - switch_channel_t *fsChannel = switch_core_session_get_channel(fsSession); - - if (fsChannel == NULL) { - switch_core_session_destroy(&fsSession); - return NULL; - } - - return new FSConnection(call, *this, userData, options, stringOptions, (switch_caller_profile_t *)userData, fsSession, fsChannel); + return new FSConnection(call, *this, options, stringOptions, (FSConnection::outgoing_params *)userData); } /////////////////////////////////////////////////////////////////////// -FSCall::FSCall(OpalManager & manager) - : OpalCall(manager) -{ -} - - -PBoolean FSCall::OnSetUp(OpalConnection & connection) -{ - // Transfer FS caller_id_number & caller_id_name from the FSConnection - // to the protocol connectionm (e.g. H.323) so gets sent correctly - // in outgoing packets - PSafePtr local = GetConnectionAs(); - if (local != NULL) { - PSafePtr proto = local->GetOtherPartyConnection(); - if (proto != NULL) { - proto->SetLocalPartyName(local->GetLocalPartyName()); - proto->SetDisplayName(local->GetDisplayName()); - } - } - - return OpalCall::OnSetUp(connection); -} - - -/////////////////////////////////////////////////////////////////////// - - -FSConnection::FSConnection(OpalCall & call, FSEndPoint & endpoint, void* userData, unsigned options, OpalConnection::StringOptions* stringOptions, switch_caller_profile_t *outbound_profile, switch_core_session_t *fsSession, switch_channel_t *fsChannel) - : OpalLocalConnection(call, endpoint, userData, options, stringOptions) +FSConnection::FSConnection(OpalCall & call, + FSEndPoint & endpoint, + unsigned options, + OpalConnection::StringOptions* stringOptions, + outgoing_params * params) + : OpalLocalConnection(call, endpoint, NULL, options, stringOptions) , m_endpoint(endpoint) - , m_fsSession(fsSession) - , m_fsChannel(fsChannel) + , m_fsSession(NULL) + , m_fsChannel(NULL) + , m_flushAudio(false) { - opal_private_t *tech_pvt; + memset(&m_read_timer, 0, sizeof(m_read_timer)); + memset(&m_read_codec, 0, sizeof(m_read_codec)); + memset(&m_write_codec, 0, sizeof(m_write_codec)); + memset(&m_vid_read_timer, 0, sizeof(m_vid_read_timer)); + memset(&m_vid_read_codec, 0, sizeof(m_vid_read_codec)); + memset(&m_vid_write_codec, 0, sizeof(m_vid_write_codec)); - tech_pvt = (opal_private_t *) switch_core_session_alloc(m_fsSession, sizeof(*tech_pvt)); - tech_pvt->me = this; - switch_core_session_set_private(m_fsSession, tech_pvt); + if (params != NULL) { + // If we fail, this is the cause + params->fail_cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; - if (outbound_profile != NULL) { - SetLocalPartyName(outbound_profile->caller_id_number); - SetDisplayName(outbound_profile->caller_id_name); - - switch_caller_profile_t *caller_profile = switch_caller_profile_clone(m_fsSession, outbound_profile); - switch_channel_set_caller_profile(m_fsChannel, caller_profile); - - PString name = "opal/"; - name += outbound_profile->destination_number; - switch_channel_set_name(m_fsChannel, name); - - switch_channel_set_state(m_fsChannel, CS_INIT); + if ((m_fsSession = switch_core_session_request(endpoint.GetManager().GetSwitchInterface(), + SWITCH_CALL_DIRECTION_INBOUND, params->flags, params->pool)) == NULL) { + PTRACE(1, "mod_opal\tCannot create session for outgoing call."); + return; + } } + else { + if ((m_fsSession = switch_core_session_request(endpoint.GetManager().GetSwitchInterface(), + SWITCH_CALL_DIRECTION_INBOUND, SOF_NONE, NULL)) == NULL) { + PTRACE(1, "mod_opal\tCannot create session for incoming call."); + return; + } + } + + if ((m_fsChannel = switch_core_session_get_channel(m_fsSession)) == NULL) { + switch_core_session_destroy(&m_fsSession); + return; + } + + switch_core_session_set_private(m_fsSession, this); + SafeReference(); // Make sure cannot be deleted until on_destroy() + + if (params != NULL) { + switch_caller_profile_t *caller_profile = switch_caller_profile_clone(m_fsSession, params->outbound_profile); + switch_channel_set_caller_profile(m_fsChannel, caller_profile); + SetLocalPartyName(caller_profile->caller_id_number); + SetDisplayName(caller_profile->caller_id_name); + *params->new_session = m_fsSession; + } + + switch_channel_set_state(m_fsChannel, CS_INIT); +} + + +bool FSConnection::OnOutgoingSetUp() +{ + if (m_fsSession == NULL || m_fsChannel == NULL) { + PTRACE(1, "mod_opal\tSession request failed."); + return false; + } + + // Transfer FS caller_id_number & caller_id_name from the FSConnection + // to the protocol connection (e.g. H.323) so gets sent correctly + // in outgoing packets + PSafePtr proto = GetOtherPartyConnection(); + if (proto == NULL) { + PTRACE(1, "mod_opal\tNo protocol connection in call."); + return false; + } + + proto->SetLocalPartyName(GetLocalPartyName()); + proto->SetDisplayName(GetDisplayName()); + + switch_channel_set_name(m_fsChannel, ModuleName + '/' + GetRemotePartyURL()); + return true; } bool FSConnection::OnIncoming() { - if (m_fsSession == NULL) { + if (m_fsSession == NULL || m_fsChannel == NULL) { PTRACE(1, "mod_opal\tSession request failed."); return false; } switch_core_session_add_stream(m_fsSession, NULL); - switch_channel_t *channel = switch_core_session_get_channel(m_fsSession); - if (channel == NULL) { - PTRACE(1, "mod_opal\tSession does not have a channel"); - return false; - } - PURL url = GetRemotePartyURL(); - switch_caller_profile_t *caller_profile = switch_caller_profile_new(switch_core_session_get_pool(m_fsSession), - url.GetUserName(), - /** username */ - mod_opal_globals.dialplan, - /** dial plan */ - GetRemotePartyName(), - /** caller_id_name */ - GetRemotePartyNumber(), - /** caller_id_number */ - url.GetHostName(), - /** network addr */ - NULL, - /** ANI */ - NULL, - /** ANI II */ - NULL, - /** RDNIS */ - ModuleName, - /** source */ - mod_opal_globals.context, - /** set context */ - GetCalledPartyNumber() - /** destination_number */ - ); + switch_caller_profile_t *caller_profile = switch_caller_profile_new( + switch_core_session_get_pool(m_fsSession), + url.GetUserName(), /** username */ + m_endpoint.GetManager().GetDialPlan(), /** dial plan */ + GetRemotePartyName(), /** caller_id_name */ + GetRemotePartyNumber(), /** caller_id_number */ + url.GetHostName(), /** network addr */ + NULL, /** ANI */ + NULL, /** ANI II */ + NULL, /** RDNIS */ + ModuleName, /** source */ + m_endpoint.GetManager().GetContext(), /** set context */ + GetCalledPartyNumber() /** destination_number */ + ); if (caller_profile == NULL) { PTRACE(1, "mod_opal\tCould not create caller profile"); return false; } PTRACE(4, "mod_opal\tCreated switch caller profile:\n" - " username = " << caller_profile->username << "\n" - " dialplan = " << caller_profile->dialplan << "\n" - " caller_id_name = " << caller_profile->caller_id_name << "\n" - " caller_id_number = " << caller_profile->caller_id_number << "\n" - " network_addr = " << caller_profile->network_addr << "\n" - " source = " << caller_profile->source << "\n" - " context = " << caller_profile->context << "\n" " destination_number= " << caller_profile->destination_number); - switch_channel_set_caller_profile(channel, caller_profile); + " username = " << caller_profile->username << "\n" + " dialplan = " << caller_profile->dialplan << "\n" + " caller_id_name = " << caller_profile->caller_id_name << "\n" + " caller_id_number = " << caller_profile->caller_id_number << "\n" + " network_addr = " << caller_profile->network_addr << "\n" + " source = " << caller_profile->source << "\n" + " context = " << caller_profile->context << "\n" + " destination_number= " << caller_profile->destination_number); + switch_channel_set_caller_profile(m_fsChannel, caller_profile); - char name[256] = "opal/in:"; - switch_copy_string(name + 8, caller_profile->destination_number, sizeof(name)-8); - switch_channel_set_name(channel, name); - switch_channel_set_state(channel, CS_INIT); + switch_channel_set_name(m_fsChannel, ModuleName + '/' + url.GetScheme() + ':' + caller_profile->destination_number); if (switch_core_session_thread_launch(m_fsSession) != SWITCH_STATUS_SUCCESS) { PTRACE(1, "mod_opal\tCould not launch session thread"); + switch_core_session_destroy(&m_fsSession); + m_fsChannel = NULL; return false; } @@ -656,57 +579,44 @@ bool FSConnection::OnIncoming() void FSConnection::OnReleased() { - opal_private_t *tech_pvt = (opal_private_t *) switch_core_session_get_private(m_fsSession); - - /* so FS on_hangup will not try to deref a landmine */ - tech_pvt->me = NULL; - m_rxAudioOpened.Signal(); // Just in case m_txAudioOpened.Signal(); - H225_ReleaseCompleteReason dummy; - switch_channel_hangup(switch_core_session_get_channel(m_fsSession), - (switch_call_cause_t)H323TranslateFromCallEndReason(GetCallEndReason(), dummy)); + + if (m_fsChannel == NULL) { + PTRACE(3, "mod_opal\tHanging up FS side"); + switch_channel_hangup(m_fsChannel, (switch_call_cause_t)callEndReason.q931); + } + OpalLocalConnection::OnReleased(); } -void FSConnection::OnAlerting() -{ - switch_channel_mark_ring_ready(m_fsChannel); - return OpalLocalConnection::OnAlerting(); -} - PBoolean FSConnection::SetAlerting(const PString & calleeName, PBoolean withMedia) { + if (PAssertNULL(m_fsChannel) == NULL) + return false; + + switch_channel_mark_ring_ready(m_fsChannel); return OpalLocalConnection::SetAlerting(calleeName, withMedia); } -void FSConnection::OnEstablished() -{ - OpalLocalConnection::OnEstablished(); -} - - PBoolean FSConnection::SendUserInputTone(char tone, unsigned duration) { + if (PAssertNULL(m_fsChannel) == NULL) + return false; + switch_dtmf_t dtmf = { tone, duration }; return switch_channel_queue_dtmf(m_fsChannel, &dtmf) == SWITCH_STATUS_SUCCESS; } -PBoolean FSConnection::SendUserInputString(const PString & value) -{ - return OpalConnection::SendUserInputString(value); -} - - OpalMediaFormatList FSConnection::GetMediaFormats() const { if (m_switchMediaFormats.IsEmpty()) { const_cast(this)->SetCodecs(); } - + return m_switchMediaFormats; } @@ -714,39 +624,29 @@ OpalMediaFormatList FSConnection::GetMediaFormats() const void FSConnection::SetCodecs() { int numCodecs = 0; - const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS]; - const char *codec_string = NULL, *abs, *ocodec; - char *tmp_codec_string = NULL; - char *codec_order[SWITCH_MAX_CODECS]; - int codec_order_last; + const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS]; - - if ((abs = switch_channel_get_variable(m_fsChannel, "absolute_codec_string"))) { - codec_string = abs; - } else { - if ((abs = switch_channel_get_variable(m_fsChannel, "codec_string"))) { - codec_string = abs; - } - - if ((ocodec = switch_channel_get_variable(m_fsChannel, SWITCH_ORIGINATOR_CODEC_VARIABLE))) { - codec_string = switch_core_session_sprintf(m_fsSession, "%s,%s", ocodec, codec_string); + PString codec_string = switch_channel_get_variable(m_fsChannel, "absolute_codec_string"); + if (codec_string.IsEmpty()) { + codec_string = switch_channel_get_variable(m_fsChannel, "codec_string"); + const char *orig_codec = switch_channel_get_variable(m_fsChannel, SWITCH_ORIGINATOR_CODEC_VARIABLE); + if (orig_codec) { + codec_string.Splice(orig_codec, 0); } } - - if (!codec_string) { - codec_string = mod_opal_globals.codec_string; + + if (codec_string.IsEmpty()) { + codec_string = m_endpoint.GetManager().GetCodecPrefs(); } - if (codec_string) { - if ((tmp_codec_string = strdup(codec_string))) { - codec_order_last = switch_separate_string(tmp_codec_string, ',', codec_order, SWITCH_MAX_CODECS); - numCodecs = switch_loadable_module_get_codecs_sorted(codecs, SWITCH_MAX_CODECS, codec_order, codec_order_last); - - } - } else { + if (codec_string.IsEmpty()) { numCodecs = switch_loadable_module_get_codecs(codecs, sizeof(codecs) / sizeof(codecs[0])); + } else { + char *codec_order[SWITCH_MAX_CODECS]; + int codec_order_last = switch_separate_string((char *)codec_string.GetPointer(), ',', codec_order, SWITCH_MAX_CODECS); + numCodecs = switch_loadable_module_get_codecs_sorted(codecs, SWITCH_MAX_CODECS, codec_order, codec_order_last); } - + for (int i = 0; i < numCodecs; i++) { const switch_codec_implementation_t *codec = codecs[i]; @@ -762,12 +662,12 @@ void FSConnection::SetCodecs() continue; } } - // Did we match or create a new media format? if (switchFormat.IsValid() && codec->codec_type == SWITCH_CODEC_TYPE_AUDIO) { - PTRACE(2, "mod_opal\tMatched FS codec " << codec->iananame << " to OPAL media format " << switchFormat); + PTRACE(3, "mod_opal\tMatched FS codec " << codec->iananame << " to OPAL media format " << switchFormat); +#if IMPLEMENT_MULTI_FAME_AUDIO // Calculate frames per packet, do not use codec->codec_frames_per_packet as that field // has slightly different semantics when used in streamed codecs such as G.711 int fpp = codec->samples_per_packet/switchFormat.GetFrameTime(); @@ -778,7 +678,7 @@ void FSConnection::SetCodecs() could end up with 60ms and the codec cannot be created. The "holes" are unlikely in all but streamed codecs such as G.711, where it is theoretically possible for OPAL to come up with 32ms and there is only 30ms and 40ms in the FS table. We deem these - scenarios succifiently rare that we can safely ignore them ... for now. */ + scenarios sufficiently rare that we can safely ignore them ... for now. */ if (fpp > switchFormat.GetOptionInteger(OpalAudioFormat::RxFramesPerPacketOption())) { switchFormat.SetOptionInteger(OpalAudioFormat::RxFramesPerPacketOption(), fpp); @@ -787,12 +687,11 @@ void FSConnection::SetCodecs() if (fpp > switchFormat.GetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption())) { switchFormat.SetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption(), fpp); } +#endif // IMPLEMENT_MULTI_FAME_AUDIO } m_switchMediaFormats += switchFormat; } - - switch_safe_free(tmp_codec_string); } @@ -802,110 +701,91 @@ OpalMediaStream *FSConnection::CreateMediaStream(const OpalMediaFormat & mediaFo } -PBoolean FSConnection::OnOpenMediaStream(OpalMediaStream & stream) +void FSConnection::OnPatchMediaStream(PBoolean isSource, OpalMediaPatch & patch) { - if (!OpalConnection::OnOpenMediaStream(stream)) { - return false; - } + OpalConnection::OnPatchMediaStream(isSource, patch); - if (stream.GetMediaFormat().GetMediaType() != OpalMediaType::Audio()) { - return true; - } + if (PAssertNULL(m_fsChannel) == NULL) + return; - if (stream.IsSource()) { - m_rxAudioOpened.Signal(); - } else { - m_txAudioOpened.Signal(); - } + if (patch.GetSource().GetMediaFormat().GetMediaType() != OpalMediaType::Audio()) + return; - if (GetMediaStream(stream.GetSessionID(), stream.IsSink()) != NULL) { + if (switch_channel_direction(m_fsChannel) == SWITCH_CALL_DIRECTION_INBOUND) { + if (isSource) + m_rxAudioOpened.Signal(); + else + m_txAudioOpened.Signal(); + } + else if (GetMediaStream(OpalMediaType::Audio(), !isSource) != NULL) { // Have open media in both directions. - if (GetPhase() == AlertingPhase) { - switch_channel_mark_pre_answered(m_fsChannel); - } else if (GetPhase() < ReleasingPhase) { + if (IsEstablished()) switch_channel_mark_answered(m_fsChannel); - } + else if (!IsReleased()) + switch_channel_mark_pre_answered(m_fsChannel); } - - return true; } switch_status_t FSConnection::on_init() { - switch_channel_t *channel = switch_core_session_get_channel(m_fsSession); - if (channel == NULL) { + if (PAssertNULL(m_fsChannel) == NULL) return SWITCH_STATUS_FALSE; - } - PTRACE(3, "mod_opal\tStarted routing for connection " << *this); - switch_channel_set_state(channel, CS_ROUTING); + PTRACE(4, "mod_opal\tStarted routing for connection " << *this); + switch_channel_set_state(m_fsChannel, CS_ROUTING); return SWITCH_STATUS_SUCCESS; } switch_status_t FSConnection::on_routing() { - PTRACE(3, "mod_opal\tRouting connection " << *this); + if (PAssertNULL(m_fsChannel) == NULL) + return SWITCH_STATUS_FALSE; + + PTRACE(4, "mod_opal\tRouting connection " << *this); return SWITCH_STATUS_SUCCESS; } switch_status_t FSConnection::on_execute() { - PTRACE(3, "mod_opal\tExecuting connection " << *this); + if (PAssertNULL(m_fsChannel) == NULL) + return SWITCH_STATUS_FALSE; + + PTRACE(4, "mod_opal\tExecuting connection " << *this); return SWITCH_STATUS_SUCCESS; } -static switch_status_t on_destroy(switch_core_session_t *session) + +switch_status_t FSConnection::on_destroy() { - //switch_channel_t *channel = switch_core_session_get_channel(session); - opal_private_t *tech_pvt = (opal_private_t *) switch_core_session_get_private(session); - - if (tech_pvt) { - if (tech_pvt->read_codec.implementation) { - switch_core_codec_destroy(&tech_pvt->read_codec); - } + PTRACE(3, "mod_opal\tFS on_destroy for connection " << *this); - if (tech_pvt->write_codec.implementation) { - switch_core_codec_destroy(&tech_pvt->write_codec); - } + m_fsChannel = NULL; // Will be destoyed by FS, so don't use it any more. - if (tech_pvt->vid_read_codec.implementation) { - switch_core_codec_destroy(&tech_pvt->vid_read_codec); - } + switch_core_codec_destroy(&m_read_codec); + switch_core_codec_destroy(&m_write_codec); + switch_core_codec_destroy(&m_vid_read_codec); + switch_core_codec_destroy(&m_vid_write_codec); + switch_core_timer_destroy(&m_read_timer); + switch_core_timer_destroy(&m_vid_read_timer); - if (tech_pvt->vid_write_codec.implementation) { - switch_core_codec_destroy(&tech_pvt->vid_write_codec); - } - - if (tech_pvt->read_timer.timer_interface) { - switch_core_timer_destroy(&tech_pvt->read_timer); - } - - if (tech_pvt->vid_read_timer.timer_interface) { - switch_core_timer_destroy(&tech_pvt->vid_read_timer); - } - } + switch_core_session_set_private(m_fsSession, NULL); + SafeDereference(); return SWITCH_STATUS_SUCCESS; } -/* this function has to be called with the original session beause the FSConnection might already be destroyed and we - will can't have it be a method of a dead object - */ -static switch_status_t on_hangup(switch_core_session_t *session) + +switch_status_t FSConnection::on_hangup() { - switch_channel_t *channel = switch_core_session_get_channel(session); - opal_private_t *tech_pvt = (opal_private_t *) switch_core_session_get_private(session); - + if (PAssertNULL(m_fsChannel) == NULL) + return SWITCH_STATUS_FALSE; + /* if this is still here it was our idea to hangup not opal's */ - if (tech_pvt->me) { - Q931::CauseValues cause = (Q931::CauseValues)switch_channel_get_cause_q850(channel); - tech_pvt->me->SetQ931Cause(cause); - tech_pvt->me->ClearCallSynchronous(NULL, H323TranslateToCallEndReason(cause, UINT_MAX)); - tech_pvt->me = NULL; - } + ClearCallSynchronous(NULL, H323TranslateToCallEndReason( + (Q931::CauseValues)switch_channel_get_cause_q850(m_fsChannel), UINT_MAX)); return SWITCH_STATUS_SUCCESS; } @@ -913,30 +793,30 @@ static switch_status_t on_hangup(switch_core_session_t *session) switch_status_t FSConnection::on_exchange_media() { - PTRACE(3, "mod_opal\tLoopback on connection " << *this); + PTRACE(4, "mod_opal\tExchanging media on connection " << *this); return SWITCH_STATUS_SUCCESS; } switch_status_t FSConnection::on_soft_execute() { - PTRACE(3, "mod_opal\tTransmit on connection " << *this); + PTRACE(4, "mod_opal\tTransmit on connection " << *this); return SWITCH_STATUS_SUCCESS; } switch_status_t FSConnection::kill_channel(int sig) { - PTRACE(3, "mod_opal\tKill " << sig << " on connection " << *this); - switch (sig) { - case SWITCH_SIG_BREAK: - break; case SWITCH_SIG_KILL: m_rxAudioOpened.Signal(); m_txAudioOpened.Signal(); + PTRACE(4, "mod_opal\tSignal channel KILL on connection " << *this); break; + case SWITCH_SIG_XFER: + case SWITCH_SIG_BREAK: default: + PTRACE(4, "mod_opal\tSignal channel " << sig << " on connection " << *this); break; } @@ -953,41 +833,16 @@ switch_status_t FSConnection::send_dtmf(const switch_dtmf_t *dtmf) switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg) { - switch_channel_t *channel = switch_core_session_get_channel(m_fsSession); + if (PAssertNULL(m_fsChannel) == NULL) + return SWITCH_STATUS_FALSE; - - /* - SWITCH_MESSAGE_INDICATE_PROGRESS: establish early media now and return SWITCH_STATUS_FALSE if you can't - SWITCH_MESSAGE_INDICATE_ANSWER: answer and set up media now if it's not already and return SWITCH_STATUS_FALSE if you can't - - Neither message means anything on an outbound call.... - - It would only happen if someone called switch_channel_answer() instead of switch_channel_mark_answered() on an outbound call. - it should not do anything if someone does it by accident somewhere hense this in both cases: - - if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { - return SWITCH_STATUS_FALSE; - } - - - When we get these messages the core will trust that you have triggered FSMediaStream::Open and are ready for media if we do not - have media we MUST return SWITCH_STATUS_FALSE or it will cause a CRASH. - - - - */ switch (msg->message_id) { - case SWITCH_MESSAGE_INDICATE_BRIDGE: - case SWITCH_MESSAGE_INDICATE_UNBRIDGE: - case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC: - switch_channel_set_private_flag(channel, CF_NEED_FLUSH); - break; - case SWITCH_MESSAGE_INDICATE_RINGING: case SWITCH_MESSAGE_INDICATE_PROGRESS: case SWITCH_MESSAGE_INDICATE_ANSWER: - { - switch_caller_profile_t * profile = switch_channel_get_caller_profile(channel); + case SWITCH_MESSAGE_INDICATE_DEFLECT: + if (switch_channel_direction(m_fsChannel) == SWITCH_CALL_DIRECTION_INBOUND) { + switch_caller_profile_t * profile = switch_channel_get_caller_profile(m_fsChannel); if (profile != NULL && profile->caller_extension != NULL) { PSafePtr other = GetOtherPartyConnection(); @@ -999,6 +854,9 @@ switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg SetDisplayName(profile->caller_extension->extension_name); } } + else { + return SWITCH_STATUS_FALSE; + } break; default: @@ -1006,89 +864,78 @@ switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg } switch (msg->message_id) { - case SWITCH_MESSAGE_INDICATE_RINGING: - SetPhase(OpalConnection::AlertingPhase); - OnAlerting(); + case SWITCH_MESSAGE_INDICATE_BRIDGE: + case SWITCH_MESSAGE_INDICATE_UNBRIDGE: + case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC: + m_flushAudio = true; break; - case SWITCH_MESSAGE_INDICATE_DEFLECT: - { - PSafePtr other = GetOtherPartyConnection(); - if (other != NULL) - other->TransferConnection(msg->string_arg); + case SWITCH_MESSAGE_INDICATE_RINGING: + AlertingIncoming(); break; - } case SWITCH_MESSAGE_INDICATE_PROGRESS: - case SWITCH_MESSAGE_INDICATE_ANSWER: - { - int fixed = 0; - - if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { - return SWITCH_STATUS_FALSE; - } + AutoStartMediaStreams(); + AlertingIncoming(); - if (msg->message_id == SWITCH_MESSAGE_INDICATE_PROGRESS) { - if (fixed) { - /* this should send alerting + media and wait for it to be established and return SUCCESS or FAIL - depending on if media was able to be established. Need code to tell the other side we want early media here. - */ - GetCall().OpenSourceMediaStreams(*this, OpalMediaType::Audio()); - SetPhase(OpalConnection::AlertingPhase); - /* how do i say please establish early media ? */ - OnAlerting(); - } else { - /* hack to avoid getting stuck, pre_answer will imply answer */ - OnConnectedInternal(); - } - } else { - OnConnectedInternal(); - } - - // Wait for media - PTRACE(2, "mod_opal\tAwaiting media start on connection " << *this); - m_rxAudioOpened.Wait(); - m_txAudioOpened.Wait(); - - if (GetPhase() >= ReleasingPhase) { - // Call got aborted - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(m_fsSession), SWITCH_LOG_ERROR, "Call abandoned!\n"); - return SWITCH_STATUS_FALSE; - } - - PTRACE(4, "mod_opal\tMedia started on connection " << *this); - - if (msg->message_id == SWITCH_MESSAGE_INDICATE_PROGRESS) { - if (!switch_channel_test_flag(m_fsChannel, CF_EARLY_MEDIA)) { - switch_channel_mark_pre_answered(m_fsChannel); - } - } else { - if (!switch_channel_test_flag(m_fsChannel, CF_EARLY_MEDIA)) { - switch_channel_mark_answered(m_fsChannel); - } - } + if (!WaitForMedia()) + return SWITCH_STATUS_FALSE; + if (!switch_channel_test_flag(m_fsChannel, CF_EARLY_MEDIA)) { + switch_channel_mark_pre_answered(m_fsChannel); } break; + case SWITCH_MESSAGE_INDICATE_ANSWER: + AcceptIncoming(); + + if (!WaitForMedia()) + return SWITCH_STATUS_FALSE; + + if (!switch_channel_test_flag(m_fsChannel, CF_ANSWERED)) { + switch_channel_mark_answered(m_fsChannel); + } + break; + + case SWITCH_MESSAGE_INDICATE_DEFLECT: + ownerCall.Transfer(msg->string_arg, GetOtherPartyConnection()); + break; + default: - PTRACE(3, "mod_opal\tReceived message " << msg->message_id << " on connection " << *this); + PTRACE(3, "mod_opal\tReceived unhandled message " << msg->message_id << " on connection " << *this); } return SWITCH_STATUS_SUCCESS; } +bool FSConnection::WaitForMedia() +{ + PTRACE(4, "mod_opal\tAwaiting media start on connection " << *this); + m_rxAudioOpened.Wait(); + m_txAudioOpened.Wait(); + + if (IsReleased()) { + // Call got aborted + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(m_fsSession), SWITCH_LOG_ERROR, "Call abandoned!\n"); + return false; + } + + PTRACE(3, "mod_opal\tMedia started on connection " << *this); + return true; +} + + switch_status_t FSConnection::receive_event(switch_event_t *event) { - PTRACE(3, "mod_opal\tReceived event " << event->event_id << " on connection " << *this); + PTRACE(4, "mod_opal\tReceived event " << event->event_id << " on connection " << *this); return SWITCH_STATUS_SUCCESS; } switch_status_t FSConnection::state_change() { - PTRACE(3, "mod_opal\tState changed on connection " << *this); + PTRACE(4, "mod_opal\tState changed on connection " << *this); return SWITCH_STATUS_SUCCESS; } @@ -1119,14 +966,14 @@ switch_status_t FSConnection::write_video_frame(switch_frame_t *frame, switch_io switch_status_t FSConnection::read_frame(const OpalMediaType & mediaType, switch_frame_t **frame, switch_io_flag_t flags) { - PSafePtr < FSMediaStream > stream = PSafePtrCast < OpalMediaStream, FSMediaStream > (GetMediaStream(mediaType, false)); + PSafePtr stream = PSafePtrCast (GetMediaStream(mediaType, false)); return stream != NULL ? stream->read_frame(frame, flags) : SWITCH_STATUS_FALSE; } switch_status_t FSConnection::write_frame(const OpalMediaType & mediaType, const switch_frame_t *frame, switch_io_flag_t flags) { - PSafePtr < FSMediaStream > stream = PSafePtrCast < OpalMediaStream, FSMediaStream > (GetMediaStream(mediaType, true)); + PSafePtr stream = PSafePtrCast(GetMediaStream(mediaType, true)); return stream != NULL ? stream->write_frame(frame, flags) : SWITCH_STATUS_FALSE; } @@ -1135,24 +982,24 @@ switch_status_t FSConnection::write_frame(const OpalMediaType & mediaType, const FSMediaStream::FSMediaStream(FSConnection & conn, const OpalMediaFormat & mediaFormat, unsigned sessionID, bool isSource) : OpalMediaStream(conn, mediaFormat, sessionID, isSource) - , m_fsSession(conn.GetSession()) - , m_readRTP(0, 512) - , m_callOnStart(true) + , m_connection(conn) + , m_readRTP(0, SWITCH_RECOMMENDED_BUFFER_SIZE) { memset(&m_readFrame, 0, sizeof(m_readFrame)); - m_readFrame.codec = m_switchCodec; - m_readFrame.flags = SFF_RAW_RTP; } PBoolean FSMediaStream::Open() { - opal_private_t *tech_pvt = (opal_private_t *) switch_core_session_get_private(m_fsSession); - if (IsOpen()) { return true; } + switch_core_session_t *fsSession = m_connection.GetSession(); + switch_channel_t *fsChannel = m_connection.GetChannel(); + if (PAssertNULL(fsSession) == NULL || PAssertNULL(fsChannel) == NULL) + return false; + bool isAudio; if (mediaFormat.GetMediaType() == OpalMediaType::Audio()) { isAudio = true; @@ -1162,86 +1009,76 @@ PBoolean FSMediaStream::Open() return OpalMediaStream::Open(); } - m_fsChannel = switch_core_session_get_channel(m_fsSession); - int ptime = mediaFormat.GetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption()) * mediaFormat.GetFrameTime() / mediaFormat.GetTimeUnits(); - if (IsSink()) { - m_switchCodec = isAudio ? &tech_pvt->read_codec : &tech_pvt->vid_read_codec; - m_switchTimer = isAudio ? &tech_pvt->read_timer : &tech_pvt->vid_read_timer; + m_switchCodec = isAudio ? &m_connection.m_read_codec : &m_connection.m_vid_read_codec; + m_switchTimer = isAudio ? &m_connection.m_read_timer : &m_connection.m_vid_read_timer; + m_readFrame.codec = m_switchCodec; + m_readFrame.rate = mediaFormat.GetClockRate(); } else { - m_switchCodec = isAudio ? &tech_pvt->write_codec : &tech_pvt->vid_write_codec; + m_switchCodec = isAudio ? &m_connection.m_write_codec : &m_connection.m_vid_write_codec; } // The following is performed on two different instances of this object. if (switch_core_codec_init(m_switchCodec, mediaFormat.GetEncodingName(), NULL, // FMTP mediaFormat.GetClockRate(), ptime, 1, // Channels SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, // Settings - switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) { + switch_core_session_get_pool(fsSession)) != SWITCH_STATUS_SUCCESS) { // Could not select a codecs using negotiated frames/packet, so try using default. if (switch_core_codec_init(m_switchCodec, mediaFormat.GetEncodingName(), NULL, // FMTP mediaFormat.GetClockRate(), 0, 1, // Channels SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, // Settings - switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) { - PTRACE(1, "mod_opal " << switch_channel_get_name(m_fsChannel)<< " Cannot initialise " << (IsSink()? "read" : "write") << ' ' + switch_core_session_get_pool(fsSession)) != SWITCH_STATUS_SUCCESS) { + PTRACE(1, "mod_opal\t" << switch_channel_get_name(fsChannel) + << " cannot initialise " << (IsSink()? "read" : "write") << ' ' << mediaFormat.GetMediaType() << " codec " << mediaFormat << " for connection " << *this); - switch_channel_hangup(m_fsChannel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); + switch_channel_hangup(fsChannel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); return false; } - PTRACE(2, "mod_opal " << switch_channel_get_name(m_fsChannel)<< " Unsupported ptime of " << ptime << " on " << (IsSink()? "read" : "write") << ' ' + PTRACE(2, "mod_opal\t" << switch_channel_get_name(fsChannel) + << " unsupported ptime of " << ptime << " on " << (IsSink()? "read" : "write") << ' ' << mediaFormat.GetMediaType() << " codec " << mediaFormat << " for connection " << *this); } - PTRACE(1, "mod_opal " << switch_channel_get_name(m_fsChannel)<< " initialise " << - switch_channel_get_name(m_fsChannel) << (IsSink()? "read" : "write") << ' ' - << mediaFormat.GetMediaType() << " codec " << mediaFormat << " for connection " << *this); - if (IsSink()) { - m_readFrame.rate = mediaFormat.GetClockRate(); - if (isAudio) { - switch_core_session_set_read_codec(m_fsSession, m_switchCodec); + switch_core_session_set_read_codec(fsSession, m_switchCodec); if (switch_core_timer_init(m_switchTimer, "soft", m_switchCodec->implementation->microseconds_per_packet / 1000, m_switchCodec->implementation->samples_per_packet, - switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) { + switch_core_session_get_pool(fsSession)) != SWITCH_STATUS_SUCCESS) { + PTRACE(1, "mod_opal\t" << switch_channel_get_name(fsChannel) + << " timer init failed on " << (IsSink()? "read" : "write") << ' ' + << mediaFormat.GetMediaType() << " codec " << mediaFormat << " for connection " << *this); switch_core_codec_destroy(m_switchCodec); m_switchCodec = NULL; return false; } } else { - switch_core_session_set_video_read_codec(m_fsSession, m_switchCodec); - switch_channel_set_flag(m_fsChannel, CF_VIDEO); + switch_core_session_set_video_read_codec(fsSession, m_switchCodec); + switch_channel_set_flag(fsChannel, CF_VIDEO); } } else { if (isAudio) { - switch_core_session_set_write_codec(m_fsSession, m_switchCodec); + switch_core_session_set_write_codec(fsSession, m_switchCodec); } else { - switch_core_session_set_video_write_codec(m_fsSession, m_switchCodec); - switch_channel_set_flag(m_fsChannel, CF_VIDEO); + switch_core_session_set_video_write_codec(fsSession, m_switchCodec); + switch_channel_set_flag(fsChannel, CF_VIDEO); } } - PTRACE(3, "mod_opal\tSet " << (IsSink()? "read" : "write") << ' ' - << mediaFormat.GetMediaType() << " codec to << " << mediaFormat << " for connection " << *this); + PTRACE(3, "mod_opal\t" << switch_channel_get_name(fsChannel) + << " initialised " << (IsSink()? "read" : "write") << ' ' + << mediaFormat.GetMediaType() << " codec " << mediaFormat << " for connection " << *this); return OpalMediaStream::Open(); } -PBoolean FSMediaStream::Close() +void FSMediaStream::InternalClose() { - if (!IsOpen()) - return false; - - /* forget these FS will properly destroy them for us */ - - m_switchTimer = NULL; - m_switchCodec = NULL; - - return OpalMediaStream::Close(); } @@ -1256,149 +1093,88 @@ PBoolean FSMediaStream::RequiresPatchThread(OpalMediaStream *) const return false; } -bool FSMediaStream::CheckPatchAndLock() -{ - if (GetConnection().GetPhase() >= GetConnection().ReleasingPhase || !IsOpen()) - return false; - if (LockReadWrite()) { - if (!GetPatch() || !IsOpen()) { - UnlockReadWrite(); - return false; - } - return true; - } else { - return false; +int FSMediaStream::StartReadWrite(PatchPtr & mediaPatch) const +{ + if (!IsOpen()) { + PTRACE(2, "mod_opal\tNot open!"); + return -1; } + + if (!m_switchCodec) { + PTRACE(2, "mod_opal\tNo codec!"); + return -1; + } + + if (!m_connection.IsChannelReady()) { + PTRACE(2, "mod_opal\tChannel not ready!"); + return -1; + } + + // We make referenced copy of pointer so can't be deleted out from under us + mediaPatch = m_mediaPatch; + if (mediaPatch == NULL) { + /*There is a race here... sometimes we make it here and m_mediaPatch is NULL + if we wait it shows up in 1ms, maybe there is a better way to wait. */ + PTRACE(3, "mod_opal\tPatch not ready!"); + return 1; + } + + return 0; } + switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag_t flags) { - - if (!m_switchCodec) { + PatchPtr mediaPatch; + switch (StartReadWrite(mediaPatch)) { + case -1 : return SWITCH_STATUS_FALSE; + case 1 : + return SWITCH_STATUS_SUCCESS; } - if (m_callOnStart) { - /* - There is a race here... sometimes we make it here and GetPatch() is NULL - if we wait it shows up in 1ms, maybe there is a better way to wait. - - */ - while(!GetPatch()) { - if (!m_fsChannel || !switch_channel_up(m_fsChannel)) { - return SWITCH_STATUS_FALSE; - } - switch_cond_next(); - } - if (CheckPatchAndLock()) { - GetPatch()->OnStartMediaPatch(); - m_callOnStart = false; - UnlockReadWrite(); - } else { - return SWITCH_STATUS_FALSE; - } - } - - m_readFrame.flags = 0; - - /* - while (switch_channel_ready(m_fsChannel)) { - if (CheckPatchAndLock()) { - if (!GetPatch()->GetSource().ReadPacket(m_readRTP)) { - UnlockReadWrite(); - return SWITCH_STATUS_FALSE; - } - UnlockReadWrite(); - } else { - return SWITCH_STATUS_FALSE; - } - - if ((m_readFrame.datalen = m_readRTP.GetPayloadSize()) || switch_core_timer_check(&m_switchTimer, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) { - if (m_readFrame.datalen) { - } else { - m_readFrame.flags = SFF_CNG; - } - break; - } - - switch_yield(1000); - } - */ - - if (switch_channel_test_private_flag(m_fsChannel, CF_NEED_FLUSH)) { - switch_channel_clear_private_flag(m_fsChannel, CF_NEED_FLUSH); - for(;;) { - if (CheckPatchAndLock()) { - if (!GetPatch()->GetSource().ReadPacket(m_readRTP)) { - UnlockReadWrite(); - return SWITCH_STATUS_FALSE; - } - UnlockReadWrite(); - } else { - return SWITCH_STATUS_FALSE; - } - - if (!m_readRTP.GetPayloadSize()) { - m_readFrame.flags = SFF_CNG; - break; - } - } + if (m_connection.NeedFlushAudio()) { + mediaPatch->GetSource().EnableJitterBuffer(); // This flushes data and resets jitter buffer + m_readRTP.SetPayloadSize(0); } else { + m_readRTP.SetTimestamp(m_readFrame.timestamp + m_switchCodec->implementation->samples_per_packet); - if (CheckPatchAndLock()) { - if (!m_switchTimer || !GetPatch()->GetSource().ReadPacket(m_readRTP)) { - UnlockReadWrite(); - return SWITCH_STATUS_FALSE; - } - UnlockReadWrite(); - } else { - return SWITCH_STATUS_FALSE; - } - - switch_core_timer_next(m_switchTimer); - - if (!(m_readFrame.datalen = m_readRTP.GetPayloadSize())) { - m_readFrame.flags = SFF_CNG; + if (!mediaPatch->GetSource().ReadPacket(m_readRTP)) { + return SWITCH_STATUS_FALSE; } } - if (!switch_channel_ready(m_fsChannel)) { + if (!m_switchTimer) { + PTRACE(2, "mod_opal\tread_frame: no timer!"); return SWITCH_STATUS_FALSE; } + switch_core_timer_next(m_switchTimer); if (!switch_core_codec_ready(m_switchCodec)) { + PTRACE(2, "mod_opal\tread_frame: codec not ready!"); return SWITCH_STATUS_FALSE; } - //switch_core_timer_step(&m_switchTimer); +#if IMPLEMENT_MULTI_FAME_AUDIO + // Repackage frames in incoming packet to agree with what FS expects. + // Not implmented yet!!!!!!!!! + // Cheating and only supporting one frame per packet +#endif - if (m_readFrame.payload == RTP_DataFrame::CN || m_readFrame.payload == RTP_DataFrame::Cisco_CN) { - m_readFrame.flags = SFF_CNG; - } - - if (m_readFrame.flags & SFF_CNG) { - m_readFrame.buflen = sizeof(m_buf); - m_readFrame.data = m_buf; - m_readFrame.packet = NULL; - m_readFrame.packetlen = 0; - m_readFrame.timestamp = 0; - m_readFrame.m = SWITCH_FALSE; - m_readFrame.seq = 0; - m_readFrame.ssrc = 0; - m_readFrame.codec = m_switchCodec; - } else { - m_readFrame.buflen = m_readRTP.GetSize(); - m_readFrame.data = m_readRTP.GetPayloadPtr(); - m_readFrame.packet = m_readRTP.GetPointer(); - m_readFrame.packetlen = m_readRTP.GetHeaderSize() + m_readFrame.datalen; - m_readFrame.payload = (switch_payload_t) m_readRTP.GetPayloadType(); - m_readFrame.timestamp = m_readRTP.GetTimestamp(); - m_readFrame.m = (switch_bool_t) m_readRTP.GetMarker(); - m_readFrame.seq = m_readRTP.GetSequenceNumber(); - m_readFrame.ssrc = m_readRTP.GetSyncSource(); - m_readFrame.codec = m_switchCodec; - } + m_readFrame.buflen = m_readRTP.GetSize(); + m_readFrame.data = m_readRTP.GetPayloadPtr(); + m_readFrame.datalen = m_readRTP.GetPayloadSize(); + m_readFrame.packet = m_readRTP.GetPointer(); + m_readFrame.packetlen = m_readRTP.GetHeaderSize() + m_readFrame.datalen; + m_readFrame.timestamp = m_readRTP.GetTimestamp(); + m_readFrame.seq = m_readRTP.GetSequenceNumber(); + m_readFrame.ssrc = m_readRTP.GetSyncSource(); + m_readFrame.m = m_readRTP.GetMarker() ? SWITCH_TRUE : SWITCH_FALSE; + m_readFrame.payload = (switch_payload_t)m_readRTP.GetPayloadType(); + m_readFrame.flags = m_readFrame.datalen == 0 || + m_readFrame.payload == RTP_DataFrame::CN || + m_readFrame.payload == RTP_DataFrame::Cisco_CN ? SFF_CNG : 0; *frame = &m_readFrame; @@ -1408,69 +1184,35 @@ switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag switch_status_t FSMediaStream::write_frame(const switch_frame_t *frame, switch_io_flag_t flags) { - if (!switch_channel_ready(m_fsChannel)) { + PatchPtr mediaPatch; + switch (StartReadWrite(mediaPatch)) { + case -1 : return SWITCH_STATUS_FALSE; - } - - if (m_callOnStart) { - if (CheckPatchAndLock()) { - GetPatch()->OnStartMediaPatch(); - m_callOnStart = false; - UnlockReadWrite(); - } else { - return SWITCH_STATUS_FALSE; - } - } - - if ((frame->flags & SFF_CNG)) { + case 1 : return SWITCH_STATUS_SUCCESS; } if ((frame->flags & SFF_RAW_RTP) != 0) { - RTP_DataFrame rtp((const BYTE *) frame->packet, frame->packetlen, false); - - if (CheckPatchAndLock()) { - if (GetPatch()->PushFrame(rtp)) { - UnlockReadWrite(); - return SWITCH_STATUS_SUCCESS; - } - UnlockReadWrite(); - } else { - return SWITCH_STATUS_FALSE; - } - } - - /* If we reach this code it means a call to an ivr or something else that does not generate timestamps - Its possible that frame->timestamp is set but not guarenteed and is best ignored for the time being. - We are probably relying on the rtp stack to generate the timestamp and ssrc for us at this point. - As a quick hack I am going to keep a sample counter and increment it by frame->samples but it would be - better if we could engage whatever it is in opal that makes it generate the timestamp. - */ - - RTP_DataFrame rtp(frame->datalen); - rtp.SetPayloadType(mediaFormat.GetPayloadType()); - - m_timeStamp += frame->samples; - rtp.SetTimestamp(m_timeStamp); - - //rtp.SetTimestamp(frame->timestamp); - //rtp.SetSyncSource(frame->ssrc); - //rtp.SetMarker(frame->m); - - memcpy(rtp.GetPayloadPtr(), frame->data, frame->datalen); - - if (CheckPatchAndLock()) { - if (GetPatch()->PushFrame(rtp)) { - UnlockReadWrite(); - return SWITCH_STATUS_SUCCESS; - } - UnlockReadWrite(); - } else { - return SWITCH_STATUS_FALSE; + RTP_DataFrame rtp((const BYTE *)frame->packet, frame->packetlen, false); + return mediaPatch->PushFrame(rtp) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; } + RTP_DataFrame rtp(frame->datalen); + memcpy(rtp.GetPayloadPtr(), frame->data, frame->datalen); - return SWITCH_STATUS_FALSE; + rtp.SetPayloadType(mediaFormat.GetPayloadType()); + + /* Not sure what FS is going to give us! + Suspect it depends on the mod on the other side sending it. */ + if (frame->timestamp != 0) + timestamp = frame->timestamp; + else if (frame->samples != 0) + timestamp += frame->samples; + else + timestamp += m_switchCodec->implementation->samples_per_packet; + rtp.SetTimestamp(timestamp); + + return mediaPatch->PushFrame(rtp) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; } diff --git a/src/mod/endpoints/mod_opal/mod_opal.h b/src/mod/endpoints/mod_opal/mod_opal.h index 1915d54b90..07ba28a1f3 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.h +++ b/src/mod/endpoints/mod_opal/mod_opal.h @@ -4,6 +4,7 @@ * Version: MPL 1.1 * * Copyright (c) 2007 Tuyan Ozipek (tuyanozipek@gmail.com) + * Copyright (c) 2008-2012 Vox Lucida Pty. Ltd. (robertj@voxlucida.com.au) * * 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 @@ -46,6 +47,8 @@ #define HAVE_APR #include #include + + #define MODNAME "mod_opal" @@ -53,206 +56,239 @@ class FSEndPoint; class FSManager; -struct mod_opal_globals { - int trace_level; - char *codec_string; - char *context; - char *dialplan; +class FSProcess : public PLibraryProcess +{ + PCLASSINFO(FSProcess, PLibraryProcess); + public: + FSProcess(); + ~FSProcess(); + + bool Initialise(switch_loadable_module_interface_t *iface); + + FSManager & GetManager() const + { + return *m_manager; + } + + protected: + FSManager * m_manager; }; -extern struct mod_opal_globals mod_opal_globals; + +struct FSListener +{ + FSListener() : m_port(H323EndPoint::DefaultTcpSignalPort) { } + + PString m_name; + PIPSocket::Address m_address; + uint16_t m_port; +}; -class FSProcess:public PLibraryProcess { - PCLASSINFO(FSProcess, PLibraryProcess); +class FSManager : public OpalManager +{ + PCLASSINFO(FSManager, OpalManager); public: - FSProcess(); - ~FSProcess(); + FSManager(); - bool Initialise(switch_loadable_module_interface_t *iface); + bool Initialise(switch_loadable_module_interface_t *iface); - FSManager & GetManager() const { - return *m_manager; - } protected: - FSManager * m_manager; -}; + switch_status_t ReadConfig(int reload); - -struct FSListener { - FSListener() { - } PString name; - OpalTransportAddress listenAddress; - PString localUserName; - PString gatekeeper; -}; - - -class FSCall:public OpalCall { - PCLASSINFO(FSCall, OpalCall); - public: - FSCall(OpalManager & manager); - virtual PBoolean OnSetUp(OpalConnection & connection); -}; - - -class FSManager:public OpalManager { - PCLASSINFO(FSManager, OpalManager); - - public: - FSManager(); - - bool Initialise(switch_loadable_module_interface_t *iface); - - switch_status_t ReadConfig(int reload); - - switch_endpoint_interface_t *GetSwitchInterface() const { - return m_FreeSwitch; - } virtual OpalCall *CreateCall(void *userData); + switch_endpoint_interface_t *GetSwitchInterface() const { return m_FreeSwitch; } + const PString & GetContext() const { return m_context; } + const PString & GetDialPlan() const { return m_dialplan; } + const PString & GetCodecPrefs() const { return m_codecPrefs; } private: - switch_endpoint_interface_t *m_FreeSwitch; + switch_endpoint_interface_t *m_FreeSwitch; - H323EndPoint *m_h323ep; - IAX2EndPoint *m_iaxep; - FSEndPoint *m_fsep; + H323EndPoint *m_h323ep; + IAX2EndPoint *m_iaxep; + FSEndPoint *m_fsep; - PString m_gkAddress; - PString m_gkIdentifer; - PString m_gkInterface; + PString m_context; + PString m_dialplan; + PString m_codecPrefs; + PString m_gkAddress; + PString m_gkIdentifer; + PString m_gkInterface; - list < FSListener > m_listeners; + list m_listeners; +}; + + +class FSEndPoint : public OpalLocalEndPoint +{ + PCLASSINFO(FSEndPoint, OpalLocalEndPoint); + public: + FSEndPoint(FSManager & manager); + + virtual OpalLocalConnection *CreateConnection(OpalCall & call, void *userData, unsigned options, OpalConnection::StringOptions * stringOptions); + + FSManager & GetManager() const { return m_manager; } + + protected: + FSManager & m_manager; }; class FSConnection; -typedef struct { - switch_timer_t read_timer; - switch_codec_t read_codec; - switch_codec_t write_codec; - - switch_timer_t vid_read_timer; - switch_codec_t vid_read_codec; - switch_codec_t vid_write_codec; - FSConnection *me; -} opal_private_t; -class FSEndPoint:public OpalLocalEndPoint { - PCLASSINFO(FSEndPoint, OpalLocalEndPoint); +class FSMediaStream : public OpalMediaStream +{ + PCLASSINFO(FSMediaStream, OpalMediaStream); public: - FSEndPoint(FSManager & manager); + FSMediaStream( + FSConnection & conn, + const OpalMediaFormat & mediaFormat, ///< Media format for stream + unsigned sessionID, ///< Session number for stream + bool isSource ///< Is a source stream + ); - virtual bool OnIncomingCall(OpalLocalConnection &); - virtual OpalLocalConnection *CreateConnection(OpalCall & call, void *userData, unsigned options, OpalConnection::StringOptions * stringOptions); + virtual PBoolean Open(); + virtual PBoolean IsSynchronous() const; + virtual PBoolean RequiresPatchThread(OpalMediaStream *) const; + + switch_status_t read_frame(switch_frame_t **frame, switch_io_flag_t flags); + switch_status_t write_frame(const switch_frame_t *frame, switch_io_flag_t flags); + + protected: + virtual void InternalClose(); + int StartReadWrite(PatchPtr & mediaPatch) const; + + private: + bool CheckPatchAndLock(); + + FSConnection &m_connection; + switch_timer_t *m_switchTimer; + switch_codec_t *m_switchCodec; + switch_frame_t m_readFrame; + RTP_DataFrame m_readRTP; }; #define DECLARE_CALLBACK0(name) \ static switch_status_t name(switch_core_session_t *session) { \ - opal_private_t *tech_pvt = (opal_private_t *) switch_core_session_get_private(session); \ - return tech_pvt && tech_pvt->me != NULL ? tech_pvt->me->name() : SWITCH_STATUS_FALSE; } \ -switch_status_t name() + FSConnection *tech_pvt = (FSConnection *) switch_core_session_get_private(session); \ + return tech_pvt != NULL ? tech_pvt->name() : SWITCH_STATUS_FALSE; } \ + switch_status_t name() #define DECLARE_CALLBACK1(name, type1, name1) \ static switch_status_t name(switch_core_session_t *session, type1 name1) { \ - opal_private_t *tech_pvt = (opal_private_t *) switch_core_session_get_private(session); \ - return tech_pvt && tech_pvt->me != NULL ? tech_pvt->me->name(name1) : SWITCH_STATUS_FALSE; } \ -switch_status_t name(type1 name1) + FSConnection *tech_pvt = (FSConnection *) switch_core_session_get_private(session); \ + return tech_pvt != NULL ? tech_pvt->name(name1) : SWITCH_STATUS_FALSE; } \ + switch_status_t name(type1 name1) #define DECLARE_CALLBACK3(name, type1, name1, type2, name2, type3, name3) \ static switch_status_t name(switch_core_session_t *session, type1 name1, type2 name2, type3 name3) { \ - opal_private_t *tech_pvt = (opal_private_t *) switch_core_session_get_private(session); \ - return tech_pvt && tech_pvt->me != NULL ? tech_pvt->me->name(name1, name2, name3) : SWITCH_STATUS_FALSE; } \ -switch_status_t name(type1 name1, type2 name2, type3 name3) + FSConnection *tech_pvt = (FSConnection *) switch_core_session_get_private(session); \ + return tech_pvt != NULL ? tech_pvt->name(name1, name2, name3) : SWITCH_STATUS_FALSE; } \ + switch_status_t name(type1 name1, type2 name2, type3 name3) -class FSConnection:public OpalLocalConnection { - PCLASSINFO(FSConnection, OpalLocalConnection) +class FSConnection : public OpalLocalConnection +{ + PCLASSINFO(FSConnection, OpalLocalConnection) public: - FSConnection(OpalCall & call, - FSEndPoint & endpoint, - void *userData, - unsigned options, - OpalConnection::StringOptions * stringOptions, - switch_caller_profile_t *outbound_profile, switch_core_session_t *fsSession, switch_channel_t *fsChannel); + struct outgoing_params { + switch_event_t *var_event; + switch_caller_profile_t *outbound_profile; + switch_core_session_t **new_session; + switch_memory_pool_t **pool; + switch_originate_flag_t flags; + switch_call_cause_t *cancel_cause; + switch_call_cause_t fail_cause; + }; - virtual bool OnIncoming(); - virtual void OnReleased(); - virtual PBoolean SetAlerting(const PString & calleeName, PBoolean withMedia); - virtual void OnAlerting(); - virtual void OnEstablished(); - virtual OpalMediaStream *CreateMediaStream(const OpalMediaFormat &, unsigned, PBoolean); - virtual PBoolean OnOpenMediaStream(OpalMediaStream & stream); - virtual OpalMediaFormatList GetMediaFormats() const; - virtual PBoolean SendUserInputTone(char tone, unsigned duration); - virtual PBoolean SendUserInputString(const PString & value); + FSConnection(OpalCall & call, + FSEndPoint & endpoint, + unsigned options, + OpalConnection::StringOptions * stringOptions, + outgoing_params * params); - void SetCodecs(); + virtual bool OnOutgoingSetUp(); + virtual bool OnIncoming(); + virtual void OnReleased(); + virtual PBoolean SetAlerting(const PString & calleeName, PBoolean withMedia); + virtual OpalMediaStream *CreateMediaStream(const OpalMediaFormat &, unsigned, PBoolean); + virtual void OnPatchMediaStream(PBoolean isSource, OpalMediaPatch & patch); + virtual OpalMediaFormatList GetMediaFormats() const; + virtual PBoolean SendUserInputTone(char tone, unsigned duration); - DECLARE_CALLBACK0(on_init); - DECLARE_CALLBACK0(on_routing); - DECLARE_CALLBACK0(on_execute); + void SetCodecs(); + bool WaitForMedia(); - DECLARE_CALLBACK0(on_exchange_media); - DECLARE_CALLBACK0(on_soft_execute); + DECLARE_CALLBACK0(on_init); + DECLARE_CALLBACK0(on_destroy); + DECLARE_CALLBACK0(on_routing); + DECLARE_CALLBACK0(on_execute); + DECLARE_CALLBACK0(on_hangup); - DECLARE_CALLBACK1(kill_channel, int, sig); - DECLARE_CALLBACK1(send_dtmf, const switch_dtmf_t *, dtmf); - DECLARE_CALLBACK1(receive_message, switch_core_session_message_t *, msg); - DECLARE_CALLBACK1(receive_event, switch_event_t *, event); - DECLARE_CALLBACK0(state_change); - DECLARE_CALLBACK3(read_audio_frame, switch_frame_t **, frame, switch_io_flag_t, flags, int, stream_id); - DECLARE_CALLBACK3(write_audio_frame, switch_frame_t *, frame, switch_io_flag_t, flags, int, stream_id); - DECLARE_CALLBACK3(read_video_frame, switch_frame_t **, frame, switch_io_flag_t, flag, int, stream_id); - DECLARE_CALLBACK3(write_video_frame, switch_frame_t *, frame, switch_io_flag_t, flag, int, stream_id); + DECLARE_CALLBACK0(on_exchange_media); + DECLARE_CALLBACK0(on_soft_execute); - switch_status_t read_frame(const OpalMediaType & mediaType, switch_frame_t **frame, switch_io_flag_t flags); - switch_status_t write_frame(const OpalMediaType & mediaType, const switch_frame_t *frame, switch_io_flag_t flags); + DECLARE_CALLBACK1(kill_channel, int, sig); + DECLARE_CALLBACK1(send_dtmf, const switch_dtmf_t *, dtmf); + DECLARE_CALLBACK1(receive_message, switch_core_session_message_t *, msg); + DECLARE_CALLBACK1(receive_event, switch_event_t *, event); + DECLARE_CALLBACK0(state_change); + DECLARE_CALLBACK3(read_audio_frame, switch_frame_t **, frame, switch_io_flag_t, flags, int, stream_id); + DECLARE_CALLBACK3(write_audio_frame, switch_frame_t *, frame, switch_io_flag_t, flags, int, stream_id); + DECLARE_CALLBACK3(read_video_frame, switch_frame_t **, frame, switch_io_flag_t, flag, int, stream_id); + DECLARE_CALLBACK3(write_video_frame, switch_frame_t *, frame, switch_io_flag_t, flag, int, stream_id); - switch_core_session_t *GetSession() const { - return m_fsSession; - } private: - FSEndPoint & m_endpoint; - switch_core_session_t *m_fsSession; - switch_channel_t *m_fsChannel; - PSyncPoint m_rxAudioOpened; - PSyncPoint m_txAudioOpened; - OpalMediaFormatList m_switchMediaFormats; -}; + switch_status_t read_frame(const OpalMediaType & mediaType, switch_frame_t **frame, switch_io_flag_t flags); + switch_status_t write_frame(const OpalMediaType & mediaType, const switch_frame_t *frame, switch_io_flag_t flags); + __inline switch_core_session_t *GetSession() const + { + return m_fsSession; + } -class FSMediaStream:public OpalMediaStream { - PCLASSINFO(FSMediaStream, OpalMediaStream); - public: - FSMediaStream(FSConnection & conn, const OpalMediaFormat & mediaFormat, ///< Media format for stream - unsigned sessionID, ///< Session number for stream - bool isSource ///< Is a source stream - ); + __inline switch_channel_t *GetChannel() const + { + return m_fsChannel; + } - virtual PBoolean Open(); - virtual PBoolean Close(); - virtual PBoolean IsSynchronous() const; - virtual PBoolean RequiresPatchThread(OpalMediaStream *) const; + bool IsChannelReady() const + { + return m_fsChannel != NULL && switch_channel_ready(m_fsChannel); + } - switch_status_t read_frame(switch_frame_t **frame, switch_io_flag_t flags); - switch_status_t write_frame(const switch_frame_t *frame, switch_io_flag_t flags); + bool NeedFlushAudio() + { + if (!m_flushAudio) + return false; + m_flushAudio = false; + return true; + } private: - switch_core_session_t *m_fsSession; - switch_channel_t *m_fsChannel; - switch_timer_t *m_switchTimer; - switch_codec_t *m_switchCodec; - switch_frame_t m_readFrame; - unsigned char m_buf[SWITCH_RECOMMENDED_BUFFER_SIZE]; - RTP_DataFrame m_readRTP; - bool m_callOnStart; - uint32_t m_timeStamp; + FSEndPoint &m_endpoint; + switch_core_session_t *m_fsSession; + switch_channel_t *m_fsChannel; + PSyncPoint m_rxAudioOpened; + PSyncPoint m_txAudioOpened; + OpalMediaFormatList m_switchMediaFormats; - bool CheckPatchAndLock(); + // If FS ever supports more than one audio and one video, this needs to change + switch_timer_t m_read_timer; + switch_codec_t m_read_codec; + switch_codec_t m_write_codec; + + switch_timer_t m_vid_read_timer; + switch_codec_t m_vid_read_codec; + switch_codec_t m_vid_write_codec; + + bool m_flushAudio; + + friend PBoolean FSMediaStream::Open(); }; From 22bc29b5e0b4be2f342d0f1ec34da89adf2bbd1d Mon Sep 17 00:00:00 2001 From: root Date: Mon, 30 Jul 2012 12:32:46 -0400 Subject: [PATCH 378/822] sending termination in-service/out-of-service service change for termination whenever there is alarm indication from freetdm --- libs/freetdm/mod_freetdm/tdm.c | 7 +- .../mod_media_gateway/media_gateway.c | 39 ++++- .../media_gateway_cmd_handler.c | 13 +- .../mod_media_gateway/media_gateway_stack.h | 6 +- .../mod_media_gateway/media_gateway_utils.c | 12 +- .../mod_media_gateway/media_gateway_xml.c | 154 +++++++++++------- .../mod_media_gateway/mod_media_gateway.c | 30 +--- .../mod_media_gateway/mod_media_gateway.h | 8 +- 8 files changed, 167 insertions(+), 102 deletions(-) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index 790f7c17d3..0cc02a85c7 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -84,7 +84,7 @@ switch_io_routines_t ctdm_io_routines = { .receive_message = channel_receive_message }; -static void ctdm_report_alarms(ftdm_channel_t *channel, const char* mg_profile_name) +static void ctdm_report_alarms(ftdm_channel_t *channel) { switch_event_t *event = NULL; ftdm_alarm_flag_t alarmflag = 0; @@ -109,8 +109,6 @@ static void ctdm_report_alarms(ftdm_channel_t *channel, const char* mg_profile_n switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-trap"); } - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "mg-profile-name", mg_profile_name); - if (alarmflag & FTDM_ALARM_RED) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "red"); } @@ -149,7 +147,6 @@ static void ctdm_event_handler(switch_event_t *event) const char *chan_number = NULL; uint32_t chan_id = 0; const char *cond = switch_event_get_header(event, "condition"); - const char *mg_profile_name = switch_event_get_header(event, "mg-profile-name"); if (zstr(cond)) { return; @@ -187,7 +184,7 @@ static void ctdm_event_handler(switch_event_t *event) return; } - ctdm_report_alarms(channel, mg_profile_name); + ctdm_report_alarms(channel); } } break; diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 7e13fbaebe..8beeedc3ca 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -22,6 +22,8 @@ megaco_profile_t *megaco_profile_locate(const char *name) return profile; } + + mg_peer_profile_t *megaco_peer_profile_locate(const char *name) { mg_peer_profile_t *profile = switch_core_hash_find_rdlock(megaco_globals.peer_profile_hash, name, megaco_globals.peer_profile_rwlock); @@ -171,7 +173,6 @@ switch_status_t megaco_prepare_tdm_termination(mg_termination_t *term) return SWITCH_STATUS_SUCCESS; } -/* @Kapil Call this function once H.248 link is up */ switch_status_t megaco_check_tdm_termination(mg_termination_t *term) { switch_event_t *event = NULL; @@ -186,7 +187,6 @@ switch_status_t megaco_check_tdm_termination(mg_termination_t *term) switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", term->u.tdm.span_name); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", term->u.tdm.channel); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "mg-tdm-check"); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "mg-profile-name", term->profile->name); switch_event_fire(&event); return SWITCH_STATUS_SUCCESS; @@ -241,7 +241,34 @@ mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const cha return term; } -mg_termination_t* megaco_find_termination_by_span_chan(megaco_profile_t *profile, char *span_name, char *chan_number) +mg_termination_t *megaco_term_locate_by_span_chan_id(const char *span_name, const char *chan_number) +{ + void *val = NULL; + switch_hash_index_t *hi = NULL; + mg_termination_t *term = NULL; + megaco_profile_t *profile = NULL; + const void *var; + + switch_assert(span_name); + switch_assert(chan_number); + + /* span + chan will be unique across all the mg_profiles * + * loop through all profiles and then all terminations to * + * get the mg termination associated with input span+chan */ + + switch_thread_rwlock_rdlock(megaco_globals.profile_rwlock); + for (hi = switch_hash_first(NULL, megaco_globals.profile_hash); hi; hi = switch_hash_next(hi)) { + switch_hash_this(hi, &var, NULL, &val); + profile = (megaco_profile_t *) val; + + if(NULL != (term = megaco_find_termination_by_span_chan(profile, span_name, chan_number))) break; + } + switch_thread_rwlock_unlock(megaco_globals.profile_rwlock); + + return term; +} + +mg_termination_t* megaco_find_termination_by_span_chan(megaco_profile_t *profile, const char *span_name, const char *chan_number) { void *val = NULL; switch_hash_index_t *hi = NULL; @@ -262,7 +289,8 @@ mg_termination_t* megaco_find_termination_by_span_chan(megaco_profile_t *profile if ((!strcasecmp(span_name, term->u.tdm.span_name))&& (atoi(chan_number) == term->u.tdm.channel)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, - "Got term[%s] associated with span[%s], channel[%s]\n",term->name, span_name, chan_number); + "Got term[%s] associated with span[%s], channel[%s] in MG profile[%s]\n", + term->name, span_name, chan_number, profile->name); found = 0x01; break; } @@ -271,7 +299,8 @@ mg_termination_t* megaco_find_termination_by_span_chan(megaco_profile_t *profile if(!found){ term = NULL; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, - " Not able to find termination associated with span[%s], channel[%s]\n", span_name, chan_number); + " MG profile[%s] does not have termination associated with span[%s], channel[%s]\n", + profile->name, span_name, chan_number); } return term; diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index ca2209b087..f392612cbb 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -2288,18 +2288,15 @@ U32 get_txn_id(){ return outgoing_txn_id; } /*****************************************************************************************************************************/ -switch_status_t mg_send_term_service_change(char* mg_profile_name,char *span_name, char *chan_number, mg_term_states_e term_state) +switch_status_t mg_send_term_service_change(char *span_name, char *chan_number, mg_term_states_e term_state) { mg_termination_t* term = NULL; switch_status_t ret = SWITCH_STATUS_SUCCESS; - megaco_profile_t *profile = NULL; switch_assert(span_name); switch_assert(chan_number); - profile = megaco_profile_locate(mg_profile_name); - - term = megaco_find_termination_by_span_chan(profile, span_name, chan_number); + term = megaco_term_locate_by_span_chan_id(span_name, chan_number); if(!term || !term->profile){ return SWITCH_STATUS_FALSE; @@ -2309,11 +2306,17 @@ switch_status_t mg_send_term_service_change(char* mg_profile_name,char *span_nam { case MG_TERM_SERVICE_STATE_IN_SERVICE: { + /* set INS flag...clear oos flag */ + switch_clear_flag(term, MG_OUT_OF_SERVICE); + switch_set_flag(term, MG_IN_SERVICE); ret = mg_send_ins_service_change(term->profile, term->name, 0x00 ); break; } case MG_TERM_SERVICE_STATE_OUT_OF_SERVICE: { + /* set OOS flag...clear ins flag */ + switch_clear_flag(term, MG_IN_SERVICE); + switch_set_flag(term, MG_OUT_OF_SERVICE); ret = mg_send_oos_service_change(term->profile, term->name, 0x00 ); break; } diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index 3e2ec81bdb..994b1a573a 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -164,8 +164,7 @@ void mg_util_set_err_string ( MgStr *errTxt, char* str); switch_status_t mg_build_sdp(MgMgcoMediaDesc* out, MgMgcoMediaDesc* inc, megaco_profile_t* mg_profile, mg_termination_t* term, CmMemListCp *memCp); switch_status_t mg_add_local_descriptor(MgMgcoMediaDesc* media, megaco_profile_t* mg_profile, mg_termination_t* term, CmMemListCp *memCp); -switch_status_t mg_send_term_service_change(char* mg_profile_name, char *span_name, char *chan_number, mg_term_states_e term_state); -mg_termination_t* megaco_find_termination_by_span_chan(megaco_profile_t *profile , char *span_name, char *chan_number); +switch_status_t mg_send_term_service_change(char *span_name, char *chan_number, mg_term_states_e term_state); switch_status_t sng_mgco_cfg(megaco_profile_t* profile); @@ -190,7 +189,8 @@ void mg_util_set_txn_string(MgStr *errTxt, U32 *txnId); switch_status_t mg_build_mgco_err_request(MgMgcoInd **errcmd,U32 trans_id, MgMgcoContextId *ctxt_id, U32 err, MgStr *errTxt); switch_status_t mg_send_audit_rsp(SuId suId, MgMgcoCommand *req); switch_status_t handle_mg_audit_cmd(SuId suId, MgMgcoCommand *auditReq); -switch_status_t mg_stack_termination_is_in_service(char* term_str, int len); +switch_status_t mg_stack_termination_is_in_service(megaco_profile_t* mg_profile, char* term_str, int len); +void mg_create_tdm_term(megaco_profile_t *profile, const char *tech, const char *channel_prefix, const char *prefix, int j); void mg_util_set_cmd_name_string (MgStr *errTxt, MgMgcoCommand *cmd); switch_status_t mgco_init_ins_service_change(SuId suId); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index f7e9dde544..c565da7e6b 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -80,10 +80,16 @@ switch_status_t mg_stack_free_mem(void* msg) /*****************************************************************************************************************************/ -/* TODO - Matt - to see if term is in service or not */ -switch_status_t mg_stack_termination_is_in_service(char* term_str,int len) +/* To see if term is in service or not */ +switch_status_t mg_stack_termination_is_in_service(megaco_profile_t* mg_profile, char* term_str,int len) { - return SWITCH_STATUS_SUCCESS; + mg_termination_t* term = NULL; + term = megaco_find_termination(mg_profile, term_str); + if(switch_test_flag(term, MG_IN_SERVICE)){ + return SWITCH_STATUS_SUCCESS; + } else { + return SWITCH_STATUS_FALSE; + } } /*****************************************************************************************************************************/ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index 6c87afa780..9890f152c3 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -65,62 +65,74 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) profile->idx = ++mg_sap_id; - - - if ((mg_phys_terms = switch_xml_child(mg_interface, "physical_terminations"))) { - for (mg_term = switch_xml_child(mg_phys_terms, "map"); mg_term; mg_term = mg_term->next) { - switch_memory_pool_t *pool; - mg_termination_t *term; - // - const char *prefix = switch_xml_attr(mg_term, "termination-id-prefix"); - //const char *sztermination_id_base = switch_xml_attr(mg_term, "termination-id-base"); - const char *tech = switch_xml_attr(mg_term, "tech"); - const char *channel_prefix = switch_xml_attr(mg_term, "channel-prefix"); - const char *channel_map = switch_xml_attr(mg_term, "channel-map"); - - - if (!zstr(channel_map)) { - /* Split channel-map */ - char *channel_map_dup = strdup(channel_map); - char *chanmap[24]; - int chanmap_count, i; - chanmap_count = switch_split(channel_map_dup, ',', chanmap); - for (i = 0; i < chanmap_count; i++) { - char *p = strchr(chanmap[i], '-'); - if (p) { - int startchan, endchan, j; - *p++ = '\0'; - startchan = atoi(chanmap[i]); - endchan = atoi(p); - - for (j = startchan; j < endchan; j++) { - switch_core_new_memory_pool(&pool); - term = switch_core_alloc(profile->pool, sizeof *term); - term->pool = pool; - term->type = MG_TERM_TDM; - term->profile = profile; - term->mg_ctxt = NULL; - term->tech = switch_core_strdup(pool, tech); - term->active_events = NULL; - term->name = switch_core_sprintf(pool, "%s%d", prefix, j); - term->u.tdm.channel = j; - term->u.tdm.span_name = switch_core_strdup(pool, channel_prefix); - - switch_core_hash_insert_wrlock(profile->terminations, term->name, term, profile->terminations_rwlock); - term->next = profile->physical_terminations; - profile->physical_terminations = term; - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Mapped termination [%s] to freetdm span: %s chan: %d\n", term->name, term->u.tdm.span_name, term->u.tdm.channel); - megaco_prepare_tdm_termination(term); - } - } - } - - free(channel_map_dup); - } - } - } + + if ((mg_phys_terms = switch_xml_child(mg_interface, "physical_terminations"))) { + for (mg_term = switch_xml_child(mg_phys_terms, "map"); mg_term; mg_term = mg_term->next) { + // + const char *prefix = switch_xml_attr(mg_term, "termination-id-prefix"); + //const char *sztermination_id_base = switch_xml_attr(mg_term, "termination-id-base"); + const char *tech = switch_xml_attr(mg_term, "tech"); + const char *channel_prefix = switch_xml_attr(mg_term, "channel-prefix"); + const char *channel_map = switch_xml_attr(mg_term, "channel-map"); + char *p = NULL; + + if (!zstr(channel_map)) { + /* Split channel-map */ + char *channel_map_dup = strdup(channel_map); + char *chanmap[24] = {0}; + int chanmap_count = 0; + int i = 0; + int startchan, endchan, j; + + /* we can have following combinations * + * i) only one channel i.e. channel-map="1" + * ii) only one chanel range i.e channel-map="1-15" + * iii) full channel range i.e. channel-map="1-15,17-31" + */ + + + chanmap_count = switch_split(channel_map_dup, ',', chanmap); + + if(1 == chanmap_count) { + p = strchr(channel_map_dup, '-'); + if(NULL != p){ + /* case (ii) */ + i = switch_split(channel_map_dup, '-', chanmap); + if(i && chanmap[0] && chanmap[1]) { + startchan = atoi(chanmap[0]); + endchan = atoi(chanmap[1]); + for (j = startchan; j < endchan; j++) { + mg_create_tdm_term(profile, tech, channel_prefix, prefix, j); + } + } + }else{ + /* case (i) */ + p = channel_map_dup; + startchan = endchan = atoi(p); + mg_create_tdm_term(profile, tech, channel_prefix, prefix, startchan); + } + }else + { + /* case (iii) */ + for (i = 0; i < chanmap_count; i++) { + p = strchr(chanmap[i], '-'); + if (p) { + *p++ = '\0'; + startchan = atoi(chanmap[i]); + endchan = atoi(p); + + for (j = startchan; j < endchan; j++) { + mg_create_tdm_term(profile, tech, channel_prefix, prefix, j); + } + } + } + } + + free(channel_map_dup); + } + } + } /* we should break from here , profile name should be unique */ @@ -129,7 +141,7 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) if (!mg_interface) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error profile %s not found\n", profile->name); - return SWITCH_STATUS_FALSE; + return SWITCH_STATUS_FALSE; } /* go through the peer configuration and get the mg profile associated peers only */ @@ -169,7 +181,7 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) } } } - + /* configure the MEGACO stack */ status = sng_mgco_cfg(profile); @@ -184,6 +196,34 @@ done: return status; } +/****************************************************************************************************************************/ +void mg_create_tdm_term(megaco_profile_t *profile, const char *tech, const char *channel_prefix, const char *prefix, int chan_num) +{ + mg_termination_t *term; + switch_memory_pool_t *pool; + + switch_core_new_memory_pool(&pool); + term = switch_core_alloc(profile->pool, sizeof *term); + term->pool = pool; + term->type = MG_TERM_TDM; + term->profile = profile; + term->mg_ctxt = NULL; + term->tech = switch_core_strdup(pool, tech); + term->active_events = NULL; + term->name = switch_core_sprintf(pool, "%s%d", prefix, chan_num); + term->u.tdm.channel = chan_num; + term->u.tdm.span_name = switch_core_strdup(pool, channel_prefix); + + switch_core_hash_insert_wrlock(profile->terminations, term->name, term, profile->terminations_rwlock); + term->next = profile->physical_terminations; + profile->physical_terminations = term; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + "Mapped termination [%s] to freetdm span: %s chan: %d\n", + term->name, term->u.tdm.span_name, term->u.tdm.channel); + megaco_prepare_tdm_termination(term); + +} /****************************************************************************************************************************/ switch_status_t mg_config_cleanup(megaco_profile_t* profile) { diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 97158fdcea..22c07275a8 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -64,38 +64,23 @@ static void mg_event_handler(switch_event_t *event) const char *span_name = NULL; const char *chan_number = NULL; const char *cond = NULL; - const char *mg_profile_name = NULL; - cond = switch_event_get_header(event, "condition"); if (zstr(cond)) { - printf("Condition NULL, returning \n"); return; } - mg_profile_name = switch_event_get_header(event, "mg-profile-name"); - if (zstr(mg_profile_name)) { - printf("mg_profile_name NULL, returning \n"); - return; - } - - span_name = switch_event_get_header(event, "span-name"); + span_name = switch_event_get_header(event, "span-name"); chan_number = switch_event_get_header(event, "chan-number"); if (!strcmp(cond, "ftdm-alarm-trap")) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, - "ftdm-alarm-trap for span_name[%s] chan_number[%s] associated with MG profile[%s]\n", - span_name,chan_number, mg_profile_name); - /* @KAPIL: TDM is in alarm, notify MGC */ - mg_send_term_service_change( - (char*)mg_profile_name, (char*)span_name, (char*)chan_number, MG_TERM_SERVICE_STATE_OUT_OF_SERVICE); + "ftdm-alarm-trap for span_name[%s] chan_number[%s]\n", span_name,chan_number); + mg_send_term_service_change((char*)span_name, (char*)chan_number, MG_TERM_SERVICE_STATE_OUT_OF_SERVICE); } else if (!strcmp(cond, "ftdm-alarm-clear")) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, - "ftdm-alarm-clear for span_name[%s] chan_number[%s] associated with MG profile[%s] \n", - span_name,chan_number, mg_profile_name); - /* TDM alarm cleared, notify MGC */ - mg_send_term_service_change( - (char*)mg_profile_name, (char*)span_name, (char*)chan_number, MG_TERM_SERVICE_STATE_IN_SERVICE); + "ftdm-alarm-clear for span_name[%s] chan_number[%s] \n", span_name,chan_number); + mg_send_term_service_change( (char*)span_name, (char*)chan_number, MG_TERM_SERVICE_STATE_IN_SERVICE); } } break; @@ -561,8 +546,9 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) } /*If term type is other then check if that term is configured with us..for term type CHOOSE/ALL , no need to check */ - if (MGT_TERMID_OTHER == termId->type.val){ - if(SWITCH_STATUS_FALSE == mg_stack_termination_is_in_service((char*)termId->name.lcl.val, termId->name.lcl.len)){ + if ((CH_CMD_TYPE_IND == cmd->cmdType.val) && + (MGT_TERMID_OTHER == termId->type.val)){ + if(SWITCH_STATUS_FALSE == mg_stack_termination_is_in_service(mg_profile, (char*)termId->name.lcl.val, termId->name.lcl.len)){ mg_util_set_term_string(&errTxt, termId); err_code = MGT_MGCO_RSP_CODE_UNKNOWN_TERM_ID; goto error; diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index 86acb28861..06cbffca11 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -89,8 +89,10 @@ typedef struct mg_context_s mg_context_t; typedef struct mg_termination_s mg_termination_t; enum { - MGT_ALLOCATED = (1 << 0), - MGT_ACTIVE = (1 << 1), + MGT_ALLOCATED = (1 << 0), + MGT_ACTIVE = (1 << 1), + MG_IN_SERVICE = (1 << 2), + MG_OUT_OF_SERVICE = (1 << 3), } mg_termination_flags; @@ -222,8 +224,10 @@ static inline megaco_codec_t megaco_codec_parse(const char *codec) { megaco_profile_t *megaco_profile_locate(const char *name); +mg_termination_t *megaco_term_locate_by_span_chan_id(const char *span_name, const char *chan_number); mg_peer_profile_t *megaco_peer_profile_locate(const char *name); void megaco_profile_release(megaco_profile_t *profile); +mg_termination_t* megaco_find_termination_by_span_chan(megaco_profile_t *profile, const char *span_name, const char *chan_number); switch_status_t megaco_profile_start(const char *profilename); switch_status_t megaco_profile_destroy(megaco_profile_t **profile); From 0c87442dd78fd3492aa4006b8a46fdb3bea2dfb0 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 30 Jul 2012 13:17:39 -0400 Subject: [PATCH 379/822] adding termination service states(in-service/out-of-service) flags and reject incoming megaco request if requested termination is not in service --- libs/freetdm/mod_freetdm/tdm.c | 5 +++++ .../mod_media_gateway/media_gateway.c | 3 ++- .../media_gateway_cmd_handler.c | 20 +++++++++++-------- .../mod_media_gateway/media_gateway_xml.c | 2 +- .../mod_media_gateway/mod_media_gateway.c | 1 + 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index 0cc02a85c7..22ffb5463e 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -128,6 +128,8 @@ static void ctdm_report_alarms(ftdm_channel_t *channel) switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "general"); } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Reporting [%s] alarms for %s:%d\n", + (alarmflag?"ftdm-alarm-clear":"ftdm-alarm-trap"), ftdm_channel_get_span_name(channel), ftdm_channel_get_id(channel)); switch_event_fire(&event); return; @@ -184,6 +186,9 @@ static void ctdm_event_handler(switch_event_t *event) return; } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Requesting alarm status for %s:%d\n", + ftdm_channel_get_span_name(channel), ftdm_channel_get_id(channel)); + ctdm_report_alarms(channel); } } diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 8beeedc3ca..dc789c3511 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -578,8 +578,9 @@ switch_status_t megaco_profile_start(const char *profilename) switch_core_new_memory_pool(&pool); profile = switch_core_alloc(pool, sizeof(*profile)); profile->pool = pool; + profile->physical_terminations = NULL; profile->name = switch_core_strdup(pool, profilename); - profile->next_context_id++; + profile->next_context_id++; profile->inact_tmr = 0x00; profile->inact_tmr_task_id = 0x00; diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index f392612cbb..5fa9d45663 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -2306,18 +2306,22 @@ switch_status_t mg_send_term_service_change(char *span_name, char *chan_number, { case MG_TERM_SERVICE_STATE_IN_SERVICE: { - /* set INS flag...clear oos flag */ - switch_clear_flag(term, MG_OUT_OF_SERVICE); - switch_set_flag(term, MG_IN_SERVICE); - ret = mg_send_ins_service_change(term->profile, term->name, 0x00 ); + if(switch_test_flag(term, MG_OUT_OF_SERVICE)){ + /* set INS flag...clear oos flag */ + switch_clear_flag(term, MG_OUT_OF_SERVICE); + switch_set_flag(term, MG_IN_SERVICE); + ret = mg_send_ins_service_change(term->profile, term->name, 0x00 ); + } break; } case MG_TERM_SERVICE_STATE_OUT_OF_SERVICE: { - /* set OOS flag...clear ins flag */ - switch_clear_flag(term, MG_IN_SERVICE); - switch_set_flag(term, MG_OUT_OF_SERVICE); - ret = mg_send_oos_service_change(term->profile, term->name, 0x00 ); + if(switch_test_flag(term, MG_IN_SERVICE)){ + /* set OOS flag...clear ins flag */ + switch_clear_flag(term, MG_IN_SERVICE); + switch_set_flag(term, MG_OUT_OF_SERVICE); + ret = mg_send_oos_service_change(term->profile, term->name, 0x00 ); + } break; } default: diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index 9890f152c3..98b46a9302 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -213,6 +213,7 @@ void mg_create_tdm_term(megaco_profile_t *profile, const char *tech, const char term->name = switch_core_sprintf(pool, "%s%d", prefix, chan_num); term->u.tdm.channel = chan_num; term->u.tdm.span_name = switch_core_strdup(pool, channel_prefix); + switch_set_flag(term, MG_OUT_OF_SERVICE); switch_core_hash_insert_wrlock(profile->terminations, term->name, term, profile->terminations_rwlock); term->next = profile->physical_terminations; @@ -222,7 +223,6 @@ void mg_create_tdm_term(megaco_profile_t *profile, const char *tech, const char "Mapped termination [%s] to freetdm span: %s chan: %d\n", term->name, term->u.tdm.span_name, term->u.tdm.channel); megaco_prepare_tdm_termination(term); - } /****************************************************************************************************************************/ switch_status_t mg_config_cleanup(megaco_profile_t* profile) diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 22c07275a8..95f9d3b2cb 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -549,6 +549,7 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) if ((CH_CMD_TYPE_IND == cmd->cmdType.val) && (MGT_TERMID_OTHER == termId->type.val)){ if(SWITCH_STATUS_FALSE == mg_stack_termination_is_in_service(mg_profile, (char*)termId->name.lcl.val, termId->name.lcl.len)){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Termination[%s] not in service \n", (char*)termId->name.lcl.val); mg_util_set_term_string(&errTxt, termId); err_code = MGT_MGCO_RSP_CODE_UNKNOWN_TERM_ID; goto error; From 3c8d14a2263e86be4d902547adb5a5a31dab8008 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Mon, 30 Jul 2012 13:36:36 -0400 Subject: [PATCH 380/822] Adding mod_media_gateway --- build/modules.conf.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/modules.conf.in b/build/modules.conf.in index 83986b996c..34ffb2121b 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -8,7 +8,7 @@ applications/mod_spandsp dialplans/mod_dialplan_xml endpoints/mod_sofia endpoints/mod_opal -#endpoints/mod_media_gateway +endpoints/mod_media_gateway ../../libs/freetdm/mod_freetdm xml_int/mod_xml_cdr event_handlers/mod_event_socket From 4fd24d6172f2c8a6c9ff5773ac59ba2e0e1074cf Mon Sep 17 00:00:00 2001 From: root Date: Mon, 30 Jul 2012 13:44:40 -0400 Subject: [PATCH 381/822] adding code to return Audit of termination state based on termination's state(in-service/oos) --- .../media_gateway_cmd_handler.c | 12 ++++++------ .../mod_media_gateway/media_gateway_stack.h | 4 ++-- .../mod_media_gateway/media_gateway_utils.c | 18 +++++++++++++++--- .../mod_media_gateway/mod_media_gateway.c | 6 ++++-- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 5fa9d45663..a1fd12b3df 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -1526,7 +1526,7 @@ switch_status_t mg_build_mgco_err_request(MgMgcoInd **errcmd,U32 trans_id, MgM /*****************************************************************************************************************************/ -switch_status_t handle_mg_audit_cmd( SuId suId, MgMgcoCommand *auditReq) +switch_status_t handle_mg_audit_cmd( megaco_profile_t* mg_profile, MgMgcoCommand *auditReq) { MgMgcoContextId *ctxtId; MgMgcoTermIdLst *term_list; @@ -1562,7 +1562,7 @@ switch_status_t handle_mg_audit_cmd( SuId suId, MgMgcoCommand *auditReq) if((NOTPRSNT == audit_desc->pres.pres) || ( NOTPRSNT == audit_desc->num.pres)){ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Audit Descriptor not present.. Could be HeartBeat message\n"); - return mg_send_heartbeat_audit_rsp(suId, auditReq); + return mg_send_heartbeat_audit_rsp(mg_profile->idx, auditReq); } /* dump AUDIT message information */ @@ -1682,7 +1682,7 @@ switch_status_t handle_mg_audit_cmd( SuId suId, MgMgcoCommand *auditReq) adtRep->u.other.audit.parms[numOfParms - 1]->type.pres = PRSNT_NODEF; adtRep->u.other.audit.parms[numOfParms - 1]->type.val = MGT_MEDIADESC; - media = get_default_media_desc(); + media = get_default_media_desc(mg_profile, termId); if(!media){ return SWITCH_STATUS_FALSE; } @@ -1780,7 +1780,7 @@ switch_status_t handle_mg_audit_cmd( SuId suId, MgMgcoCommand *auditReq) /* send command reply */ - sng_mgco_send_cmd(suId, &reply); + sng_mgco_send_cmd(mg_profile->idx, &reply); /* send indication to stack , so he can send response back to peer */ memcpy(&ctxt.transId,&auditReq->transId,sizeof(MgMgcoTransId)); @@ -1788,14 +1788,14 @@ switch_status_t handle_mg_audit_cmd( SuId suId, MgMgcoCommand *auditReq) memcpy(&ctxt.peerId, &auditReq->peerId,sizeof(TknU32)); ctxt.cmdStatus.pres = PRSNT_NODEF; ctxt.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; - sng_mgco_send_axn_req(suId, &ctxt); + sng_mgco_send_axn_req(mg_profile->idx, &ctxt); /***********************************************************************************************************************************/ return SWITCH_STATUS_SUCCESS; error: if (SWITCH_STATUS_SUCCESS == mg_build_mgco_err_request(&mgErr, auditReq->transId.val, ctxtId, err_code, &errTxt)) { - sng_mgco_send_err(suId, mgErr); + sng_mgco_send_err(mg_profile->idx, mgErr); } /* deallocate the msg */ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index 994b1a573a..4d79a96078 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -181,14 +181,14 @@ switch_status_t handle_mg_subtract_cmd(megaco_profile_t* mg_profile, MgMgcoComma switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *cmd); switch_status_t mg_stack_free_mem(void* msg); switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ); -MgMgcoMediaDesc* get_default_media_desc(void); +MgMgcoMediaDesc* get_default_media_desc(megaco_profile_t* mg_profile, MgMgcoTermId* termId); switch_status_t handle_media_audit( SuId suId, MgMgcoCommand *auditReq); switch_status_t mg_send_add_rsp(SuId suId, MgMgcoCommand *req); S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, char* term_str, int term_len, CmMemListCp *memCp); void mg_util_set_txn_string(MgStr *errTxt, U32 *txnId); switch_status_t mg_build_mgco_err_request(MgMgcoInd **errcmd,U32 trans_id, MgMgcoContextId *ctxt_id, U32 err, MgStr *errTxt); switch_status_t mg_send_audit_rsp(SuId suId, MgMgcoCommand *req); -switch_status_t handle_mg_audit_cmd(SuId suId, MgMgcoCommand *auditReq); +switch_status_t handle_mg_audit_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *auditReq); switch_status_t mg_stack_termination_is_in_service(megaco_profile_t* mg_profile, char* term_str, int len); void mg_create_tdm_term(megaco_profile_t *profile, const char *tech, const char *channel_prefix, const char *prefix, int j); void mg_util_set_cmd_name_string (MgStr *errTxt, MgMgcoCommand *cmd); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index c565da7e6b..b4b3663fa4 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -1214,7 +1214,7 @@ void mg_util_set_term_string ( MgStr *errTxt, MgMgcoTermId *termId) "info, error-text is: %s\n", __PRETTY_FUNCTION__,errTxt->val); } /*****************************************************************************************************************************/ -MgMgcoMediaDesc* get_default_media_desc() +MgMgcoMediaDesc* get_default_media_desc(megaco_profile_t* mg_profile, MgMgcoTermId* termId) { MgMgcoMediaDesc *media = NULL; MgMgcoMediaPar *mediaPar = NULL; @@ -1268,8 +1268,20 @@ MgMgcoMediaDesc* get_default_media_desc() trmStPar->type.pres = PRSNT_NODEF; trmStPar->type.val = MGT_TERMST_SVCST; trmStPar->u.svcState.pres = PRSNT_NODEF; - /*TODO - ADD CHECK if term is in svc or not */ - trmStPar->u.svcState.val = MGT_SVCST_INSVC; + + if ((NOTPRSNT != termId->type.pres) && + (MGT_TERMID_ROOT == termId->type.val)){ + trmStPar->u.svcState.val = MGT_SVCST_INSVC; + }else{ + /*not root termination */ + mg_termination_t* term = NULL; + term = megaco_find_termination(mg_profile, (char*)termId->name.lcl.val); + if(term && switch_test_flag(term, MG_OUT_OF_SERVICE)){ + trmStPar->u.svcState.val = MGT_SVCST_OUTOFSVC; + }else{ + trmStPar->u.svcState.val = MGT_SVCST_INSVC; + } + } mediaPar->u.tstate.trmStPar[0] = trmStPar; media->parms[0] = mediaPar; diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 95f9d3b2cb..d650ef7637 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -546,8 +546,10 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) } /*If term type is other then check if that term is configured with us..for term type CHOOSE/ALL , no need to check */ + /* check is only if command is not AUDIT */ if ((CH_CMD_TYPE_IND == cmd->cmdType.val) && - (MGT_TERMID_OTHER == termId->type.val)){ + (MGT_TERMID_OTHER == termId->type.val) && + (MGT_AUDITVAL != cmd->u.mgCmdInd[0]->cmd.type.val)){ if(SWITCH_STATUS_FALSE == mg_stack_termination_is_in_service(mg_profile, (char*)termId->name.lcl.val, termId->name.lcl.len)){ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Termination[%s] not in service \n", (char*)termId->name.lcl.val); mg_util_set_term_string(&errTxt, termId); @@ -643,7 +645,7 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) case MGT_AUDITVAL: { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received Audit-Value Method \n"); - handle_mg_audit_cmd(suId, cmd); + handle_mg_audit_cmd(mg_profile, cmd); break; } break; From 39b6233abb9260520adcc2dc4f85e54661322316 Mon Sep 17 00:00:00 2001 From: Kapil Date: Mon, 30 Jul 2012 16:00:15 -0400 Subject: [PATCH 382/822] adding T.38 required packages --- .../mod_media_gateway/media_gateway_packages.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_packages.c b/src/mod/endpoints/mod_media_gateway/media_gateway_packages.c index 0c6f17b0df..7d40a64b19 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_packages.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_packages.c @@ -123,6 +123,21 @@ MgPackage_t mg_pkg_list [] = 1, /* Version 1 */ "analog", /* Package name */ }, + { /* INDEX : 22 */ + MGT_PKG_FAX_TONE_DET, + 1, /* Version 1 */ + "ftmd", /* Package name */ + }, + { /* INDEX : 24 */ + MGT_PKG_CALL_TYP_DISCR, + 1, /* Version 1 */ + "ctype", /* Package name */ + }, + { /* INDEX : 25 */ + MGT_PKG_IP_FAX, + 1, /* Version 1 */ + "ipfax", /* Package name */ + }, /* Add more packages */ }; From 4423077a4e6406bac3d28a933ffdb606a5a1e862 Mon Sep 17 00:00:00 2001 From: Kapil Date: Mon, 30 Jul 2012 16:48:53 -0400 Subject: [PATCH 383/822] adding API to send T.38 CNG tone notify to MGC --- .../mod_media_gateway/media_gateway_cli.c | 30 +++++++++--- .../media_gateway_cmd_handler.c | 47 +++++++++++++++++++ .../mod_media_gateway/media_gateway_stack.h | 3 ++ 3 files changed, 73 insertions(+), 7 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c index e8cb79097b..080ca4b709 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c @@ -146,23 +146,39 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre } case 5: { - /* mg profile send ito notify */ if(zstr(argv[3])){ goto usage; } - if(strcasecmp(argv[3],"ito")){ + /*************************************************************************/ + if(!strcasecmp(argv[3],"ito")){ + /* mg profile send ito notify */ + + printf("Sending In-Activity NOTIFY \n"); + + megaco_profile_release(profile); + mg_send_ito_notify(profile); + /*************************************************************************/ + }else if(!strcasecmp(argv[3],"cng")){ + /*************************************************************************/ + /* mg profile send cng */ + + if(zstr(argv[4])){ + goto usage; + } + megaco_profile_release(profile); + mg_send_t38_cng_notify(profile, argv[4]); + + /*************************************************************************/ + }else { stream->write_function(stream, "-ERR wrong input \n"); goto usage; } - - printf("Sending In-Activity NOTIFY \n"); - - megaco_profile_release(profile); - mg_send_ito_notify(profile); + /*************************************************************************/ break; } + default: { goto usage; diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index a1fd12b3df..5a7786839b 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -2480,6 +2480,53 @@ switch_status_t mg_send_ito_notify(megaco_profile_t* mg_profile ) return mg_send_notify(mg_profile, "ROOT", oevt); } + +/*****************************************************************************************************************************/ +/* API to send T.38 CNG tone Notification */ + +switch_status_t mg_send_t38_cng_notify(megaco_profile_t* mg_profile, const char* term_name) +{ + MgMgcoObsEvt *oevt; + MgMgcoEvtPar* param; + + switch_assert(term_name); + switch_assert(mg_profile); + + mg_stack_alloc_mem((Ptr*)&oevt, sizeof(MgMgcoObsEvt)); + + oevt->pres.pres = PRSNT_NODEF; + + mg_get_time_stamp(&oevt->time); + + MG_INIT_TOKEN_VALUE(&(oevt->pkg.pkgType), MGT_PKG_KNOWN); + + MG_INIT_TOKEN_VALUE(&(oevt->pkg.valType), MGT_PKG_KNOWN); + + MG_INIT_TOKEN_VALUE(&(oevt->pkg.u.val), MGT_PKG_CALL_TYP_DISCR); + + MG_INIT_TOKEN_VALUE(&(oevt->name.type),MGT_GEN_TYPE_KNOWN); + + MG_INIT_TOKEN_VALUE(&(oevt->name.u.val),(U8)MGT_PKG_ENUM_OBSEVTOTHERCALLTYPDISCRDISCTONEDETDISCTONETYPCNG); + + if (mgUtlGrowList((void ***)&oevt->pl.parms, sizeof(MgMgcoEvtPar), &oevt->pl.num, NULL) != ROK) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + param = oevt->pl.parms[0]; + + MG_INIT_TOKEN_VALUE(&(param->type),(U8)MGT_EVTPAR_OTHER); + + MG_INIT_TOKEN_VALUE(&(param->u.other.name.type),MGT_GEN_TYPE_KNOWN); + MG_INIT_TOKEN_VALUE(&(param->u.other.name.u.val), MGT_PKG_ENUM_OBSEVTOTHERCALLTYPDISCRDISCTONEDETDISCTONETYP); + + MG_INIT_TOKEN_VALUE(&(param->u.other.val.type),MGT_VALUE_EQUAL); + MG_INIT_TOKEN_VALUE(&(param->u.other.val.u.eq.type),MGT_VALTYPE_ENUM); + MG_INIT_TOKEN_VALUE(&(param->u.other.val.u.eq.u.enume),MGT_PKG_ENUM_OBSEVTOTHERCALLTYPDISCRDISCTONEDETDISCTONETYPCNG); + + + return mg_send_notify(mg_profile, term_name, oevt); +} /*****************************************************************************************************************************/ /* API to send DTMF Digits Notification */ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index 4d79a96078..28ff0c2c03 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -167,6 +167,9 @@ switch_status_t mg_add_local_descriptor(MgMgcoMediaDesc* media, megaco_profile_t switch_status_t mg_send_term_service_change(char *span_name, char *chan_number, mg_term_states_e term_state); +switch_status_t mg_send_t38_cng_notify(megaco_profile_t* mg_profile, const char* term_name); + + switch_status_t sng_mgco_cfg(megaco_profile_t* profile); switch_status_t sng_mgco_init(sng_mg_event_interface_t* event); switch_status_t sng_mgco_stack_shutdown(void); From 7421bcfb3431ebe3c60b5e08e7482a598230b5c3 Mon Sep 17 00:00:00 2001 From: Kapil Date: Tue, 31 Jul 2012 09:26:46 -0400 Subject: [PATCH 384/822] adding safe check for term ptr --- src/mod/endpoints/mod_media_gateway/media_gateway_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index b4b3663fa4..1f883a6740 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -85,7 +85,7 @@ switch_status_t mg_stack_termination_is_in_service(megaco_profile_t* mg_profile, { mg_termination_t* term = NULL; term = megaco_find_termination(mg_profile, term_str); - if(switch_test_flag(term, MG_IN_SERVICE)){ + if(term && switch_test_flag(term, MG_IN_SERVICE)){ return SWITCH_STATUS_SUCCESS; } else { return SWITCH_STATUS_FALSE; From b9db9e44ff7469b89744e38f7f7740da27fdb8da Mon Sep 17 00:00:00 2001 From: root Date: Tue, 31 Jul 2012 13:45:08 -0400 Subject: [PATCH 385/822] fixing warnings --- src/mod/endpoints/mod_media_gateway/Makefile | 1 + src/mod/endpoints/mod_media_gateway/media_gateway.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_media_gateway/Makefile b/src/mod/endpoints/mod_media_gateway/Makefile index 66ad05c428..30b36a1b20 100644 --- a/src/mod/endpoints/mod_media_gateway/Makefile +++ b/src/mod/endpoints/mod_media_gateway/Makefile @@ -8,5 +8,6 @@ endif BASE=../../../.. LOCAL_OBJS=media_gateway.o media_gateway_stack.o media_gateway_xml.o media_gateway_cli.o media_gateway_stack_alarms.o media_gateway_cmd_handler.o media_gateway_utils.o media_gateway_packages.o +LOCAL_CFLAGS=-fno-strict-aliasing LOCAL_LDFLAGS=-lsng_mg include $(BASE)/build/modmake.rules diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index dc789c3511..10e4b1bd5a 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -480,7 +480,7 @@ mg_context_t *megaco_get_context(megaco_profile_t *profile, uint32_t context_id) /* Returns a fresh new context */ mg_context_t *megaco_choose_context(megaco_profile_t *profile) { - mg_context_t *ctx; + mg_context_t *ctx=NULL; switch_thread_rwlock_wrlock(profile->contexts_rwlock); /* Try the next one */ From 85bb06ba5640e81fbca1ff5e440e196b9d85f81a Mon Sep 17 00:00:00 2001 From: Kapil Date: Tue, 31 Jul 2012 15:07:44 -0400 Subject: [PATCH 386/822] adding code to parse signal descriptor for detecting T.38 CED/ANS signal request from MGC --- .../media_gateway_cmd_handler.c | 97 ++++++++++++++++++- .../mod_media_gateway/media_gateway_utils.c | 2 +- 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 5a7786839b..c6ec61e430 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -187,6 +187,58 @@ switch_status_t mg_is_ito_pkg_req(megaco_profile_t* mg_profile, MgMgcoCommand *c return SWITCH_STATUS_SUCCESS; } +/*****************************************************************************************************************************/ +switch_status_t mg_prc_sig_desc(MgMgcoSignalsReq* req, megaco_profile_t* mg_profile, mg_termination_t* term) +{ + MgMgcoSigPar *p = NULL; + MgMgcoSigOther* o = NULL; + int sig = 0x00; + + switch_assert(req); + switch_assert(mg_profile); + switch_assert(term); + + + /* As of now only checking T.38 CED tone */ + + /* Modify message will have following signal descriptor * + * Signals{ctyp/ANS{anstype=ans}} * + */ + + /* check for T.38 CED tone package i.e. MGT_PKG_CALL_TYP_DISCR */ + if((MGT_PKG_KNOWN == req->pkg.valType.val) && + (NOTPRSNT != req->pkg.u.val.pres) && + (MGT_PKG_CALL_TYP_DISCR == req->pkg.u.val.val) && + (NOTPRSNT != req->name.type.pres) && + (MGT_GEN_TYPE_KNOWN == req->name.type.val)) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"Received Signal Descriptor : T.38 ctyp package\n"); + + if((NOTPRSNT != req->pl.num.pres) && (NOTPRSNT != req->pl.num.val)){ + for(sig = 0x00; sig < req->pl.num.val; sig++){ + p = req->pl.parms[sig]; + + if(NOTPRSNT == p->type.pres) continue; + + if((MGT_SIGPAR_OTHER == p->type.val) && + (NULL != (o = &p->u.other)) && + (NOTPRSNT != o->name.type.pres) && + (MGT_GEN_TYPE_KNOWN == o->name.type.val) && + (MGT_PKG_ENUM_SIGOTHERCALLTYPDISCRANSSIGANSTYP == o->name.u.val.val) && + (MGT_VALUE_EQUAL == o->val.type.val) && + (NOTPRSNT != o->val.u.eq.type.pres) && + (MGT_VALTYPE_ENUM == o->val.u.eq.type.val) && + (MGT_PKG_ENUM_SIGOTHERCALLTYPDISCRANSSIGANSTYPANS == o->val.u.eq.u.enume.val)){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"Signal Descriptor : T.38 CED/ANS TONE \n"); + /* apply CED/ANS tone to specify channel */ + } + } + } + } + + + return SWITCH_STATUS_SUCCESS; +} /*****************************************************************************************************************************/ @@ -313,7 +365,7 @@ switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand * remote = &mediaPar->u.remote; sdp = remote->sdp.info[0]; /* for Matt - same like local descriptor */ - mgco_handle_incoming_sdp(&remote->sdp, term, MG_SDP_REMOTE, mg_profile, memCp); + mgco_handle_incoming_sdp(&remote->sdp, term, MG_SDP_REMOTE, mg_profile, memCp); break; } @@ -453,7 +505,50 @@ switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand * } case MGT_SIGNALSDESC: { + MgMgcoSignalsDesc* sig = &desc->dl.descs[descId]->u.sig; + MgMgcoSignalsParm* param = NULL; + int i = 0x00; switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," Requested Signal descriptor\n"); + + if((NOTPRSNT != sig->pres.pres) && (NOTPRSNT != sig->num.pres) && (0 != sig->num.val)){ + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Total number of Signal descriptors[%d]\n", sig->num.val); + + for(i=0; i< sig->num.val; i++){ + param = sig->parms[i]; + + if(NOTPRSNT == param->type.pres) continue; + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Signal Descriptor[%d] type[%s]\n", + i, ((MGT_SIGSPAR_LST == param->type.val)?"MGT_SIGSPAR_LST":"MGT_SIGSPAR_REQ")); + + switch(param->type.val) + { + case MGT_SIGSPAR_LST: + { + MgMgcoSignalsLst* lst = ¶m->u.lst; + int sigId = 0x00; + + if((NOTPRSNT == lst->pl.num.pres) || (0 == lst->pl.num.val)) break; + + for(sigId = 0; sigId < lst->pl.num.val; sigId++){ + mg_prc_sig_desc(lst->pl.reqs[sigId], mg_profile, term); + } + + break; + } + case MGT_SIGSPAR_REQ: + { + MgMgcoSignalsReq* req = ¶m->u.req; + mg_prc_sig_desc(req, mg_profile, term); + break; + } + default: + break; + } + } + } + break; } case MGT_MODEMDESC: diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index 1f883a6740..cb57668e04 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -2017,4 +2017,4 @@ switch_status_t mg_build_sdp(MgMgcoMediaDesc* out, MgMgcoMediaDesc* inc, megaco_ } return SWITCH_STATUS_SUCCESS; } - +/*****************************************************************************************************************************/ From b4b7be7a8363355e4fbfc0aa75dedc0e9de54e73 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 1 Aug 2012 12:14:52 -0400 Subject: [PATCH 387/822] fix leak --- src/mod/endpoints/mod_media_gateway/media_gateway_utils.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index cb57668e04..8063c68289 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -802,6 +802,7 @@ const char* mg_get_codec_name(megaco_profile_t* mg_profile, int iana_code) char *codec_prefs[16] = { 0 }; char *szcodec_prefs; int codec_count; + const char *name = NULL; szcodec_prefs = strdup(mg_profile->codec_prefs); codec_count = switch_split(szcodec_prefs, ',', codec_prefs); @@ -811,11 +812,12 @@ const char* mg_get_codec_name(megaco_profile_t* mg_profile, int iana_code) /* see if received codec is present in our codec supported list */ for (i = 0; codecs[i] && i < codec_count; i++) { if(iana_code == codecs[i]->ianacode){ - return codecs[i]->iananame; + name = codecs[i]->iananame; + break; } } - return NULL; + return name; } void mgco_handle_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sdp_types_e sdp_type, megaco_profile_t* mg_profile, CmSdpAttrSet *attrSet, CmMemListCp *memCp) From d96687a35224213082fcd05e425794b804c44017 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 1 Aug 2012 13:18:37 -0400 Subject: [PATCH 388/822] Fix for TDM termination alarms --- libs/freetdm/mod_freetdm/tdm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index 22ffb5463e..7b04d9f67f 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -104,9 +104,9 @@ static void ctdm_report_alarms(ftdm_channel_t *channel) switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", ftdm_channel_get_id(channel)); if (alarmflag) { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-clear"); - } else { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-trap"); + } else { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-clear"); } if (alarmflag & FTDM_ALARM_RED) { From 61f0237670474be05c5b8d97fbe874b09cf77721 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 1 Aug 2012 13:21:47 -0400 Subject: [PATCH 389/822] print modification --- libs/freetdm/mod_freetdm/tdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index 7b04d9f67f..af39c655f0 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -129,7 +129,7 @@ static void ctdm_report_alarms(ftdm_channel_t *channel) } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Reporting [%s] alarms for %s:%d\n", - (alarmflag?"ftdm-alarm-clear":"ftdm-alarm-trap"), ftdm_channel_get_span_name(channel), ftdm_channel_get_id(channel)); + (alarmflag?"ftdm-alarm-trap":"ftdm-alarm-clear"), ftdm_channel_get_span_name(channel), ftdm_channel_get_id(channel)); switch_event_fire(&event); return; From e718b3a8faf1ca95d7fec73c0f12a940db442bf8 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Fri, 3 Aug 2012 05:27:21 -0400 Subject: [PATCH 390/822] fixing issue - shouldnt check rtp termination service state --- src/mod/endpoints/mod_media_gateway/media_gateway_utils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index 8063c68289..2431e01fa3 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -85,7 +85,8 @@ switch_status_t mg_stack_termination_is_in_service(megaco_profile_t* mg_profile, { mg_termination_t* term = NULL; term = megaco_find_termination(mg_profile, term_str); - if(term && switch_test_flag(term, MG_IN_SERVICE)){ + if(term && (MG_TERM_TDM == term->type) && + switch_test_flag(term, MG_IN_SERVICE)){ return SWITCH_STATUS_SUCCESS; } else { return SWITCH_STATUS_FALSE; From 34000bf18837707b2cdc4347f42cd585a636682a Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Fri, 3 Aug 2012 12:07:02 -0400 Subject: [PATCH 391/822] adding "interface-identifier" field to configuration --- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c | 2 +- .../src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h | 1 + .../ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c | 7 +++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c index 5b173bfc8b..810c5a2902 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c @@ -1039,7 +1039,7 @@ static int ftmod_m2ua_dlsap_config(int id) cfg.t.cfg.s.dlSapCfg.lnkNmb = id; /* SapId */ cfg.t.cfg.s.dlSapCfg.intfId.type = LMW_INTFID_INT; - cfg.t.cfg.s.dlSapCfg.intfId.id.intId = id; + cfg.t.cfg.s.dlSapCfg.intfId.id.intId = m2ua->iid; cfg.t.cfg.s.dlSapCfg.swtch = LMW_SAP_ITU; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h index c7ce2e74eb..8bb564d284 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h @@ -59,6 +59,7 @@ typedef struct sng_m2ua_cfg{ char name[MAX_NAME_LEN]; uint32_t flags; uint32_t id; /* ID */ + uint32_t iid; /* ID */ uint8_t nodeType; /*Node Type SG/ASP */ uint8_t end_point_opened; /* flag to check is end-point already opened */ uint16_t clusterId; /* idx to m2ua_cluster profile */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c index b9ae986402..bb011c364e 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c @@ -242,6 +242,12 @@ static int ftmod_ss7_parse_m2ua_interface(ftdm_conf_node_t *m2ua_interface) SS7_DEBUG("Found an m2ua cluster_id = %d\n", sng_m2ua.clusterId); /**********************************************************************/ + } else if (!strcasecmp(parm->var, "interface-identifier")) { + /**********************************************************************/ + sng_m2ua.iid=atoi(parm->val); + + SS7_DEBUG("Found an m2ua interface-identifier = %d\n", sng_m2ua.iid); + /**********************************************************************/ } else { /**********************************************************************/ SS7_ERROR("Found an invalid parameter %s!\n", parm->var); @@ -271,6 +277,7 @@ static int ftmod_ss7_fill_in_m2ua_interface(sng_m2ua_cfg_t *m2ua_iface) g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].id = m2ua_iface->id; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].nodeType = m2ua_iface->nodeType; g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].clusterId = m2ua_iface->clusterId; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].iid = m2ua_iface->iid; sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_M2UA_PRESENT); return 0; From f92b66eae081835252d729d33542ba6692fc58b4 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 3 Aug 2012 12:48:54 -0400 Subject: [PATCH 392/822] added mod_distributor --- build/modules.conf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/build/modules.conf.in b/build/modules.conf.in index 1d27aaad1b..1284bb8bc1 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -5,6 +5,7 @@ applications/mod_dptools applications/mod_commands applications/mod_hash applications/mod_spandsp +applications/mod_distributor dialplans/mod_dialplan_xml endpoints/mod_sofia ../../libs/freetdm/mod_freetdm From 2c6245b0f7b8b8c781e16c52f1805b4498d16e93 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Sat, 4 Aug 2012 10:37:25 -0400 Subject: [PATCH 393/822] debug prints modification --- .../mod_media_gateway/media_gateway_cmd_handler.c | 10 ++++------ .../endpoints/mod_media_gateway/mod_media_gateway.c | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index c6ec61e430..42a77aba67 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -688,7 +688,7 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i } else { switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Termination[%s] already in context..rejecting ADD \n", term->name); mg_util_set_err_string(&errTxt, " Term already is in call "); - err_code = MGT_MGCP_RSP_CODE_PROT_ERROR; + err_code = MGT_MGCO_RSP_CODE_DUP_TERM_CTXT; goto error; } @@ -1545,11 +1545,11 @@ switch_status_t mg_send_end_of_axn(SuId suId, MgMgcoTransId* transId, MgMgcoCont ctxt.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; #ifdef BIT_64 - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "mg_send_end_of_axn: Sending END_OF_AXN for transId[%d], peerId[%d], context[type = %s, value = %d]\n", transId->val, peerId->val, PRNT_MG_CTXT_TYPE(ctxtId->type.val), ctxtId->val.val); #else - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "mg_send_end_of_axn: Sending END_OF_AXN for transId[%lu], peerId[%lu], context[type = %s, value = %lu]\n", transId->val, peerId->val, PRNT_MG_CTXT_TYPE(ctxtId->type.val), ctxtId->val.val); @@ -1646,8 +1646,6 @@ switch_status_t handle_mg_audit_cmd( megaco_profile_t* mg_profile, MgMgcoCommand audit = &auditReq->u.mgCmdReq[0]->cmd.u.aval; wild = auditReq->u.mgCmdReq[0]->wild.pres; - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"%s :: wild card request = %s \n",__FUNCTION__,(1==wild)?"TRUE":"FALSE"); - if(NOTPRSNT == audit->pres.pres){ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Audit structure not present..rejecting \n"); return SWITCH_STATUS_FALSE; @@ -1656,7 +1654,7 @@ switch_status_t handle_mg_audit_cmd( megaco_profile_t* mg_profile, MgMgcoCommand audit_desc = &audit->audit; if((NOTPRSNT == audit_desc->pres.pres) || ( NOTPRSNT == audit_desc->num.pres)){ - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Audit Descriptor not present.. Could be HeartBeat message\n"); + //switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Audit Descriptor not present.. Could be HeartBeat message\n"); return mg_send_heartbeat_audit_rsp(mg_profile->idx, auditReq); } diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index d650ef7637..1cecbda181 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -523,7 +523,7 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) termId = termLst->terms[0]; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Termination-Id received..value[%s] type[%d] \n", termId->name.lcl.val, termId->type.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Termination-Id received..value[%s] type[%d] \n", termId->name.lcl.val, termId->type.val); /* Not sure - IF Stack fills term type properly..but adding code just to be sure ...*/ if ((PRSNT_NODEF == termId->type.pres) && From 7b7256b55f76c16184a60d8179d6b29254d78926 Mon Sep 17 00:00:00 2001 From: Kapil Date: Mon, 6 Aug 2012 10:20:02 -0400 Subject: [PATCH 394/822] fixing issues --- libs/freetdm/mod_freetdm/tdm.c | 2 +- libs/freetdm/src/ftdm_io.c | 135 ++++++++++++++++++ libs/freetdm/src/include/freetdm.h | 2 + .../media_gateway_cmd_handler.c | 6 +- .../mod_media_gateway/media_gateway_xml.c | 4 +- 5 files changed, 144 insertions(+), 5 deletions(-) diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index af39c655f0..7f44b640a9 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -327,7 +327,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi channel = switch_core_session_get_channel(*new_session); - if (ftdm_channel_open(span_id, chan_id, &chan) != FTDM_SUCCESS) { + if (ftdm_raw_channel_open(span_id, chan_id, &chan) != FTDM_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't open span or channel.\n"); goto fail; } diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 4e110df659..6bc5471e5a 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -1892,6 +1892,130 @@ done: return status; } +static ftdm_status_t _ftdm_raw_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan) +{ + ftdm_channel_t *check = NULL; + ftdm_span_t *span = NULL; + ftdm_channel_t *best_rated = NULL; + ftdm_status_t status = FTDM_FAIL; + int best_rate = 0; + + *ftdmchan = NULL; + + ftdm_mutex_lock(globals.mutex); + + ftdm_span_find(span_id, &span); + + if (!span) { + ftdm_log(FTDM_LOG_CRIT, "Could not find span!\n"); + goto done; + } + + if (!ftdm_test_flag(span, FTDM_SPAN_CONFIGURED)) { + ftdm_log(FTDM_LOG_CRIT, "Span %d is not configured\n", span_id); + goto done; + } + + if (span->channel_request) { + ftdm_log(FTDM_LOG_ERROR, "Individual channel selection not implemented on this span.\n"); + goto done; + } + + if (chan_id < 1 || chan_id > span->chan_count) { + ftdm_log(FTDM_LOG_ERROR, "Invalid channel %d to open in span %d\n", chan_id, span_id); + goto done; + } + + if (!(check = span->channels[chan_id])) { + ftdm_log(FTDM_LOG_CRIT, "Wow, no channel %d in span %d\n", chan_id, span_id); + goto done; + } + + ftdm_channel_lock(check); + + if (ftdm_test_flag(check, FTDM_CHANNEL_OPEN)) { + /* let them know is already open, but return the channel anyway */ + status = FTDM_EBUSY; + *ftdmchan = check; + goto unlockchan; + } + + /* The following if's and gotos replace a big if (this || this || this || this) else { nothing; } */ + + /* if it is not a voice channel, nothing else to check to open it */ + if (!FTDM_IS_VOICE_CHANNEL(check)) { + goto openchan; + } + + /* if it's an FXS device with a call active and has callwaiting enabled, we allow to open it twice */ + if (check->type == FTDM_CHAN_TYPE_FXS + && check->token_count == 1 + && ftdm_channel_test_feature(check, FTDM_CHANNEL_FEATURE_CALLWAITING)) { + goto openchan; + } + + /* chan_is_avail API without signaling check */ + if (check->span->signal_type == FTDM_SIGTYPE_NONE) { + if (!ftdm_test_flag(check, FTDM_CHANNEL_READY) || + ftdm_test_flag(check, FTDM_CHANNEL_INUSE) || + ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) || + ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) || + check->state != FTDM_CHANNEL_STATE_DOWN) { + + ftdm_log(FTDM_LOG_ERROR, "channel %d not available to open in span %d\n", chan_id, span_id); + goto done; + } + } else if (!ftdm_test_flag(check, FTDM_CHANNEL_READY) || + ftdm_test_flag(check, FTDM_CHANNEL_INUSE) || + ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) || + ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) || + check->state != FTDM_CHANNEL_STATE_DOWN) { + ftdm_log(FTDM_LOG_ERROR, "channel %d not available to open in span %d\n", chan_id, span_id); + goto done; + }else { + /* channel is ready to open */ + ftdm_log(FTDM_LOG_INFO, "channel %d available to open in span %d\n", chan_id, span_id); + goto openchan; + } + + + /* not available, but still might be available ... */ + calculate_best_rate(check, &best_rated, &best_rate); + if (best_rated) { + goto openchan; + } + + /* channel is unavailable, do not open the channel */ + goto unlockchan; + +openchan: + if (!ftdm_test_flag(check, FTDM_CHANNEL_OPEN)) { + status = check->fio->open(check); + if (status == FTDM_SUCCESS) { + ftdm_set_flag(check, FTDM_CHANNEL_OPEN); + } + } else { + status = FTDM_SUCCESS; + } + ftdm_set_flag(check, FTDM_CHANNEL_INUSE); + ftdm_set_flag(check, FTDM_CHANNEL_OUTBOUND); + *ftdmchan = check; + + /* we've got the channel, do not unlock it */ + goto done; + +unlockchan: + ftdm_channel_unlock(check); + +done: + ftdm_mutex_unlock(globals.mutex); + if (status != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "Failed to open channel %d:%d\n", span_id, chan_id); + } + + return status; +} + static ftdm_status_t _ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan) { ftdm_channel_t *check = NULL; @@ -2007,6 +2131,17 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, return status; } +FT_DECLARE(ftdm_status_t) ftdm_raw_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan) +{ + ftdm_status_t status; + status = _ftdm_raw_channel_open(span_id, chan_id, ftdmchan); + if (status == FTDM_SUCCESS) { + ftdm_channel_t *fchan = *ftdmchan; + ftdm_channel_unlock(fchan); + } + return status; +} + FT_DECLARE(uint32_t) ftdm_channel_get_id(const ftdm_channel_t *ftdmchan) { return ftdmchan->chan_id; diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index e041e1f0e7..b875388ad8 100755 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -1374,6 +1374,8 @@ FT_DECLARE(uint32_t) ftdm_group_get_id(const ftdm_group_t *group); */ FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan); +FT_DECLARE(ftdm_status_t) ftdm_raw_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan); + /*! * \brief Hunts and opens a channel specifying the span id only * diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 42a77aba67..5d087298ea 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -1374,8 +1374,10 @@ switch_status_t handle_mg_subtract_cmd(megaco_profile_t* mg_profile, MgMgcoComma megaco_context_sub_termination(mg_ctxt, term); } - /* release context*/ - megaco_release_context(mg_ctxt); + if ((NULL == mg_ctxt->terminations[0]) && (NULL == mg_ctxt->terminations[1])) { + /* release context*/ + megaco_release_context(mg_ctxt); + } } /************************************************************************************************************************************************************/ diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index 98b46a9302..44c716152a 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -102,7 +102,7 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) if(i && chanmap[0] && chanmap[1]) { startchan = atoi(chanmap[0]); endchan = atoi(chanmap[1]); - for (j = startchan; j < endchan; j++) { + for (j = startchan; j <= endchan; j++) { mg_create_tdm_term(profile, tech, channel_prefix, prefix, j); } } @@ -122,7 +122,7 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) startchan = atoi(chanmap[i]); endchan = atoi(p); - for (j = startchan; j < endchan; j++) { + for (j = startchan; j <= endchan; j++) { mg_create_tdm_term(profile, tech, channel_prefix, prefix, j); } } From 57ca2bbe8d890711066aabeb3207dec7d02e5c15 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Mon, 6 Aug 2012 10:44:34 -0400 Subject: [PATCH 395/822] fixing term state issue --- src/mod/endpoints/mod_media_gateway/media_gateway_utils.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index 2431e01fa3..297fe72c69 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -85,7 +85,10 @@ switch_status_t mg_stack_termination_is_in_service(megaco_profile_t* mg_profile, { mg_termination_t* term = NULL; term = megaco_find_termination(mg_profile, term_str); - if(term && (MG_TERM_TDM == term->type) && + + if(term && MG_TERM_RTP == term->type) { + return SWITCH_STATUS_SUCCESS; + }else if(term && (MG_TERM_TDM == term->type) && switch_test_flag(term, MG_IN_SERVICE)){ return SWITCH_STATUS_SUCCESS; } else { From 80b9a587db5464243df11baeee45cc8ee6d5e773 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Mon, 6 Aug 2012 12:19:34 -0400 Subject: [PATCH 396/822] adding code to start mg profile during load itself. --- .../mod_media_gateway/media_gateway.c | 2 +- .../media_gateway_cmd_handler.c | 17 ++ .../mod_media_gateway/media_gateway_utils.c | 197 +++++++++--------- .../mod_media_gateway/mod_media_gateway.c | 109 +++++++--- .../mod_media_gateway/mod_media_gateway.h | 1 + 5 files changed, 200 insertions(+), 126 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 10e4b1bd5a..20e72d1c18 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -63,7 +63,7 @@ megaco_profile_t* megaco_get_profile_by_suId(SuId suId) switch_hash_this(hi, &var, NULL, &val); profile = (megaco_profile_t *) val; if (profile->idx == suId) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got profile[%s] associated with suId[%d]\n",profile->name, suId); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Got profile[%s] associated with suId[%d]\n",profile->name, suId); found = 0x01; break; } diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 5d087298ea..61896ce9b9 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -1179,6 +1179,23 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand goto error; } + if(MG_TERM_RTP == term->type){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"MODIFY REQUEST - Updated RTP attributes:" + " local_addr[%s] local_port[%d] remote_addr[%s], remote_port[%d], ptime[%d] pt[%d], " + " rfc2833_pt[%d] rate[%d], codec[%s], term_id[%d]\n", + ((NULL != term->u.rtp.local_addr)?term->u.rtp.local_addr:NULL), + term->u.rtp.local_port, + ((NULL != term->u.rtp.remote_addr)?term->u.rtp.remote_addr:NULL), + term->u.rtp.remote_port, + term->u.rtp.ptime, + term->u.rtp.pt, + term->u.rtp.rfc2833_pt, + term->u.rtp.rate, + ((NULL != term->u.rtp.codec)?term->u.rtp.codec:NULL), + term->u.rtp.term_id); + } + + /* SDP updated to termination */ megaco_activate_termination(term); } diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index 297fe72c69..e622038ee6 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -129,7 +129,7 @@ S16 mg_fill_mgco_termid ( MgMgcoTermId *termId, char* term_str, int term_len, C strncpy((char*)(termId->name.lcl.val), term_str, termId->name.lcl.len); termId->name.lcl.val[termId->name.lcl.len] = '\0'; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,"mg_fill_mgco_termid: name.lcl.val[%s], len[%d], term_str[%s], term_len[%d]\n",termId->name.lcl.val, termId->name.lcl.len, term_str,term_len); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"mg_fill_mgco_termid: name.lcl.val[%s], len[%d], term_str[%s], term_len[%d]\n",termId->name.lcl.val, termId->name.lcl.len, term_str,term_len); } @@ -242,7 +242,7 @@ MgMgcoTermIdLst *mg_get_term_id_list(MgMgcoCommand *cmd) break; default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); break; } break; @@ -295,12 +295,12 @@ MgMgcoTermIdLst *mg_get_term_id_list(MgMgcoCommand *cmd) break; default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); } /* switch command type for reply */ break; default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported api_type[%s]!\n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(api_type)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: failed, Unsupported api_type[%s]!\n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(api_type)); break; } /* switch -api_type */ @@ -327,7 +327,7 @@ void mg_util_set_txn_string(MgStr *errTxt, U32 *txnId) errTxt->val[errTxt->len] = '\"'; errTxt->len += 1; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s:" + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s:" "info, error-text is: %s\n", __PRETTY_FUNCTION__,errTxt->val); } @@ -376,7 +376,7 @@ void mg_util_set_ctxt_string ( MgStr *errTxt, MgMgcoContextId *ctxtId) errTxt->val[errTxt->len] = '\"'; errTxt->len += 1; } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s:" + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s:" "info, error-text is: %s\n", __PRETTY_FUNCTION__,errTxt->val); } @@ -422,7 +422,7 @@ void mg_util_set_cmd_name_string (MgStr *errTxt, MgMgcoCommand *cmd) break; default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: Not expected command Type[%d]\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: Not expected command Type[%d]\n", __PRETTY_FUNCTION__,cmd->u.mgCmdInd[0]->cmd.type.val); break; @@ -441,7 +441,7 @@ void mgco_handle_sdp_attr_set(CmSdpAttrSet *s, mg_termination_t* term) if(NOTPRSNT == a->type.pres) continue; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Attribute Type[%d]\n",a->type.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Attribute Type[%d]\n",a->type.val); switch(a->type.val) { @@ -465,30 +465,31 @@ void mgco_handle_sdp_attr_set(CmSdpAttrSet *s, mg_termination_t* term) case CM_SDP_ATTR_PTIME: { #ifdef BIT_64 - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t PTIME = %d \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t PTIME = %d \n", (NOTPRSNT != a->u.ptime.pres)?a->u.ptime.val:-1); #else - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t PTIME = %ld \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t PTIME = %ld \n", (NOTPRSNT != a->u.ptime.pres)?a->u.ptime.val:-1); #endif if(MG_TERM_RTP == term->type){ term->u.rtp.ptime = a->u.ptime.val; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"Updating ptime to [%d]\n", term->u.rtp.ptime); } break; } case CM_SDP_ATTR_RECVONLY: { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_ATTR_RECVONLY: \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t CM_SDP_ATTR_RECVONLY: \n"); break; } case CM_SDP_ATTR_SENDRECV: { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_ATTR_SENDRECV: \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t CM_SDP_ATTR_SENDRECV: \n"); break; } case CM_SDP_ATTR_SENDONLY: { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_ATTR_SENDONLY: \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t CM_SDP_ATTR_SENDONLY: \n"); break; } case CM_SDP_ATTR_ORIENT: @@ -497,7 +498,7 @@ void mgco_handle_sdp_attr_set(CmSdpAttrSet *s, mg_termination_t* term) } case CM_SDP_ATTR_TYPE: { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_ATTR_TYPE: \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t CM_SDP_ATTR_TYPE: \n"); break; } case CM_SDP_ATTR_CHARSET: @@ -525,50 +526,50 @@ void mgco_handle_sdp_attr_set(CmSdpAttrSet *s, mg_termination_t* term) case CM_SDP_ATTR_FMTP: { CmSdpAttrFmtp* f = &a->u.fmtp; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_ATTR_FMTP: \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t CM_SDP_ATTR_FMTP: \n"); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Format Type = %d \n",(NOTPRSNT == f->type.pres)?f->type.val:-1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Format Type = %d \n",(NOTPRSNT == f->type.pres)?f->type.val:-1); break; } case CM_SDP_ATTR_RTPMAP: { CmSdpAttrRtpMap* r = &a->u.rtpmap; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_ATTR_RTPMAP: \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t CM_SDP_ATTR_RTPMAP: \n"); if(NOTPRSNT != r->pres.pres){ /* payload type */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Payload Type = %d \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Payload Type = %d \n", (NOTPRSNT != r->pay.type.pres)?r->pay.type.val:-1); /* payload value */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Payload Value = %d \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Payload Value = %d \n", (NOTPRSNT != r->pay.val.pres)?r->pay.val.val:-1); /* encoding name */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Encoding Name value = %d \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Encoding Name value = %d \n", (NOTPRSNT != r->enc.val.pres)?r->enc.val.val:-1); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Encoding Name name = %s \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Encoding Name name = %s \n", (NOTPRSNT != r->enc.name.pres)?(char*)r->enc.name.val:"Not Present"); #ifdef BIT_64 - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Clock Rate = %d \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Clock Rate = %d \n", (NOTPRSNT != r->clk.pres)?r->clk.val:-1); #else - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Clock Rate = %ld \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Clock Rate = %ld \n", (NOTPRSNT != r->clk.pres)?r->clk.val:-1); #endif - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Encoding Parameters = %s \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Encoding Parameters = %s \n", (NOTPRSNT != r->parms.pres)?(char*)r->parms.val:"Not Present"); } break; } case CM_SDP_ATTR_INACTIVE: { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_ATTR_INACTIVE: \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t CM_SDP_ATTR_INACTIVE: \n"); break; } case CM_SDP_ATTR_CONTROL: @@ -740,12 +741,12 @@ void mgco_handle_sdp_attr_set(CmSdpAttrSet *s, mg_termination_t* term) break; } default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Not supported Type[%d]\n",a->type.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Not supported Type[%d]\n",a->type.val); break; } } }else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "a-line not present \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "a-line not present \n"); } @@ -756,12 +757,12 @@ void mgco_handle_sdp_c_line(CmSdpConn *s, mg_termination_t* term, mgco_sdp_types char ipadd[32]; memset(ipadd, 0, sizeof(ipadd)); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "********** SDP connection line ****** \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "********** SDP connection line ****** \n"); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Net Type = %d \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Net Type = %d \n", (NOTPRSNT != s->netType.type.pres)?s->netType.type.val:-1); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Address Type = %d \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Address Type = %d \n", (NOTPRSNT != s->addrType.pres)?s->addrType.val:-1); if (s->addrType.pres && s->addrType.val == CM_SDP_ADDR_TYPE_IPV4 && @@ -769,7 +770,7 @@ void mgco_handle_sdp_c_line(CmSdpConn *s, mg_termination_t* term, mgco_sdp_types s->u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) { if (s->u.ip4.addrType.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Address: %d.%d.%d.%d\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Address: %d.%d.%d.%d\n", s->u.ip4.u.uniIp.b[0].val, s->u.ip4.u.uniIp.b[1].val, s->u.ip4.u.uniIp.b[2].val, @@ -784,19 +785,19 @@ void mgco_handle_sdp_c_line(CmSdpConn *s, mg_termination_t* term, mgco_sdp_types /* update remote ip */ if(MG_TERM_RTP == term->type){ term->u.rtp.remote_addr = switch_core_strdup(term->pool,ipadd); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,"Update remote ip to [%s]\n", term->u.rtp.remote_addr); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"Update remote ip to [%s]\n", term->u.rtp.remote_addr); } } } } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "**************** \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "**************** \n"); } void mgco_print_CmSdpU8OrNil(CmSdpU8OrNil* p) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,"CmSdpU8OrNil: Type = %d \n", (NOTPRSNT != p->type.pres)?p->type.val:-1); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,"CmSdpU8OrNil: Value = %d \n", (NOTPRSNT != p->val.pres)?p->val.val:-1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"CmSdpU8OrNil: Type = %d \n", (NOTPRSNT != p->type.pres)?p->type.val:-1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"CmSdpU8OrNil: Value = %d \n", (NOTPRSNT != p->val.pres)?p->val.val:-1); } const char* mg_get_codec_name(megaco_profile_t* mg_profile, int iana_code) @@ -827,32 +828,32 @@ const char* mg_get_codec_name(megaco_profile_t* mg_profile, int iana_code) void mgco_handle_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sdp_types_e sdp_type, megaco_profile_t* mg_profile, CmSdpAttrSet *attrSet, CmMemListCp *memCp) { int i=0x00; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "***** Media Parameter *********** \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "***** Media Parameter *********** \n"); if (s->numProtFmts.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Media Formats = %d \n", s->numProtFmts.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Media Formats = %d \n", s->numProtFmts.val); for (i = 0; i < s->numProtFmts.val; i++) { CmSdpMedProtoFmts *a = s->pflst[i]; /*Prot*/ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " Proto Type = %d \n", (NOTPRSNT != a->prot.type.pres)?a->prot.type.val:-1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " Proto Type = %d \n", (NOTPRSNT != a->prot.type.pres)?a->prot.type.val:-1); switch(a->prot.type.val) { case CM_SDP_MEDIA_PROTO_UNKNOWN: { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " Proto Type Unknown , name = %s \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " Proto Type Unknown , name = %s \n", (NOTPRSNT != a->prot.u.name.pres)?(char*)a->prot.u.name.val:"Not Present "); break; } case CM_SDP_MEDIA_PROTO_RTP: { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " Proto Type RTP , subtype = %d \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " Proto Type RTP , subtype = %d \n", (NOTPRSNT != a->prot.u.subtype.type.pres)?a->prot.u.subtype.type.val: -1); break; } } /*repeated from "prot" field */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " Proto Type = %d \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " Proto Type = %d \n", (NOTPRSNT != a->protType.pres)?a->protType.val: -1); switch(a->protType.val) @@ -861,17 +862,17 @@ void mgco_handle_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sd { CmSdpMedFmtRtpList* r = &a->u.rtp; int i = 0x00; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " CM_SDP_MEDIA_PROTO_RTP: \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " CM_SDP_MEDIA_PROTO_RTP: \n"); if(NOTPRSNT != r->num.pres){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " Number of Formats[%d] \n", r->num.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " Number of Formats[%d] \n", r->num.val); for(i=0;inum.val;i++){ mgco_print_CmSdpU8OrNil(r->fmts[i]); if(MG_RTP_AVP_PROFILE_A_LAW == r->fmts[i]->val.val){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " MG_RTP_AVP_PROFILE_A_LAW: \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " MG_RTP_AVP_PROFILE_A_LAW: \n"); }else if(MG_RTP_AVP_PROFILE_U_LAW == r->fmts[i]->val.val){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " MG_RTP_AVP_PROFILE_U_LAW: \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " MG_RTP_AVP_PROFILE_U_LAW: \n"); } } } @@ -884,11 +885,13 @@ void mgco_handle_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sd if((NOTPRSNT != r->num.pres) && (0 != r->num.val) && (NULL != r->fmts[0])){ const char* name = mg_get_codec_name(mg_profile, r->fmts[0]->val.val); if(name){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " Updating codec to[%d], name[%s] \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " Updating codec to[%d], name[%s] \n", r->fmts[0]->val.val, name); if(MG_TERM_RTP == term->type){ term->u.rtp.codec = name; term->u.rtp.pt = r->fmts[0]->val.val; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"Updating pt to [%d]\n", + term->u.rtp.pt); } }else{ /* ERROR */ @@ -902,7 +905,7 @@ void mgco_handle_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sd case CM_SDP_UDPTL_FMT_T38: { /*CmSdpMedFmtUdptlList* t = &a->u.t38;*/ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " CM_SDP_UDPTL_FMT_T38: \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " CM_SDP_UDPTL_FMT_T38: \n"); break; } default: @@ -910,15 +913,20 @@ void mgco_handle_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sd } } } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "**************** \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "**************** \n"); } void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sdp_types_e sdp_type, megaco_profile_t* mg_profile, CmMemListCp *memCp) { int i; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + " Parsing %s SDP for Term[%s] \n", + (MG_SDP_LOCAL== sdp_type)?"MG_SDP_LOCAL":"MG_SDP_REMOTE", + (MG_TERM_RTP == term->type)?"MG_TERM_RTP":"MG_TERM_TDM"); if (sdp->numComp.pres == NOTPRSNT) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " No %s SDP present \n", (MG_SDP_LOCAL== sdp_type)?"MG_SDP_LOCAL":"MG_SDP_REMOTE"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + " No %s SDP present \n", (MG_SDP_LOCAL== sdp_type)?"MG_SDP_LOCAL":"MG_SDP_REMOTE"); return; } @@ -933,29 +941,29 @@ void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sd /************************************************************************************************************************/ /* Version */ if(NOTPRSNT != s->ver.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, " SDP Version = %d \n", s->ver.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " SDP Version = %d \n", s->ver.val); } /************************************************************************************************************************/ /* Orig */ if(NOTPRSNT != s->orig.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "********** SDP orig line ****** \n \t Type = %d \n", s->orig.type.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "********** SDP orig line ****** \n \t Type = %d \n", s->orig.type.val); if(NOTPRSNT != s->orig.orig.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t User Name = %s \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t User Name = %s \n", (NOTPRSNT != s->orig.orig.usrName.pres)?(char*)s->orig.orig.usrName.val:"Not Present"); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Id = %s \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Session Id = %s \n", (NOTPRSNT != s->orig.orig.sessId.pres)?(char*)s->orig.orig.sessId.val:"Not Present"); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Version = %s \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Session Version = %s \n", (NOTPRSNT != s->orig.orig.sessVer.pres)?(char*)s->orig.orig.sessVer.val:"Not Present"); /* sdpAddr */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Net Type = %d \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Net Type = %d \n", (NOTPRSNT != s->orig.orig.sdpAddr.netType.type.pres)?s->orig.orig.sdpAddr.netType.type.val:-1); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Address Type = %d \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Address Type = %d \n", (NOTPRSNT != s->orig.orig.sdpAddr.addrType.pres)?s->orig.orig.sdpAddr.addrType.val:-1); /* print IPV4 address */ @@ -964,7 +972,7 @@ void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sd s->orig.orig.sdpAddr.u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) { if (s->orig.orig.sdpAddr.u.ip4.addrType.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Address: %d.%d.%d.%d\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Address: %d.%d.%d.%d\n", s->orig.orig.sdpAddr.u.ip4.u.ip.b[0].val, s->orig.orig.sdpAddr.u.ip4.u.ip.b[1].val, s->orig.orig.sdpAddr.u.ip4.u.ip.b[2].val, @@ -972,38 +980,38 @@ void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sd } }else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t O-line not present \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t O-line not present \n"); } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "********** ****** \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "********** ****** \n"); } } else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t O-line not present \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t O-line not present \n"); } /************************************************************************************************************************/ /* Session Name (s = line) */ if(NOTPRSNT != s->sessName.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Name = %s \n", s->sessName.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Session Name = %s \n", s->sessName.val); } else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t s-line not present \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t s-line not present \n"); } /************************************************************************************************************************/ /* Session Info(i= line) */ if(NOTPRSNT != s->info.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Info = %s \n", s->info.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Session Info = %s \n", s->info.val); } else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t i-line not present \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t i-line not present \n"); } /************************************************************************************************************************/ /* Session Uri */ if(NOTPRSNT != s->uri.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Session Uri = %s \n", s->uri.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Session Uri = %s \n", s->uri.val); } else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t uri not present \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t uri not present \n"); } /************************************************************************************************************************/ @@ -1027,54 +1035,54 @@ void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sd /************************************************************************************************************************/ /* SDP Time (t= line)*/ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "*** t-line **************** \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "*** t-line **************** \n"); if(NOTPRSNT != s->sdpTime.pres.pres) { if(NOTPRSNT != s->sdpTime.sdpOpTimeSet.numComp.pres) { int i = 0x00; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "SDP op time present with total component[%d]\n", s->sdpTime.sdpOpTimeSet.numComp.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SDP op time present with total component[%d]\n", s->sdpTime.sdpOpTimeSet.numComp.val); for (i = 0;isdpTime.sdpOpTimeSet.numComp.val;i++){ CmSdpOpTime* t = s->sdpTime.sdpOpTimeSet.sdpOpTime[i]; if(NOTPRSNT == t->pres.pres) continue; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Start Time = %s \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Start Time = %s \n", (NOTPRSNT != t->startTime.pres)?(char*)t->startTime.val:"Not Present"); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Stop Time = %s \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Stop Time = %s \n", (NOTPRSNT != t->stopTime.pres)?(char*)t->stopTime.val:"Not Present"); /*repeat time repFieldSet */ if(NOTPRSNT != t->repFieldSet.numComp.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "SDP repeat time present with total component[%d]\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SDP repeat time present with total component[%d]\n", t->repFieldSet.numComp.val); /*TODO - print repeat fields */ }else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "SDP repeat time not present \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SDP repeat time not present \n"); } } /* sdpOpTimeSet.numComp for loop -- end */ }else{/*sdpOpTimeSet.numComp.pres if -- end */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "SDP op time not present \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SDP op time not present \n"); } /*TODO - zoneAdjSet */ }else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "t-line not present \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "t-line not present \n"); } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "**************** \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "**************** \n"); /************************************************************************************************************************/ /* key type (k= line)*/ if(NOTPRSNT != s->keyType.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Key Type = %d \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Key Type = %d \n", (NOTPRSNT != s->keyType.keyType.pres)?s->keyType.keyType.val:-1); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Key Data = %s \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Key Data = %s \n", (NOTPRSNT != s->keyType.key_data.pres)?(char*)s->keyType.key_data.val:"Not Present"); }else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "k-line not present \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "k-line not present \n"); } /************************************************************************************************************************/ @@ -1086,7 +1094,7 @@ void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sd /* Media Descriptor Set */ if (s->mediaDescSet.numComp.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "****** Media Descriptor Set present with numComp[%d]\n", s->mediaDescSet.numComp.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "****** Media Descriptor Set present with numComp[%d]\n", s->mediaDescSet.numComp.val); for (mediaId = 0; mediaId < s->mediaDescSet.numComp.val; mediaId++) { CmSdpMediaDesc *desc = s->mediaDescSet.mediaDesc[mediaId]; @@ -1095,36 +1103,37 @@ void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sd /* Media Field */ { CmSdpMediaField* f = &desc->field; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Media Type = %d \n",(NOTPRSNT == f->mediaType.pres)?f->mediaType.val:-1); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Media = %s \n",(NOTPRSNT == f->media.pres)?(char*)f->media.val:"Not Present"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Media Type = %d \n",(NOTPRSNT != f->mediaType.pres)?f->mediaType.val:-1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Media = %s \n",(NOTPRSNT != f->media.pres)?(char*)f->media.val:"Not Present"); /* Channel ID */ if(NOTPRSNT != f->id.type.pres){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t VcId Type = %d \n", f->id.type.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t VcId Type = %d \n", f->id.type.val); switch(f->id.type.val){ case CM_SDP_VCID_PORT: { CmSdpPort *p = &f->id.u.port; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "CM_SDP_VCID_PORT:\n"); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t SDP port type = %d \n", (NOTPRSNT == p->type.pres)?p->type.val:-1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CM_SDP_VCID_PORT:\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t SDP port type = %d \n", (NOTPRSNT != p->type.pres)?p->type.val:-1); switch(p->type.val) { case CM_SDP_PORT_INT: { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t CM_SDP_PORT_INT: SDP port = %d type = %d \n", p->u.portInt.port.val.val, p->u.portInt.port.type.val); if(MG_SDP_REMOTE == sdp_type) { /* update remote information */ if(MG_TERM_RTP == term->type){ - term->u.rtp.remote_port = p->u.portInt.port.val.val; - printf("Update remote port to [%d]\n", term->u.rtp.remote_port); + term->u.rtp.remote_port + = p->u.portInt.port.val.val; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"Updating remote port to [%d]\n", term->u.rtp.remote_port); } } break; } case CM_SDP_PORT_VPCID: { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t CM_SDP_PORT_VPCID: \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t CM_SDP_PORT_VPCID: \n"); break; } default: @@ -1140,17 +1149,17 @@ void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sd } /*info */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Info = %s \n",(NOTPRSNT == desc->info.pres)?(char*)desc->info.val:"Not Present"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Info = %s \n",(NOTPRSNT != desc->info.pres)?(char*)desc->info.val:"Not Present"); /*connection set */ { int cnt=0x00; if(NOTPRSNT != desc->connSet.numComp.pres){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\t Number of Connection component[%d]\n",desc->connSet.numComp.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Number of Connection component[%d]\n",desc->connSet.numComp.val); for(cnt=0;cntconnSet.numComp.val;cnt++){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "************************\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "************************\n"); mgco_handle_sdp_c_line(desc->connSet.connSet[cnt], term, sdp_type); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "************************\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "************************\n"); } } } @@ -1165,7 +1174,7 @@ void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sd desc->field.id.u.port.u.portInt.port.type.val == CM_SDP_SPEC) { int port = desc->field.id.u.port.u.portInt.port.val.val; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Port: %d\n", port); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Port: %d\n", port); } } } @@ -1216,7 +1225,7 @@ void mg_util_set_term_string ( MgStr *errTxt, MgMgcoTermId *termId) errTxt->len += 1; } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s:" + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s:" "info, error-text is: %s\n", __PRETTY_FUNCTION__,errTxt->val); } /*****************************************************************************************************************************/ diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 1cecbda181..698efc0798 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -92,20 +92,20 @@ static void mg_event_handler(switch_event_t *event) SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load) { switch_api_interface_t *api_interface; - + memset(&megaco_globals, 0, sizeof(megaco_globals)); megaco_globals.pool = pool; - + *module_interface = switch_loadable_module_create_module_interface(pool, modname); - + switch_core_hash_init(&megaco_globals.profile_hash, pool); switch_thread_rwlock_create(&megaco_globals.profile_rwlock, pool); switch_core_hash_init(&megaco_globals.peer_profile_hash, pool); switch_thread_rwlock_create(&megaco_globals.peer_profile_rwlock, pool); - + SWITCH_ADD_API(api_interface, "mg", "media_gateway", megaco_function, MEGACO_FUNCTION_SYNTAX); - + switch_console_set_complete("add mg profile ::mg::list_profiles start"); switch_console_set_complete("add mg profile ::mg::list_profiles stop"); switch_console_set_complete("add mg profile ::mg::list_profiles status"); @@ -131,7 +131,15 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load) switch_event_bind("mod_media_gateway", SWITCH_EVENT_TRAP, SWITCH_EVENT_SUBCLASS_ANY, mg_event_handler, NULL); /* initualize MEGACO stack */ - return sng_mgco_init(&sng_event); + if(SWITCH_STATUS_FALSE == sng_mgco_init(&sng_event)){ + return SWITCH_STATUS_FALSE; + } + + if(SWITCH_STATUS_FALSE == megaco_start_all_profiles()){ + return SWITCH_STATUS_FALSE; + } + + return SWITCH_STATUS_SUCCESS; } SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_media_gateway_shutdown) @@ -172,6 +180,44 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_media_gateway_shutdown) return SWITCH_STATUS_SUCCESS; } +/*****************************************************************************************************************************/ +switch_status_t megaco_start_all_profiles() +{ + switch_xml_t cfg, xml, mg_interfaces, mg_interface ; + switch_status_t status = SWITCH_STATUS_FALSE; + const char *file = "media_gateway.conf"; + + if (!(xml = switch_xml_open_cfg(file, &cfg, NULL))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not open %s\n", file); + status = SWITCH_STATUS_FALSE; + goto done; + } + + if (!(mg_interfaces = switch_xml_child(cfg, "mg_profiles"))) { + status = SWITCH_STATUS_FALSE; + goto done; + } + + for (mg_interface = switch_xml_child(mg_interfaces, "mg_profile"); mg_interface; mg_interface = mg_interface->next) { + const char *name = switch_xml_attr_soft(mg_interface, "name"); + + if(SWITCH_STATUS_FALSE == megaco_profile_start(name)){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error starting MEGACO profile %s\n", name); + status = SWITCH_STATUS_FALSE; + goto done; + } + } + + status = SWITCH_STATUS_SUCCESS; + +done: + if (xml) { + switch_xml_free(xml); + } + + return status; +} + /*****************************************************************************************************************************/ void handle_sng_log(uint8_t level, char *fmt, ...) { @@ -230,7 +276,7 @@ static switch_status_t mgco_parse_local_sdp(mg_termination_t *term, CmSdpInfoSet s->conn.u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) { if (s->conn.u.ip4.addrType.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Local address: %d.%d.%d.%d\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Local address: %d.%d.%d.%d\n", s->conn.u.ip4.u.uniIp.b[0].val, s->conn.u.ip4.u.uniIp.b[1].val, s->conn.u.ip4.u.uniIp.b[2].val, @@ -244,7 +290,7 @@ static switch_status_t mgco_parse_local_sdp(mg_termination_t *term, CmSdpInfoSet CmSdpAttr *a = s->attrSet.attr[mediaId]; local_sdp->info[i]->attrSet.attr[mediaId] = switch_core_alloc(term->context->pool, sizeof(CmSdpAttr)); *(local_sdp->info[i]->attrSet.attr[mediaId]) = *a; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Media %p\n", (void*)a); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Media %p\n", (void*)a); } } @@ -260,7 +306,7 @@ static switch_status_t mgco_parse_local_sdp(mg_termination_t *term, CmSdpInfoSet desc->field.id.u.port.u.portInt.port.type.val == CM_SDP_SPEC) { int port = desc->field.id.u.port.u.portInt.port.val.val; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Port: %d\n", port); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Port: %d\n", port); } } @@ -363,23 +409,23 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) switch (mediaPar->type.val) { case MGT_MEDIAPAR_LOCAL: { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCAL"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "MGT_MEDIAPAR_LOCAL"); break; } case MGT_MEDIAPAR_REMOTE: { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_REMOTE"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "MGT_MEDIAPAR_REMOTE"); break; } case MGT_MEDIAPAR_LOCCTL: { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_LOCCTL"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "MGT_MEDIAPAR_LOCCTL"); break; } case MGT_MEDIAPAR_TERMST: { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "MGT_MEDIAPAR_TERMST"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "MGT_MEDIAPAR_TERMST"); break; } case MGT_MEDIAPAR_STRPAR: @@ -480,7 +526,8 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) inc_context = &cmd->contextId; memcpy(&out_ctxt, inc_context,sizeof(MgMgcoContextId)); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: Received Command Type[%s] \n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(cmd->cmdType.val)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "%s: Received Command Type[%s] \n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(cmd->cmdType.val)); /*get mg profile associated with SuId */ if(NULL == (mg_profile = megaco_get_profile_by_suId(suId))){ @@ -494,7 +541,7 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) if (NOTPRSNT != cmd->transId.pres){ txn_id = cmd->transId.val; } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: Transaction Id not present, rejecting\n", __PRETTY_FUNCTION__); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s: Transaction Id not present, rejecting\n", __PRETTY_FUNCTION__); /*-- Send Error to MG Stack --*/ MG_ZERO(&ctxtId, sizeof(MgMgcoContextId)); @@ -523,7 +570,6 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) termId = termLst->terms[0]; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Termination-Id received..value[%s] type[%d] \n", termId->name.lcl.val, termId->type.val); /* Not sure - IF Stack fills term type properly..but adding code just to be sure ...*/ if ((PRSNT_NODEF == termId->type.pres) && @@ -545,6 +591,9 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) } } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "Termination-Id received..value[%s] type[%d] \n", termId->name.lcl.val, termId->type.val); + /*If term type is other then check if that term is configured with us..for term type CHOOSE/ALL , no need to check */ /* check is only if command is not AUDIT */ if ((CH_CMD_TYPE_IND == cmd->cmdType.val) && @@ -592,7 +641,7 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) { case CH_CMD_TYPE_IND: { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: Received Command indication for command[%s]\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: Received Command indication for command[%s]\n", __PRETTY_FUNCTION__,PRNT_MG_CMD(cmd->u.mgCmdInd[0]->cmd.type.val)); switch(cmd->u.mgCmdInd[0]->cmd.type.val) @@ -644,7 +693,6 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) } case MGT_AUDITVAL: { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received Audit-Value Method \n"); handle_mg_audit_cmd(mg_profile, cmd); break; } @@ -664,10 +712,10 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) case CH_CMD_TYPE_CFM: { #ifdef BIT_64 - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Received Command[%s] txn[%d] Response/Confirmation \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Received Command[%s] txn[%d] Response/Confirmation \n", PRNT_MG_CMD(cmd->u.mgCmdCfm[0]->type.val), txn_id); #else - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Received Command[%s] txn[%ld] Response/Confirmation \n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Received Command[%s] txn[%ld] Response/Confirmation \n", PRNT_MG_CMD(cmd->u.mgCmdCfm[0]->type.val), txn_id); #endif switch(cmd->u.mgCmdCfm[0]->type.val) @@ -706,12 +754,12 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) if(NOTPRSNT != ntfy->pres.pres){ if((NOTPRSNT != ntfy->err.pres.pres) && (NOTPRSNT != ntfy->err.code.pres)){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Received NOTIFY command response with ErroCode[%d] for Termination[%s] \n", ntfy->err.code.val, &term_name[0]); } else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Received Successful NOTIFY command response for Termination[%s] \n", &term_name[0]); } } @@ -753,12 +801,12 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) if((NOTPRSNT != svc->res.type.pres) && (MGT_ERRDESC == svc->res.type.val)){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Received Service-Change command response with ErroCode[%d] for Termination[%s] \n", svc->res.u.err.code.val, &term_name[0]); } else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Received Successful Service-Change command response for Termination[%s] \n", &term_name[0]); } } @@ -772,14 +820,13 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) } default: #ifdef BIT_64 - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Invalid command type[%d]\n",cmd->cmdType.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Invalid command type[%d]\n",cmd->cmdType.val); #else - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Invalid command type[%d]\n",cmd->cmdType.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Invalid command type[%d]\n",cmd->cmdType.val); #endif return; } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "cmd->cmdStatus.val[%d]\n",cmd->cmdStatus.val); /* END OF TXN received - means last command in txn to process. * Send response to peer */ if(CH_CMD_TYPE_IND == cmd->cmdType.val){ @@ -808,7 +855,7 @@ error1: /*****************************************************************************************************************************/ void handle_mgco_sta_ind(Pst *pst, SuId suId, MgMgtSta* sta) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s\n", __PRETTY_FUNCTION__); /*TODO*/ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s\n", __PRETTY_FUNCTION__); /*TODO*/ } /*****************************************************************************************************************************/ @@ -816,7 +863,7 @@ void handle_mgco_sta_ind(Pst *pst, SuId suId, MgMgtSta* sta) void handle_mgco_txn_sta_ind(Pst *pst, SuId suId, MgMgcoInd* txn_sta_ind) { /*TODO*/ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s\n", __PRETTY_FUNCTION__); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s\n", __PRETTY_FUNCTION__); /*dump information*/ mgAccEvntPrntMgMgcoInd(txn_sta_ind, stdout); @@ -826,14 +873,14 @@ void handle_mgco_txn_sta_ind(Pst *pst, SuId suId, MgMgcoInd* txn_sta_ind) void handle_mgco_cntrl_cfm(Pst *pst, SuId suId, MgMgtCntrl* cntrl, Reason reason) { /*TODO*/ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s\n", __PRETTY_FUNCTION__); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s\n", __PRETTY_FUNCTION__); } /*****************************************************************************************************************************/ void handle_mgco_audit_cfm(Pst *pst, SuId suId, MgMgtAudit* audit, Reason reason) { /*TODO*/ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s\n", __PRETTY_FUNCTION__); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s\n", __PRETTY_FUNCTION__); } diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index 06cbffca11..36bcf5146f 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -229,6 +229,7 @@ mg_peer_profile_t *megaco_peer_profile_locate(const char *name); void megaco_profile_release(megaco_profile_t *profile); mg_termination_t* megaco_find_termination_by_span_chan(megaco_profile_t *profile, const char *span_name, const char *chan_number); +switch_status_t megaco_start_all_profiles(void); switch_status_t megaco_profile_start(const char *profilename); switch_status_t megaco_profile_destroy(megaco_profile_t **profile); From f7ca7ebb71c28870d71e153c22b6d81933912858 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Tue, 7 Aug 2012 05:49:07 -0400 Subject: [PATCH 397/822] adding CLI command to dump termination status --- .../mod_media_gateway/media_gateway_cli.c | 244 ++++++++++++------ 1 file changed, 170 insertions(+), 74 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c index 080ca4b709..a714c6bd15 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c @@ -15,7 +15,9 @@ switch_status_t megaco_profile_status(switch_stream_handle_t *stream, megaco_profile_t* mg_cfg); switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, megaco_profile_t* mg_cfg); switch_status_t megaco_profile_peer_xmlstatus(switch_stream_handle_t *stream, megaco_profile_t* mg_cfg); +switch_status_t handle_term_status_cli_cmd(switch_stream_handle_t *stream, megaco_profile_t* mg_profile, char* term_id); void get_peer_xml_buffer(char* prntBuf, MgPeerSta* cfm); +void megaco_cli_print_usage(switch_stream_handle_t *stream); /******************************************************************************/ @@ -68,6 +70,7 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre } else { stream->write_function(stream, "-ERR No such profile\n"); } + /**********************************************************************************/ }else if(!strcmp(argv[2], "status")) { /**********************************************************************************/ @@ -98,95 +101,105 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre /**********************************************************************************/ }else if(!strcmp(argv[2], "send")) { /**********************************************************************************/ - printf("count = %d \n",argc); + if (profile) { + switch(argc) + { + case 7: + { + /* mg profile send sc */ + if(zstr(argv[3]) || zstr(argv[4]) || zstr(argv[5]) || zstr(argv[6])){ + goto usage; + } - if (profile) { + if(!zstr(argv[7]) && !strcasecmp(argv[7],"wild")){ + wild = 0x01; + } - switch(argc) - { - case 7: - { - /* mg profile send sc */ - printf("ARGC = 7 \n"); - if(zstr(argv[3]) || zstr(argv[4]) || zstr(argv[5]) || zstr(argv[6])){ - goto usage; - } + printf("Input to Send Service Change command : " + "Profile Name[%s], term-id[%s] method[%s] reason[%s] \n", + profile->name, argv[4], argv[5], argv[6]); - if(!zstr(argv[7]) && !strcasecmp(argv[7],"wild")){ - wild = 0x01; - } + megaco_profile_release(profile); + mg_send_service_change(profile->idx, argv[4], atoi(argv[5]), atoi(argv[6]),wild); - printf("Input to Send Service Change command : " - "Profile Name[%s], term-id[%s] method[%s] reason[%s] \n", - profile->name, argv[4], argv[5], argv[6]); + break; + } + case 6: + { + /* mg profile send notify */ + if(zstr(argv[3]) || zstr(argv[4]) || zstr(argv[5])){ + goto usage; + } - megaco_profile_release(profile); - mg_send_service_change(profile->idx, argv[4], atoi(argv[5]), atoi(argv[6]),wild); + if(strcasecmp(argv[3],"notify")){ + stream->write_function(stream, "-ERR wrong input \n"); + goto usage; + } - break; - } - case 6: - { - /* mg profile send notify */ - if(zstr(argv[3]) || zstr(argv[4]) || zstr(argv[5])){ - goto usage; - } + printf("Sending DTMF digits[%s] NOTIFY for termination[%s]\n", argv[5], argv[4]); - if(strcasecmp(argv[3],"notify")){ - stream->write_function(stream, "-ERR wrong input \n"); - goto usage; - } + megaco_profile_release(profile); + mg_send_dtmf_notify(profile, argv[4], (char*)argv[5], (int)strlen(argv[5])); - printf("Sending DTMF digits[%s] NOTIFY for termination[%s]\n", argv[5], argv[4]); + break; + } + case 5: + { + if(zstr(argv[3])){ + goto usage; + } - megaco_profile_release(profile); - mg_send_dtmf_notify(profile, argv[4], (char*)argv[5], (int)strlen(argv[5])); + /*************************************************************************/ + if(!strcasecmp(argv[3],"ito")){ + /* mg profile send ito notify */ - break; - } - case 5: - { - if(zstr(argv[3])){ - goto usage; - } + printf("Sending In-Activity NOTIFY \n"); - /*************************************************************************/ - if(!strcasecmp(argv[3],"ito")){ - /* mg profile send ito notify */ + megaco_profile_release(profile); + mg_send_ito_notify(profile); + /*************************************************************************/ + }else if(!strcasecmp(argv[3],"cng")){ + /*************************************************************************/ + /* mg profile send cng */ - printf("Sending In-Activity NOTIFY \n"); + if(zstr(argv[4])){ + goto usage; + } + megaco_profile_release(profile); + mg_send_t38_cng_notify(profile, argv[4]); - megaco_profile_release(profile); - mg_send_ito_notify(profile); - /*************************************************************************/ - }else if(!strcasecmp(argv[3],"cng")){ - /*************************************************************************/ - /* mg profile send cng */ + /*************************************************************************/ + }else { + stream->write_function(stream, "-ERR wrong input \n"); + goto usage; + } + /*************************************************************************/ - if(zstr(argv[4])){ - goto usage; - } - megaco_profile_release(profile); - mg_send_t38_cng_notify(profile, argv[4]); - - /*************************************************************************/ - }else { - stream->write_function(stream, "-ERR wrong input \n"); - goto usage; - } - /*************************************************************************/ + break; + } + + default: + { + goto usage; + } + } + }else{ + stream->write_function(stream, "-ERR No such profile\n"); + } + +/**********************************************************************************/ + }else if (!strcmp(argv[2], "termstatus")) { +/**********************************************************************************/ + /* mg termstatus */ + + if (zstr(argv[3])) { + goto usage; + } + + megaco_profile_release(profile); + handle_term_status_cli_cmd(stream, profile, argv[3]); - break; - } - default: - { - goto usage; - } - } - }else{ - stream->write_function(stream, "-ERR No such profile\n"); - } /**********************************************************************************/ }else { @@ -212,6 +225,7 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre goto usage; } /**********************************************************************************/ + }else { /**********************************************************************************/ goto usage; @@ -223,13 +237,35 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre usage: if(profile) megaco_profile_release(profile); - stream->write_function(stream, "-ERR Usage: \n""\t"MEGACO_CLI_SYNTAX" \n \t"MEGACO_FUNCTION_SYNTAX"\n \t" MEGACO_LOGGING_CLI_SYNTAX "\n"); + megaco_cli_print_usage(stream); done: switch_safe_free(dup); return SWITCH_STATUS_SUCCESS; } +/******************************************************************************/ +void megaco_cli_print_usage(switch_stream_handle_t *stream) +{ + + stream->write_function(stream, "Usage: Profile Specific\n"); + stream->write_function(stream, "mg profile start \n"); + stream->write_function(stream, "mg profile stop \n"); + stream->write_function(stream, "mg profile termstatus \n"); + stream->write_function(stream, "mg profile status \n"); + stream->write_function(stream, "mg profile xmlstatus \n"); + stream->write_function(stream, "mg profile peerxmlstatus \n"); + stream->write_function(stream, "mg profile send sc \n"); + stream->write_function(stream, "mg profile send notify \n"); + stream->write_function(stream, "mg profile send ito notify \n"); + stream->write_function(stream, "mg profile send cng \n"); + + stream->write_function(stream, "Usage: Logging \n"); + stream->write_function(stream, "mg logging enable \n"); + stream->write_function(stream, "mg logging disable \n"); + +} + /******************************************************************************/ switch_status_t megaco_profile_peer_xmlstatus(switch_stream_handle_t *stream, megaco_profile_t* mg_cfg) { @@ -642,3 +678,63 @@ void get_peer_xml_buffer(char* prntBuf, MgPeerSta* cfm) } /******************************************************************************/ +switch_status_t handle_term_status_cli_cmd(switch_stream_handle_t *stream, megaco_profile_t* mg_profile, char* term_id) +{ + mg_termination_t* term = NULL; + + if(!mg_profile || !term_id){ + stream->write_function(stream, "-ERR NULL profile/term pointer \n"); + return SWITCH_STATUS_FALSE; + } + + term = megaco_find_termination(mg_profile, term_id); + + if(!term || !term->profile){ + stream->write_function(stream, "-ERR No such termination\n"); + return SWITCH_STATUS_FALSE; + } + + stream->write_function(stream, "Associated MG Profile Name [%s] \n",term->profile->name); + stream->write_function(stream, "MEGACO Termination Name[%s] \n",(NULL != term->name)?term->name:"NULL"); + stream->write_function(stream, "MEGACO Termination Type[%s] \n",(MG_TERM_RTP != term->type)?"MG_TERM_RTP":"MG_TERM_TDM"); + stream->write_function(stream, "Termination UUID[%s] \n",(NULL != term->uuid)?term->uuid:"Term Not Activated"); + if(term->context){ + stream->write_function(stream, "Associated Context-Id[%d] \n",term->context->context_id); + if(term->context->terminations[0] && term->context->terminations[1]){ + if(term == term->context->terminations[0]){ + stream->write_function(stream, "Associated Termination Name[%s] \n", + (NULL != term->context->terminations[1]->name)?term->context->terminations[1]->name:"NULL"); + }else { + stream->write_function(stream, "Associated Termination Name[%s] \n", + (NULL != term->context->terminations[0]->name)?term->context->terminations[0]->name:"NULL"); + } + } + } + + + if(MG_TERM_RTP == term->type){ + stream->write_function(stream, "RTP Termination ID [%d] \n",term->u.rtp.term_id); + stream->write_function(stream, "RTP Termination Local Address[%s] \n", + (NULL != term->u.rtp.local_addr)?term->u.rtp.local_addr:"NULL"); + stream->write_function(stream, "RTP Termination Local Port[%d] \n",term->u.rtp.local_port); + stream->write_function(stream, "RTP Termination Remote Address[%s] \n", + (NULL != term->u.rtp.remote_addr)?term->u.rtp.remote_addr:"NULL"); + stream->write_function(stream, "RTP Termination Remote Port[%d] \n",term->u.rtp.remote_port); + stream->write_function(stream, "RTP Termination PTIME [%d] \n",term->u.rtp.ptime); + stream->write_function(stream, "RTP Termination PT [%d] \n",term->u.rtp.pt); + stream->write_function(stream, "RTP Termination rfc2833_pt [%d] \n",term->u.rtp.rfc2833_pt); + stream->write_function(stream, "RTP Termination Sampling Rate [%d] \n",term->u.rtp.rate); + stream->write_function(stream, "RTP Termination Codec [%s] \n", + (NULL != term->u.rtp.codec)?term->u.rtp.codec:"NULL"); + }else{ + stream->write_function(stream, "TDM Termination Service-State [%s] \n", + (switch_test_flag(term, MG_IN_SERVICE))?"IN-SERVICE":"OUT-OF-SERVICE"); + stream->write_function(stream, "TDM Termination channel [%d] \n",term->u.tdm.channel); + stream->write_function(stream, "TDM Termination span name [%s] \n", + (NULL != term->u.tdm.span_name)?term->u.tdm.span_name:"NULL"); + } + + return SWITCH_STATUS_SUCCESS; +} +/******************************************************************************/ + From 4200a427c861ee8dad0f7766f6c91c470270a681 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Tue, 7 Aug 2012 05:56:09 -0400 Subject: [PATCH 398/822] adding default values of sampling rate based on codec type --- .../mod_media_gateway/media_gateway_utils.c | 52 +++++++++++++++++-- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index e622038ee6..3801ade93b 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -885,17 +885,59 @@ void mgco_handle_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sd if((NOTPRSNT != r->num.pres) && (0 != r->num.val) && (NULL != r->fmts[0])){ const char* name = mg_get_codec_name(mg_profile, r->fmts[0]->val.val); if(name){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " Updating codec to[%d], name[%s] \n", - r->fmts[0]->val.val, name); if(MG_TERM_RTP == term->type){ term->u.rtp.codec = name; term->u.rtp.pt = r->fmts[0]->val.val; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"Updating pt to [%d]\n", - term->u.rtp.pt); + /* Set default value of sampling rate depends on codec */ + switch(megaco_codec_parse(name)) + { + case MEGACO_CODEC_PCMA: + { + term->u.rtp.rate = 8000; + break; + } + case MEGACO_CODEC_PCMU: + { + /* TODO - proper values */ + term->u.rtp.rate = 8000; + break; + } + case MEGACO_CODEC_G729: + { + /* TODO - proper values */ + term->u.rtp.rate = 8000; + break; + } + case MEGACO_CODEC_G723_1: + { + /* TODO - proper values */ + term->u.rtp.rate = 8000; + break; + } + case MEGACO_CODEC_ILBC: + { + /* TODO - proper values */ + term->u.rtp.rate = 8000; + break; + } + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + " not updating sampling rate \n"); + break; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + " Updating codec to[%d], name[%s] \n", + r->fmts[0]->val.val, name); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "Updating pt to [%d], rate to[%d]\n", + term->u.rtp.pt, term->u.rtp.rate); } }else{ /* ERROR */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " NO Codec Name found against iana[%d] \n", r->fmts[0]->val.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + " NO Codec Name found against iana[%d] \n", r->fmts[0]->val.val); } } From e7c2e18f7915c4483b1258187e6342921a7ac120 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 7 Aug 2012 06:02:58 -0400 Subject: [PATCH 399/822] fixing cli issue --- src/mod/endpoints/mod_media_gateway/media_gateway_cli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c index a714c6bd15..4fe1876277 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c @@ -696,7 +696,7 @@ switch_status_t handle_term_status_cli_cmd(switch_stream_handle_t *stream, megac stream->write_function(stream, "Associated MG Profile Name [%s] \n",term->profile->name); stream->write_function(stream, "MEGACO Termination Name[%s] \n",(NULL != term->name)?term->name:"NULL"); - stream->write_function(stream, "MEGACO Termination Type[%s] \n",(MG_TERM_RTP != term->type)?"MG_TERM_RTP":"MG_TERM_TDM"); + stream->write_function(stream, "MEGACO Termination Type[%s] \n",(MG_TERM_RTP == term->type)?"MG_TERM_RTP":"MG_TERM_TDM"); stream->write_function(stream, "Termination UUID[%s] \n",(NULL != term->uuid)?term->uuid:"Term Not Activated"); if(term->context){ stream->write_function(stream, "Associated Context-Id[%d] \n",term->context->context_id); From feb3bd78acc978c5209b0663afae2a30526d25b9 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Tue, 7 Aug 2012 06:30:05 -0400 Subject: [PATCH 400/822] cli issue fix --- .../endpoints/mod_media_gateway/media_gateway_cli.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c index 4fe1876277..e131747f5b 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c @@ -196,10 +196,12 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre goto usage; } - megaco_profile_release(profile); - handle_term_status_cli_cmd(stream, profile, argv[3]); - - + if(profile){ + megaco_profile_release(profile); + handle_term_status_cli_cmd(stream, profile, argv[3]); + } else { + stream->write_function(stream, "-ERR No such profile\n"); + } /**********************************************************************************/ }else { @@ -237,6 +239,7 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre usage: if(profile) megaco_profile_release(profile); + megaco_cli_print_usage(stream); done: From 3b0290b61635e71c67eb2a1440f1a9391e17e22a Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Tue, 7 Aug 2012 09:54:02 -0400 Subject: [PATCH 401/822] adding cli command to dump "activecalls" at present --- .../mod_media_gateway/media_gateway_cli.c | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c index e131747f5b..a93bd0467c 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c @@ -18,6 +18,7 @@ switch_status_t megaco_profile_peer_xmlstatus(switch_stream_handle_t *stream, me switch_status_t handle_term_status_cli_cmd(switch_stream_handle_t *stream, megaco_profile_t* mg_profile, char* term_id); void get_peer_xml_buffer(char* prntBuf, MgPeerSta* cfm); void megaco_cli_print_usage(switch_stream_handle_t *stream); +switch_status_t handle_show_activecalls_cli_cmd(switch_stream_handle_t *stream, megaco_profile_t* mg_profile); /******************************************************************************/ @@ -202,6 +203,22 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre } else { stream->write_function(stream, "-ERR No such profile\n"); } +/**********************************************************************************/ + }else if (!strcmp(argv[2], "show")) { +/**********************************************************************************/ + /* mg show activecalls*/ + if(zstr(argv[3])) { + goto usage; + } + + if(profile){ + megaco_profile_release(profile); + if(!strcasecmp(argv[3], "activecalls")){ + handle_show_activecalls_cli_cmd(stream, profile); + } + } else { + stream->write_function(stream, "-ERR No such profile\n"); + } /**********************************************************************************/ }else { @@ -262,6 +279,7 @@ void megaco_cli_print_usage(switch_stream_handle_t *stream) stream->write_function(stream, "mg profile send notify \n"); stream->write_function(stream, "mg profile send ito notify \n"); stream->write_function(stream, "mg profile send cng \n"); + stream->write_function(stream, "mg profile show activecalls \n"); stream->write_function(stream, "Usage: Logging \n"); stream->write_function(stream, "mg logging enable \n"); @@ -740,4 +758,46 @@ switch_status_t handle_term_status_cli_cmd(switch_stream_handle_t *stream, megac return SWITCH_STATUS_SUCCESS; } /******************************************************************************/ +switch_status_t handle_show_activecalls_cli_cmd(switch_stream_handle_t *stream, megaco_profile_t* mg_profile) +{ + void *val = NULL; + switch_hash_index_t *hi = NULL; + mg_termination_t *term = NULL; + const void *var; + int found = 0x00; + + if(!mg_profile || !mg_profile->terminations){ + stream->write_function(stream, "-ERR NULL profile/term pointer \n"); + return SWITCH_STATUS_FALSE; + } + + stream->write_function(stream, "\n ------- Active Calls Terminations ------- \n"); + for (hi = switch_hash_first(NULL, mg_profile->terminations); hi; hi = switch_hash_next(hi)) { + switch_hash_this(hi, &var, NULL, &val); + term = (mg_termination_t *) val; + if(!term) continue; + if(NULL == term->uuid) continue; + + found = 0x01; + stream->write_function(stream, "\n ********************************* \n"); + stream->write_function(stream, "MEGACO Termination Name[%s] \n",(NULL != term->name)?term->name:"NULL"); + stream->write_function(stream, "MEGACO Termination Type[%s] \n",(MG_TERM_RTP == term->type)?"MG_TERM_RTP":"MG_TERM_TDM"); + stream->write_function(stream, "Termination UUID[%s] \n",(NULL != term->uuid)?term->uuid:"Term Not Activated"); + if(MG_TERM_RTP == term->type){ + stream->write_function(stream, "RTP Termination ID [%d] \n",term->u.rtp.term_id); + }else{ + stream->write_function(stream, "TDM Termination channel [%d] \n",term->u.tdm.channel); + stream->write_function(stream, "TDM Termination span name [%s] \n", + (NULL != term->u.tdm.span_name)?term->u.tdm.span_name:"NULL"); + } + stream->write_function(stream, "\n ********************************* \n"); + } + + + if(!found) + stream->write_function(stream, "\n ------- NO Active Calls FOUND ------- \n"); + + + return SWITCH_STATUS_SUCCESS; +} From 6046698b290864abd89553ec36c2ecd8894f5496 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 7 Aug 2012 09:57:51 -0400 Subject: [PATCH 402/822] fixing channel mapping issue and removing unwanted prints --- src/mod/endpoints/mod_media_gateway/media_gateway.c | 2 +- .../mod_media_gateway/media_gateway_cmd_handler.c | 2 ++ .../mod_media_gateway/media_gateway_stack.h | 2 +- .../endpoints/mod_media_gateway/media_gateway_xml.c | 13 ++++++++----- .../endpoints/mod_media_gateway/mod_media_gateway.c | 8 ++++---- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 20e72d1c18..52081dbc12 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -63,7 +63,7 @@ megaco_profile_t* megaco_get_profile_by_suId(SuId suId) switch_hash_this(hi, &var, NULL, &val); profile = (megaco_profile_t *) val; if (profile->idx == suId) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Got profile[%s] associated with suId[%d]\n",profile->name, suId); + //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Got profile[%s] associated with suId[%d]\n",profile->name, suId); found = 0x01; break; } diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 61896ce9b9..b3661f75e8 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -1563,6 +1563,7 @@ switch_status_t mg_send_end_of_axn(SuId suId, MgMgcoTransId* transId, MgMgcoCont ctxt.cmdStatus.pres = PRSNT_NODEF; ctxt.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; +#if 0 #ifdef BIT_64 switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "mg_send_end_of_axn: Sending END_OF_AXN for transId[%d], peerId[%d], context[type = %s, value = %d]\n", @@ -1572,6 +1573,7 @@ switch_status_t mg_send_end_of_axn(SuId suId, MgMgcoTransId* transId, MgMgcoCont "mg_send_end_of_axn: Sending END_OF_AXN for transId[%lu], peerId[%lu], context[type = %s, value = %lu]\n", transId->val, peerId->val, PRNT_MG_CTXT_TYPE(ctxtId->type.val), ctxtId->val.val); +#endif #endif ret = sng_mgco_send_axn_req(suId, &ctxt); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index 28ff0c2c03..1c7e8c614c 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -193,7 +193,7 @@ switch_status_t mg_build_mgco_err_request(MgMgcoInd **errcmd,U32 trans_id, MgM switch_status_t mg_send_audit_rsp(SuId suId, MgMgcoCommand *req); switch_status_t handle_mg_audit_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *auditReq); switch_status_t mg_stack_termination_is_in_service(megaco_profile_t* mg_profile, char* term_str, int len); -void mg_create_tdm_term(megaco_profile_t *profile, const char *tech, const char *channel_prefix, const char *prefix, int j); +void mg_create_tdm_term(megaco_profile_t *profile, const char *tech, const char *channel_prefix, const char *prefix, int j, int k); void mg_util_set_cmd_name_string (MgStr *errTxt, MgMgcoCommand *cmd); switch_status_t mgco_init_ins_service_change(SuId suId); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index 44c716152a..4b242a6b9b 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -103,14 +103,14 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) startchan = atoi(chanmap[0]); endchan = atoi(chanmap[1]); for (j = startchan; j <= endchan; j++) { - mg_create_tdm_term(profile, tech, channel_prefix, prefix, j); + mg_create_tdm_term(profile, tech, channel_prefix, prefix, j, j); } } }else{ /* case (i) */ p = channel_map_dup; startchan = endchan = atoi(p); - mg_create_tdm_term(profile, tech, channel_prefix, prefix, startchan); + mg_create_tdm_term(profile, tech, channel_prefix, prefix, startchan, startchan); } }else { @@ -123,7 +123,10 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) endchan = atoi(p); for (j = startchan; j <= endchan; j++) { - mg_create_tdm_term(profile, tech, channel_prefix, prefix, j); +if (0 == i) + mg_create_tdm_term(profile, tech, channel_prefix, prefix, j, j); +else + mg_create_tdm_term(profile, tech, channel_prefix, prefix, j, j-1); } } } @@ -197,7 +200,7 @@ done: } /****************************************************************************************************************************/ -void mg_create_tdm_term(megaco_profile_t *profile, const char *tech, const char *channel_prefix, const char *prefix, int chan_num) +void mg_create_tdm_term(megaco_profile_t *profile, const char *tech, const char *channel_prefix, const char *prefix, int chan_num, int tdm_chan_num) { mg_termination_t *term; switch_memory_pool_t *pool; @@ -211,7 +214,7 @@ void mg_create_tdm_term(megaco_profile_t *profile, const char *tech, const char term->tech = switch_core_strdup(pool, tech); term->active_events = NULL; term->name = switch_core_sprintf(pool, "%s%d", prefix, chan_num); - term->u.tdm.channel = chan_num; + term->u.tdm.channel = tdm_chan_num; term->u.tdm.span_name = switch_core_strdup(pool, channel_prefix); switch_set_flag(term, MG_OUT_OF_SERVICE); diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 698efc0798..771732d680 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -526,8 +526,8 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) inc_context = &cmd->contextId; memcpy(&out_ctxt, inc_context,sizeof(MgMgcoContextId)); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, - "%s: Received Command Type[%s] \n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(cmd->cmdType.val)); + /*switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "%s: Received Command Type[%s] \n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(cmd->cmdType.val));*/ /*get mg profile associated with SuId */ if(NULL == (mg_profile = megaco_get_profile_by_suId(suId))){ @@ -591,8 +591,8 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) } } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, - "Termination-Id received..value[%s] type[%d] \n", termId->name.lcl.val, termId->type.val); + /*switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "Termination-Id received..value[%s] type[%d] \n", termId->name.lcl.val, termId->type.val);*/ /*If term type is other then check if that term is configured with us..for term type CHOOSE/ALL , no need to check */ /* check is only if command is not AUDIT */ From d806014009624e76bc252b2e09da19b62559655f Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 7 Aug 2012 17:23:01 -0500 Subject: [PATCH 403/822] FS-4079 try this --- src/mod/endpoints/mod_sofia/sofia.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 99f42169f1..08f0686625 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -972,7 +972,13 @@ static void our_sofia_event_callback(nua_event_t event, if (sofia_private && sofia_private->is_call && sofia_private->de) { sofia_dispatch_event_t *qde = sofia_private->de; sofia_private->de = NULL; - sofia_process_dispatch_event(&qde); + + if (event == nua_i_cancel) { + nua_destroy_event(qde->event); + su_free(nh->nh_home, qde); + } else { + sofia_process_dispatch_event(&qde); + } } profile->last_sip_event = switch_time_now(); From 9ac586adc826030422b2dd0910873aca3de268ac Mon Sep 17 00:00:00 2001 From: William King Date: Tue, 7 Aug 2012 21:57:58 -0500 Subject: [PATCH 404/822] Add param variable where needed. --- src/mod/xml_int/mod_xml_radius/mod_xml_radius.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c b/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c index 28fd56eca6..c561eb7051 100644 --- a/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c +++ b/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c @@ -100,7 +100,7 @@ switch_status_t mod_xml_radius_new_handle(rc_handle **new_handle, switch_xml_t x switch_status_t do_config() { char *conf = "xml_radius.conf"; - switch_xml_t xml, cfg, tmp, server; + switch_xml_t xml, cfg, tmp, server, param; int serv, timeout, deadtime, retries, dict, seq; /* TODO: 1. read new auth_invite_configs From 65ffaa8ca90e5befa4cbac64d723d53a98a4fc8f Mon Sep 17 00:00:00 2001 From: Steve Underwood Date: Wed, 8 Aug 2012 19:46:31 +0800 Subject: [PATCH 405/822] Someone's been doing something odd to t30.h :-\ --- libs/spandsp/src/spandsp/t30.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/spandsp/src/spandsp/t30.h b/libs/spandsp/src/spandsp/t30.h index 1e66a95a27..ee842afea8 100644 --- a/libs/spandsp/src/spandsp/t30.h +++ b/libs/spandsp/src/spandsp/t30.h @@ -373,12 +373,12 @@ enum /*! T.81 + T.30 Annex K colour sYCC-JPEG compression */ T30_SUPPORT_SYCC_T81_COMPRESSION = 0x200, /*! T.88 monochrome JBIG2 compression */ - T30_SUPPORT_T88_COMPRESSION = 0x400 -}; + T30_SUPPORT_T88_COMPRESSION = 0x400, /*! Dither a gray scale image down a simple bilevel image, with rescaling to fit a FAX page */ -#define T30_SUPPORT_GRAY_TO_BILEVEL 0x10000000 + T30_SUPPORT_GRAY_TO_BILEVEL = 0x10000000, /*! Dither a colour image down a simple bilevel image, with rescaling to fit a FAX page */ -#define T30_SUPPORT_COLOUR_TO_BILEVEL 0x20000000 + T30_SUPPORT_COLOUR_TO_BILEVEL = 0x20000000 +}; enum { From 14a6e0cfc284348bc0a3a2312d82a43b2a256456 Mon Sep 17 00:00:00 2001 From: Daniel Swarbrick Date: Wed, 8 Aug 2012 14:08:31 +0200 Subject: [PATCH 406/822] CGI specifies that REQUEST_URI is relative to the root (and does not include scheme name, hostname, port) --- src/mod/xml_int/mod_xml_scgi/mod_xml_scgi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mod/xml_int/mod_xml_scgi/mod_xml_scgi.c b/src/mod/xml_int/mod_xml_scgi/mod_xml_scgi.c index 1ac74ebbdf..a0898fb1cd 100644 --- a/src/mod/xml_int/mod_xml_scgi/mod_xml_scgi.c +++ b/src/mod/xml_int/mod_xml_scgi/mod_xml_scgi.c @@ -40,6 +40,7 @@ SWITCH_MODULE_DEFINITION(mod_xml_scgi, mod_xml_scgi_load, mod_xml_scgi_shutdown, struct xml_binding { char *host; switch_port_t port; + char *uri; char *url; int timeout; @@ -144,7 +145,7 @@ static switch_xml_t xml_url_fetch(const char *section, const char *tag_name, con switch_stream_handle_t stream = { 0 }; char *txt = NULL; - strncpy(hostname, switch_core_get_switchname(), sizeof(hostname)); + strncpy(hostname, switch_core_get_switchname(), sizeof(hostname)); if (!binding) { return NULL; @@ -157,7 +158,7 @@ static switch_xml_t xml_url_fetch(const char *section, const char *tag_name, con switch_assert(data); scgi_add_param(&handle, "REQUEST_METHOD", "POST"); - scgi_add_param(&handle, "REQUEST_URI", binding->url); + scgi_add_param(&handle, "REQUEST_URI", binding->uri); scgi_add_body(&handle, data); if (scgi_connect(&handle, binding->host, binding->port, binding->timeout * 1000) == SCGI_SUCCESS) { @@ -318,6 +319,7 @@ static switch_status_t do_config(void) binding->host = switch_core_strdup(globals.pool, host); binding->port = atoi(port); binding->vars_map = vars_map; + binding->uri = switch_mprintf("/%s", bname); binding->url = switch_mprintf("scgi://%s:%s/%s", host, port, bname); if (server) { From f3c1f5aa686231959e9b139d9982c89506a364a9 Mon Sep 17 00:00:00 2001 From: Daniel Swarbrick Date: Wed, 8 Aug 2012 14:14:54 +0200 Subject: [PATCH 407/822] missed this one --- src/mod/xml_int/mod_xml_scgi/mod_xml_scgi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/xml_int/mod_xml_scgi/mod_xml_scgi.c b/src/mod/xml_int/mod_xml_scgi/mod_xml_scgi.c index a0898fb1cd..3e39e65407 100644 --- a/src/mod/xml_int/mod_xml_scgi/mod_xml_scgi.c +++ b/src/mod/xml_int/mod_xml_scgi/mod_xml_scgi.c @@ -409,7 +409,7 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_xml_scgi_shutdown) int x = 3; scgi_add_param(&handle, "REQUEST_METHOD", "POST"); - scgi_add_param(&handle, "REQUEST_URI", bp->url); + scgi_add_param(&handle, "REQUEST_URI", bp->uri); scgi_add_body(&handle, "SHUTDOWN"); while(x--) { From bb96d091fc33e5d43b6a87810fa09a3185ce7619 Mon Sep 17 00:00:00 2001 From: Steve Underwood Date: Wed, 8 Aug 2012 21:16:38 +0800 Subject: [PATCH 408/822] Tweaks --- libs/spandsp/src/spandsp/private/t4_rx.h | 2 -- libs/spandsp/src/spandsp/private/t4_tx.h | 2 -- libs/spandsp/src/t4_rx.c | 18 ------------------ libs/spandsp/src/t4_tx.c | 18 ------------------ 4 files changed, 40 deletions(-) diff --git a/libs/spandsp/src/spandsp/private/t4_rx.h b/libs/spandsp/src/spandsp/private/t4_rx.h index 4dc2b21e21..44eb2d2664 100644 --- a/libs/spandsp/src/spandsp/private/t4_rx.h +++ b/libs/spandsp/src/spandsp/private/t4_rx.h @@ -109,9 +109,7 @@ struct t4_rx_state_s union { t4_t6_decode_state_t t4_t6; -#if defined(SPANDSP_SUPPORT_T42) t42_decode_state_t t42; -#endif #if defined(SPANDSP_SUPPORT_T43) t43_decode_state_t t43; #endif diff --git a/libs/spandsp/src/spandsp/private/t4_tx.h b/libs/spandsp/src/spandsp/private/t4_tx.h index 9f4bf463be..360315a9d2 100644 --- a/libs/spandsp/src/spandsp/private/t4_tx.h +++ b/libs/spandsp/src/spandsp/private/t4_tx.h @@ -133,9 +133,7 @@ struct t4_tx_state_s union { t4_t6_encode_state_t t4_t6; -#if defined(SPANDSP_SUPPORT_T42) t42_encode_state_t t42; -#endif #if defined(SPANDSP_SUPPORT_T43) t43_encode_state_t t43; #endif diff --git a/libs/spandsp/src/t4_rx.c b/libs/spandsp/src/t4_rx.c index 7de952b890..c152d31871 100644 --- a/libs/spandsp/src/t4_rx.c +++ b/libs/spandsp/src/t4_rx.c @@ -253,11 +253,9 @@ static int set_tiff_directory_info(t4_rx_state_t *s) case T4_COMPRESSION_ITU_T6: TIFFSetField(t->tiff_file, TIFFTAG_IMAGELENGTH, t4_t6_decode_get_image_length(&s->decoder.t4_t6)); break; -#if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_ITU_T42: TIFFSetField(t->tiff_file, TIFFTAG_IMAGELENGTH, t42_decode_get_image_length(&s->decoder.t42)); break; -#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_ITU_T43: TIFFSetField(t->tiff_file, TIFFTAG_IMAGELENGTH, t43_decode_get_image_length(&s->decoder.t43)); @@ -360,10 +358,8 @@ SPAN_DECLARE(int) t4_rx_put_byte(t4_rx_state_t *s, uint8_t byte) case T4_COMPRESSION_ITU_T4_2D: case T4_COMPRESSION_ITU_T6: return t4_t6_decode_put_byte(&s->decoder.t4_t6, byte); -#if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_ITU_T42: return t42_decode_put_byte(&s->decoder.t42, byte); -#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_ITU_T43: return t43_decode_put_byte(&s->decoder.t43, byte); @@ -385,10 +381,8 @@ SPAN_DECLARE(int) t4_rx_put_chunk(t4_rx_state_t *s, const uint8_t buf[], int len case T4_COMPRESSION_ITU_T4_2D: case T4_COMPRESSION_ITU_T6: return t4_t6_decode_put_chunk(&s->decoder.t4_t6, buf, len); -#if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_ITU_T42: return t42_decode_put_chunk(&s->decoder.t42, buf, len); -#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_ITU_T43: return t43_decode_put_chunk(&s->decoder.t43, buf, len); @@ -462,7 +456,6 @@ SPAN_DECLARE(int) t4_rx_set_rx_encoding(t4_rx_state_t *s, int encoding) } s->line_encoding = encoding; return t4_t6_decode_set_encoding(&s->decoder.t4_t6, encoding); -#if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_ITU_T42: switch (s->line_encoding) { @@ -478,7 +471,6 @@ SPAN_DECLARE(int) t4_rx_set_rx_encoding(t4_rx_state_t *s, int encoding) } s->line_encoding = encoding; return 0; -#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_ITU_T43: switch (s->line_encoding) @@ -534,10 +526,8 @@ SPAN_DECLARE(int) t4_rx_set_row_write_handler(t4_rx_state_t *s, t4_row_write_han case T4_COMPRESSION_ITU_T4_2D: case T4_COMPRESSION_ITU_T6: return t4_t6_decode_set_row_write_handler(&s->decoder.t4_t6, handler, user_data); -#if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_ITU_T42: return t42_decode_set_row_write_handler(&s->decoder.t42, handler, user_data); -#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_ITU_T43: return t43_decode_set_row_write_handler(&s->decoder.t43, handler, user_data); @@ -569,13 +559,11 @@ SPAN_DECLARE(void) t4_rx_get_transfer_statistics(t4_rx_state_t *s, t4_stats_t *t t->bad_rows = s->decoder.t4_t6.bad_rows; t->longest_bad_row_run = s->decoder.t4_t6.longest_bad_row_run; break; -#if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_ITU_T42: t->width = t42_decode_get_image_width(&s->decoder.t42); t->length = t42_decode_get_image_length(&s->decoder.t42); t->line_image_size = t42_decode_get_compressed_image_size(&s->decoder.t42)/8; break; -#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_ITU_T43: t->width = t43_decode_get_image_width(&s->decoder.t43); @@ -604,11 +592,9 @@ SPAN_DECLARE(int) t4_rx_start_page(t4_rx_state_t *s) case T4_COMPRESSION_ITU_T6: t4_t6_decode_restart(&s->decoder.t4_t6, s->image_width); break; -#if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_ITU_T42: t42_decode_restart(&s->decoder.t42); break; -#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_ITU_T43: t43_decode_restart(&s->decoder.t43); @@ -663,12 +649,10 @@ SPAN_DECLARE(int) t4_rx_end_page(t4_rx_state_t *s) t4_t6_decode_put_byte(&s->decoder.t4_t6, SIG_STATUS_END_OF_DATA); length = t4_t6_decode_get_image_length(&s->decoder.t4_t6); break; -#if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_ITU_T42: t42_decode_put_byte(&s->decoder.t42, SIG_STATUS_END_OF_DATA); length = t42_decode_get_image_length(&s->decoder.t42); break; -#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_ITU_T43: t43_decode_put_byte(&s->decoder.t43, SIG_STATUS_END_OF_DATA); @@ -759,10 +743,8 @@ SPAN_DECLARE(int) t4_rx_release(t4_rx_state_t *s) case T4_COMPRESSION_ITU_T4_2D: case T4_COMPRESSION_ITU_T6: return t4_t6_decode_release(&s->decoder.t4_t6); -#if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_ITU_T42: return t42_decode_release(&s->decoder.t42); -#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_ITU_T43: return t43_decode_release(&s->decoder.t43); diff --git a/libs/spandsp/src/t4_tx.c b/libs/spandsp/src/t4_tx.c index 17c832ecf5..49f059e89c 100644 --- a/libs/spandsp/src/t4_tx.c +++ b/libs/spandsp/src/t4_tx.c @@ -524,10 +524,8 @@ static int set_row_read_handler(t4_tx_state_t *s, t4_row_read_handler_t handler, case T4_COMPRESSION_ITU_T4_2D: case T4_COMPRESSION_ITU_T6: return t4_t6_encode_set_row_read_handler(&s->encoder.t4_t6, handler, user_data); -#if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_ITU_T42: return t42_encode_set_row_read_handler(&s->encoder.t42, handler, user_data); -#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_ITU_T43: return t43_encode_set_row_read_handler(&s->encoder.t43, handler, user_data); @@ -686,7 +684,6 @@ SPAN_DECLARE(int) t4_tx_set_tx_encoding(t4_tx_state_t *s, int encoding) } s->line_encoding = encoding; return t4_t6_encode_set_encoding(&s->encoder.t4_t6, encoding); -#if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_ITU_T42: switch (s->line_encoding) { @@ -698,7 +695,6 @@ SPAN_DECLARE(int) t4_tx_set_tx_encoding(t4_tx_state_t *s, int encoding) } s->line_encoding = encoding; return 0; -#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_ITU_T43: switch (s->line_encoding) @@ -753,11 +749,9 @@ SPAN_DECLARE(void) t4_tx_set_image_width(t4_tx_state_t *s, int image_width) case T4_COMPRESSION_ITU_T6: t4_t6_encode_set_image_width(&s->encoder.t4_t6, image_width); break; -#if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_ITU_T42: t42_encode_set_image_width(&s->encoder.t42, image_width); break; -#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_ITU_T43: t43_encode_set_image_width(&s->encoder.t43, image_width); @@ -776,11 +770,9 @@ static void t4_tx_set_image_length(t4_tx_state_t *s, int image_length) s->image_length = image_length; switch (s->line_encoding) { -#if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_ITU_T42: t42_encode_set_image_length(&s->encoder.t42, image_length); break; -#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_ITU_T43: t43_encode_set_image_length(&s->encoder.t43, image_length); @@ -886,13 +878,11 @@ SPAN_DECLARE(void) t4_tx_get_transfer_statistics(t4_tx_state_t *s, t4_stats_t *t t->length = t4_t6_encode_get_image_length(&s->encoder.t4_t6); t->line_image_size = t4_t6_encode_get_compressed_image_size(&s->encoder.t4_t6)/8; break; -#if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_ITU_T42: t->width = t42_encode_get_image_width(&s->encoder.t42); t->length = t42_encode_get_image_length(&s->encoder.t42); t->line_image_size = t42_encode_get_compressed_image_size(&s->encoder.t42)/8; break; -#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_ITU_T43: t->width = t43_encode_get_image_width(&s->encoder.t43); @@ -930,10 +920,8 @@ SPAN_DECLARE(int) t4_tx_get_byte(t4_tx_state_t *s) case T4_COMPRESSION_ITU_T4_2D: case T4_COMPRESSION_ITU_T6: return t4_t6_encode_get_byte(&s->encoder.t4_t6); -#if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_ITU_T42: return t42_encode_get_byte(&s->encoder.t42); -#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_ITU_T43: return t43_encode_get_byte(&s->encoder.t43); @@ -954,10 +942,8 @@ SPAN_DECLARE(int) t4_tx_get_chunk(t4_tx_state_t *s, uint8_t buf[], int max_len) case T4_COMPRESSION_ITU_T4_2D: case T4_COMPRESSION_ITU_T6: return t4_t6_encode_get_chunk(&s->encoder.t4_t6, buf, max_len); -#if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_ITU_T42: return t42_encode_get_chunk(&s->encoder.t42, buf, max_len); -#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_ITU_T43: return t43_encode_get_chunk(&s->encoder.t43, buf, max_len); @@ -995,11 +981,9 @@ SPAN_DECLARE(int) t4_tx_start_page(t4_tx_state_t *s) case T4_COMPRESSION_ITU_T6: t4_t6_encode_restart(&s->encoder.t4_t6, s->image_width); break; -#if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_ITU_T42: t42_encode_restart(&s->encoder.t42, s->image_width, s->image_length); break; -#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_ITU_T43: t43_encode_restart(&s->encoder.t43, s->image_width, s->image_length); @@ -1106,10 +1090,8 @@ SPAN_DECLARE(int) t4_tx_release(t4_tx_state_t *s) case T4_COMPRESSION_ITU_T4_2D: case T4_COMPRESSION_ITU_T6: return t4_t6_encode_release(&s->encoder.t4_t6); -#if defined(SPANDSP_SUPPORT_T42) case T4_COMPRESSION_ITU_T42: return t42_encode_release(&s->encoder.t42); -#endif #if defined(SPANDSP_SUPPORT_T43) case T4_COMPRESSION_ITU_T43: return t43_encode_release(&s->encoder.t43); From 42c5ab08d3369f16983599174507adb356fae6ce Mon Sep 17 00:00:00 2001 From: Steve Underwood Date: Wed, 8 Aug 2012 21:26:06 +0800 Subject: [PATCH 409/822] Image translate moves forward a little, towards colour support --- libs/spandsp/src/image_translate.c | 264 +++++++++++++--- libs/spandsp/src/spandsp/image_translate.h | 5 +- .../src/spandsp/private/image_translate.h | 5 +- libs/spandsp/tests/image_translate_tests.c | 288 +++++++++++++++--- 4 files changed, 489 insertions(+), 73 deletions(-) diff --git a/libs/spandsp/src/image_translate.c b/libs/spandsp/src/image_translate.c index 785997def5..54037990fc 100644 --- a/libs/spandsp/src/image_translate.c +++ b/libs/spandsp/src/image_translate.c @@ -2,8 +2,9 @@ * SpanDSP - a series of DSP components for telephony * * image_translate.c - Image translation routines for reworking colour - * and gray scale images to be bi-level images of an - * appropriate size to be FAX compatible. + * and gray scale images to be colour, gray scale or + * bi-level images of an appropriate size to be FAX + * compatible. * * Written by Steve Underwood * @@ -80,69 +81,237 @@ #include "spandsp/private/t4_rx.h" #include "spandsp/private/t4_tx.h" -static int image_colour16_to_gray8_row(uint8_t mono[], uint16_t colour[], int pixels) +static int image_colour16_to_colour8_row(uint8_t colour8[], uint16_t colour16[], int pixels) +{ + int i; + + for (i = 0; i < 3*pixels; i++) + colour8[i] = colour16[i] >> 8; + return pixels; +} +/*- End of function --------------------------------------------------------*/ + +static int image_colour16_to_gray16_row(uint16_t gray16[], uint16_t colour16[], int pixels) { int i; uint32_t gray; for (i = 0; i < pixels; i++) { - gray = colour[3*i]*19595 + colour[3*i + 1]*38469 + colour[3*i + 2]*7472; - mono[i] = saturateu8(gray >> 24); + gray = colour16[3*i]*19595 + colour16[3*i + 1]*38469 + colour16[3*i + 2]*7472; + gray16[i] = saturateu16(gray >> 16); } return pixels; } /*- End of function --------------------------------------------------------*/ -static int image_colour8_to_gray8_row(uint8_t mono[], uint8_t colour[], int pixels) +static int image_colour16_to_gray8_row(uint8_t gray8[], uint16_t colour16[], int pixels) { int i; uint32_t gray; for (i = 0; i < pixels; i++) { - gray = colour[3*i]*19595 + colour[3*i + 1]*38469 + colour[3*i + 2]*7472; - mono[i] = saturateu8(gray >> 16); + gray = colour16[3*i]*19595 + colour16[3*i + 1]*38469 + colour16[3*i + 2]*7472; + gray8[i] = saturateu8(gray >> 24); } return pixels; } /*- End of function --------------------------------------------------------*/ -static int image_gray16_to_gray8_row(uint8_t mono[], uint16_t gray[], int pixels) +static int image_colour8_to_gray16_row(uint16_t gray16[], uint8_t colour8[], int pixels) { int i; + uint32_t gray; for (i = 0; i < pixels; i++) - mono[i] = gray[i] >> 8; + { + gray = colour8[3*i]*19595 + colour8[3*i + 1]*38469 + colour8[3*i + 2]*7472; + gray16[i] = saturateu16(gray >> 8); + } return pixels; } /*- End of function --------------------------------------------------------*/ -static int get_and_scrunch_row(image_translate_state_t *s, uint8_t buf[], size_t len) +static int image_colour8_to_gray8_row(uint8_t gray8[], uint8_t colour8[], int pixels) { - int row_len; + int i; + uint32_t gray; - row_len = (*s->row_read_handler)(s->row_read_user_data, buf, s->input_width*s->bytes_per_pixel); - if (row_len != s->input_width*s->bytes_per_pixel) + for (i = 0; i < pixels; i++) + { + gray = colour8[3*i]*19595 + colour8[3*i + 1]*38469 + colour8[3*i + 2]*7472; + gray8[i] = saturateu8(gray >> 16); + } + return pixels; +} +/*- End of function --------------------------------------------------------*/ + +static int image_colour8_to_colour16_row(uint16_t colour16[], uint8_t colour8[], int pixels) +{ + int i; + + for (i = 3*pixels - 1; i >= 0; i--) + colour16[i] = colour8[i] << 8; + return pixels; +} +/*- End of function --------------------------------------------------------*/ + +static int image_gray16_to_colour16_row(uint16_t colour16[], uint16_t gray16[], int pixels) +{ + int i; + + for (i = pixels - 1; i >= 0; i--) + { + /* TODO: need to balance the colours */ + colour16[3*i] = gray16[i]; + colour16[3*i + 1] = gray16[i]; + colour16[3*i + 2] = gray16[i]; + } + return pixels; +} +/*- End of function --------------------------------------------------------*/ + +static int image_gray16_to_colour8_row(uint8_t colour8[], uint16_t gray16[], int pixels) +{ + int i; + + for (i = pixels - 1; i >= 0; i--) + { + /* TODO: need to balance the colours */ + colour8[3*i] = gray16[i] >> 8; + colour8[3*i + 1] = gray16[i] >> 8; + colour8[3*i + 2] = gray16[i] >> 8; + } + return pixels; +} +/*- End of function --------------------------------------------------------*/ + +static int image_gray16_to_gray8_row(uint8_t gray8[], uint16_t gray16[], int pixels) +{ + int i; + + for (i = 0; i < pixels; i++) + gray8[i] = gray16[i] >> 8; + return pixels; +} +/*- End of function --------------------------------------------------------*/ + +static int image_gray8_to_colour16_row(uint16_t colour16[], uint8_t gray8[], int pixels) +{ + int i; + + for (i = pixels - 1; i >= 0; i--) + { + /* TODO: need to balance the colours */ + colour16[3*i] = gray8[i] << 8; + colour16[3*i + 1] = gray8[i] << 8; + colour16[3*i + 2] = gray8[i] << 8; + } + return pixels; +} +/*- End of function --------------------------------------------------------*/ + +static int image_gray8_to_colour8_row(uint8_t colour8[], uint8_t gray8[], int pixels) +{ + int i; + + for (i = pixels - 1; i >= 0; i--) + { + /* TODO: need to balance the colours */ + colour8[3*i] = gray8[i]; + colour8[3*i + 1] = gray8[i]; + colour8[3*i + 2] = gray8[i]; + } + return pixels; +} +/*- End of function --------------------------------------------------------*/ + +static int image_gray8_to_gray16_row(uint16_t gray16[], uint8_t gray8[], int pixels) +{ + int i; + + for (i = pixels - 1; i >= 0; i--) + gray16[i] = gray8[i] << 8; + return pixels; +} +/*- End of function --------------------------------------------------------*/ + +static int get_and_scrunch_row(image_translate_state_t *s, uint8_t buf[]) +{ + int input_row_len; + + input_row_len = (*s->row_read_handler)(s->row_read_user_data, buf, s->input_width*s->input_bytes_per_pixel); + if (input_row_len != s->input_width*s->input_bytes_per_pixel) return 0; - /* Scrunch colour down to gray, and scrunch 16 bit pixels down to 8 bit pixels */ + /* Scrunch colour down to gray, vice versa. Scrunch 16 bit pixels down to 8 bit pixels, or vice versa. */ switch (s->input_format) { case T4_IMAGE_TYPE_GRAY_12BIT: - image_gray16_to_gray8_row(buf, (uint16_t *) buf, s->input_width); + switch (s->output_format) + { + case T4_IMAGE_TYPE_BILEVEL: + case T4_IMAGE_TYPE_GRAY_8BIT: + image_gray16_to_gray8_row(buf, (uint16_t *) buf, s->input_width); + break; + case T4_IMAGE_TYPE_COLOUR_12BIT: + image_gray16_to_colour16_row((uint16_t *) buf, (uint16_t *) buf, s->input_width); + break; + case T4_IMAGE_TYPE_COLOUR_8BIT: + image_gray16_to_colour8_row(buf, (uint16_t *) buf, s->input_width); + break; + } + break; + case T4_IMAGE_TYPE_GRAY_8BIT: + switch (s->output_format) + { + case T4_IMAGE_TYPE_GRAY_12BIT: + image_gray8_to_gray16_row((uint16_t *) buf, buf, s->input_width); + break; + case T4_IMAGE_TYPE_COLOUR_12BIT: + image_gray8_to_colour16_row((uint16_t *) buf, buf, s->input_width); + break; + case T4_IMAGE_TYPE_COLOUR_8BIT: + image_gray8_to_colour8_row(buf, buf, s->input_width); + break; + } break; case T4_IMAGE_TYPE_COLOUR_12BIT: - image_colour16_to_gray8_row(buf, (uint16_t *) buf, s->input_width); + switch (s->output_format) + { + case T4_IMAGE_TYPE_GRAY_12BIT: + image_colour16_to_gray16_row((uint16_t *) buf, (uint16_t *) buf, s->input_width); + break; + case T4_IMAGE_TYPE_BILEVEL: + case T4_IMAGE_TYPE_GRAY_8BIT: + image_colour16_to_gray8_row(buf, (uint16_t *) buf, s->input_width); + break; + case T4_IMAGE_TYPE_COLOUR_8BIT: + image_colour16_to_colour8_row(buf, (uint16_t *) buf, s->input_width); + break; + } break; case T4_IMAGE_TYPE_COLOUR_8BIT: - image_colour8_to_gray8_row(buf, buf, s->input_width); + switch (s->output_format) + { + case T4_IMAGE_TYPE_GRAY_12BIT: + image_colour8_to_gray16_row((uint16_t *) buf, buf, s->input_width); + break; + case T4_IMAGE_TYPE_BILEVEL: + case T4_IMAGE_TYPE_GRAY_8BIT: + image_colour8_to_gray8_row(buf, buf, s->input_width); + break; + case T4_IMAGE_TYPE_COLOUR_12BIT: + image_colour8_to_colour16_row((uint16_t *) buf, buf, s->input_width); + break; + } break; } - return row_len; + return s->output_width; } /*- End of function --------------------------------------------------------*/ -static int image_resize_row(image_translate_state_t *s, uint8_t buf[], size_t len) +static int image_resize_row(image_translate_state_t *s, uint8_t buf[]) { int i; int output_width; @@ -184,8 +353,8 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[], size_t le s->raw_output_row = -1; break; } - row_len = get_and_scrunch_row(s, s->raw_pixel_row[0], s->input_width*s->bytes_per_pixel); - if (row_len != s->input_width*s->bytes_per_pixel) + row_len = get_and_scrunch_row(s, s->raw_pixel_row[0]); + if (row_len != s->output_width) { s->raw_output_row = -1; return 0; @@ -221,7 +390,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[], size_t le #endif if (++s->raw_output_row >= s->output_length) s->raw_output_row = -1; - return len; + return s->output_width; } /*- End of function --------------------------------------------------------*/ @@ -335,6 +504,7 @@ SPAN_DECLARE(int) image_translate_row(image_translate_state_t *s, uint8_t buf[], - At the last row we dither and output, without getting an extra row in. */ for (i = (y == 0) ? 0 : 1; i < 2; i++) { + /* Swap the row buffers */ p = s->pixel_row[0]; s->pixel_row[0] = s->pixel_row[1]; s->pixel_row[1] = p; @@ -344,17 +514,24 @@ SPAN_DECLARE(int) image_translate_row(image_translate_state_t *s, uint8_t buf[], will fail, with the end of image condition (i.e. returning zero length) */ if (s->resize) { - if (image_resize_row(s, s->pixel_row[1], s->output_width*s->bytes_per_pixel) != s->output_width*s->bytes_per_pixel) + if (image_resize_row(s, s->pixel_row[1]) != s->output_width) s->output_row = -1; } else { - if (get_and_scrunch_row(s, s->pixel_row[1], s->output_width*s->bytes_per_pixel) != s->output_width*s->bytes_per_pixel) + if (get_and_scrunch_row(s, s->pixel_row[1]) != s->output_width) s->output_row = -1; } } if (s->output_format == T4_IMAGE_TYPE_BILEVEL) + { i = floyd_steinberg_dither_row(s, buf, y); + } + else + { + i = s->output_width*s->output_bytes_per_pixel; + memcpy(buf, s->pixel_row[1], i); + } return i; } /*- End of function --------------------------------------------------------*/ @@ -413,19 +590,38 @@ SPAN_DECLARE(image_translate_state_t *) image_translate_init(image_translate_sta switch (s->input_format) { case T4_IMAGE_TYPE_GRAY_8BIT: - s->bytes_per_pixel = 1; + s->input_bytes_per_pixel = 1; break; case T4_IMAGE_TYPE_GRAY_12BIT: - s->bytes_per_pixel = 2; + s->input_bytes_per_pixel = 2; break; case T4_IMAGE_TYPE_COLOUR_8BIT: - s->bytes_per_pixel = 3; + s->input_bytes_per_pixel = 3; break; case T4_IMAGE_TYPE_COLOUR_12BIT: - s->bytes_per_pixel = 6; + s->input_bytes_per_pixel = 6; break; default: - s->bytes_per_pixel = 1; + s->input_bytes_per_pixel = 1; + break; + } + + switch (s->output_format) + { + case T4_IMAGE_TYPE_GRAY_8BIT: + s->output_bytes_per_pixel = 1; + break; + case T4_IMAGE_TYPE_GRAY_12BIT: + s->output_bytes_per_pixel = 2; + break; + case T4_IMAGE_TYPE_COLOUR_8BIT: + s->output_bytes_per_pixel = 3; + break; + case T4_IMAGE_TYPE_COLOUR_12BIT: + s->output_bytes_per_pixel = 6; + break; + default: + s->output_bytes_per_pixel = 1; break; } @@ -434,9 +630,9 @@ SPAN_DECLARE(image_translate_state_t *) image_translate_init(image_translate_sta { for (i = 0; i < 2; i++) { - if ((s->raw_pixel_row[i] = (uint8_t *) malloc(s->input_width*s->bytes_per_pixel)) == NULL) + if ((s->raw_pixel_row[i] = (uint8_t *) malloc(s->input_width*s->input_bytes_per_pixel)) == NULL) return NULL; - memset(s->raw_pixel_row[i], 0, s->input_width*s->bytes_per_pixel); + memset(s->raw_pixel_row[i], 0, s->input_width*s->input_bytes_per_pixel); if ((s->pixel_row[i] = (uint8_t *) malloc(s->output_width*sizeof(uint8_t))) == NULL) return NULL; memset(s->pixel_row[i], 0, s->output_width*sizeof(uint8_t)); @@ -446,9 +642,9 @@ SPAN_DECLARE(image_translate_state_t *) image_translate_init(image_translate_sta { for (i = 0; i < 2; i++) { - if ((s->pixel_row[i] = (uint8_t *) malloc(s->output_width*s->bytes_per_pixel)) == NULL) + if ((s->pixel_row[i] = (uint8_t *) malloc(s->output_width*s->input_bytes_per_pixel)) == NULL) return NULL; - memset(s->pixel_row[i], 0, s->output_width*s->bytes_per_pixel); + memset(s->pixel_row[i], 0, s->output_width*s->input_bytes_per_pixel); } } diff --git a/libs/spandsp/src/spandsp/image_translate.h b/libs/spandsp/src/spandsp/image_translate.h index 31f13d2845..7f91c2db0a 100644 --- a/libs/spandsp/src/spandsp/image_translate.h +++ b/libs/spandsp/src/spandsp/image_translate.h @@ -2,8 +2,9 @@ * SpanDSP - a series of DSP components for telephony * * image_translate.h - Image translation routines for reworking colour - * and gray scale images to be bi-level images of an - * appropriate size to be FAX compatible. + * and gray scale images to be colour, gray scale or + * bi-level images of an appropriate size to be FAX + * compatible. * * Written by Steve Underwood * diff --git a/libs/spandsp/src/spandsp/private/image_translate.h b/libs/spandsp/src/spandsp/private/image_translate.h index e473a0f644..02a13506df 100644 --- a/libs/spandsp/src/spandsp/private/image_translate.h +++ b/libs/spandsp/src/spandsp/private/image_translate.h @@ -1,7 +1,7 @@ /* * SpanDSP - a series of DSP components for telephony * - * private/image_translate.c - Image translation routines for reworking colour + * private/image_translate.h - Image translation routines for reworking colour * and gray scale images to be bi-level images of an * appropriate size to be FAX compatible. * @@ -33,11 +33,12 @@ struct image_translate_state_s int input_format; int input_width; int input_length; + int input_bytes_per_pixel; int output_format; int output_width; int output_length; + int output_bytes_per_pixel; int resize; - int bytes_per_pixel; int raw_input_row; int raw_output_row; int output_row; diff --git a/libs/spandsp/tests/image_translate_tests.c b/libs/spandsp/tests/image_translate_tests.c index b57fe3965b..b1930c12a3 100644 --- a/libs/spandsp/tests/image_translate_tests.c +++ b/libs/spandsp/tests/image_translate_tests.c @@ -159,7 +159,7 @@ static int row_read(void *user_data, uint8_t buf[], size_t len) } /*- End of function --------------------------------------------------------*/ -static void get_flattened_image(image_translate_state_t *s, int compare) +static void get_bilevel_image(image_translate_state_t *s, int compare) { int i; int len; @@ -191,12 +191,147 @@ static void get_flattened_image(image_translate_state_t *s, int compare) } /*- End of function --------------------------------------------------------*/ +static void get_gray8_image(image_translate_state_t *s, int compare) +{ + int i; + int j; + int len; + uint8_t row_buf[5000]; + + for (i = 0; i < s->output_length; i++) + { + if ((len = image_translate_row(s, row_buf, s->output_width)) != s->output_width) + { + printf("Image finished early - %d %d\n", len, s->output_width); + exit(2); + } + if (compare) + { + for (j = 0; j < 50; j++) + { + if (row_buf[j] != j*1200/256) + { + printf("Image mismatch - %d - %d\n", j, row_buf[3*j]); + exit(2); + } + } + } + } + if ((len = image_translate_row(s, row_buf, s->output_width)) != 0) + { + printf("Image finished late - %d %d\n", len, s->output_width); + exit(2); + } +} +/*- End of function --------------------------------------------------------*/ + +static void get_gray16_image(image_translate_state_t *s, int compare) +{ + int i; + int j; + int len; + uint16_t row_buf[5000]; + + for (i = 0; i < s->output_length; i++) + { + if ((len = image_translate_row(s, (uint8_t *) row_buf, 2*s->output_width)) != 2*s->output_width) + { + printf("Image finished early - %d %d\n", len, 2*s->output_width); + exit(2); + } + if (compare) + { + for (j = 0; j < 50; j++) + { + if (row_buf[j] != j*1200) + { + printf("Image mismatch - %d - %d\n", j, row_buf[j]); + exit(2); + } + } + } + } + if ((len = image_translate_row(s, (uint8_t *) row_buf, 2*s->output_width)) != 0) + { + printf("Image finished late - %d %d\n", len, 2*s->output_width); + exit(2); + } +} +/*- End of function --------------------------------------------------------*/ + +static void get_colour8_image(image_translate_state_t *s, int compare) +{ + int i; + int j; + int len; + uint8_t row_buf[5000]; + + for (i = 0; i < s->output_length; i++) + { + if ((len = image_translate_row(s, row_buf, 3*s->output_width)) != 3*s->output_width) + { + printf("Image finished early - %d %d\n", len, 3*s->output_width); + exit(2); + } + if (compare) + { + for (j = 0; j < 50; j++) + { + if (row_buf[3*j + 0] != j*1200/256 || row_buf[3*j + 1] != j*1200/256 || row_buf[3*j + 2] != j*1200/256) + { + printf("Image mismatch - %d - %d %d %d\n", j, row_buf[3*j + 0], row_buf[3*j + 1], row_buf[3*j + 2]); + exit(2); + } + } + } + } + if ((len = image_translate_row(s, row_buf, 2*s->output_width)) != 0) + { + printf("Image finished late - %d %d\n", len, 3*s->output_width); + exit(2); + } +} +/*- End of function --------------------------------------------------------*/ + +static void get_colour16_image(image_translate_state_t *s, int compare) +{ + int i; + int j; + int len; + uint16_t row_buf[5000]; + + for (i = 0; i < s->output_length; i++) + { + if ((len = image_translate_row(s, (uint8_t *) row_buf, 6*s->output_width)) != 6*s->output_width) + { + printf("Image finished early - %d %d\n", len, 6*s->output_width); + exit(2); + } + if (compare) + { + for (j = 0; j < 50; j++) + { + if (row_buf[3*j + 0] != j*1200 || row_buf[3*j + 1] != j*1200 || row_buf[3*j + 2] != j*1200) + { + printf("Image mismatch - %d - %d %d %d\n", j, row_buf[3*j + 0], row_buf[3*j + 1], row_buf[3*j + 2]); + exit(2); + } + } + } + } + if ((len = image_translate_row(s, (uint8_t *) row_buf, 6*s->output_width)) != 0) + { + printf("Image finished late - %d %d\n", len, 6*s->output_width); + exit(2); + } +} +/*- End of function --------------------------------------------------------*/ + static void dither_tests_gray16(void) { int i; int j; - image_translate_state_t bw; - image_translate_state_t *s = &bw; + image_translate_state_t *s; uint16_t image[50*50]; image_descriptor_t im; @@ -213,8 +348,9 @@ static void dither_tests_gray16(void) image[i*im.width + j] = j*1200; } - s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im); - get_flattened_image(s, TRUE); + s = image_translate_init(NULL, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im); + get_bilevel_image(s, TRUE); + image_translate_free(s); } /*- End of function --------------------------------------------------------*/ @@ -222,8 +358,7 @@ static void dither_tests_gray8(void) { int i; int j; - image_translate_state_t bw; - image_translate_state_t *s = &bw; + image_translate_state_t *s; uint8_t image[50*50]; image_descriptor_t im; @@ -239,8 +374,10 @@ static void dither_tests_gray8(void) for (j = 0; j < im.width; j++) image[i*im.width + j] = j*1200/256; } - s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_8BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im); - get_flattened_image(s, TRUE); + + s = image_translate_init(NULL, T4_IMAGE_TYPE_GRAY_8BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im); + get_bilevel_image(s, TRUE); + image_translate_free(s); } /*- End of function --------------------------------------------------------*/ @@ -248,8 +385,7 @@ static void dither_tests_colour16(void) { int i; int j; - image_translate_state_t bw; - image_translate_state_t *s = &bw; + image_translate_state_t *s; uint16_t image[50*50*3]; image_descriptor_t im; @@ -264,13 +400,96 @@ static void dither_tests_colour16(void) { for (j = 0; j < im.width; j++) { - image[i*3*im.width + 3*j + 0] = j*1200; - image[i*3*im.width + 3*j + 1] = j*1200; - image[i*3*im.width + 3*j + 2] = j*1200; + image[i*3*im.width + 3*j + 0] = j*1200 + i; + image[i*3*im.width + 3*j + 1] = j*1200 + i; + image[i*3*im.width + 3*j + 2] = j*1200 + i; } } - s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im); - get_flattened_image(s, TRUE); + + s = image_translate_init(NULL, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im); + get_bilevel_image(s, TRUE); + + printf("Scrunching from a 3x16 bit per sample colour to 8 bit per sample gray scale\n"); + im.image = (const uint8_t *) image; + im.width = 50; + im.length = 50; + im.bytes_per_pixel = 6; + im.current_row = 0; + + for (i = 0; i < im.length; i++) + { + for (j = 0; j < im.width; j++) + { + image[i*3*im.width + 3*j + 0] = j*1200 + i; + image[i*3*im.width + 3*j + 1] = j*1200 + i; + image[i*3*im.width + 3*j + 2] = j*1200 + i; + } + } + + s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, T4_IMAGE_TYPE_GRAY_8BIT, -1, -1, row_read, &im); + get_gray8_image(s, TRUE); + + printf("Scrunching from a 3x16 bit per sample colour to 16 bit per sample gray scale\n"); + im.image = (const uint8_t *) image; + im.width = 50; + im.length = 50; + im.bytes_per_pixel = 6; + im.current_row = 0; + + for (i = 0; i < im.length; i++) + { + for (j = 0; j < im.width; j++) + { + image[i*3*im.width + 3*j + 0] = j*1200 + i; + image[i*3*im.width + 3*j + 1] = j*1200 + i; + image[i*3*im.width + 3*j + 2] = j*1200 + i; + } + } + + s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, T4_IMAGE_TYPE_GRAY_12BIT, -1, -1, row_read, &im); + get_gray16_image(s, TRUE); + + printf("Scrunching from a 3x16 bit per sample colour to 3x8 bit per sample colour\n"); + im.image = (const uint8_t *) image; + im.width = 50; + im.length = 50; + im.bytes_per_pixel = 6; + im.current_row = 0; + + for (i = 0; i < im.length; i++) + { + for (j = 0; j < im.width; j++) + { + image[i*3*im.width + 3*j + 0] = j*1200 + i; + image[i*3*im.width + 3*j + 1] = j*1200 + i; + image[i*3*im.width + 3*j + 2] = j*1200 + i; + } + } + + s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, T4_IMAGE_TYPE_COLOUR_8BIT, -1, -1, row_read, &im); + get_colour8_image(s, TRUE); + + printf("Scrunching from a 3x16 bit per sample colour to 3x16 bit per sample colour\n"); + im.image = (const uint8_t *) image; + im.width = 50; + im.length = 50; + im.bytes_per_pixel = 6; + im.current_row = 0; + + for (i = 0; i < im.length; i++) + { + for (j = 0; j < im.width; j++) + { + image[i*3*im.width + 3*j + 0] = j*1200 + i; + image[i*3*im.width + 3*j + 1] = j*1200 + i; + image[i*3*im.width + 3*j + 2] = j*1200 + i; + } + } + + s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, T4_IMAGE_TYPE_COLOUR_12BIT, -1, -1, row_read, &im); + get_colour16_image(s, TRUE); + + image_translate_free(s); } /*- End of function --------------------------------------------------------*/ @@ -278,8 +497,7 @@ static void dither_tests_colour8(void) { int i; int j; - image_translate_state_t bw; - image_translate_state_t *s = &bw; + image_translate_state_t *s; uint8_t image[50*50*3]; image_descriptor_t im; @@ -294,14 +512,15 @@ static void dither_tests_colour8(void) { for (j = 0; j < im.width; j++) { - image[i*3*im.width + 3*j + 0] = j*1200/256; - image[i*3*im.width + 3*j + 1] = j*1200/256; - image[i*3*im.width + 3*j + 2] = j*1200/256; + image[i*3*im.width + 3*j + 0] = j*1200/256 + i; + image[i*3*im.width + 3*j + 1] = j*1200/256 + i; + image[i*3*im.width + 3*j + 2] = j*1200/256 + i; } } - s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im); - get_flattened_image(s, TRUE); + s = image_translate_init(NULL, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im); + get_bilevel_image(s, TRUE); + image_translate_free(s); } /*- End of function --------------------------------------------------------*/ @@ -309,8 +528,7 @@ static void grow_tests_colour8(void) { int i; int j; - image_translate_state_t resize; - image_translate_state_t *s1 = &resize; + image_translate_state_t *s; uint8_t image[50*50*3]; image_descriptor_t im; @@ -325,15 +543,15 @@ static void grow_tests_colour8(void) { for (j = 0; j < im.width; j++) { - image[i*3*im.width + 3*j + 0] = j*1200/256; - image[i*3*im.width + 3*j + 1] = j*1200/256; - image[i*3*im.width + 3*j + 2] = j*1200/256; + image[i*3*im.width + 3*j + 0] = j*1200/256 + i; + image[i*3*im.width + 3*j + 1] = j*1200/256 + i; + image[i*3*im.width + 3*j + 2] = j*1200/256 + i; } } - s1 = image_translate_init(s1, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, 200, -1, row_read, &im); - - get_flattened_image(s1, FALSE); + s = image_translate_init(NULL, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, 200, -1, row_read, &im); + get_bilevel_image(s, FALSE); + image_translate_free(s); } /*- End of function --------------------------------------------------------*/ @@ -352,8 +570,7 @@ static void lenna_tests(int output_width, int output_length_scaling, const char int16_t samples_per_pixel; int i; int n; - image_translate_state_t bw; - image_translate_state_t *s = &bw; + image_translate_state_t *s; image_descriptor_t im; float x_resolution; float y_resolution; @@ -375,7 +592,7 @@ static void lenna_tests(int output_width, int output_length_scaling, const char y_resolution = 200.0; TIFFGetField(in_file, TIFFTAG_YRESOLUTION, &y_resolution); res_unit = RESUNIT_INCH; - TIFFSetField(in_file, TIFFTAG_RESOLUTIONUNIT, &res_unit); + TIFFGetField(in_file, TIFFTAG_RESOLUTIONUNIT, &res_unit); bits_per_sample = 0; TIFFGetField(in_file, TIFFTAG_BITSPERSAMPLE, &bits_per_sample); samples_per_pixel = 0; @@ -409,7 +626,7 @@ static void lenna_tests(int output_width, int output_length_scaling, const char im.current_row = 0; im.bytes_per_pixel = samples_per_pixel; - s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_8BIT, image_width, image_length, T4_IMAGE_TYPE_BILEVEL, output_width, output_length, row_read, &im); + s = image_translate_init(NULL, T4_IMAGE_TYPE_COLOUR_8BIT, image_width, image_length, T4_IMAGE_TYPE_BILEVEL, output_width, output_length, row_read, &im); output_width = image_translate_get_output_width(s); output_length = image_translate_get_output_length(s); @@ -445,6 +662,7 @@ static void lenna_tests(int output_width, int output_length_scaling, const char TIFFWriteEncodedStrip(out_file, 0, image2, output_width*output_length/8); TIFFWriteDirectory(out_file); TIFFClose(out_file); + image_translate_free(s); } /*- End of function --------------------------------------------------------*/ From 9a26b3a8a78d2e948d1e293c3775485982489d93 Mon Sep 17 00:00:00 2001 From: Steve Underwood Date: Wed, 8 Aug 2012 21:31:45 +0800 Subject: [PATCH 410/822] Fixed harmless typos in comments --- libs/spandsp/src/spandsp/ima_adpcm.h | 2 +- libs/spandsp/src/spandsp/private/ima_adpcm.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/spandsp/src/spandsp/ima_adpcm.h b/libs/spandsp/src/spandsp/ima_adpcm.h index 27be7ec736..292bdd5d83 100644 --- a/libs/spandsp/src/spandsp/ima_adpcm.h +++ b/libs/spandsp/src/spandsp/ima_adpcm.h @@ -2,7 +2,7 @@ * SpanDSP - a series of DSP components for telephony * * ima_adpcm.c - Conversion routines between linear 16 bit PCM data and - * IMA/DVI/Intel ADPCM format. + * IMA/DVI/Intel ADPCM format. * * Written by Steve Underwood * diff --git a/libs/spandsp/src/spandsp/private/ima_adpcm.h b/libs/spandsp/src/spandsp/private/ima_adpcm.h index 1685906c28..21ead941af 100644 --- a/libs/spandsp/src/spandsp/private/ima_adpcm.h +++ b/libs/spandsp/src/spandsp/private/ima_adpcm.h @@ -2,7 +2,7 @@ * SpanDSP - a series of DSP components for telephony * * private/ima_adpcm.c - Conversion routines between linear 16 bit PCM data - * and IMA/DVI/Intel ADPCM format. + * and IMA/DVI/Intel ADPCM format. * * Written by Steve Underwood * From 16692837c168ac22eb8c52a099286ce05750adc4 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Wed, 8 Aug 2012 09:58:41 -0400 Subject: [PATCH 411/822] freetdm: Process OOB events even in M2UA mode --- .../ftmod_sangoma_ss7_main.c | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 90202d3989..ab74a9830a 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -338,14 +338,38 @@ static void handle_hw_alarm(ftdm_event_t *e) } } + +static void check_span_oob_events(ftdm_span_t *ftdmspan) +{ + ftdm_event_t *event = NULL; + /* Poll for events, e.g HW DTMF */ + switch (ftdm_span_poll_event(ftdmspan, 0, NULL)) { + /**********************************************************************/ + case FTDM_SUCCESS: + while (ftdm_span_next_event(ftdmspan, &event) == FTDM_SUCCESS) { + if (event->e_type == FTDM_EVENT_OOB) { + handle_hw_alarm(event); + } + } + break; + /**********************************************************************/ + case FTDM_TIMEOUT: + /* No events pending */ + break; + /**********************************************************************/ + default: + SS7_ERROR("%s:Failed to poll span event\n", ftdmspan->name); + /**********************************************************************/ + } +} + /* MONITIOR THREADS ***********************************************************/ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) { ftdm_interrupt_t *ftdm_sangoma_ss7_int[2]; ftdm_span_t *ftdmspan = (ftdm_span_t *) obj; ftdm_channel_t *ftdmchan = NULL; - ftdm_event_t *event = NULL; - sngss7_event_data_t *sngss7_event = NULL; + sngss7_event_data_t *sngss7_event = NULL; sngss7_span_data_t *sngss7_span = (sngss7_span_data_t *)ftdmspan->signal_data; int b_alarm_test = 1; @@ -398,8 +422,7 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) break; /**********************************************************************/ } - - + check_span_oob_events(ftdmspan); } goto ftdm_sangoma_ss7_stop; } @@ -514,25 +537,7 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) /* check each channel on the span to see if it needs to be reconfigured */ check_for_reconfig_flag(ftdmspan); - /* Poll for events, e.g HW DTMF */ - switch (ftdm_span_poll_event(ftdmspan, 0, NULL)) { - /**********************************************************************/ - case FTDM_SUCCESS: - while (ftdm_span_next_event(ftdmspan, &event) == FTDM_SUCCESS) { - if (event->e_type == FTDM_EVENT_OOB) { - handle_hw_alarm(event); - } - } - break; - /**********************************************************************/ - case FTDM_TIMEOUT: - /* No events pending */ - break; - /**********************************************************************/ - default: - SS7_ERROR("%s:Failed to poll span event\n", ftdmspan->name); - /**********************************************************************/ - } + check_span_oob_events(ftdmspan); } ftdm_sangoma_ss7_stop: From 99e04bf1d86b6b184a926e88f8be551623550369 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 8 Aug 2012 10:17:42 -0400 Subject: [PATCH 412/822] debug prints modification --- .../mod_media_gateway/media_gateway.c | 3 -- .../media_gateway_cmd_handler.c | 54 +++++++++++-------- .../mod_media_gateway/media_gateway_xml.c | 1 - .../mod_media_gateway/mod_media_gateway.h | 1 - 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 52081dbc12..a9bcd85fe2 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -222,7 +222,6 @@ mg_termination_t *megaco_choose_termination(megaco_profile_t *profile, const cha term->pool = pool; term->type = termtype; term->active_events = NULL; - term->mg_ctxt = NULL; term->profile = profile; switch_set_flag(term, MGT_ALLOCATED); @@ -335,8 +334,6 @@ void megaco_termination_destroy(mg_termination_t *term) term->active_events = NULL; } - term->mg_ctxt = NULL; - switch_clear_flag(term, MGT_ALLOCATED); switch_clear_flag(term, MGT_ACTIVE); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index b3661f75e8..13f8107665 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -347,7 +347,7 @@ switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand * for(fmtCnt = 0; fmtCnt < fmt_list->num.val; fmtCnt++){ fmt = &fmt_list->fmts[i]->val; if(fmt->pres == NOTPRSNT) continue; - printf("Format [%d]\n", fmt->val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,"Format [%d]\n", fmt->val); } } } @@ -381,30 +381,30 @@ switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand * case MGT_LCLCTL_MODE: { /* Mode Property */ - printf("MGT_LCLCTL_MODE - Mode value [%d]\n", lclParm->u.mode.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,"MGT_LCLCTL_MODE - Mode value [%d]\n", lclParm->u.mode.val); break; } case MGT_LCLCTL_RESVAL: { /* Reserve Value */ - printf("MGT_LCLCTL_RESVAL: Reserve Value[%d] \n", lclParm->u.resVal.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,"MGT_LCLCTL_RESVAL: Reserve Value[%d] \n", lclParm->u.resVal.val); break; } case MGT_LCLCTL_RESGRP: { /* Reserve group */ - printf("MGT_LCLCTL_RESGRP: Reserve Group[%d]\n", lclParm->u.resGrp.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,"MGT_LCLCTL_RESGRP: Reserve Group[%d]\n", lclParm->u.resGrp.val); break; } case MGT_LCLCTL_PROPPARM: { /* Properties (of a termination) */ /* Matt - See how we can apply this to a termination */ - printf("MGT_LCLCTL_PROPPARM: \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,"MGT_LCLCTL_PROPPARM: \n"); break; } default: - printf("Invalid local control descriptor type[%d]\n",lclParm->type.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,"Invalid local control descriptor type[%d]\n",lclParm->type.val); break; } } @@ -429,23 +429,23 @@ switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand * { /* Matt to see how to apply properties to a termination */ /* Properties of a termination */ - printf("MGT_TERMST_PROPLST:\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,"MGT_TERMST_PROPLST:\n"); break; } case MGT_TERMST_EVTBUFCTL: { /* Event /buffer Control Properties */ - printf(" MGT_TERMST_EVTBUFCTL: value[%d]\n", tsp->u.evtBufCtl.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE," MGT_TERMST_EVTBUFCTL: value[%d]\n", tsp->u.evtBufCtl.val); break; } case MGT_TERMST_SVCST: { /* Service State Properties */ - printf(" MGT_TERMST_SVCST: value[%d]\n", tsp->u.svcState.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE," MGT_TERMST_SVCST: value[%d]\n", tsp->u.svcState.val); break; } default: - printf("Invalid termination state descriptor type[%d]\n",tsp->type.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,"Invalid termination state descriptor type[%d]\n",tsp->type.val); break; } } @@ -630,6 +630,7 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i mg_ctxt = megaco_choose_context(mg_profile); if(NULL == mg_ctxt){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," megaco_choose_context failed \n"); mg_util_set_err_string(&errTxt, " Resource Failure "); err_code = MGT_MGCO_RSP_CODE_RSRC_ERROR; goto error; @@ -646,6 +647,13 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i memcpy(new_ctxtId, &inc_cmd->contextId,sizeof(MgMgcoContextId)); mg_ctxt = megaco_get_context(mg_profile, inc_cmd->contextId.val.val); if(NULL == mg_ctxt){ +#ifdef BIT_64 + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, + " megaco_get_context failed for context-id[%d]\n", inc_cmd->contextId.val.val); +#else + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, + " megaco_get_context failed for context-id[%ld]\n", inc_cmd->contextId.val.val); +#endif mg_util_set_err_string(&errTxt, " Resource Failure "); err_code = MGT_MGCO_RSP_CODE_RSRC_ERROR; goto error; @@ -660,15 +668,12 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i term = megaco_choose_termination(mg_profile, mg_profile->rtp_termination_id_prefix); if(NULL == term){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR," megaco_choose_termination failed \n"); mg_util_set_err_string(&errTxt, " Resource Failure "); err_code = MGT_MGCO_RSP_CODE_RSRC_ERROR; goto error; } - if(!term->mg_ctxt){ - term->mg_ctxt = mg_ctxt; - } - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Allocated Termination[%p] with term name[%s]\n", (void*)term, term->name); is_rtp = 0x01; @@ -678,26 +683,33 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i term = megaco_find_termination(mg_profile, (char*)termId->name.lcl.val); if(NULL == term){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, + " megaco_find_termination failed for term-id[%s] \n",(char*)termId->name.lcl.val); mg_util_set_err_string(&errTxt, " Resource Failure "); err_code = MGT_MGCO_RSP_CODE_RSRC_ERROR; goto error; } - if(!term->mg_ctxt){ - term->mg_ctxt = mg_ctxt; - } else { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Termination[%s] already in context..rejecting ADD \n", term->name); + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Allocated Termination[%p] with term name[%s]\n", (void*)term, term->name); + } + + /********************************************************************/ + /* check if termination already is in call */ + + if(term->context){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Termination[%p : %s] " + "already in context[%p -%d]..rejecting ADD \n", + (void*)term, term->name, (void*)term->context,term->context->context_id); mg_util_set_err_string(&errTxt, " Term already is in call "); err_code = MGT_MGCO_RSP_CODE_DUP_TERM_CTXT; goto error; } - - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO," Allocated Termination[%p] with term name[%s]\n", (void*)term, term->name); - } /********************************************************************/ /* associate physical termination to context */ if(SWITCH_STATUS_FALSE == megaco_context_add_termination(mg_ctxt, term)){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"megaco_context_add_termination failed \n"); mg_util_set_err_string(&errTxt, " Resource Failure "); err_code = MGT_MGCO_RSP_CODE_RSRC_ERROR; goto error; diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index 4b242a6b9b..08044bc9f7 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -210,7 +210,6 @@ void mg_create_tdm_term(megaco_profile_t *profile, const char *tech, const char term->pool = pool; term->type = MG_TERM_TDM; term->profile = profile; - term->mg_ctxt = NULL; term->tech = switch_core_strdup(pool, tech); term->active_events = NULL; term->name = switch_core_sprintf(pool, "%s%d", prefix, chan_num); diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index 36bcf5146f..46f850ff16 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -113,7 +113,6 @@ struct mg_termination_s { megaco_profile_t *profile; /*!< Parent MG profile */ MgMgcoReqEvtDesc *active_events; /* !< active megaco events */ mg_termination_t *next; /*!< List for physical terminations */ - mg_context_t* mg_ctxt; int *mg_error_code; /* MEGACO error code */ uint32_t flags; const char *tech; /* Endpoint controlling the TDM interface - only FreeTDM tested so far */ From 47f614d40ad9b79971645fc622cd6a48bb0a4a0c Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 8 Aug 2012 09:59:36 -0500 Subject: [PATCH 413/822] FS-4507 --resolve --- src/mod/endpoints/mod_sofia/sofia_presence.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index 23db7d0094..0433f84ba1 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -2365,6 +2365,10 @@ static char *gen_pidf(char *user_agent, char *id, char *url, char *open, char *r prpid = "onthephone"; } + if (zstr(open)) { + open = "open"; + } + ret = switch_mprintf("\n" "\n" "\n" @@ -2945,7 +2949,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * open = "closed"; } - if (open_closed) { + if (!zstr(open_closed)) { open = open_closed; } @@ -2977,7 +2981,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * open = "closed"; } - if (open_closed) { + if (!zstr(open_closed)) { open = open_closed; } From 210acdd165ba39963bfc1b4c989621b31e787299 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 8 Aug 2012 10:08:29 -0500 Subject: [PATCH 414/822] FS-4505 --resolve --- src/mod/endpoints/mod_rtmp/mod_rtmp.c | 8 +++++++- src/mod/endpoints/mod_rtmp/mod_rtmp.h | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_rtmp/mod_rtmp.c b/src/mod/endpoints/mod_rtmp/mod_rtmp.c index 6b5bc862c9..0dd91cbecb 100644 --- a/src/mod/endpoints/mod_rtmp/mod_rtmp.c +++ b/src/mod/endpoints/mod_rtmp/mod_rtmp.c @@ -1048,6 +1048,10 @@ void rtmp_add_registration(rtmp_session_t *rsession, const char *auth, const cha dup = strdup(auth); switch_split_user_domain(dup, &user, &domain); + + + reg->user = switch_core_strdup(rsession->pool, user); + reg->domain = switch_core_strdup(rsession->pool, domain); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "User", user); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Domain", domain); @@ -1072,9 +1076,11 @@ static void rtmp_clear_reg_auth(rtmp_session_t *rsession, const char *auth, cons /* Replace hash entry by its next ptr */ switch_core_hash_insert(rsession->profile->reg_hash, auth, reg->next); } - + if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, RTMP_EVENT_UNREGISTER) == SWITCH_STATUS_SUCCESS) { rtmp_event_fill(rsession, event); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "User", reg->user); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Domain", reg->domain); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Nickname", switch_str_nil(reg->nickname)); switch_event_fire(&event); } diff --git a/src/mod/endpoints/mod_rtmp/mod_rtmp.h b/src/mod/endpoints/mod_rtmp/mod_rtmp.h index 6109c8544e..24ef575449 100644 --- a/src/mod/endpoints/mod_rtmp/mod_rtmp.h +++ b/src/mod/endpoints/mod_rtmp/mod_rtmp.h @@ -529,6 +529,8 @@ typedef struct rtmp_reg rtmp_reg_t; struct rtmp_reg { const char *uuid; /* < The rtmp session id */ const char *nickname; /* < This instance's nickname, optional */ + const char *user; + const char *domain; rtmp_reg_t *next; /* < Next entry */ }; From e5d140d1e6934fc266d1ddc606ed2d099044e860 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Wed, 8 Aug 2012 13:34:42 -0400 Subject: [PATCH 415/822] adding code for reporting DTMF to MGC --- .../mod_media_gateway/media_gateway.c | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index a9bcd85fe2..ca973e10a9 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -7,6 +7,7 @@ */ #include "mod_media_gateway.h" +#include "media_gateway_stack.h" megaco_profile_t *megaco_profile_locate(const char *name) { @@ -79,6 +80,24 @@ megaco_profile_t* megaco_get_profile_by_suId(SuId suId) return profile; } + +static switch_status_t mg_on_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + mg_termination_t *term = switch_channel_get_private(channel, "_mg_term_"); + char digit[2] = { dtmf->digit }; + if (!term) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find termination structure for session [%s]\n", + switch_core_session_get_uuid(session)); + return SWITCH_STATUS_SUCCESS; + } + + //switch_status_t mg_send_dtmf_notify(megaco_profile_t* mg_profile, const char* term_name, char* digits, int num_of_collected_digits); + //mg_send_dtmf_notify(term->profile, term->name, digit, 1); + switch_log_printf("NOT Sending notify to MGC for dtmf: %c\n", dtmf->digit); + return SWITCH_STATUS_SUCCESS; +} + /* * Creates a freeswitch channel for the specified termination. * The channel will be parked until future actions are taken @@ -136,6 +155,7 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) } if (zstr(term->uuid)) { + switch_channel_t *channel; if (switch_ivr_originate(NULL, &session, &cause, dialstring, 0, NULL, NULL, NULL, NULL, var_event, 0, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to instanciate termination [%s]: %s\n", term->name, switch_channel_cause2str(cause)); status = SWITCH_STATUS_FALSE; @@ -144,6 +164,9 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) term->uuid = switch_core_strdup(term->pool, switch_core_session_get_uuid(session)); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Termination [%s] successfully instanciated as [%s] [%s]\n", term->name, dialstring, switch_core_session_get_uuid(session)); + channel = switch_core_session_get_channel(session); + switch_channel_set_private(channel, "_mg_term_", term); + switch_core_event_hook_add_recv_dtmf(session, mg_on_dtmf); } switch_set_flag(term, MGT_ACTIVE); From d04606fb091fc97a9dc00b5a2a91b0e619be9a2e Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Wed, 8 Aug 2012 14:43:55 -0400 Subject: [PATCH 416/822] updating rfc2833 variable code --- .../mod_media_gateway/media_gateway.c | 4 +- .../mod_media_gateway/media_gateway_utils.c | 52 +++++++++++++------ 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index ca973e10a9..9df5e2a2e0 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -85,7 +85,7 @@ static switch_status_t mg_on_dtmf(switch_core_session_t *session, const switch_d { switch_channel_t *channel = switch_core_session_get_channel(session); mg_termination_t *term = switch_channel_get_private(channel, "_mg_term_"); - char digit[2] = { dtmf->digit }; + //char digit[2] = { dtmf->digit }; if (!term) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find termination structure for session [%s]\n", switch_core_session_get_uuid(session)); @@ -94,7 +94,7 @@ static switch_status_t mg_on_dtmf(switch_core_session_t *session, const switch_d //switch_status_t mg_send_dtmf_notify(megaco_profile_t* mg_profile, const char* term_name, char* digits, int num_of_collected_digits); //mg_send_dtmf_notify(term->profile, term->name, digit, 1); - switch_log_printf("NOT Sending notify to MGC for dtmf: %c\n", dtmf->digit); + //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MEGACO DTMF Signaling NOT Sending notify to MGC for dtmf:%c\n",dtmf->digit); return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index 3801ade93b..11d68f026c 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -528,7 +528,7 @@ void mgco_handle_sdp_attr_set(CmSdpAttrSet *s, mg_termination_t* term) CmSdpAttrFmtp* f = &a->u.fmtp; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t CM_SDP_ATTR_FMTP: \n"); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Format Type = %d \n",(NOTPRSNT == f->type.pres)?f->type.val:-1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Format Type = %d \n",(NOTPRSNT != f->type.pres)?f->type.val:-1); break; } @@ -540,30 +540,47 @@ void mgco_handle_sdp_attr_set(CmSdpAttrSet *s, mg_termination_t* term) if(NOTPRSNT != r->pres.pres){ /* payload type */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Payload Type = %d \n", - (NOTPRSNT != r->pay.type.pres)?r->pay.type.val:-1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t Payload Type = %d \n", + (NOTPRSNT != r->pay.type.pres)?r->pay.type.val:-1); /* payload value */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Payload Value = %d \n", - (NOTPRSNT != r->pay.val.pres)?r->pay.val.val:-1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t Payload Value = %d \n", + (NOTPRSNT != r->pay.val.pres)?r->pay.val.val:-1); /* encoding name */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Encoding Name value = %d \n", - (NOTPRSNT != r->enc.val.pres)?r->enc.val.val:-1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t Encoding Name value = %d \n", + (NOTPRSNT != r->enc.val.pres)?r->enc.val.val:-1); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Encoding Name name = %s \n", - (NOTPRSNT != r->enc.name.pres)?(char*)r->enc.name.val:"Not Present"); + if((NOTPRSNT != r->enc.val.pres ) && + (CM_SDP_ENC_TELEPHONE_EVENT == r->enc.val.val)){ + + term->u.rtp.rfc2833_pt=r->pay.val.val; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + " Updating rfc2833_pt to [%d] \n", term->u.rtp.rfc2833_pt); + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t Encoding Name name = %s \n", + (NOTPRSNT != r->enc.name.pres)? + (char*)r->enc.name.val:"Not Present"); #ifdef BIT_64 - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Clock Rate = %d \n", - (NOTPRSNT != r->clk.pres)?r->clk.val:-1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t Clock Rate = %d \n", + (NOTPRSNT != r->clk.pres)?r->clk.val:-1); #else - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Clock Rate = %ld \n", - (NOTPRSNT != r->clk.pres)?r->clk.val:-1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t Clock Rate = %ld \n", + (NOTPRSNT != r->clk.pres)?r->clk.val:-1); #endif - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Encoding Parameters = %s \n", - (NOTPRSNT != r->parms.pres)?(char*)r->parms.val:"Not Present"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t Encoding Parameters = %s \n", + (NOTPRSNT != r->parms.pres)? + (char*)r->parms.val:"Not Present"); } break; } @@ -1832,8 +1849,11 @@ switch_status_t mg_rem_unsupported_codecs (megaco_profile_t* mg_profile, mg_term /* see if received codec is present in our codec supported list */ for (id = 0; codecs[id] && id < codec_count; id++) { int pt = codecs[id]->ianacode; - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "Matching recv codec[%d] with supported codec[%d] \n", fmt->val.val, pt); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + "Matching recv codec[%d] with supported codec[%d] \n", fmt->val.val, pt); //const char *name = codecs[id]->iananame; + /* anything > 96 is dymanic we should skip codec match */ + if(fmt->val.val >= 96) {foundCodec = 0x01; break;} if(pt == fmt->val.val){ foundCodec = 0x01; break; From e0a7c69ca05a8df79e0cab2f8264c5c4497d9171 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Wed, 8 Aug 2012 15:21:42 -0400 Subject: [PATCH 417/822] fixing rfc2833 issue --- .../media_gateway_cmd_handler.c | 22 +++++++++------- src/mod/endpoints/mod_sofia/rtp.c | 26 ++++++++++++++++--- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 13f8107665..1eacf4fb23 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -705,6 +705,17 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i err_code = MGT_MGCO_RSP_CODE_DUP_TERM_CTXT; goto error; } + +/********************************************************************/ + + ret = mg_prc_descriptors(mg_profile, inc_cmd, term, &inc_cmd->u.mgCmdInd[0]->memCp); + + /* IF there is any error , return */ + if(term->mg_error_code && (*term->mg_error_code == MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT)){ + mg_util_set_err_string(&errTxt, " Unsupported Codec "); + err_code = MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT; + goto error; + } /********************************************************************/ /* associate physical termination to context */ @@ -715,16 +726,7 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i goto error; } - /********************************************************************/ - - ret = mg_prc_descriptors(mg_profile, inc_cmd, term, &inc_cmd->u.mgCmdInd[0]->memCp); - - /* IF there is any error , return */ - if(term->mg_error_code && (*term->mg_error_code == MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT)){ - mg_util_set_err_string(&errTxt, " Unsupported Codec "); - err_code = MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT; - goto error; - } + /* TODO - locally assigned SDP must be the part of termination...which we can use to fill responses*/ diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index bf3e36ca19..2afbb3fe02 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -74,6 +74,8 @@ typedef struct { switch_port_t local_port; switch_port_t remote_port; switch_payload_t agreed_pt; /*XXX*/ + switch_payload_t rfc2833_pt; + sofia_dtmf_t dtmf_type; enum { RTP_SENDONLY, @@ -146,7 +148,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi *codec = switch_event_get_header_nil(var_event, kCODEC), *szptime = switch_event_get_header_nil(var_event, kPTIME), //*mode = switch_event_get_header_nil(var_event, kMODE), - //*szrfc2833_pt = switch_event_get_header_nil(var_event, kRFC2833PT), + *szrfc2833_pt = switch_event_get_header_nil(var_event, kRFC2833PT), *szrate = switch_event_get_header_nil(var_event, kRATE), *szpt = switch_event_get_header_nil(var_event, kPT); @@ -155,7 +157,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi remote_port = !zstr(szremote_port) ? atoi(szremote_port) : 0; int ptime = !zstr(szptime) ? atoi(szptime) : 0, - //rfc2833_pt = !zstr(szrfc2833_pt) ? atoi(szrfc2833_pt) : 0, + rfc2833_pt = !zstr(szrfc2833_pt) ? atoi(szrfc2833_pt) : 0, rate = !zstr(szrate) ? atoi(szrate) : 8000, pt = !zstr(szpt) ? atoi(szpt) : 0; @@ -185,7 +187,12 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi tech_pvt->remote_port = remote_port; tech_pvt->ptime = ptime; tech_pvt->agreed_pt = pt; - tech_pvt->dtmf_type = DTMF_2833; /* XXX */ + tech_pvt->rfc2833_pt = rfc2833_pt; + if (rfc2833_pt) { + tech_pvt->dtmf_type = DTMF_2833; + } else { + tech_pvt->dtmf_type = DTMF_NONE; + } if (zstr(local_addr) || local_port == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "The local address and port must be set\n"); @@ -247,6 +254,10 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't setup RTP session: [%s]\n", err); goto fail; } + + if (tech_pvt->dtmf_type == DTMF_2833) { + switch_rtp_set_telephony_event(tech_pvt->rtp_session, tech_pvt->rfc2833_pt); + } if (switch_core_session_thread_launch(*new_session) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't start session thread.\n"); @@ -500,11 +511,18 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi if (compare_var(event, channel, kRFC2833PT)) { const char *szpt = switch_channel_get_variable(channel, kRFC2833PT); int pt = !zstr(szpt) ? atoi(szpt) : 0; + + tech_pvt->rfc2833_pt = pt; + + if (pt) { + tech_pvt->dtmf_type = DTMF_2833; + } else { + tech_pvt->dtmf_type = DTMF_NONE; + } switch_channel_set_variable(channel, kRFC2833PT, szpt); switch_rtp_set_telephony_event(tech_pvt->rtp_session, pt); } - } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Received unknown command [%s] in event.\n", !command ? "null" : command); } From ef5c1256f3a64502880bb232ea17a673e3e4eb10 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 8 Aug 2012 14:46:38 -0500 Subject: [PATCH 418/822] add rtp endpoint contributed by sangoma --- src/mod/endpoints/mod_sofia/Makefile.am | 2 +- src/mod/endpoints/mod_sofia/mod_sofia.c | 2 + src/mod/endpoints/mod_sofia/mod_sofia.h | 1 + src/mod/endpoints/mod_sofia/rtp.c | 649 ++++++++++++++++++++++++ 4 files changed, 653 insertions(+), 1 deletion(-) create mode 100644 src/mod/endpoints/mod_sofia/rtp.c diff --git a/src/mod/endpoints/mod_sofia/Makefile.am b/src/mod/endpoints/mod_sofia/Makefile.am index fb0ab25e0b..efd6b2c385 100644 --- a/src/mod/endpoints/mod_sofia/Makefile.am +++ b/src/mod/endpoints/mod_sofia/Makefile.am @@ -9,7 +9,7 @@ SOFIAUA_BUILDDIR=$(SOFIA_BUILDDIR)/libsofia-sip-ua SOFIALA=$(SOFIAUA_BUILDDIR)/libsofia-sip-ua.la mod_LTLIBRARIES = mod_sofia.la -mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sip-dig.c mod_sofia.h +mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sip-dig.c rtp.c mod_sofia.h mod_sofia_la_CFLAGS = $(AM_CFLAGS) -I. $(SOFIA_CMD_LINE_CFLAGS) mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/bnf -I$(SOFIAUA_BUILDDIR)/bnf mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/http -I$(SOFIAUA_BUILDDIR)/http diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 52e7333607..650b898399 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -5705,6 +5705,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load) SWITCH_ADD_API(api_interface, "sofia_dig", "SIP DIG", sip_dig_function, ""); SWITCH_ADD_CHAT(chat_interface, SOFIA_CHAT_PROTO, sofia_presence_chat_send); + crtp_init(*module_interface); + /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 5ef35315e7..6d01de8a38 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -1190,6 +1190,7 @@ void sofia_process_dispatch_event(sofia_dispatch_event_t **dep); char *sofia_glue_get_host(const char *str, switch_memory_pool_t *pool); void sofia_presence_check_subscriptions(sofia_profile_t *profile, time_t now); void sofia_msg_thread_start(int idx); +void crtp_init(switch_loadable_module_interface_t *module_interface); /* For Emacs: diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c new file mode 100644 index 0000000000..bf3e36ca19 --- /dev/null +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -0,0 +1,649 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2011, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Mathieu Rene + * + * rtp.c -- RTP Controllable Channel Module + * + */ + +#include +#include "mod_sofia.h" + +#define kLOCALADDR "local_addr" +#define kLOCALPORT "local_port" +#define kREMOTEADDR "remote_addr" +#define kREMOTEPORT "remote_port" +#define kCODEC "codec" +#define kPTIME "ptime" +#define kPT "pt" +#define kRFC2833PT "rfc2833_pt" +#define kMODE "mode" +#define kRATE "rate" + +static struct { + switch_memory_pool_t *pool; + switch_endpoint_interface_t *endpoint_interface; +} crtp; + +typedef struct { + switch_core_session_t *session; + switch_channel_t *channel; + switch_codec_t read_codec, write_codec; + switch_frame_t read_frame; + + + + switch_rtp_bug_flag_t rtp_bugs; + switch_rtp_t *rtp_session; + + uint32_t timestamp_send; + + const char *local_address; + const char *remote_address; + const char *codec; + int ptime; + + const switch_codec_implementation_t *negotiated_codecs[SWITCH_MAX_CODECS]; + int num_negotiated_codecs; + + char *origin; + + switch_port_t local_port; + switch_port_t remote_port; + switch_payload_t agreed_pt; /*XXX*/ + sofia_dtmf_t dtmf_type; + enum { + RTP_SENDONLY, + RTP_RECVONLY, + RTP_SENDRECV + } mode; +} crtp_private_t; + +static switch_status_t channel_on_init(switch_core_session_t *session); +static switch_status_t channel_on_destroy(switch_core_session_t *session); +static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, + switch_memory_pool_t **pool, + switch_originate_flag_t flags, switch_call_cause_t *cancel_cause); +static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id); +static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id); +static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg); +static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf); +static switch_status_t channel_receive_event(switch_core_session_t *session, switch_event_t *event); + +switch_state_handler_table_t crtp_state_handlers = { + .on_init = channel_on_init, + .on_destroy = channel_on_destroy +}; + +switch_io_routines_t crtp_io_routines = { + .outgoing_channel = channel_outgoing_channel, + .read_frame = channel_read_frame, + .write_frame = channel_write_frame, + .receive_message = channel_receive_message, + .receive_event = channel_receive_event, + .send_dtmf = channel_send_dtmf +}; + + +void crtp_init(switch_loadable_module_interface_t *module_interface) +{ + switch_endpoint_interface_t *endpoint_interface; + //switch_api_interface_t *api_interface; + + crtp.pool = module_interface->pool; + endpoint_interface = switch_loadable_module_create_interface(module_interface, SWITCH_ENDPOINT_INTERFACE); + endpoint_interface->interface_name = "rtp"; + endpoint_interface->io_routines = &crtp_io_routines; + endpoint_interface->state_handler = &crtp_state_handlers; + crtp.endpoint_interface = endpoint_interface; + + //SWITCH_ADD_API(api_interface, "rtp_test", "test", test_function, ""); +} + +static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, + switch_memory_pool_t **pool, + switch_originate_flag_t flags, switch_call_cause_t *cancel_cause) +{ + switch_channel_t *channel; + char name[128]; + crtp_private_t *tech_pvt = NULL; + switch_caller_profile_t *caller_profile; + + const char *err; + + + const char *local_addr = switch_event_get_header_nil(var_event, kLOCALADDR), + *szlocal_port = switch_event_get_header_nil(var_event, kLOCALPORT), + *remote_addr = switch_event_get_header_nil(var_event, kREMOTEADDR), + *szremote_port = switch_event_get_header_nil(var_event, kREMOTEPORT), + *codec = switch_event_get_header_nil(var_event, kCODEC), + *szptime = switch_event_get_header_nil(var_event, kPTIME), + //*mode = switch_event_get_header_nil(var_event, kMODE), + //*szrfc2833_pt = switch_event_get_header_nil(var_event, kRFC2833PT), + *szrate = switch_event_get_header_nil(var_event, kRATE), + *szpt = switch_event_get_header_nil(var_event, kPT); + + + switch_port_t local_port = !zstr(szlocal_port) ? atoi(szlocal_port) : 0, + remote_port = !zstr(szremote_port) ? atoi(szremote_port) : 0; + + int ptime = !zstr(szptime) ? atoi(szptime) : 0, + //rfc2833_pt = !zstr(szrfc2833_pt) ? atoi(szrfc2833_pt) : 0, + rate = !zstr(szrate) ? atoi(szrate) : 8000, + pt = !zstr(szpt) ? atoi(szpt) : 0; + + if ( + ((zstr(remote_addr) || remote_port == 0) && (zstr(local_addr) || local_port == 0)) || + zstr(codec) || + zstr(szpt)) { + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing required arguments\n"); + goto fail; + } + + + if (!(*new_session = switch_core_session_request(crtp.endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, 0, pool))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't request session.\n"); + goto fail; + } + + channel = switch_core_session_get_channel(*new_session); + + tech_pvt = switch_core_session_alloc(*new_session, sizeof *tech_pvt); + tech_pvt->session = *new_session; + tech_pvt->channel = channel; + tech_pvt->local_address = switch_core_session_strdup(*new_session, local_addr); + tech_pvt->local_port = local_port; + tech_pvt->remote_address = switch_core_session_strdup(*new_session, remote_addr); + tech_pvt->remote_port = remote_port; + tech_pvt->ptime = ptime; + tech_pvt->agreed_pt = pt; + tech_pvt->dtmf_type = DTMF_2833; /* XXX */ + + if (zstr(local_addr) || local_port == 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "The local address and port must be set\n"); + goto fail; + } else if (zstr(remote_addr) || remote_port == 0) { + tech_pvt->mode = RTP_RECVONLY; + } else { + tech_pvt->mode = RTP_SENDRECV; + } + + switch_core_session_set_private(*new_session, tech_pvt); + + caller_profile = switch_caller_profile_clone(*new_session, outbound_profile); + switch_channel_set_caller_profile(channel, caller_profile); + + + snprintf(name, sizeof(name), "rtp/%s", outbound_profile->destination_number); + switch_channel_set_name(channel, name); + + switch_channel_set_state(channel, CS_INIT); + + if (switch_core_codec_init(&tech_pvt->read_codec, + codec, + NULL, + rate, + ptime, + 1, + /*SWITCH_CODEC_FLAG_ENCODE |*/ SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); + goto fail; + } else { + if (switch_core_codec_init(&tech_pvt->write_codec, + codec, + NULL, + rate, + ptime, + 1, + SWITCH_CODEC_FLAG_ENCODE /*| SWITCH_CODEC_FLAG_DECODE*/, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); + goto fail; + } + } + + if (switch_core_session_set_read_codec(*new_session, &tech_pvt->read_codec) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set read codec?\n"); + goto fail; + } + + if (switch_core_session_set_write_codec(*new_session, &tech_pvt->write_codec) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set write codec?\n"); + goto fail; + } + + if (!(tech_pvt->rtp_session = switch_rtp_new(local_addr, local_port, remote_addr, remote_port, tech_pvt->agreed_pt, + tech_pvt->read_codec.implementation->samples_per_packet, ptime * 1000, + flags, "soft", &err, switch_core_session_get_pool(*new_session)))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't setup RTP session: [%s]\n", err); + goto fail; + } + + if (switch_core_session_thread_launch(*new_session) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't start session thread.\n"); + goto fail; + } + + switch_channel_mark_answered(channel); + + return SWITCH_CAUSE_SUCCESS; + +fail: + if (tech_pvt) { + if (tech_pvt->read_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->read_codec); + } + + if (tech_pvt->write_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->write_codec); + } + } + + if (*new_session) { + switch_core_session_destroy(new_session); + } + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; +} + +static switch_status_t channel_on_init(switch_core_session_t *session) +{ + + switch_channel_t *channel = switch_core_session_get_channel(session); + + switch_channel_set_state(channel, CS_CONSUME_MEDIA); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_on_destroy(switch_core_session_t *session) +{ + crtp_private_t *tech_pvt = switch_core_session_get_private(session); + + if ((tech_pvt = switch_core_session_get_private(session))) { + + if (tech_pvt->read_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->read_codec); + } + + if (tech_pvt->write_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->write_codec); + } + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id) +{ + crtp_private_t *tech_pvt; + switch_channel_t *channel; + 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); + + if (!tech_pvt->rtp_session || tech_pvt->mode == RTP_SENDONLY) { + switch_yield(20000); /* replace by local timer XXX */ + goto cng; + } + + if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) { + switch_dtmf_t dtmf = { 0 }; + switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, &dtmf); + switch_channel_queue_dtmf(channel, &dtmf); + } + + tech_pvt->read_frame.flags = SFF_NONE; + tech_pvt->read_frame.codec = &tech_pvt->read_codec; + status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame, flags); + + if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { + goto cng; + } + + *frame = &tech_pvt->read_frame; + return SWITCH_STATUS_SUCCESS; + +cng: + *frame = &tech_pvt->read_frame; + tech_pvt->read_frame.codec = &tech_pvt->read_codec; + tech_pvt->read_frame.flags |= SFF_CNG; + tech_pvt->read_frame.datalen = 0; + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id) +{ + crtp_private_t *tech_pvt; + switch_channel_t *channel; + //int frames = 0, bytes = 0, samples = 0; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + +#if 0 + if (!switch_test_flag(frame, SFF_CNG) && !switch_test_flag(frame, SFF_PROXY_PACKET)) { + if (tech_pvt->read_codec.implementation->encoded_bytes_per_packet) { + bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_packet; + frames = ((int) frame->datalen / bytes); + } else + frames = 1; + + samples = frames * tech_pvt->read_codec.implementation->samples_per_packet; + } + + tech_pvt->timestamp_send += samples; +#endif + if (tech_pvt->mode == RTP_RECVONLY) { + return SWITCH_STATUS_SUCCESS; + } + + switch_rtp_write_frame(tech_pvt->rtp_session, frame); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf) +{ + crtp_private_t *tech_pvt = NULL; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + switch(tech_pvt->dtmf_type) { + case DTMF_2833: + { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Enqueuing RFC2833 DTMF %c of length %d\n", dtmf->digit, dtmf->duration); + return switch_rtp_queue_rfc2833(tech_pvt->rtp_session, dtmf); + } + case DTMF_NONE: + default: + { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Discarding DTMF %c of length %d, DTMF type is NONE\n", dtmf->digit, dtmf->duration); + } + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_bool_t compare_var(switch_event_t *event, switch_channel_t *channel, const char *varname) +{ + const char *chan_val = switch_channel_get_variable_dup(channel, varname, SWITCH_FALSE, -1); + const char *event_val = switch_event_get_header(event, varname); + + if (zstr(chan_val) || zstr(event_val)) { + return 1; + } + + return strcasecmp(chan_val, event_val); +} + +static switch_status_t channel_receive_event(switch_core_session_t *session, switch_event_t *event) +{ + const char *command = switch_event_get_header(event, "command"); + switch_channel_t *channel = switch_core_session_get_channel(session); + crtp_private_t *tech_pvt = switch_core_session_get_private(session); + char *codec = switch_event_get_header_nil(event, kCODEC); + char *szptime = switch_event_get_header_nil(event, kPTIME); + char *szrate = switch_event_get_header_nil(event, kRATE); + char *szpt = switch_event_get_header_nil(event, kPT); + + int ptime = !zstr(szptime) ? atoi(szptime) : 0, + rate = !zstr(szrate) ? atoi(szrate) : 8000, + pt = !zstr(szpt) ? atoi(szpt) : 0; + + + if (!zstr(command) && !strcasecmp(command, "media_modify")) { + /* Compare parameters */ + if (compare_var(event, channel, kREMOTEADDR) || + compare_var(event, channel, kREMOTEPORT)) { + char *remote_addr = switch_event_get_header(event, kREMOTEADDR); + char *szremote_port = switch_event_get_header(event, kREMOTEPORT); + switch_port_t remote_port = !zstr(szremote_port) ? atoi(szremote_port) : 0; + const char *err; + + + switch_channel_set_variable(channel, kREMOTEADDR, remote_addr); + switch_channel_set_variable(channel, kREMOTEPORT, szremote_port); + + if (switch_rtp_set_remote_address(tech_pvt->rtp_session, remote_addr, remote_port, 0, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error setting RTP remote address: %s\n", err); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set RTP remote: %s:%d\n", remote_addr, (int)remote_port); + tech_pvt->mode = RTP_SENDRECV; + } + } + + if (compare_var(event, channel, kCODEC) || + compare_var(event, channel, kPTIME) || + compare_var(event, channel, kPT) || + compare_var(event, channel, kRATE)) { + /* Reset codec */ + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Switching codec updating \n"); + + if (switch_core_codec_init(&tech_pvt->read_codec, + codec, + NULL, + rate, + ptime, + 1, + /*SWITCH_CODEC_FLAG_ENCODE |*/ SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); + goto fail; + } else { + if (switch_core_codec_init(&tech_pvt->write_codec, + codec, + NULL, + rate, + ptime, + 1, + SWITCH_CODEC_FLAG_ENCODE /*| SWITCH_CODEC_FLAG_DECODE*/, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); + goto fail; + } + } + + if (switch_core_session_set_read_codec(session, &tech_pvt->read_codec) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set read codec?\n"); + goto fail; + } + + if (switch_core_session_set_write_codec(session, &tech_pvt->write_codec) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set write codec?\n"); + goto fail; + } + + switch_rtp_set_default_payload(tech_pvt->rtp_session, pt); + switch_rtp_set_recv_pt(tech_pvt->rtp_session, pt); + } + + if (compare_var(event, channel, kRFC2833PT)) { + const char *szpt = switch_channel_get_variable(channel, kRFC2833PT); + int pt = !zstr(szpt) ? atoi(szpt) : 0; + + switch_channel_set_variable(channel, kRFC2833PT, szpt); + switch_rtp_set_telephony_event(tech_pvt->rtp_session, pt); + } + + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Received unknown command [%s] in event.\n", !command ? "null" : command); + } + + return SWITCH_STATUS_SUCCESS; +fail: + if (tech_pvt) { + if (tech_pvt->read_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->read_codec); + } + + if (tech_pvt->write_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->write_codec); + } + } + + if (session) { + switch_core_session_destroy(&session); + } + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + +} + +static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + crtp_private_t *tech_pvt = NULL; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + switch (msg->message_id) { + case SWITCH_MESSAGE_INDICATE_DEBUG_AUDIO: + { + if (switch_rtp_ready(tech_pvt->rtp_session) && !zstr(msg->string_array_arg[0]) && !zstr(msg->string_array_arg[1])) { + int32_t flags = 0; + if (!strcasecmp(msg->string_array_arg[0], "read")) { + flags |= SWITCH_RTP_FLAG_DEBUG_RTP_READ; + } else if (!strcasecmp(msg->string_array_arg[0], "write")) { + flags |= SWITCH_RTP_FLAG_DEBUG_RTP_WRITE; + } else if (!strcasecmp(msg->string_array_arg[0], "both")) { + flags |= SWITCH_RTP_FLAG_DEBUG_RTP_READ | SWITCH_RTP_FLAG_DEBUG_RTP_WRITE; + } + + if (flags) { + if (switch_true(msg->string_array_arg[1])) { + switch_rtp_set_flag(tech_pvt->rtp_session, flags); + } else { + switch_rtp_clear_flag(tech_pvt->rtp_session, flags); + } + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid Options\n"); + } + } + break; + } + case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC: + if (switch_rtp_ready(tech_pvt->rtp_session)) { + rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_ONCE); + } + break; + case SWITCH_MESSAGE_INDICATE_JITTER_BUFFER: + { + if (switch_rtp_ready(tech_pvt->rtp_session)) { + int len = 0, maxlen = 0, qlen = 0, maxqlen = 50, max_drift = 0; + + if (msg->string_arg) { + char *p, *q; + const char *s; + + if (!strcasecmp(msg->string_arg, "pause")) { + switch_rtp_pause_jitter_buffer(tech_pvt->rtp_session, SWITCH_TRUE); + goto end; + } else if (!strcasecmp(msg->string_arg, "resume")) { + switch_rtp_pause_jitter_buffer(tech_pvt->rtp_session, SWITCH_FALSE); + goto end; + } else if (!strncasecmp(msg->string_arg, "debug:", 6)) { + s = msg->string_arg + 6; + if (s && !strcmp(s, "off")) { + s = NULL; + } + switch_rtp_debug_jitter_buffer(tech_pvt->rtp_session, s); + goto end; + } + + + if ((len = atoi(msg->string_arg))) { + qlen = len / (tech_pvt->read_codec.implementation->microseconds_per_packet / 1000); + if (qlen < 1) { + qlen = 3; + } + } + + if (qlen) { + if ((p = strchr(msg->string_arg, ':'))) { + p++; + maxlen = atol(p); + if ((q = strchr(p, ':'))) { + q++; + max_drift = abs(atol(q)); + } + } + } + + + if (maxlen) { + maxqlen = maxlen / (tech_pvt->read_codec.implementation->microseconds_per_packet / 1000); + } + } + + if (qlen) { + if (maxqlen < qlen) { + maxqlen = qlen * 5; + } + if (switch_rtp_activate_jitter_buffer(tech_pvt->rtp_session, qlen, maxqlen, + tech_pvt->read_codec.implementation->samples_per_packet, + tech_pvt->read_codec.implementation->samples_per_second, max_drift) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), + SWITCH_LOG_DEBUG, "Setting Jitterbuffer to %dms (%d frames) (%d max frames) (%d max drift)\n", + len, qlen, maxqlen, max_drift); + switch_channel_set_flag(tech_pvt->channel, CF_JITTERBUFFER); + if (!switch_false(switch_channel_get_variable(tech_pvt->channel, "sip_jitter_buffer_plc"))) { + switch_channel_set_flag(tech_pvt->channel, CF_JITTERBUFFER_PLC); + } + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), + SWITCH_LOG_WARNING, "Error Setting Jitterbuffer to %dms (%d frames)\n", len, qlen); + } + + } else { + switch_rtp_deactivate_jitter_buffer(tech_pvt->rtp_session); + } + } + } + break; + + default: + break; + } +end: + return SWITCH_STATUS_SUCCESS; +} + From 6fa2fd36787b0908bb8bf2f9299aa5280629cccc Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Wed, 8 Aug 2012 17:05:01 -0500 Subject: [PATCH 419/822] add ws --- libs/libwebsockets/.gitignore | 16 + libs/libwebsockets/COPYING | 503 +++ libs/libwebsockets/INSTALL | 365 ++ libs/libwebsockets/Makefile.am | 2 + libs/libwebsockets/Makefile.in | 738 ++++ libs/libwebsockets/README-test-server | 292 ++ libs/libwebsockets/configure.ac | 130 + libs/libwebsockets/lib/Makefile.am | 44 + libs/libwebsockets/lib/Makefile.in | 665 ++++ libs/libwebsockets/lib/base64-decode.c | 188 + libs/libwebsockets/lib/client-handshake.c | 408 +++ .../lib/extension-deflate-stream.c | 150 + .../lib/extension-deflate-stream.h | 18 + .../lib/extension-x-google-mux.c | 1223 +++++++ .../lib/extension-x-google-mux.h | 96 + libs/libwebsockets/lib/extension.c | 22 + libs/libwebsockets/lib/handshake.c | 722 ++++ libs/libwebsockets/lib/libwebsockets.c | 3183 +++++++++++++++++ libs/libwebsockets/lib/libwebsockets.h | 731 ++++ libs/libwebsockets/lib/md5.c | 217 ++ libs/libwebsockets/lib/parsers.c | 1967 ++++++++++ .../libwebsockets/lib/private-libwebsockets.h | 445 +++ libs/libwebsockets/lib/sha-1.c | 326 ++ libs/libwebsockets/libwebsockets-api-doc.html | 933 +++++ libs/libwebsockets/libwebsockets.spec | 63 + libs/libwebsockets/scripts/kernel-doc | 2238 ++++++++++++ libs/libwebsockets/test-server/Makefile.am | 61 + libs/libwebsockets/test-server/Makefile.in | 722 ++++ libs/libwebsockets/test-server/favicon.ico | Bin 0 -> 1406 bytes libs/libwebsockets/test-server/test-client.c | 341 ++ libs/libwebsockets/test-server/test-fraggle.c | 333 ++ libs/libwebsockets/test-server/test-ping.c | 512 +++ .../test-server/test-server-extpoll.c | 553 +++ libs/libwebsockets/test-server/test-server.c | 551 +++ libs/libwebsockets/test-server/test.html | 361 ++ .../win32port/client/client.vcxproj | 259 ++ .../win32port/client/client.vcxproj.filters | 39 + .../libwebsocketswin32.vcxproj | 274 ++ .../libwebsocketswin32.vcxproj.filters | 72 + .../win32port/server/server.vcxproj | 276 ++ .../win32port/server/server.vcxproj.filters | 51 + .../win32port/win32helpers/getopt.c | 153 + .../win32port/win32helpers/getopt.h | 33 + .../win32port/win32helpers/getopt_long.c | 237 ++ .../win32port/win32helpers/gettimeofday.c | 48 + .../win32port/win32helpers/gettimeofday.h | 28 + .../win32port/win32helpers/netdb.h | 1 + .../win32port/win32helpers/strings.h | 0 .../win32port/win32helpers/sys/time.h | 1 + .../win32port/win32helpers/unistd.h | 0 .../win32port/win32helpers/websock-w32.c | 104 + .../win32port/win32helpers/websock-w32.h | 64 + libs/libwebsockets/win32port/win32port.sln | 100 + .../libwebsockets/win32port/zlib/ZLib.vcxproj | 374 ++ .../win32port/zlib/ZLib.vcxproj.filters | 95 + libs/libwebsockets/win32port/zlib/adler32.c | 169 + libs/libwebsockets/win32port/zlib/compress.c | 80 + libs/libwebsockets/win32port/zlib/crc32.c | 442 +++ libs/libwebsockets/win32port/zlib/crc32.h | 441 +++ libs/libwebsockets/win32port/zlib/deflate.c | 1834 ++++++++++ libs/libwebsockets/win32port/zlib/deflate.h | 342 ++ libs/libwebsockets/win32port/zlib/gzclose.c | 25 + libs/libwebsockets/win32port/zlib/gzguts.h | 132 + libs/libwebsockets/win32port/zlib/gzio.c | 1005 ++++++ libs/libwebsockets/win32port/zlib/gzlib.c | 537 +++ libs/libwebsockets/win32port/zlib/gzread.c | 653 ++++ libs/libwebsockets/win32port/zlib/gzwrite.c | 531 +++ libs/libwebsockets/win32port/zlib/infback.c | 632 ++++ libs/libwebsockets/win32port/zlib/inffast.c | 340 ++ libs/libwebsockets/win32port/zlib/inffast.h | 11 + libs/libwebsockets/win32port/zlib/inffixed.h | 94 + libs/libwebsockets/win32port/zlib/inflate.c | 1480 ++++++++ libs/libwebsockets/win32port/zlib/inflate.h | 122 + libs/libwebsockets/win32port/zlib/inftrees.c | 330 ++ libs/libwebsockets/win32port/zlib/inftrees.h | 62 + libs/libwebsockets/win32port/zlib/trees.c | 1244 +++++++ libs/libwebsockets/win32port/zlib/trees.h | 128 + libs/libwebsockets/win32port/zlib/uncompr.c | 59 + libs/libwebsockets/win32port/zlib/zconf.h | 428 +++ libs/libwebsockets/win32port/zlib/zlib.h | 1613 +++++++++ libs/libwebsockets/win32port/zlib/zutil.c | 318 ++ libs/libwebsockets/win32port/zlib/zutil.h | 274 ++ 82 files changed, 34654 insertions(+) create mode 100644 libs/libwebsockets/.gitignore create mode 100644 libs/libwebsockets/COPYING create mode 100644 libs/libwebsockets/INSTALL create mode 100644 libs/libwebsockets/Makefile.am create mode 100644 libs/libwebsockets/Makefile.in create mode 100644 libs/libwebsockets/README-test-server create mode 100644 libs/libwebsockets/configure.ac create mode 100644 libs/libwebsockets/lib/Makefile.am create mode 100644 libs/libwebsockets/lib/Makefile.in create mode 100644 libs/libwebsockets/lib/base64-decode.c create mode 100644 libs/libwebsockets/lib/client-handshake.c create mode 100644 libs/libwebsockets/lib/extension-deflate-stream.c create mode 100644 libs/libwebsockets/lib/extension-deflate-stream.h create mode 100644 libs/libwebsockets/lib/extension-x-google-mux.c create mode 100644 libs/libwebsockets/lib/extension-x-google-mux.h create mode 100644 libs/libwebsockets/lib/extension.c create mode 100644 libs/libwebsockets/lib/handshake.c create mode 100644 libs/libwebsockets/lib/libwebsockets.c create mode 100644 libs/libwebsockets/lib/libwebsockets.h create mode 100644 libs/libwebsockets/lib/md5.c create mode 100644 libs/libwebsockets/lib/parsers.c create mode 100644 libs/libwebsockets/lib/private-libwebsockets.h create mode 100644 libs/libwebsockets/lib/sha-1.c create mode 100644 libs/libwebsockets/libwebsockets-api-doc.html create mode 100644 libs/libwebsockets/libwebsockets.spec create mode 100755 libs/libwebsockets/scripts/kernel-doc create mode 100644 libs/libwebsockets/test-server/Makefile.am create mode 100644 libs/libwebsockets/test-server/Makefile.in create mode 100644 libs/libwebsockets/test-server/favicon.ico create mode 100644 libs/libwebsockets/test-server/test-client.c create mode 100644 libs/libwebsockets/test-server/test-fraggle.c create mode 100644 libs/libwebsockets/test-server/test-ping.c create mode 100644 libs/libwebsockets/test-server/test-server-extpoll.c create mode 100644 libs/libwebsockets/test-server/test-server.c create mode 100644 libs/libwebsockets/test-server/test.html create mode 100644 libs/libwebsockets/win32port/client/client.vcxproj create mode 100644 libs/libwebsockets/win32port/client/client.vcxproj.filters create mode 100644 libs/libwebsockets/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj create mode 100644 libs/libwebsockets/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.filters create mode 100644 libs/libwebsockets/win32port/server/server.vcxproj create mode 100644 libs/libwebsockets/win32port/server/server.vcxproj.filters create mode 100644 libs/libwebsockets/win32port/win32helpers/getopt.c create mode 100644 libs/libwebsockets/win32port/win32helpers/getopt.h create mode 100644 libs/libwebsockets/win32port/win32helpers/getopt_long.c create mode 100644 libs/libwebsockets/win32port/win32helpers/gettimeofday.c create mode 100644 libs/libwebsockets/win32port/win32helpers/gettimeofday.h create mode 100644 libs/libwebsockets/win32port/win32helpers/netdb.h create mode 100644 libs/libwebsockets/win32port/win32helpers/strings.h create mode 100644 libs/libwebsockets/win32port/win32helpers/sys/time.h create mode 100644 libs/libwebsockets/win32port/win32helpers/unistd.h create mode 100644 libs/libwebsockets/win32port/win32helpers/websock-w32.c create mode 100644 libs/libwebsockets/win32port/win32helpers/websock-w32.h create mode 100644 libs/libwebsockets/win32port/win32port.sln create mode 100644 libs/libwebsockets/win32port/zlib/ZLib.vcxproj create mode 100644 libs/libwebsockets/win32port/zlib/ZLib.vcxproj.filters create mode 100644 libs/libwebsockets/win32port/zlib/adler32.c create mode 100644 libs/libwebsockets/win32port/zlib/compress.c create mode 100644 libs/libwebsockets/win32port/zlib/crc32.c create mode 100644 libs/libwebsockets/win32port/zlib/crc32.h create mode 100644 libs/libwebsockets/win32port/zlib/deflate.c create mode 100644 libs/libwebsockets/win32port/zlib/deflate.h create mode 100755 libs/libwebsockets/win32port/zlib/gzclose.c create mode 100755 libs/libwebsockets/win32port/zlib/gzguts.h create mode 100644 libs/libwebsockets/win32port/zlib/gzio.c create mode 100755 libs/libwebsockets/win32port/zlib/gzlib.c create mode 100755 libs/libwebsockets/win32port/zlib/gzread.c create mode 100755 libs/libwebsockets/win32port/zlib/gzwrite.c create mode 100644 libs/libwebsockets/win32port/zlib/infback.c create mode 100644 libs/libwebsockets/win32port/zlib/inffast.c create mode 100644 libs/libwebsockets/win32port/zlib/inffast.h create mode 100644 libs/libwebsockets/win32port/zlib/inffixed.h create mode 100644 libs/libwebsockets/win32port/zlib/inflate.c create mode 100644 libs/libwebsockets/win32port/zlib/inflate.h create mode 100644 libs/libwebsockets/win32port/zlib/inftrees.c create mode 100644 libs/libwebsockets/win32port/zlib/inftrees.h create mode 100644 libs/libwebsockets/win32port/zlib/trees.c create mode 100644 libs/libwebsockets/win32port/zlib/trees.h create mode 100644 libs/libwebsockets/win32port/zlib/uncompr.c create mode 100644 libs/libwebsockets/win32port/zlib/zconf.h create mode 100644 libs/libwebsockets/win32port/zlib/zlib.h create mode 100644 libs/libwebsockets/win32port/zlib/zutil.c create mode 100644 libs/libwebsockets/win32port/zlib/zutil.h diff --git a/libs/libwebsockets/.gitignore b/libs/libwebsockets/.gitignore new file mode 100644 index 0000000000..5431dbcc9e --- /dev/null +++ b/libs/libwebsockets/.gitignore @@ -0,0 +1,16 @@ +output/ +win32port/ipch/ +win32port/Debug*/ +win32port/Release*/ +win32port/server/Debug*/ +win32port/server/Release*/ +win32port/client/Debug*/ +win32port/client/Release*/ +win32port/libwebsocketswin32/Debug*/ +win32port/libwebsocketswin32/Release*/ +win32port/zlib/Debug*/ +win32port/zlib/Release*/ +*.vcxproj.user +*.opensdf +*.sdf +*.suo diff --git a/libs/libwebsockets/COPYING b/libs/libwebsockets/COPYING new file mode 100644 index 0000000000..a134777643 --- /dev/null +++ b/libs/libwebsockets/COPYING @@ -0,0 +1,503 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + diff --git a/libs/libwebsockets/INSTALL b/libs/libwebsockets/INSTALL new file mode 100644 index 0000000000..7d1c323bea --- /dev/null +++ b/libs/libwebsockets/INSTALL @@ -0,0 +1,365 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006, 2007, 2008, 2009 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/libs/libwebsockets/Makefile.am b/libs/libwebsockets/Makefile.am new file mode 100644 index 0000000000..dec9704f49 --- /dev/null +++ b/libs/libwebsockets/Makefile.am @@ -0,0 +1,2 @@ + +SUBDIRS=lib test-server diff --git a/libs/libwebsockets/Makefile.in b/libs/libwebsockets/Makefile.in new file mode 100644 index 0000000000..f795692828 --- /dev/null +++ b/libs/libwebsockets/Makefile.in @@ -0,0 +1,738 @@ +# Makefile.in generated by automake 1.11.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = . +DIST_COMMON = $(am__configure_deps) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/config.h.in \ + $(top_srcdir)/configure COPYING INSTALL config.guess \ + config.sub depcomp install-sh ltmain.sh missing +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir dist dist-all distcheck +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + if test -d "$(distdir)"; then \ + find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -rf "$(distdir)" \ + || { sleep 5 && rm -rf "$(distdir)"; }; \ + else :; fi +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ + | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +clientcertdir = @clientcertdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = lib test-server +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +am--refresh: Makefile + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +config.h: stamp-h1 + @if test ! -f $@; then rm -f stamp-h1; else :; fi + @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.h.in: $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzip: distdir + tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.lz*) \ + lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(AM_DISTCHECK_CONFIGURE_FLAGS) \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @test -n '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: trying to run $@ with an empty' \ + '$$(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + $(am__cd) '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile config.h +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-hdr \ + distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all \ + ctags-recursive install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am am--refresh check check-am clean clean-generic \ + clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \ + dist-gzip dist-lzip dist-lzma dist-shar dist-tarZ dist-xz \ + dist-zip distcheck distclean distclean-generic distclean-hdr \ + distclean-libtool distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-recursive uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libs/libwebsockets/README-test-server b/libs/libwebsockets/README-test-server new file mode 100644 index 0000000000..e2e0116015 --- /dev/null +++ b/libs/libwebsockets/README-test-server @@ -0,0 +1,292 @@ +Using test-server as a quickstart +--------------------------------- + +You need to regenerate the autotools and libtoolize stuff for your system + +$ autoreconf +$ libtoolize + +Then for a Fedora x86_86 box, the following config line was +needed: + + ./configure --prefix=/usr --libdir=/usr/lib64 --enable-openssl + +For Apple systems, Christopher Baker reported that this is needed +(and I was told separately enabling openssl makes trouble somehow) + +./configure CC="gcc -arch i386 -arch x86_64" CXX="g++ -arch i386 -arch +x86_64" CPP="gcc -E" CXXCPP="g++ -E" --enable-nofork + +For mingw build, I did the following to get working build, ping test is +disabled when building this way + +1) install mingw64_w32 compiler packages from Fedora +2) additionally install mingw64-zlib package +3) ./configure --prefix=/usr --enable-mingw --host=x86_64-w64-mingw32 +4) make + +otherwise if /usr/local/... and /usr/local/lib are OK then... + +$ ./configure +$ make clean +$ make +$ sudo make install +$ libwebsockets-test-server + +should be enough to get a test server listening on port 7861. + +There are a couple of other possible configure options + +--enable-nofork disables the fork into the background API + and removes all references to fork() and + pr_ctl() from the sources. Use it if your + platform doesn't support forking. + +--enable-libcrypto by default libwebsockets uses its own + built-in md5 and sha-1 implementation for + simplicity. However the libcrypto ones + may be faster, and in a distro context it + may be highly desirable to use a common + library implementation for ease of security + upgrades. Give this configure option + to disable the built-in ones and force use + of the libcrypto (part of openssl) ones. + +--with-client-cert-dir=dir tells the client ssl support where to + look for trust certificates to validate + the remote certificate against. + +--enable-noping Don't try to build the ping test app + It needs some unixy environment that + may choke in other build contexts, this + lets you cleanly stop it being built + +--enable-x-google-mux Enable experimental x-google-mux support + in the build (see notes later in document) + +Testing server with a browser +----------------------------- + +If you point your browser (eg, Chrome) to + + http://127.0.0.1:7681 + +It will fetch a script in the form of test.html, and then run the +script in there on the browser to open a websocket connection. +Incrementing numbers should appear in the browser display. + +Using SSL on the server side +---------------------------- + +To test it using SSL/WSS, just run the test server with + +$ libwebsockets-test-server --ssl + +and use the URL + + https://127.0.0.1:7681 + +The connection will be entirely encrypted using some generated +certificates that your browser will not accept, since they are +not signed by any real Certificate Authority. Just accept the +certificates in the browser and the connection will proceed +in first https and then websocket wss, acting exactly the +same. + +test-server.c is all that is needed to use libwebsockets for +serving both the script html over http and websockets. + + +Forkless operation +------------------ + +If your target device does not offer fork(), you can use +libwebsockets from your own main loop instead. Use the +configure option --nofork and simply call libwebsocket_service() +from your own main loop as shown in the test app sources. + + +Testing websocket client support +-------------------------------- + +If you run the test server as described above, you can also +connect to it using the test client as well as a browser. + +$ libwebsockets-test-client localhost + +will by default connect to the test server on localhost:7681 +and print the dumb increment number from the server at the +same time as drawing random circles in the mirror protocol; +if you connect to the test server using a browser at the +same time you will be able to see the circles being drawn. + + +Testing SSL on the client side +------------------------------ + +To test SSL/WSS client action, just run the client test with + +$ libwebsockets-test-client localhost --ssl + +By default the client test applet is set to accept selfsigned +certificates used by the test server, this is indicated by the +use_ssl var being set to 2. Set it to 1 to reject any server +certificate that it doesn't have a trusted CA cert for. + + +Using the websocket ping utility +-------------------------------- + +libwebsockets-test-ping connects as a client to a remote +websocket server using 04 protocol and pings it like the +normal unix ping utility. + +$ libwebsockets-test-ping localhost +handshake OK for protocol lws-mirror-protocol +Websocket PING localhost.localdomain (127.0.0.1) 64 bytes of data. +64 bytes from localhost: req=1 time=0.1ms +64 bytes from localhost: req=2 time=0.1ms +64 bytes from localhost: req=3 time=0.1ms +64 bytes from localhost: req=4 time=0.2ms +64 bytes from localhost: req=5 time=0.1ms +64 bytes from localhost: req=6 time=0.2ms +64 bytes from localhost: req=7 time=0.2ms +64 bytes from localhost: req=8 time=0.1ms +^C +--- localhost.localdomain websocket ping statistics --- +8 packets transmitted, 8 received, 0% packet loss, time 7458ms +rtt min/avg/max = 0.110/0.185/0.218 ms +$ + +By default it sends 64 byte payload packets using the 04 +PING packet opcode type. You can change the payload size +using the -s= flag, up to a maximum of 125 mandated by the +04 standard. + +Using the lws-mirror protocol that is provided by the test +server, libwebsockets-test-ping can also use larger payload +sizes up to 4096 is BINARY packets; lws-mirror will copy +them back to the client and they appear as a PONG. Use the +-m flag to select this operation. + +The default interval between pings is 1s, you can use the -i= +flag to set this, including fractions like -i=0.01 for 10ms +interval. + +Before you can even use the PING opcode that is part of the +standard, you must complete a handshake with a specified +protocol. By default lws-mirror-protocol is used which is +supported by the test server. But if you are using it on +another server, you can specify the protcol to handshake with +by --protocol=protocolname + + +Fraggle test app +---------------- + +By default it runs in server mode + +$ libwebsockets-test-fraggle +libwebsockets test fraggle +(C) Copyright 2010-2011 Andy Green licensed under LGPL2.1 + Compiled with SSL support, not using it + Listening on port 7681 +server sees client connect +accepted v06 connection +Spamming 360 random fragments +Spamming session over, len = 371913. sum = 0x2D3C0AE +Spamming 895 random fragments +Spamming session over, len = 875970. sum = 0x6A74DA1 +... + +You need to run a second session in client mode, you have to +give the -c switch and the server address at least: + +$ libwebsockets-test-fraggle -c localhost +libwebsockets test fraggle +(C) Copyright 2010-2011 Andy Green licensed under LGPL2.1 + Client mode +Connecting to localhost:7681 +denied deflate-stream extension +handshake OK for protocol fraggle-protocol +client connects to server +EOM received 371913 correctly from 360 fragments +EOM received 875970 correctly from 895 fragments +EOM received 247140 correctly from 258 fragments +EOM received 695451 correctly from 692 fragments +... + +The fraggle test sends a random number up to 1024 fragmented websocket frames +each of a random size between 1 and 2001 bytes in a single message, then sends +a checksum and starts sending a new randomly sized and fragmented message. + +The fraggle test client receives the same message fragments and computes the +same checksum using websocket framing to see when the message has ended. It +then accepts the server checksum message and compares that to its checksum. + + +proxy support +------------- + +The http_proxy environment variable is respected by the client +connection code for both ws:// and wss://. It doesn't support +authentication yet. + +You use it like this + +export http_proxy=myproxy.com:3128 +libwebsockets-test-client someserver.com + + +Websocket version supported +--------------------------- + +The websocket client code is 04 and 05 version, the server +supports 00/76 in text mode and 04 and 05 dynamically +per-connection depending on the version of the +client / browser. + + +External Polling Loop support +----------------------------- + +libwebsockets maintains an internal poll() array for all of its +sockets, but you can instead integrate the sockets into an +external polling array. That's needed if libwebsockets will +cooperate with an existing poll array maintained by another +server. + +Four callbacks LWS_CALLBACK_ADD_POLL_FD, LWS_CALLBACK_DEL_POLL_FD, +LWS_CALLBACK_SET_MODE_POLL_FD and LWS_CALLBACK_CLEAR_MODE_POLL_FD +appear in the callback for protocol 0 and allow interface code to +manage socket descriptors in other poll loops. + + +x-google-mux support +-------------------- + +Experimental and super-preliminary x-google-mux support is available if +enabled in ./configure with --enable-x-google-mux. Note that when changing +configurations, you will need to do a make distclean before, then the new +configure and then make ; make install. Don't forget the necessary other +flags for your platform as described at the top of the readme. + +It has the following notes: + + 1) To enable it, reconfigure with --enable-x-google-mux + + 2) It deviates from the google standard by sending full + headers in the addchannel subcommand rather than just + changed ones from original connect + + 3) Quota is not implemented yet + +However despite those caveats, in fact it can run the +test client reliably over one socket (both dumb-increment +and lws-mirror-protocol), you can open a browser on the +same test server too and see the circles, etc. + +It also works compatibly with deflate-stream automatically. + +2012-04-12 Andy Green + diff --git a/libs/libwebsockets/configure.ac b/libs/libwebsockets/configure.ac new file mode 100644 index 0000000000..3980b2d0aa --- /dev/null +++ b/libs/libwebsockets/configure.ac @@ -0,0 +1,130 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.66]) +AC_INIT(libwebsockets, 0.3, andy@warmcat.com) +AC_CONFIG_SRCDIR([test-server/test-server.c]) +AC_CONFIG_HEADERS([config.h]) + +AM_INIT_AUTOMAKE([-Wall -Werror foreign]) +LT_INIT(shared) + +#AX_PTHREAD + +# Checks for programs. +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_MAKE_SET +AC_CONFIG_MACRO_DIR([m4]) + + +# +# +# +AC_ARG_ENABLE(openssl, + [ --enable-openssl Enables https support and needs openssl libs], + [ openssl=yes + ]) + +if test "x$openssl" = "xyes" ; then +AC_CHECK_LIB([ssl], [SSL_library_init]) +CFLAGS="$CFLAGS -DLWS_OPENSSL_SUPPORT" +fi + +# +# +# +AC_ARG_ENABLE(nofork, + [ --enable-nofork Disables fork-related options], + [ nofork=yes + ]) + +if test "x$nofork" = "xyes" ; then +CFLAGS="$CFLAGS -DLWS_NO_FORK" +else +AC_FUNC_FORK +fi + +# +# +# +AC_ARG_ENABLE(libcrypto, + [ --enable-libcrypto Use libcrypto MD5 and SHA1 implementations], + [ libcrypto=yes + ]) + +if test "x$libcrypto" = "xyes" ; then +CFLAGS="$CFLAGS -DLWS_LIBCRYPTO" +LDFLAGS="$LDFLAGS -lcrypto" +fi +AM_CONDITIONAL(LIBCRYPTO, test x$libcrypto = xyes) + + +# +# +# +AC_ARG_ENABLE(x-google-mux, + [ --enable-x-google-mux Build experimental x-google-mux], + [ x_google_mux=yes + ]) +if test "x$x_google_mux" = "xyes" ; then +CFLAGS="$CFLAGS -DLWS_EXT_GOOGLE_MUX" +fi +AM_CONDITIONAL(EXT_GOOGLE_MUX, test x$x_google_mux = xyes) + +# +# +# +AC_ARG_ENABLE(mingw, + [ --enable-mingw Using mingw compilers, disables ping test build], + [ mingw=yes + noping=yes + ]) + +if test "x$mingw" = "xyes" ; then +CFLAGS="$CFLAGS -DLWS_MINGW_SUPPORT" +fi +AM_CONDITIONAL(MINGW, test x$mingw = xyes) + +# +# +# +AC_ARG_WITH([client-cert-dir], +[AS_HELP_STRING([--with-client-cert-dir],[directory containing client certs, defaults to /etc/pki/tls/certs/])], +[clientcertdir=$withval], +[clientcertdir=/etc/pki/tls/certs/] +) +AC_SUBST([clientcertdir]) + +AC_SUBST([CFLAGS]) + + +# +# +# +AC_ARG_ENABLE(noping, + [ --enable-noping Do not build ping test app, which has some unixy stuff in sources], + [ noping=yes + ]) + +AM_CONDITIONAL(NOPING, test x$noping = xyes) + + + +# Checks for header files. +AC_CHECK_HEADERS([zlib.h fcntl.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h sys/prctl.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_TYPE_SIZE_T + +# Checks for library functions. + +AC_FUNC_MALLOC +AC_FUNC_REALLOC +AC_CHECK_FUNCS([bzero memset socket strerror]) + +AC_CONFIG_FILES([Makefile + lib/Makefile + test-server/Makefile]) + +AC_OUTPUT diff --git a/libs/libwebsockets/lib/Makefile.am b/libs/libwebsockets/lib/Makefile.am new file mode 100644 index 0000000000..119366f099 --- /dev/null +++ b/libs/libwebsockets/lib/Makefile.am @@ -0,0 +1,44 @@ +lib_LTLIBRARIES=libwebsockets.la +include_HEADERS=libwebsockets.h +dist_libwebsockets_la_SOURCES=libwebsockets.c \ + handshake.c \ + parsers.c \ + libwebsockets.h \ + base64-decode.c \ + client-handshake.c \ + extension.c \ + extension-deflate-stream.c \ + private-libwebsockets.h + +if EXT_GOOGLE_MUX +dist_libwebsockets_la_SOURCES += extension-x-google-mux.c +endif + +if LIBCRYPTO +else +dist_libwebsockets_la_SOURCES += md5.c sha-1.c +endif + +libwebsockets_la_CFLAGS:=-Wall -std=gnu99 -pedantic +libwebsockets_la_LDFLAGS:= + +if MINGW +libwebsockets_la_CFLAGS+= -w -I../win32port/win32helpers -I ../win32port/zlib/ +libwebsockets_la_LDFLAGS+= -lm -luser32 -ladvapi32 -lkernel32 -lgcc +else +libwebsockets_la_CFLAGS+= -rdynamic -fPIC -Werror +libwebsockets_la_LDFLAGS+= -version-info 0:3 +endif + +libwebsockets_la_CFLAGS+= -c \ + -DINSTALL_DATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" +libwebsockets_la_LDFLAGS+= -lz + +all-local: + ../scripts/kernel-doc -html \ + libwebsockets.c \ + parsers.c \ + client-handshake.c \ + libwebsockets.h \ + > ../libwebsockets-api-doc.html + diff --git a/libs/libwebsockets/lib/Makefile.in b/libs/libwebsockets/lib/Makefile.in new file mode 100644 index 0000000000..caa44f3e02 --- /dev/null +++ b/libs/libwebsockets/lib/Makefile.in @@ -0,0 +1,665 @@ +# Makefile.in generated by automake 1.11.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@EXT_GOOGLE_MUX_TRUE@am__append_1 = extension-x-google-mux.c +@LIBCRYPTO_FALSE@am__append_2 = md5.c sha-1.c +@MINGW_TRUE@am__append_3 = -w -I../win32port/win32helpers -I ../win32port/zlib/ +@MINGW_TRUE@am__append_4 = -lm -luser32 -ladvapi32 -lkernel32 -lgcc +@MINGW_FALSE@am__append_5 = -rdynamic -fPIC -Werror +@MINGW_FALSE@am__append_6 = -version-info 0:3 +subdir = lib +DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libwebsockets_la_LIBADD = +am__dist_libwebsockets_la_SOURCES_DIST = libwebsockets.c handshake.c \ + parsers.c libwebsockets.h base64-decode.c client-handshake.c \ + extension.c extension-deflate-stream.c private-libwebsockets.h \ + extension-x-google-mux.c md5.c sha-1.c +@EXT_GOOGLE_MUX_TRUE@am__objects_1 = libwebsockets_la-extension-x-google-mux.lo +@LIBCRYPTO_FALSE@am__objects_2 = libwebsockets_la-md5.lo \ +@LIBCRYPTO_FALSE@ libwebsockets_la-sha-1.lo +dist_libwebsockets_la_OBJECTS = libwebsockets_la-libwebsockets.lo \ + libwebsockets_la-handshake.lo libwebsockets_la-parsers.lo \ + libwebsockets_la-base64-decode.lo \ + libwebsockets_la-client-handshake.lo \ + libwebsockets_la-extension.lo \ + libwebsockets_la-extension-deflate-stream.lo $(am__objects_1) \ + $(am__objects_2) +libwebsockets_la_OBJECTS = $(dist_libwebsockets_la_OBJECTS) +libwebsockets_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libwebsockets_la_CFLAGS) \ + $(CFLAGS) $(libwebsockets_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(dist_libwebsockets_la_SOURCES) +DIST_SOURCES = $(am__dist_libwebsockets_la_SOURCES_DIST) +HEADERS = $(include_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +clientcertdir = @clientcertdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +lib_LTLIBRARIES = libwebsockets.la +include_HEADERS = libwebsockets.h +dist_libwebsockets_la_SOURCES = libwebsockets.c handshake.c parsers.c \ + libwebsockets.h base64-decode.c client-handshake.c extension.c \ + extension-deflate-stream.c private-libwebsockets.h \ + $(am__append_1) $(am__append_2) +libwebsockets_la_CFLAGS := -Wall -std=gnu99 -pedantic $(am__append_3) \ + $(am__append_5) -c -DINSTALL_DATADIR=\"@datadir@\" \ + -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" +libwebsockets_la_LDFLAGS := $(am__append_4) $(am__append_6) -lz +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libwebsockets.la: $(libwebsockets_la_OBJECTS) $(libwebsockets_la_DEPENDENCIES) $(EXTRA_libwebsockets_la_DEPENDENCIES) + $(libwebsockets_la_LINK) -rpath $(libdir) $(libwebsockets_la_OBJECTS) $(libwebsockets_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_la-base64-decode.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_la-client-handshake.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_la-extension-deflate-stream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_la-extension-x-google-mux.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_la-extension.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_la-handshake.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_la-libwebsockets.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_la-md5.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_la-parsers.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_la-sha-1.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libwebsockets_la-libwebsockets.lo: libwebsockets.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -MT libwebsockets_la-libwebsockets.lo -MD -MP -MF $(DEPDIR)/libwebsockets_la-libwebsockets.Tpo -c -o libwebsockets_la-libwebsockets.lo `test -f 'libwebsockets.c' || echo '$(srcdir)/'`libwebsockets.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_la-libwebsockets.Tpo $(DEPDIR)/libwebsockets_la-libwebsockets.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libwebsockets.c' object='libwebsockets_la-libwebsockets.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -c -o libwebsockets_la-libwebsockets.lo `test -f 'libwebsockets.c' || echo '$(srcdir)/'`libwebsockets.c + +libwebsockets_la-handshake.lo: handshake.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -MT libwebsockets_la-handshake.lo -MD -MP -MF $(DEPDIR)/libwebsockets_la-handshake.Tpo -c -o libwebsockets_la-handshake.lo `test -f 'handshake.c' || echo '$(srcdir)/'`handshake.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_la-handshake.Tpo $(DEPDIR)/libwebsockets_la-handshake.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='handshake.c' object='libwebsockets_la-handshake.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -c -o libwebsockets_la-handshake.lo `test -f 'handshake.c' || echo '$(srcdir)/'`handshake.c + +libwebsockets_la-parsers.lo: parsers.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -MT libwebsockets_la-parsers.lo -MD -MP -MF $(DEPDIR)/libwebsockets_la-parsers.Tpo -c -o libwebsockets_la-parsers.lo `test -f 'parsers.c' || echo '$(srcdir)/'`parsers.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_la-parsers.Tpo $(DEPDIR)/libwebsockets_la-parsers.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='parsers.c' object='libwebsockets_la-parsers.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -c -o libwebsockets_la-parsers.lo `test -f 'parsers.c' || echo '$(srcdir)/'`parsers.c + +libwebsockets_la-base64-decode.lo: base64-decode.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -MT libwebsockets_la-base64-decode.lo -MD -MP -MF $(DEPDIR)/libwebsockets_la-base64-decode.Tpo -c -o libwebsockets_la-base64-decode.lo `test -f 'base64-decode.c' || echo '$(srcdir)/'`base64-decode.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_la-base64-decode.Tpo $(DEPDIR)/libwebsockets_la-base64-decode.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='base64-decode.c' object='libwebsockets_la-base64-decode.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -c -o libwebsockets_la-base64-decode.lo `test -f 'base64-decode.c' || echo '$(srcdir)/'`base64-decode.c + +libwebsockets_la-client-handshake.lo: client-handshake.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -MT libwebsockets_la-client-handshake.lo -MD -MP -MF $(DEPDIR)/libwebsockets_la-client-handshake.Tpo -c -o libwebsockets_la-client-handshake.lo `test -f 'client-handshake.c' || echo '$(srcdir)/'`client-handshake.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_la-client-handshake.Tpo $(DEPDIR)/libwebsockets_la-client-handshake.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='client-handshake.c' object='libwebsockets_la-client-handshake.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -c -o libwebsockets_la-client-handshake.lo `test -f 'client-handshake.c' || echo '$(srcdir)/'`client-handshake.c + +libwebsockets_la-extension.lo: extension.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -MT libwebsockets_la-extension.lo -MD -MP -MF $(DEPDIR)/libwebsockets_la-extension.Tpo -c -o libwebsockets_la-extension.lo `test -f 'extension.c' || echo '$(srcdir)/'`extension.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_la-extension.Tpo $(DEPDIR)/libwebsockets_la-extension.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='extension.c' object='libwebsockets_la-extension.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -c -o libwebsockets_la-extension.lo `test -f 'extension.c' || echo '$(srcdir)/'`extension.c + +libwebsockets_la-extension-deflate-stream.lo: extension-deflate-stream.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -MT libwebsockets_la-extension-deflate-stream.lo -MD -MP -MF $(DEPDIR)/libwebsockets_la-extension-deflate-stream.Tpo -c -o libwebsockets_la-extension-deflate-stream.lo `test -f 'extension-deflate-stream.c' || echo '$(srcdir)/'`extension-deflate-stream.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_la-extension-deflate-stream.Tpo $(DEPDIR)/libwebsockets_la-extension-deflate-stream.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='extension-deflate-stream.c' object='libwebsockets_la-extension-deflate-stream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -c -o libwebsockets_la-extension-deflate-stream.lo `test -f 'extension-deflate-stream.c' || echo '$(srcdir)/'`extension-deflate-stream.c + +libwebsockets_la-extension-x-google-mux.lo: extension-x-google-mux.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -MT libwebsockets_la-extension-x-google-mux.lo -MD -MP -MF $(DEPDIR)/libwebsockets_la-extension-x-google-mux.Tpo -c -o libwebsockets_la-extension-x-google-mux.lo `test -f 'extension-x-google-mux.c' || echo '$(srcdir)/'`extension-x-google-mux.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_la-extension-x-google-mux.Tpo $(DEPDIR)/libwebsockets_la-extension-x-google-mux.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='extension-x-google-mux.c' object='libwebsockets_la-extension-x-google-mux.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -c -o libwebsockets_la-extension-x-google-mux.lo `test -f 'extension-x-google-mux.c' || echo '$(srcdir)/'`extension-x-google-mux.c + +libwebsockets_la-md5.lo: md5.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -MT libwebsockets_la-md5.lo -MD -MP -MF $(DEPDIR)/libwebsockets_la-md5.Tpo -c -o libwebsockets_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_la-md5.Tpo $(DEPDIR)/libwebsockets_la-md5.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='md5.c' object='libwebsockets_la-md5.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -c -o libwebsockets_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c + +libwebsockets_la-sha-1.lo: sha-1.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -MT libwebsockets_la-sha-1.lo -MD -MP -MF $(DEPDIR)/libwebsockets_la-sha-1.Tpo -c -o libwebsockets_la-sha-1.lo `test -f 'sha-1.c' || echo '$(srcdir)/'`sha-1.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_la-sha-1.Tpo $(DEPDIR)/libwebsockets_la-sha-1.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sha-1.c' object='libwebsockets_la-sha-1.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_la_CFLAGS) $(CFLAGS) -c -o libwebsockets_la-sha-1.lo `test -f 'sha-1.c' || echo '$(srcdir)/'`sha-1.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ + done + +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) all-local +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-includeHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am all-local check check-am clean \ + clean-generic clean-libLTLIBRARIES clean-libtool ctags \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am \ + install-includeHEADERS install-info install-info-am \ + install-libLTLIBRARIES install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-includeHEADERS \ + uninstall-libLTLIBRARIES + + +all-local: + ../scripts/kernel-doc -html \ + libwebsockets.c \ + parsers.c \ + client-handshake.c \ + libwebsockets.h \ + > ../libwebsockets-api-doc.html + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libs/libwebsockets/lib/base64-decode.c b/libs/libwebsockets/lib/base64-decode.c new file mode 100644 index 0000000000..95d4ba4ac2 --- /dev/null +++ b/libs/libwebsockets/lib/base64-decode.c @@ -0,0 +1,188 @@ +/* + * This code originally came from here + * + * http://base64.sourceforge.net/b64.c + * + * with the following license: + * + * LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the + * Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * VERSION HISTORY: + * Bob Trower 08/04/01 -- Create Version 0.00.00B + * + * I cleaned it up quite a bit to match the (linux kernel) style of the rest + * of libwebsockets; this version is under LGPL2 like the rest of libwebsockets + * since he explictly allows sublicensing, but I give the URL above so you can + * get the original with Bob's super-liberal terms directly if you prefer. + */ + + +#include +#include + +static const char encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char decode[] = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW" + "$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; + +int +lws_b64_encode_string(const char *in, int in_len, char *out, int out_size) +{ + unsigned char triple[3]; + int i; + int len; + int line = 0; + int done = 0; + + while (in_len) { + len = 0; + for (i = 0; i < 3; i++) { + if (in_len) { + triple[i] = *in++; + len++; + in_len--; + } else + triple[i] = 0; + } + if (!len) + continue; + + if (done + 4 >= out_size) + return -1; + + *out++ = encode[triple[0] >> 2]; + *out++ = encode[((triple[0] & 0x03) << 4) | + ((triple[1] & 0xf0) >> 4)]; + *out++ = (len > 1 ? encode[((triple[1] & 0x0f) << 2) | + ((triple[2] & 0xc0) >> 6)] : '='); + *out++ = (len > 2 ? encode[triple[2] & 0x3f] : '='); + + done += 4; + line += 4; + } + + if (done + 1 >= out_size) + return -1; + + *out++ = '\0'; + + return done; +} + +/* + * returns length of decoded string in out, or -1 if out was too small + * according to out_size + */ + +int +lws_b64_decode_string(const char *in, char *out, int out_size) +{ + int len; + int i; + int done = 0; + unsigned char v; + unsigned char quad[4]; + + while (*in) { + + len = 0; + for (i = 0; i < 4 && *in; i++) { + + v = 0; + while (*in && !v) { + + v = *in++; + v = (v < 43 || v > 122) ? 0 : decode[v - 43]; + if (v) + v = (v == '$') ? 0 : v - 61; + if (*in) { + len++; + if (v) + quad[i] = v - 1; + } else + quad[i] = 0; + } + } + if (!len) + continue; + + if (out_size < (done + len - 1)) + /* out buffer is too small */ + return -1; + + if (len >= 2) + *out++ = quad[0] << 2 | quad[1] >> 4; + if (len >= 3) + *out++ = quad[1] << 4 | quad[2] >> 2; + if (len >= 4) + *out++ = ((quad[2] << 6) & 0xc0) | quad[3]; + + done += len - 1; + } + + if (done + 1 >= out_size) + return -1; + + *out++ = '\0'; + + return done; +} + +int +lws_b64_selftest(void) +{ + char buf[64]; + int n; + int test; + static const char * const plaintext[] = { + "sanity check base 64" + }; + static const char * const coded[] = { + "c2FuaXR5IGNoZWNrIGJhc2UgNjQ=" + }; + + for (test = 0; test < sizeof plaintext / sizeof(plaintext[0]); test++) { + + buf[sizeof(buf) - 1] = '\0'; + n = lws_b64_encode_string(plaintext[test], + strlen(plaintext[test]), buf, sizeof buf); + if (n != strlen(coded[test]) || strcmp(buf, coded[test])) { + fprintf(stderr, "Failed lws_b64 encode selftest " + "%d result '%s' %d\n", test, buf, n); + return -1; + } + + buf[sizeof(buf) - 1] = '\0'; + n = lws_b64_decode_string(coded[test], buf, sizeof buf); + if (n != strlen(plaintext[test]) || + strcmp(buf, plaintext[test])) { + fprintf(stderr, "Failed lws_b64 decode selftest " + "%d result '%s' %d\n", test, buf, n); + return -1; + } + } + + return 0; +} diff --git a/libs/libwebsockets/lib/client-handshake.c b/libs/libwebsockets/lib/client-handshake.c new file mode 100644 index 0000000000..ceb5f76f22 --- /dev/null +++ b/libs/libwebsockets/lib/client-handshake.c @@ -0,0 +1,408 @@ +#include "private-libwebsockets.h" + +struct libwebsocket *__libwebsocket_client_connect_2( + struct libwebsocket_context *context, + struct libwebsocket *wsi +) { + struct pollfd pfd; + struct timeval tv; + struct hostent *server_hostent; + struct sockaddr_in server_addr; + int n; + int plen = 0; + char pkt[512]; + int opt = 1; +#if defined(__APPLE__) + struct protoent *tcp_proto; +#endif + + debug("__libwebsocket_client_connect_2\n"); + + wsi->candidate_children_list = NULL; + + /* + * proxy? + */ + + if (context->http_proxy_port) { + plen = sprintf(pkt, "CONNECT %s:%u HTTP/1.0\x0d\x0a" + "User-agent: libwebsockets\x0d\x0a" +/*Proxy-authorization: basic aGVsbG86d29ybGQ= */ + "\x0d\x0a", wsi->c_address, wsi->c_port); + + /* OK from now on we talk via the proxy */ + + free(wsi->c_address); + wsi->c_address = strdup(context->http_proxy_address); + wsi->c_port = context->http_proxy_port; + } + + /* + * prepare the actual connection (to the proxy, if any) + */ + + debug("__libwebsocket_client_connect_2: address %s", wsi->c_address); + + server_hostent = gethostbyname(wsi->c_address); + if (server_hostent == NULL) { + fprintf(stderr, "Unable to get host name from %s\n", + wsi->c_address); + goto oom4; + } + + wsi->sock = socket(AF_INET, SOCK_STREAM, 0); + + if (wsi->sock < 0) { + fprintf(stderr, "Unable to open socket\n"); + goto oom4; + } + + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(wsi->c_port); + server_addr.sin_addr = *((struct in_addr *)server_hostent->h_addr); + bzero(&server_addr.sin_zero, 8); + + /* Disable Nagle */ +#if !defined(__APPLE__) + setsockopt(wsi->sock, SOL_TCP, TCP_NODELAY, + (const void *)&opt, sizeof(opt)); +#else + tcp_proto = getprotobyname("TCP"); + setsockopt(wsi->sock, tcp_proto->p_proto, TCP_NODELAY, + &opt, sizeof(opt)); +#endif + + /* Set receiving timeout */ + tv.tv_sec = 0; + tv.tv_usec = 100 * 1000; + setsockopt(wsi->sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv); + + if (connect(wsi->sock, (struct sockaddr *)&server_addr, + sizeof(struct sockaddr)) == -1) { + fprintf(stderr, "Connect failed\n"); +#ifdef WIN32 + closesocket(wsi->sock); +#else + close(wsi->sock); +#endif + goto oom4; + } + + debug("connected\n"); + + /* into fd -> wsi hashtable */ + + insert_wsi(context, wsi); + + /* into internal poll list */ + + context->fds[context->fds_count].fd = wsi->sock; + context->fds[context->fds_count].revents = 0; + context->fds[context->fds_count++].events = POLLIN; + + /* external POLL support via protocol 0 */ + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_ADD_POLL_FD, + (void *)(long)wsi->sock, NULL, POLLIN); + + /* we are connected to server, or proxy */ + + if (context->http_proxy_port) { + + n = send(wsi->sock, pkt, plen, 0); + if (n < 0) { +#ifdef WIN32 + closesocket(wsi->sock); +#else + close(wsi->sock); +#endif + fprintf(stderr, "ERROR writing to proxy socket\n"); + goto bail1; + } + + libwebsocket_set_timeout(wsi, + PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, 5); + + wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY; + + return wsi; + } + + /* + * provoke service to issue the handshake directly + * we need to do it this way because in the proxy case, this is the + * next state and executed only if and when we get a good proxy + * response inside the state machine + */ + + wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE; + pfd.fd = wsi->sock; + pfd.revents = POLLIN; + if (libwebsocket_service_fd(context, &pfd) < 0) + goto oom4; + + return wsi; + +oom4: + if (wsi->c_protocol) + free(wsi->c_protocol); + + if (wsi->c_origin) + free(wsi->c_origin); + + free(wsi->c_host); + free(wsi->c_path); + +bail1: + free(wsi); + + return NULL; +} + +/** + * libwebsocket_client_connect() - Connect to another websocket server + * @context: Websocket context + * @address: Remote server address, eg, "myserver.com" + * @port: Port to connect to on the remote server, eg, 80 + * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self + * signed certs + * @path: Websocket path on server + * @host: Hostname on server + * @origin: Socket origin name + * @protocol: Comma-separated list of protocols being asked for from + * the server, or just one. The server will pick the one it + * likes best. + * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest + * protocol supported, or the specific protocol ordinal + * + * This function creates a connection to a remote server + */ + +struct libwebsocket * +libwebsocket_client_connect(struct libwebsocket_context *context, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one) +{ + struct libwebsocket *wsi; + int n; + int m; + struct libwebsocket_extension *ext; + int handled; +#ifndef LWS_OPENSSL_SUPPORT + if (ssl_connection) { + fprintf(stderr, "libwebsockets not configured for ssl\n"); + return NULL; + } +#endif + + wsi = malloc(sizeof(struct libwebsocket)); + if (wsi == NULL) + goto bail1; + + memset(wsi, 0, sizeof *wsi); + + /* -1 means just use latest supported */ + + if (ietf_version_or_minus_one == -1) + ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED; + + wsi->ietf_spec_revision = ietf_version_or_minus_one; + wsi->name_buffer_pos = 0; + wsi->user_space = NULL; + wsi->state = WSI_STATE_CLIENT_UNCONNECTED; + wsi->pings_vs_pongs = 0; + wsi->protocol = NULL; + wsi->pending_timeout = NO_PENDING_TIMEOUT; + wsi->count_active_extensions = 0; +#ifdef LWS_OPENSSL_SUPPORT + wsi->use_ssl = ssl_connection; +#endif + + wsi->c_port = port; + wsi->c_address = strdup(address); + + /* copy parameters over so state machine has access */ + + wsi->c_path = malloc(strlen(path) + 1); + if (wsi->c_path == NULL) + goto bail1; + strcpy(wsi->c_path, path); + + wsi->c_host = malloc(strlen(host) + 1); + if (wsi->c_host == NULL) + goto oom1; + strcpy(wsi->c_host, host); + + if (origin) { + wsi->c_origin = malloc(strlen(origin) + 1); + strcpy(wsi->c_origin, origin); + if (wsi->c_origin == NULL) + goto oom2; + } else + wsi->c_origin = NULL; + + wsi->c_callback = NULL; + if (protocol) { + const char *pc; + struct libwebsocket_protocols *pp; + + wsi->c_protocol = malloc(strlen(protocol) + 1); + if (wsi->c_protocol == NULL) + goto oom3; + + strcpy(wsi->c_protocol, protocol); + + pc = protocol; + while (*pc && *pc != ',') + pc++; + n = pc - protocol; + pp = context->protocols; + while (pp->name && !wsi->c_callback) { + if (!strncmp(protocol, pp->name, n)) + wsi->c_callback = pp->callback; + pp++; + } + } else + wsi->c_protocol = NULL; + + if (!wsi->c_callback) + wsi->c_callback = context->protocols[0].callback; + + /* set up appropriate masking */ + + wsi->xor_mask = xor_no_mask; + + switch (wsi->ietf_spec_revision) { + case 0: + break; + case 4: + wsi->xor_mask = xor_mask_04; + break; + case 5: + case 6: + case 7: + case 8: + case 13: + wsi->xor_mask = xor_mask_05; + break; + default: + fprintf(stderr, + "Client ietf version %d not supported\n", + wsi->ietf_spec_revision); + goto oom4; + } + + /* force no mask if he asks for that though */ + + if (context->options & LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK) + wsi->xor_mask = xor_no_mask; + + for (n = 0; n < WSI_TOKEN_COUNT; n++) { + wsi->utf8_token[n].token = NULL; + wsi->utf8_token[n].token_len = 0; + } + + /* + * Check with each extension if it is able to route and proxy this + * connection for us. For example, an extension like x-google-mux + * can handle this and then we don't need an actual socket for this + * connection. + */ + + handled = 0; + ext = context->extensions; + n = 0; + + while (ext && ext->callback && !handled) { + m = ext->callback(context, ext, wsi, + LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION, + (void *)(long)n, (void *)address, port); + if (m) + handled = 1; + + ext++; + n++; + } + + if (handled) { + debug("libwebsocket_client_connect: ext handling conn\n"); + + libwebsocket_set_timeout(wsi, + PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, 5); + + wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT; + return wsi; + } + + debug("libwebsocket_client_connect: direct conn\n"); + + return __libwebsocket_client_connect_2(context, wsi); + + +oom4: + if (wsi->c_protocol) + free(wsi->c_protocol); + +oom3: + if (wsi->c_origin) + free(wsi->c_origin); + +oom2: + free(wsi->c_host); + +oom1: + free(wsi->c_path); + +bail1: + free(wsi); + + return NULL; +} + + +/** + * libwebsocket_client_connect_extended() - Connect to another websocket server + * @context: Websocket context + * @address: Remote server address, eg, "myserver.com" + * @port: Port to connect to on the remote server, eg, 80 + * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self + * signed certs + * @path: Websocket path on server + * @host: Hostname on server + * @origin: Socket origin name + * @protocol: Comma-separated list of protocols being asked for from + * the server, or just one. The server will pick the one it + * likes best. + * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest + * protocol supported, or the specific protocol ordinal + * @userdata: Pre-allocated user data + * + * This function creates a connection to a remote server + */ + +struct libwebsocket * +libwebsocket_client_connect_extended(struct libwebsocket_context *context, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one, + void *userdata) +{ + struct libwebsocket *ws = + libwebsocket_client_connect(context, address, port, ssl_connection, path, host, origin, protocol, ietf_version_or_minus_one) ; + + if (ws && !ws->user_space && userdata) + ws->user_space = userdata ; + + return ws ; + } diff --git a/libs/libwebsockets/lib/extension-deflate-stream.c b/libs/libwebsockets/lib/extension-deflate-stream.c new file mode 100644 index 0000000000..2e4ad6c1a4 --- /dev/null +++ b/libs/libwebsockets/lib/extension-deflate-stream.c @@ -0,0 +1,150 @@ +#include "private-libwebsockets.h" +#include "extension-deflate-stream.h" +#include +#include +#include + +#define LWS_ZLIB_WINDOW_BITS 15 +#define LWS_ZLIB_MEMLEVEL 8 + +int lws_extension_callback_deflate_stream( + struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len) +{ + struct lws_ext_deflate_stream_conn *conn = + (struct lws_ext_deflate_stream_conn *)user; + int n; + struct lws_tokens *eff_buf = (struct lws_tokens *)in; + + switch (reason) { + + /* + * for deflate-stream, both client and server sides act the same + */ + + case LWS_EXT_CALLBACK_CLIENT_CONSTRUCT: + case LWS_EXT_CALLBACK_CONSTRUCT: + conn->zs_in.zalloc = conn->zs_out.zalloc = Z_NULL; + conn->zs_in.zfree = conn->zs_out.zfree = Z_NULL; + conn->zs_in.opaque = conn->zs_out.opaque = Z_NULL; + n = inflateInit2(&conn->zs_in, -LWS_ZLIB_WINDOW_BITS); + if (n != Z_OK) { + fprintf(stderr, "deflateInit returned %d\n", n); + return 1; + } + n = deflateInit2(&conn->zs_out, + DEFLATE_STREAM_COMPRESSION_LEVEL, Z_DEFLATED, + -LWS_ZLIB_WINDOW_BITS, LWS_ZLIB_MEMLEVEL, + Z_DEFAULT_STRATEGY); + if (n != Z_OK) { + fprintf(stderr, "deflateInit returned %d\n", n); + return 1; + } + debug("zlibs constructed\n"); + break; + + case LWS_EXT_CALLBACK_DESTROY: + (void)inflateEnd(&conn->zs_in); + (void)deflateEnd(&conn->zs_out); + debug("zlibs destructed\n"); + break; + + case LWS_EXT_CALLBACK_PACKET_RX_PREPARSE: + + /* + * inflate the incoming compressed data + * Notice, length may be 0 and pointer NULL + * in the case we are flushing with nothing new coming in + */ + + conn->zs_in.next_in = (unsigned char *)eff_buf->token; + conn->zs_in.avail_in = eff_buf->token_len; + + conn->zs_in.next_out = conn->buf; + conn->zs_in.avail_out = sizeof(conn->buf); + + n = inflate(&conn->zs_in, Z_SYNC_FLUSH); + switch (n) { + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_MEM_ERROR: + /* + * screwed.. close the connection... we will get a + * destroy callback to take care of closing nicely + */ + fprintf(stderr, "zlib error inflate %d\n", n); + return -1; + } + + /* rewrite the buffer pointers and length */ + + eff_buf->token = (char *)conn->buf; + eff_buf->token_len = sizeof(conn->buf) - conn->zs_in.avail_out; + + /* + * if we filled the output buffer, signal that we likely have + * more and need to be called again + */ + + if (eff_buf->token_len == sizeof(conn->buf)) + return 1; + + /* we don't need calling again until new input data comes */ + + return 0; + + case LWS_EXT_CALLBACK_FLUSH_PENDING_TX: + case LWS_EXT_CALLBACK_PACKET_TX_PRESEND: + + /* + * deflate the outgoing compressed data + */ + + conn->zs_out.next_in = (unsigned char *)eff_buf->token; + conn->zs_out.avail_in = eff_buf->token_len; + + conn->zs_out.next_out = conn->buf; + conn->zs_out.avail_out = sizeof(conn->buf); + + n = Z_PARTIAL_FLUSH; + if (reason == LWS_EXT_CALLBACK_FLUSH_PENDING_TX) + n = Z_FULL_FLUSH; + + n = deflate(&conn->zs_out, n); + if (n == Z_STREAM_ERROR) { + /* + * screwed.. close the connection... we will get a + * destroy callback to take care of closing nicely + */ + fprintf(stderr, "zlib error deflate\n"); + + return -1; + } + + /* rewrite the buffer pointers and length */ + + eff_buf->token = (char *)conn->buf; + eff_buf->token_len = sizeof(conn->buf) - conn->zs_out.avail_out; + + /* + * if we filled the output buffer, signal that we likely have + * more and need to be called again... even in deflate case + * we might sometimes need to spill more than came in + */ + + if (eff_buf->token_len == sizeof(conn->buf)) + return 1; + + /* we don't need calling again until new input data comes */ + + return 0; + + default: + break; + } + + return 0; +} diff --git a/libs/libwebsockets/lib/extension-deflate-stream.h b/libs/libwebsockets/lib/extension-deflate-stream.h new file mode 100644 index 0000000000..a8187bc3ac --- /dev/null +++ b/libs/libwebsockets/lib/extension-deflate-stream.h @@ -0,0 +1,18 @@ + +#include + +#define DEFLATE_STREAM_CHUNK 128 +#define DEFLATE_STREAM_COMPRESSION_LEVEL 1 + +struct lws_ext_deflate_stream_conn { + z_stream zs_in; + z_stream zs_out; + unsigned char buf[2000]; +}; + +extern int lws_extension_callback_deflate_stream( + struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); diff --git a/libs/libwebsockets/lib/extension-x-google-mux.c b/libs/libwebsockets/lib/extension-x-google-mux.c new file mode 100644 index 0000000000..f501c925a5 --- /dev/null +++ b/libs/libwebsockets/lib/extension-x-google-mux.c @@ -0,0 +1,1223 @@ +#include "private-libwebsockets.h" +#include "extension-x-google-mux.h" + +#define MUX_REAL_CHILD_INDEX_OFFSET 2 + +static int ongoing_subchannel; +static struct libwebsocket * tag_with_parent = NULL; +static int client_handshake_generation_is_for_mux_child; + +static int lws_addheader_mux_opcode(unsigned char *pb, int len) +{ + unsigned char *start = pb; + + *pb++ = LWS_WS_OPCODE_07__NOSPEC__MUX | 0x80; + if (len < 126) + *pb++ = len; + else { + if (len > 65535) { + *pb++ = 127; + *pb++ = 0; + *pb++ = 0; + *pb++ = 0; + *pb++ = 0; + *pb++ = (len ) >> 24; + *pb++ = (len) >> 16; + *pb++ = (len) >> 8; + *pb++ = (len) >> 0; + } else { + *pb++ = 126; + *pb++ = (len) >> 8; + *pb++ = (len) >> 0; + } + } + + return pb - start; +} + +static int +lws_mux_subcommand_header(int cmd, int channel, unsigned char *pb, int len) +{ + unsigned char *start = pb; + + if (channel == 0) { + muxdebug("lws_mux_subcommand_header: given ch 0\n"); + *((int *)0) = 0; + } + + if (channel < 31) + *pb++ = (channel << 3) | cmd; + else { + *pb++ = (31 << 3) | cmd; + *pb++ = channel >> 8; + *pb++ = channel; + } + + if (len <= 253) + *pb++ = len; + else { + if (len <= 65535) { + *pb++ = 254; + *pb++ = len >> 8; + *pb++ = len; + } else { + *pb++ = 255; + *pb++ = len >> 24; + *pb++ = len >> 16; + *pb++ = len >> 8; + *pb++ = len; + } + } + + return pb - start; +} + +static int lws_ext_x_google_mux__send_addchannel( + struct libwebsocket_context *context, + struct libwebsocket *wsi, + struct lws_ext_x_google_mux_conn *parent_conn, + struct libwebsocket *wsi_child, + int channel, + const char *url +) { + + unsigned char send_buf[LWS_SEND_BUFFER_PRE_PADDING + 2048 + + LWS_SEND_BUFFER_POST_PADDING]; + unsigned char *pb = &send_buf[LWS_SEND_BUFFER_PRE_PADDING]; + char *p; + char delta_headers[1536]; + int delta_headers_len; + int subcommand_length; + int n; + + if (channel == 0) { + muxdebug("lws_ext_x_google_mux__send_addchannel: given ch 0\n"); + *((int *)0) = 0; + } + + wsi_child->ietf_spec_revision = wsi->ietf_spec_revision; + + client_handshake_generation_is_for_mux_child = 1; + p = libwebsockets_generate_client_handshake(context, wsi_child, + delta_headers); + client_handshake_generation_is_for_mux_child = 0; + delta_headers_len = p - delta_headers; + + subcommand_length = lws_mux_subcommand_header( + LWS_EXT_XGM_OPC__ADDCHANNEL, channel, pb, delta_headers_len); + + pb += lws_addheader_mux_opcode(pb, subcommand_length + delta_headers_len); + pb += lws_mux_subcommand_header(LWS_EXT_XGM_OPC__ADDCHANNEL, channel, + pb, delta_headers_len); + +// n = sprintf((char *)pb, "%s\x0d\x0a", url); +// pb += n; + + if (delta_headers_len) + memcpy(pb, delta_headers, delta_headers_len); + + pb += delta_headers_len; + + muxdebug("add channel sends %ld\n", + pb - &send_buf[LWS_SEND_BUFFER_PRE_PADDING]); + + parent_conn->defeat_mux_opcode_wrapping = 1; + + /* send the request to the server */ + + n = lws_issue_raw_ext_access(wsi, &send_buf[LWS_SEND_BUFFER_PRE_PADDING], + pb - &send_buf[LWS_SEND_BUFFER_PRE_PADDING]); + + parent_conn->defeat_mux_opcode_wrapping = 0; + + return n; +} + +/** + * lws_extension_x_google_mux_parser(): Parse mux buffer headers coming in + * from a muxed connection into subchannel + * specific actions + * @wsi: muxed websocket instance + * @conn: x-google-mux private data bound to that @wsi + * @c: next character in muxed stream + */ + +static int +lws_extension_x_google_mux_parser(struct libwebsocket_context *context, + struct libwebsocket *wsi, + struct libwebsocket_extension *this_ext, + struct lws_ext_x_google_mux_conn *conn, unsigned char c) +{ + struct libwebsocket *wsi_child = NULL; + struct libwebsocket_extension *ext; + struct lws_ext_x_google_mux_conn *child_conn = NULL; + int n; + void *v; + +// fprintf(stderr, "XRX: %02X %d %d\n", c, conn->state, conn->length); + + /* + * [ ] + * [ ] + */ + + switch (conn->state) { + + case LWS_EXT_XGM_STATE__MUX_BLOCK_1: +// fprintf(stderr, "LWS_EXT_XGM_STATE__MUX_BLOCK_1: opc=%d channel=%d\n", c & 7, c >> 3); + conn->block_subopcode = c & 7; + conn->block_subchannel = (c >> 3) & 0x1f; + conn->ignore_cmd = 0; + + if (conn->block_subchannel != 31) + goto interpret; + else + conn->state = LWS_EXT_XGM_STATE__MUX_BLOCK_2; + break; + + case LWS_EXT_XGM_STATE__MUX_BLOCK_2: + conn->block_subchannel = c << 8; + conn->state = LWS_EXT_XGM_STATE__MUX_BLOCK_3; + break; + + case LWS_EXT_XGM_STATE__MUX_BLOCK_3: + conn->block_subchannel |= c; + +interpret: +// fprintf(stderr, "LWS_EXT_XGM_STATE__MUX_BLOCK_3: subchannel=%d\n", conn->block_subchannel); + ongoing_subchannel = conn->block_subchannel; + + /* + * convert the subchannel index to a child wsi + */ + + /* act on the muxing opcode */ + + switch (conn->block_subopcode) { + case LWS_EXT_XGM_OPC__DATA: + conn->state = LWS_EXT_XGM_STATE__DATA; + break; + case LWS_EXT_XGM_OPC__ADDCHANNEL: + conn->state = LWS_EXT_XGM_STATE__ADDCHANNEL_LEN; + switch (wsi->mode) { + + /* client: parse accepted headers returned by server */ + + case LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY: + case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE: + case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY: + case LWS_CONNMODE_WS_CLIENT: + wsi_child = conn->wsi_children[conn->block_subchannel - MUX_REAL_CHILD_INDEX_OFFSET]; + wsi_child->state = WSI_STATE_HTTP_HEADERS; + wsi_child->parser_state = WSI_TOKEN_NAME_PART; + break; + default: + wsi_child = libwebsocket_create_new_server_wsi(context); + conn->wsi_children[conn->block_subchannel - MUX_REAL_CHILD_INDEX_OFFSET] = wsi_child; + wsi_child->state = WSI_STATE_HTTP_HEADERS; + wsi_child->parser_state = WSI_TOKEN_NAME_PART; + wsi_child->extension_handles = wsi; + muxdebug("MUX LWS_EXT_XGM_OPC__ADDCHANNEL... " + "created child subchannel %d\n", conn->block_subchannel); + break; + } + break; + case LWS_EXT_XGM_OPC__DROPCHANNEL: + conn->state = LWS_EXT_XGM_STATE__MUX_BLOCK_1; + break; + case LWS_EXT_XGM_OPC__FLOWCONTROL: + conn->state = LWS_EXT_XGM_STATE__FLOWCONTROL_1; + break; + default: + fprintf(stderr, "xgm: unknown subopcode\n"); + return -1; + } + break; + + case LWS_EXT_XGM_STATE__ADDCHANNEL_LEN: + switch (c) { + case 254: + conn->state = LWS_EXT_XGM_STATE__ADDCHANNEL_LEN16_1; + break; + case 255: + conn->state = LWS_EXT_XGM_STATE__ADDCHANNEL_LEN32_1; + break; + default: + conn->length = c; + conn->state = LWS_EXT_XGM_STATE__ADDCHANNEL_HEADERS; + break; + } + break; + + case LWS_EXT_XGM_STATE__ADDCHANNEL_LEN16_1: + conn->length = c << 8; + conn->state = LWS_EXT_XGM_STATE__ADDCHANNEL_LEN16_2; + break; + + case LWS_EXT_XGM_STATE__ADDCHANNEL_LEN16_2: + conn->length |= c; + conn->state = LWS_EXT_XGM_STATE__ADDCHANNEL_HEADERS; + muxdebug("conn->length in mux block is %d\n", conn->length); + break; + + case LWS_EXT_XGM_STATE__ADDCHANNEL_LEN32_1: + conn->length = c << 24; + conn->state = LWS_EXT_XGM_STATE__ADDCHANNEL_LEN32_2; + break; + + case LWS_EXT_XGM_STATE__ADDCHANNEL_LEN32_2: + conn->length |= c << 16; + conn->state = LWS_EXT_XGM_STATE__ADDCHANNEL_LEN32_3; + break; + + case LWS_EXT_XGM_STATE__ADDCHANNEL_LEN32_3: + conn->length |= c << 8; + conn->state = LWS_EXT_XGM_STATE__ADDCHANNEL_LEN32_4; + break; + + case LWS_EXT_XGM_STATE__ADDCHANNEL_LEN32_4: + conn->length |= c; + conn->state = LWS_EXT_XGM_STATE__ADDCHANNEL_HEADERS; + break; + + case LWS_EXT_XGM_STATE__ADDCHANNEL_HEADERS: + + if (conn->block_subchannel == 0 || conn->block_subchannel >= + (sizeof(conn->wsi_children) / + sizeof(conn->wsi_children[0]))) { + fprintf(stderr, "Illegal subchannel %d in " + "LWS_EXT_XGM_STATE__ADDCHANNEL_HEADERS, ignoring", + conn->block_subchannel); + conn->ignore_cmd = 1; + } + + if (conn->block_subchannel == 1 && !conn->original_ch1_closed) { + fprintf(stderr, "illegal request to add ch1 when it's still live, ignoring\n"); + conn->ignore_cmd = 1; + } + + if (conn->ignore_cmd) { + if (--conn->length) + return 0; + conn->state = LWS_EXT_XGM_STATE__MUX_BLOCK_1; + return 0; + } + + switch (wsi->mode) { + + /* client: parse accepted headers returned by server */ + + case LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY: + case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE: + case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY: + case LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT: + case LWS_CONNMODE_WS_CLIENT: + + muxdebug("Client LWS_EXT_XGM_STATE__ADDCHANNEL_HEADERS in %c\n", c); + if (conn->block_subchannel == 1) { + muxdebug("adding ch1\n"); + wsi_child = wsi; + child_conn = conn; + } else + wsi_child = conn->wsi_children[ + conn->block_subchannel - + MUX_REAL_CHILD_INDEX_OFFSET]; + + libwebsocket_parse(wsi_child, c); + + if (--conn->length) + return 0; + + /* it's here we create the actual ext conn via callback */ + tag_with_parent = wsi; + lws_client_interpret_server_handshake(context, wsi_child); + tag_with_parent = NULL; + + //if (wsi->parser_state != WSI_PARSING_COMPLETE) +// break; + + /* client: we received all server's ADD ack */ + + if (conn->block_subchannel != 1) { + child_conn = lws_get_extension_user_matching_ext( + wsi_child, this_ext); + muxdebug("Received server's ADD Channel ACK for " + "subchannel %d child_conn=%p!\n", + conn->block_subchannel, (void *)child_conn); + + wsi_child->xor_mask = xor_no_mask; + wsi_child->ietf_spec_revision = wsi->ietf_spec_revision; + + wsi_child->mode = LWS_CONNMODE_WS_CLIENT; + wsi_child->state = WSI_STATE_ESTABLISHED; + child_conn->state = LWS_EXT_XGM_STATE__MUX_BLOCK_1; + } + + conn->state = LWS_EXT_XGM_STATE__MUX_BLOCK_1; + child_conn->subchannel = conn->block_subchannel; + + /* allocate the per-connection user memory (if any) */ + + if (wsi_child->protocol->per_session_data_size) { + wsi_child->user_space = malloc( + wsi_child->protocol->per_session_data_size); + if (wsi_child->user_space == NULL) { + fprintf(stderr, "Out of memory for " + "conn user space\n"); + goto bail2; + } + } else + wsi_child->user_space = NULL; + + /* clear his proxy connection timeout */ + + libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); + + /* mark him as being alive */ + + wsi_child->state = WSI_STATE_ESTABLISHED; + wsi_child->mode = LWS_CONNMODE_WS_CLIENT; + + if (wsi_child->protocol) + muxdebug("mux handshake OK for protocol %s\n", + wsi_child->protocol->name); + else + muxdebug("mux child handshake ends up with no protocol!\n"); + + /* + * inform all extensions, not just active ones since they + * already know + */ + + ext = context->extensions; + + while (ext && ext->callback) { + v = NULL; + for (n = 0; n < wsi_child->count_active_extensions; n++) + if (wsi_child->active_extensions[n] == ext) { + v = wsi_child->active_extensions_user[n]; + } + + ext->callback(context, ext, wsi_child, + LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED, v, NULL, 0); + ext++; + } + + /* call him back to inform him he is up */ + + wsi->protocol->callback(context, wsi_child, + LWS_CALLBACK_CLIENT_ESTABLISHED, + wsi_child->user_space, + NULL, 0); + + return 0; + +bail2: + exit(1); + + /* server: parse proposed changed headers from client */ + + default: + break; + } + + /* + * SERVER + */ + + wsi_child = conn->wsi_children[conn->block_subchannel - MUX_REAL_CHILD_INDEX_OFFSET]; + + muxdebug("Server LWS_EXT_XGM_STATE__ADDCHANNEL_HEADERS in %d\n", conn->length); + + libwebsocket_read(context, wsi_child, &c, 1); + + if (--conn->length > 0) + break; + + muxdebug("Server LWS_EXT_XGM_STATE__ADDCHANNEL_HEADERS done\n"); + + /* + * server: header diffs are all seen, we must process + * the add action + */ + + /* reply with ADDCHANNEL to ack it */ + + wsi->xor_mask = xor_no_mask; + child_conn = lws_get_extension_user_matching_ext(wsi_child, + this_ext); + if (!child_conn) { + fprintf(stderr, "wsi_child %p has no child conn!", (void *)wsi_child); + break; + } + child_conn->wsi_parent = wsi; + conn->sticky_mux_used = 1; + child_conn->subchannel = conn->block_subchannel; + + + muxdebug("Setting child conn parent to %p\n", (void *)wsi); + + wsi_child->mode = LWS_CONNMODE_WS_SERVING; + wsi_child->state = WSI_STATE_ESTABLISHED; + wsi_child->lws_rx_parse_state = LWS_RXPS_NEW; + wsi_child->rx_packet_length = 0; + + /* allocate the per-connection user memory (if any) */ + + if (wsi_child->protocol->per_session_data_size) { + wsi_child->user_space = malloc( + wsi_child->protocol->per_session_data_size); + if (wsi_child->user_space == NULL) { + fprintf(stderr, "Out of memory for " + "conn user space\n"); + break; + } + } else + wsi_child->user_space = NULL; + + + conn->wsi_children[conn->block_subchannel - + MUX_REAL_CHILD_INDEX_OFFSET] = wsi_child; + if (conn->highest_child_subchannel <= + conn->block_subchannel - MUX_REAL_CHILD_INDEX_OFFSET) + conn->highest_child_subchannel = + conn->block_subchannel - + MUX_REAL_CHILD_INDEX_OFFSET + 1; + + + /* notify user code that we're ready to roll */ + + if (wsi_child->protocol->callback) + wsi_child->protocol->callback( + wsi_child->protocol->owning_server, + wsi_child, LWS_CALLBACK_ESTABLISHED, + wsi_child->user_space, NULL, 0); + + muxdebug("setting conn state LWS_EXT_XGM_STATE__MUX_BLOCK_1\n"); + conn->state = LWS_EXT_XGM_STATE__MUX_BLOCK_1; + break; + + case LWS_EXT_XGM_STATE__FLOWCONTROL_1: + conn->length = c << 24; + conn->state = LWS_EXT_XGM_STATE__FLOWCONTROL_2; + break; + + case LWS_EXT_XGM_STATE__FLOWCONTROL_2: + conn->length |= c << 16; + conn->state = LWS_EXT_XGM_STATE__FLOWCONTROL_3; + break; + + case LWS_EXT_XGM_STATE__FLOWCONTROL_3: + conn->length |= c << 8; + conn->state = LWS_EXT_XGM_STATE__FLOWCONTROL_4; + break; + + case LWS_EXT_XGM_STATE__FLOWCONTROL_4: + conn->length |= c; + conn->state = LWS_EXT_XGM_STATE__MUX_BLOCK_1; + break; + + case LWS_EXT_XGM_STATE__DATA: + +// fprintf(stderr, "LWS_EXT_XGM_STATE__DATA in\n"); + + /* + * we have cooked websocket frame content following just like + * it went on the wire without mux, including masking and any + * other extensions (including this guy can himself be another + * level of channel mux, there's no restriction). + * + * We deal with it by just feeding it to the child wsi's rx + * state machine. The only issue is, we need that state machine + * to tell us when it ate a full frame, so we watch its state + * afterwards + */ + if (conn->block_subchannel - MUX_REAL_CHILD_INDEX_OFFSET >= conn->highest_child_subchannel) { + fprintf(stderr, "Illegal subchannel %d\n", conn->block_subchannel); + return -1; + } + + // fprintf(stderr, "LWS_EXT_XGM_STATE__DATA: ch %d\n", conn->block_subchannel); + + if (conn->block_subchannel == 1) { + if (conn->original_ch1_closed) { + fprintf(stderr, "data sent to closed ch1\n"); + return -1; + } + wsi_child = wsi; + } else + wsi_child = conn->wsi_children[conn->block_subchannel - MUX_REAL_CHILD_INDEX_OFFSET]; + + if (!wsi_child) { + fprintf(stderr, "Bad subchannel %d\n", conn->block_subchannel); + return -1; + } + + switch (wsi_child->mode) { + + /* client receives something */ + + case LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY: + case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE: + case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY: + case LWS_CONNMODE_WS_CLIENT: +// fprintf(stderr, " client\n"); + if (libwebsocket_client_rx_sm(wsi_child, c) < 0) { + libwebsocket_close_and_free_session( + context, + wsi_child, + LWS_CLOSE_STATUS_GOINGAWAY); + } + + return 0; + + /* server is receiving from client */ + + default: +// fprintf(stderr, " server\n"); + if (libwebsocket_rx_sm(wsi_child, c) < 0) { + muxdebug("probs\n"); + libwebsocket_close_and_free_session( + context, + wsi_child, + LWS_CLOSE_STATUS_GOINGAWAY); + } + break; + } + break; + } + + return 0; +} + + + +int lws_extension_callback_x_google_mux( + struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len) +{ + unsigned char send_buf[LWS_SEND_BUFFER_PRE_PADDING + 4096 + + LWS_SEND_BUFFER_POST_PADDING]; + struct lws_ext_x_google_mux_conn *conn = + (struct lws_ext_x_google_mux_conn *)user; + struct lws_ext_x_google_mux_conn *parent_conn; + struct lws_ext_x_google_mux_conn *child_conn; + int n; + struct lws_tokens *eff_buf = (struct lws_tokens *)in; + unsigned char *p = NULL; + struct lws_ext_x_google_mux_context *mux_ctx = + ext->per_context_private_data; + struct libwebsocket *wsi_parent; + struct libwebsocket *wsi_child; + struct libwebsocket *wsi_temp; + unsigned char *pin = (unsigned char *)in; + unsigned char *basepin; + int m; + int done = 0; + unsigned char *pb = &send_buf[LWS_SEND_BUFFER_PRE_PADDING]; + int subcommand_length; + + if (eff_buf) + p = (unsigned char *)eff_buf->token; + + switch (reason) { + + /* these guys are once per context */ + + case LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT: + case LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT: + + ext->per_context_private_data = malloc( + sizeof (struct lws_ext_x_google_mux_context)); + mux_ctx = (struct lws_ext_x_google_mux_context *) + ext->per_context_private_data; + mux_ctx->active_conns = 0; + break; + + case LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT: + case LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT: + + if (!mux_ctx) + break; + for (n = 0; n < mux_ctx->active_conns; n++) + if (mux_ctx->wsi_muxconns[n]) { + libwebsocket_close_and_free_session( + context, mux_ctx->wsi_muxconns[n], + LWS_CLOSE_STATUS_GOINGAWAY); + mux_ctx->wsi_muxconns[n] = NULL; + } + + free(mux_ctx); + break; + + /* + * channel management + */ + + case LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION: + + muxdebug("LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION %s:%u\n", + (char *)in, (unsigned int)len); + + /* + * Does a physcial connection to the same server:port already + * exist so we can piggyback on it? + */ + + for (n = 0; n < mux_ctx->active_conns && !done; n++) { + + wsi_parent = mux_ctx->wsi_muxconns[n]; + if (!wsi_parent) + continue; + + muxdebug(" %s / %s\n", wsi_parent->c_address, (char *)in); + if (strcmp(wsi_parent->c_address, in)) + continue; + muxdebug(" %u / %u\n", wsi_parent->c_port, (unsigned int)len); + + if (wsi_parent->c_port != (unsigned int)len) + continue; + + /* + * does this potential parent already have an + * x-google-mux conn associated with him? + */ + + parent_conn = NULL; + for (m = 0; m < wsi_parent->count_active_extensions; m++) + if (ext == wsi_parent->active_extensions[m]) + parent_conn = (struct lws_ext_x_google_mux_conn *) + wsi_parent->active_extensions_user[m]; + + if (parent_conn == NULL) { + + /* + * he doesn't -- see if that's just because it + * is early in his connection sequence or if we + * should give up on him + */ + + switch (wsi_parent->mode) { + case LWS_CONNMODE_WS_SERVING: + case LWS_CONNMODE_WS_CLIENT: + continue; + default: + break; + } + + /* + * our putative parent is still connecting + * himself, we have to become a candidate child + * and find out our final fate when the parent + * completes connection + */ + + wsi->candidate_children_list = wsi_parent->candidate_children_list; + wsi_parent->candidate_children_list = wsi; + wsi->mode = LWS_CONNMODE_WS_CLIENT_PENDING_CANDIDATE_CHILD; + + done = 1; + continue; + } + + if (parent_conn->highest_child_subchannel >= + (sizeof(parent_conn->wsi_children) / + sizeof(parent_conn->wsi_children[0]))) { + fprintf(stderr, "Can't add any more children\n"); + continue; + } + /* + * this established connection will do, bind them + * from now on child will only operate through parent + * connection + */ + + wsi->candidate_children_list = wsi_parent->candidate_children_list; + wsi_parent->candidate_children_list = wsi; + wsi->mode = LWS_CONNMODE_WS_CLIENT_PENDING_CANDIDATE_CHILD; + + muxdebug("attaching to existing mux\n"); + + conn = parent_conn; + wsi = wsi_parent; + + goto handle_additions; + + } + + /* + * either way, note the existence of this connection in case + * he will become a possible mux parent later + */ + + mux_ctx->wsi_muxconns[mux_ctx->active_conns++] = wsi; + if (done) + return 1; + + muxdebug("x-google-mux: unable to mux connection\n"); + + break; + + /* these guys are once per connection */ + + case LWS_EXT_CALLBACK_CLIENT_CONSTRUCT: + muxdebug("LWS_EXT_CALLBACK_CLIENT_CONSTRUCT: setting parent = %p\n", (void *)tag_with_parent); + conn->state = LWS_EXT_XGM_STATE__MUX_BLOCK_1; + if (conn->block_subchannel != 1) + conn->wsi_parent = tag_with_parent; + break; + + case LWS_EXT_CALLBACK_CONSTRUCT: + muxdebug("LWS_EXT_CALLBACK_CONSTRUCT\n"); + conn->state = LWS_EXT_XGM_STATE__MUX_BLOCK_1; + break; + + case LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE: + muxdebug("LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE\n"); + + if (conn->subchannel == 1) { + + /* + * special case of original mux parent channel closing + */ + + conn->original_ch1_closed = 1; + + fprintf(stderr, "original mux parent channel closing\n"); + + parent_conn = conn; + } else { + + parent_conn = lws_get_extension_user_matching_ext(conn->wsi_parent, ext); + if (parent_conn == 0) { + muxdebug("failed to get parent conn\n"); + break; + } + } + + /* see if that was the end of the mux entirely */ + + if (!parent_conn->original_ch1_closed) + break; + + done = 0; + for (n = 0; n < !done && parent_conn->highest_child_subchannel; n++) + if (parent_conn->wsi_children[n]) + done = 1; + + /* if he has children, don't let him close for real! */ + + if (done) { + fprintf(stderr, "VETO closure\n"); + return 1; + } + + /* no children, ch1 is closed, let him destroy himself */ + + if (conn->subchannel == 1) + fprintf(stderr, "ALLOW closure of mux parent\n"); + + break; + + case LWS_EXT_CALLBACK_DESTROY: + muxdebug("LWS_EXT_CALLBACK_DESTROY\n"); + + /* + * remove us from parent if noted in parent + */ + + if (conn->subchannel == 1) { + + /* + * special case of original mux parent channel closing + */ + + conn->original_ch1_closed = 1; + + fprintf(stderr, "original mux parent channel closing\n"); + + parent_conn = conn; + wsi_parent = wsi; + } else { + + wsi_parent = conn->wsi_parent; + parent_conn = lws_get_extension_user_matching_ext(conn->wsi_parent, ext); + if (parent_conn == 0) { + muxdebug("failed to get parent conn\n"); + break; + } + for (n = 0; n < parent_conn->highest_child_subchannel; n++) + if (parent_conn->wsi_children[n] == wsi) + parent_conn->wsi_children[n] = NULL; + } + + /* see if that was the end of the mux entirely */ + + if (!parent_conn->original_ch1_closed) + break; + + done = 0; + for (n = 0; n < !done && parent_conn->highest_child_subchannel; n++) + if (parent_conn->wsi_children[n]) + done = 1; + + if (done == 0) + if (parent_conn != conn) + + /* + * parent closed last and no children left + * ... and we are not parent already ourselves + */ + + libwebsocket_close_and_free_session(context, wsi_parent, LWS_CLOSE_STATUS_NORMAL); + + break; + + case LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING: + muxdebug("LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING\n"); + + for (n = 0; n < mux_ctx->active_conns; n++) + if (mux_ctx->wsi_muxconns[n] == wsi) { + while (n++ < mux_ctx->active_conns) + mux_ctx->wsi_muxconns[n - 1] = + mux_ctx->wsi_muxconns[n]; + mux_ctx->active_conns--; + return 0; + } + + /* + * liberate any candidate children otherwise imprisoned + */ + + wsi_parent = wsi->candidate_children_list; + while (wsi_parent) { + wsi_temp = wsi_parent->candidate_children_list; + /* let them each connect privately then */ + __libwebsocket_client_connect_2(context, wsi_parent); + wsi_parent = wsi_temp; + } + + break; + + case LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED: + muxdebug("LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED\n"); + +handle_additions: + /* + * did this putative parent get x-google-mux authorized in the + * end? + */ + + if (!conn) { + + muxdebug(" Putative parent didn't get mux extension, let them go it alone\n"); + + /* + * no, we can't be a parent for mux children. Let + * them all go it alone + */ + + wsi_child = wsi->candidate_children_list; + while (wsi_child) { + wsi_temp = wsi_child->candidate_children_list; + /* let them each connect privately then */ + __libwebsocket_client_connect_2(context, wsi_child); + wsi_child = wsi_temp; + } + + return 1; + } + + /* + * we did get mux extension authorized by server, in that case + * if we have any candidate children let's try to attach them + * as mux subchannel real children + */ + + wsi_child = wsi->candidate_children_list; + n = 0; + while (wsi_child) { + + wsi_temp = wsi_child->candidate_children_list; + + /* find an empty subchannel */ + + while ((n < (sizeof(conn->wsi_children) / sizeof(conn->wsi_children[0]))) && + conn->wsi_children[n] != NULL) + n++; + + if (n >= (sizeof(conn->wsi_children) / sizeof(conn->wsi_children[0]))) { + /* no room at the inn */ + + /* let them each connect privately then */ + __libwebsocket_client_connect_2(context, wsi_child); + wsi_child = wsi_temp; + continue; + } + + muxdebug(" using mux addchannel action for candidate child\n"); + + /* pile the children on the parent */ + lws_ext_x_google_mux__send_addchannel(context, wsi, + conn, wsi_child, + n + MUX_REAL_CHILD_INDEX_OFFSET, wsi->c_path); + + conn->sticky_mux_used = 1; + + conn->wsi_children[n] = wsi_child; + if ((n + 1) > conn->highest_child_subchannel) + conn->highest_child_subchannel = n + 1; + + muxdebug("Setting CHILD LIST entry %d to %p\n", + n + MUX_REAL_CHILD_INDEX_OFFSET, (void *)wsi_parent); + wsi_child = wsi_temp; + } + wsi->candidate_children_list = NULL; + return 1; + + /* + * whenever we receive something on a muxed link + */ + + case LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX: + + muxdebug("LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX\n"); + + if (wsi->opcode != LWS_WS_OPCODE_07__NOSPEC__MUX) + return 0; /* unhandled */ + + conn->state = LWS_EXT_XGM_STATE__MUX_BLOCK_1; + + n = eff_buf->token_len; + while (n--) + if (lws_extension_x_google_mux_parser(context, wsi, ext, + conn, *p++) < 0) { + return -1; + } + return 1; /* handled */ + + /* + * when something might need sending on our transport + */ + + case LWS_EXT_CALLBACK_PACKET_TX_DO_SEND: + + muxdebug("LWS_EXT_CALLBACK_PACKET_TX_DO_SEND: %p, " + "my subchannel=%d\n", + (void *)conn->wsi_parent, conn->subchannel); + + pin = *((unsigned char **)in); + basepin = pin; + + wsi_parent = conn->wsi_parent; + + if (conn->subchannel == 1) { + + /* + * if we weren't 'closed', then we were the original + * connection that established this link, ie, it's + * the parent wsi + */ + + if (conn->original_ch1_closed) { + fprintf(stderr, "Trying to send on dead original ch1\n"); + return 0; + } + + /* send on ourselves */ + + wsi_parent = wsi; + + } else { + + /* + * he's not a child connection of a mux + */ + + if (!conn->wsi_parent) { + // fprintf(stderr, "conn %p has no parent\n", (void *)conn); + return 0; + } + + /* + * get parent / transport mux context + */ + + parent_conn = lws_get_extension_user_matching_ext(conn->wsi_parent, ext); + if (parent_conn == 0) { + muxdebug("failed to get parent conn\n"); + return 0; + } + + /* + * mux transport is in singular mode, let the caller send it + * no more muxified than it already is + */ + + if (!parent_conn->sticky_mux_used) { + // fprintf(stderr, "parent in singular mode\n"); + return 0; + } + } + + if (!conn->defeat_mux_opcode_wrapping) { + + n = 1; + if (conn->subchannel >= 31) + n = 3; + + /* + * otherwise we need to take care of the sending action using + * mux protocol. Prepend the channel + opcode + */ + + pin -= lws_addheader_mux_opcode(send_buf, len + n) + n; + basepin = pin; + pin += lws_addheader_mux_opcode(pin, len + n); + + if (conn->subchannel >= 31) { + *pin++ = (31 << 3) | LWS_EXT_XGM_OPC__DATA; + *pin++ = conn->subchannel >> 8; + *pin++ = conn->subchannel; + } else + *pin++ = (conn->subchannel << 3) | LWS_EXT_XGM_OPC__DATA; + } + + /* + * recurse to allow nesting + */ + + lws_issue_raw_ext_access(wsi_parent, basepin, (pin - basepin) + len); + + return 1; /* handled */ + + case LWS_EXT_CALLBACK_1HZ: + /* + * if we have children, service their timeouts using the same + * handler as toplevel guys to allow recursion + */ + for (n = 0; n < conn->highest_child_subchannel; n++) + if (conn->wsi_children[n]) + libwebsocket_service_timeout_check(context, + conn->wsi_children[n], len); + break; + + case LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE: + /* + * if a mux child is asking for callback on writable, we have + * to pass it up to his parent + */ + + muxdebug("LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE %s\n", wsi->protocol->name); + + if (conn->wsi_parent == NULL) { + muxdebug(" no parent\n"); + break; + } + + if (!conn->awaiting_POLLOUT) { + + muxdebug(" !conn->awaiting_POLLOUT\n"); + + conn->awaiting_POLLOUT = 1; + parent_conn = NULL; + for (m = 0; m < conn->wsi_parent->count_active_extensions; m++) + if (ext == conn->wsi_parent->active_extensions[m]) + parent_conn = (struct lws_ext_x_google_mux_conn *) + conn->wsi_parent->active_extensions_user[m]; + + if (parent_conn != NULL) { + parent_conn->count_children_needing_POLLOUT++; + muxdebug(" count_children_needing_POLLOUT bumped\n"); + } else + muxdebug("unable to identify parent conn\n"); + } + muxdebug(" requesting on parent %p\n", (void *)conn->wsi_parent); + libwebsocket_callback_on_writable(context, conn->wsi_parent); + + return 1; + + case LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX: + + muxdebug("LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX %p\n", + (void *)wsi->extension_handles); + + /* send raw if we're not a child */ + + if (!wsi->extension_handles) + return 0; + + subcommand_length = lws_mux_subcommand_header(LWS_EXT_XGM_OPC__ADDCHANNEL, ongoing_subchannel, pb, len); + + pb += lws_addheader_mux_opcode(pb, subcommand_length + len); + pb += lws_mux_subcommand_header(LWS_EXT_XGM_OPC__ADDCHANNEL, ongoing_subchannel, pb, len); + memcpy(pb, in, len); + pb += len; + + lws_issue_raw_ext_access(wsi->extension_handles, &send_buf[LWS_SEND_BUFFER_PRE_PADDING], + pb - &send_buf[LWS_SEND_BUFFER_PRE_PADDING]); + + + return 1; /* handled */ + + case LWS_EXT_CALLBACK_IS_WRITEABLE: + /* + * we are writable, inform children if any care + */ + muxdebug("LWS_EXT_CALLBACK_IS_WRITEABLE: %s\n", wsi->protocol->name); + + if (!conn->count_children_needing_POLLOUT) { + muxdebug(" no children need POLLOUT\n"); + return 0; + } + + for (n = 0; n < conn->highest_child_subchannel; n++) { + + if (!conn->wsi_children[n]) + continue; + + child_conn = NULL; + for (m = 0; m < conn->wsi_children[n]->count_active_extensions; m++) + if (ext == conn->wsi_children[n]->active_extensions[m]) + child_conn = (struct lws_ext_x_google_mux_conn *) + conn->wsi_children[n]->active_extensions_user[m]; + + if (!child_conn) { + muxdebug("unable to identify child conn\n"); + continue; + } + + if (!child_conn->awaiting_POLLOUT) + continue; + + child_conn->awaiting_POLLOUT = 0; + conn->count_children_needing_POLLOUT--; + lws_handle_POLLOUT_event(context, conn->wsi_children[n], NULL); + if (!conn->count_children_needing_POLLOUT) + return 2; /* all handled */ + else + return 1; /* handled but need more */ + } + break; + + case LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION: + + /* disallow deflate-stream if we are a mux child connection */ + + if (strcmp(in, "deflate-stream") == 0 && + client_handshake_generation_is_for_mux_child) { + + muxdebug("mux banned deflate-stream on child connection\n"); + return 1; /* disallow */ + } + break; + + default: + break; + } + + return 0; +} diff --git a/libs/libwebsockets/lib/extension-x-google-mux.h b/libs/libwebsockets/lib/extension-x-google-mux.h new file mode 100644 index 0000000000..4f4d397c2e --- /dev/null +++ b/libs/libwebsockets/lib/extension-x-google-mux.h @@ -0,0 +1,96 @@ + +#if 0 +#ifdef WIN32 +static +#else +static inline +#endif +void muxdebug(const char *format, ...) +{ + va_list ap; + va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); +} +#else +#ifdef WIN32 +static +#else +static inline +#endif +void muxdebug(const char *format, ...) +{ +} +#endif + +#define MAX_XGM_SUBCHANNELS 8192 + +enum lws_ext_x_google_mux__parser_states { + LWS_EXT_XGM_STATE__MUX_BLOCK_1, + LWS_EXT_XGM_STATE__MUX_BLOCK_2, + LWS_EXT_XGM_STATE__MUX_BLOCK_3, + LWS_EXT_XGM_STATE__ADDCHANNEL_LEN, + LWS_EXT_XGM_STATE__ADDCHANNEL_LEN16_1, + LWS_EXT_XGM_STATE__ADDCHANNEL_LEN16_2, + LWS_EXT_XGM_STATE__ADDCHANNEL_LEN32_1, + LWS_EXT_XGM_STATE__ADDCHANNEL_LEN32_2, + LWS_EXT_XGM_STATE__ADDCHANNEL_LEN32_3, + LWS_EXT_XGM_STATE__ADDCHANNEL_LEN32_4, + LWS_EXT_XGM_STATE__ADDCHANNEL_HEADERS, + LWS_EXT_XGM_STATE__FLOWCONTROL_1, + LWS_EXT_XGM_STATE__FLOWCONTROL_2, + LWS_EXT_XGM_STATE__FLOWCONTROL_3, + LWS_EXT_XGM_STATE__FLOWCONTROL_4, + LWS_EXT_XGM_STATE__DATA, +}; + +enum lws_ext_x_goole_mux__mux_opcodes { + LWS_EXT_XGM_OPC__DATA, + LWS_EXT_XGM_OPC__ADDCHANNEL, + LWS_EXT_XGM_OPC__DROPCHANNEL, + LWS_EXT_XGM_OPC__FLOWCONTROL, + LWS_EXT_XGM_OPC__RESERVED_4, + LWS_EXT_XGM_OPC__RESERVED_5, + LWS_EXT_XGM_OPC__RESERVED_6, + LWS_EXT_XGM_OPC__RESERVED_7, +}; + +/* one of these per context (server or client) */ + +struct lws_ext_x_google_mux_context { + /* + * these are listing physical connections, not children sharing a + * parent mux physical connection + */ + struct libwebsocket *wsi_muxconns[MAX_CLIENTS]; + /* + * when this is < 2, we do not do any mux blocks + * just pure websockets + */ + int active_conns; +}; + +/* one of these per connection (server or client) */ + +struct lws_ext_x_google_mux_conn { + enum lws_ext_x_goole_mux__mux_opcodes block_subopcode; + int block_subchannel; + unsigned int length; + enum lws_ext_x_google_mux__parser_states state; + /* child points to the mux wsi using this */ + struct libwebsocket *wsi_parent; + int subchannel; + struct libwebsocket *wsi_children[MAX_CLIENTS]; + int highest_child_subchannel; + char awaiting_POLLOUT; + int count_children_needing_POLLOUT; + int sticky_mux_used; + int defeat_mux_opcode_wrapping; + int original_ch1_closed; + int ignore_cmd; +}; + +extern int +lws_extension_callback_x_google_mux(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); diff --git a/libs/libwebsockets/lib/extension.c b/libs/libwebsockets/lib/extension.c new file mode 100644 index 0000000000..890930872a --- /dev/null +++ b/libs/libwebsockets/lib/extension.c @@ -0,0 +1,22 @@ +#include "private-libwebsockets.h" + +#include "extension-deflate-stream.h" +#include "extension-x-google-mux.h" + +struct libwebsocket_extension libwebsocket_internal_extensions[] = { +#ifdef LWS_EXT_GOOGLE_MUX + { + "x-google-mux", + lws_extension_callback_x_google_mux, + sizeof (struct lws_ext_x_google_mux_conn) + }, +#endif + { + "deflate-stream", + lws_extension_callback_deflate_stream, + sizeof (struct lws_ext_deflate_stream_conn) + }, + { /* terminator */ + NULL, NULL, 0 + } +}; diff --git a/libs/libwebsockets/lib/handshake.c b/libs/libwebsockets/lib/handshake.c new file mode 100644 index 0000000000..70fe3a87eb --- /dev/null +++ b/libs/libwebsockets/lib/handshake.c @@ -0,0 +1,722 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "private-libwebsockets.h" + +#define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr += strlen(str); } +#define LWS_CPYAPP_TOKEN(ptr, tok) { strcpy(p, wsi->utf8_token[tok].token); \ + p += wsi->utf8_token[tok].token_len; } + +static int +interpret_key(const char *key, unsigned long *result) +{ + char digits[20]; + int digit_pos = 0; + const char *p = key; + unsigned int spaces = 0; + unsigned long acc = 0; + int rem = 0; + + while (*p) { + if (!isdigit(*p)) { + p++; + continue; + } + if (digit_pos == sizeof(digits) - 1) + return -1; + digits[digit_pos++] = *p++; + } + digits[digit_pos] = '\0'; + if (!digit_pos) + return -2; + + while (*key) { + if (*key == ' ') + spaces++; + key++; + } + + if (!spaces) + return -3; + + p = &digits[0]; + while (*p) { + rem = (rem * 10) + ((*p++) - '0'); + acc = (acc * 10) + (rem / spaces); + rem -= (rem / spaces) * spaces; + } + + if (rem) { + fprintf(stderr, "nonzero handshake remainder\n"); + return -1; + } + + *result = acc; + + return 0; +} + + +static int +handshake_00(struct libwebsocket_context *context, struct libwebsocket *wsi) +{ + unsigned long key1, key2; + unsigned char sum[16]; + char *response; + char *p; + int n; + + /* Confirm we have all the necessary pieces */ + + if (!wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len || + !wsi->utf8_token[WSI_TOKEN_HOST].token_len || + !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len || + !wsi->utf8_token[WSI_TOKEN_KEY1].token_len || + !wsi->utf8_token[WSI_TOKEN_KEY2].token_len) + /* completed header processing, but missing some bits */ + goto bail; + + /* allocate the per-connection user memory (if any) */ + if (wsi->protocol->per_session_data_size && + !libwebsocket_ensure_user_space(wsi)) + goto bail; + + /* create the response packet */ + + /* make a buffer big enough for everything */ + + response = malloc(256 + + wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len + + wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len + + wsi->utf8_token[WSI_TOKEN_HOST].token_len + + wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len + + wsi->utf8_token[WSI_TOKEN_GET_URI].token_len + + wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len); + if (!response) { + fprintf(stderr, "Out of memory for response buffer\n"); + goto bail; + } + + p = response; + LWS_CPYAPP(p, "HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a" + "Upgrade: WebSocket\x0d\x0a" + "Connection: Upgrade\x0d\x0a" + "Sec-WebSocket-Origin: "); + strcpy(p, wsi->utf8_token[WSI_TOKEN_ORIGIN].token); + p += wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len; +#ifdef LWS_OPENSSL_SUPPORT + if (wsi->ssl) { + LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: wss://"); + } else { + LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: ws://"); + } +#else + LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: ws://"); +#endif + + LWS_CPYAPP_TOKEN(p, WSI_TOKEN_HOST); + LWS_CPYAPP_TOKEN(p, WSI_TOKEN_GET_URI); + + if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) { + LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: "); + LWS_CPYAPP_TOKEN(p, WSI_TOKEN_PROTOCOL); + } + + LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a"); + + /* convert the two keys into 32-bit integers */ + + if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY1].token, &key1)) + goto bail; + if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY2].token, &key2)) + goto bail; + + /* lay them out in network byte order (MSB first */ + + sum[0] = key1 >> 24; + sum[1] = key1 >> 16; + sum[2] = key1 >> 8; + sum[3] = key1; + sum[4] = key2 >> 24; + sum[5] = key2 >> 16; + sum[6] = key2 >> 8; + sum[7] = key2; + + /* follow them with the challenge token we were sent */ + + memcpy(&sum[8], wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 8); + + /* + * compute the md5sum of that 16-byte series and use as our + * payload after our headers + */ + + MD5(sum, 16, (unsigned char *)p); + p += 16; + + /* it's complete: go ahead and send it */ + + debug("issuing response packet %d len\n", (int)(p - response)); +#ifdef DEBUG + fwrite(response, 1, p - response, stderr); +#endif + n = libwebsocket_write(wsi, (unsigned char *)response, + p - response, LWS_WRITE_HTTP); + if (n < 0) { + fprintf(stderr, "ERROR writing to socket"); + goto bail; + } + + /* alright clean up and set ourselves into established state */ + + free(response); + wsi->state = WSI_STATE_ESTABLISHED; + wsi->lws_rx_parse_state = LWS_RXPS_NEW; + + /* notify user code that we're ready to roll */ + + if (wsi->protocol->callback) + wsi->protocol->callback(wsi->protocol->owning_server, + wsi, LWS_CALLBACK_ESTABLISHED, + wsi->user_space, NULL, 0); + + return 0; + +bail: + return -1; +} + +/* + * Perform the newer BASE64-encoded handshake scheme + */ + +static int +handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi) +{ + static const char *websocket_magic_guid_04 = + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + static const char *websocket_magic_guid_04_masking = + "61AC5F19-FBBA-4540-B96F-6561F1AB40A8"; + char accept_buf[MAX_WEBSOCKET_04_KEY_LEN + 37]; + char nonce_buf[256]; + char mask_summing_buf[256 + MAX_WEBSOCKET_04_KEY_LEN + 37]; + unsigned char hash[20]; + int n; + char *response; + char *p; + char *m = mask_summing_buf; + int nonce_len = 0; + int accept_len; + char *c; + char ext_name[128]; + struct libwebsocket_extension *ext; + int ext_count = 0; + int more = 1; + + if (!wsi->utf8_token[WSI_TOKEN_HOST].token_len || + !wsi->utf8_token[WSI_TOKEN_KEY].token_len) { + debug("handshake_04 missing pieces\n"); + /* completed header processing, but missing some bits */ + goto bail; + } + + if (wsi->utf8_token[WSI_TOKEN_KEY].token_len >= + MAX_WEBSOCKET_04_KEY_LEN) { + fprintf(stderr, "Client sent handshake key longer " + "than max supported %d\n", MAX_WEBSOCKET_04_KEY_LEN); + goto bail; + } + + strcpy(accept_buf, wsi->utf8_token[WSI_TOKEN_KEY].token); + strcpy(accept_buf + wsi->utf8_token[WSI_TOKEN_KEY].token_len, + websocket_magic_guid_04); + + SHA1((unsigned char *)accept_buf, + wsi->utf8_token[WSI_TOKEN_KEY].token_len + + strlen(websocket_magic_guid_04), hash); + + accept_len = lws_b64_encode_string((char *)hash, 20, accept_buf, + sizeof accept_buf); + if (accept_len < 0) { + fprintf(stderr, "Base64 encoded hash too long\n"); + goto bail; + } + + /* allocate the per-connection user memory (if any) */ + if (wsi->protocol->per_session_data_size && + !libwebsocket_ensure_user_space(wsi)) + goto bail; + + /* create the response packet */ + + /* make a buffer big enough for everything */ + + response = malloc(256 + + wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len + + wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len + + wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len); + if (!response) { + fprintf(stderr, "Out of memory for response buffer\n"); + goto bail; + } + + p = response; + LWS_CPYAPP(p, "HTTP/1.1 101 Switching Protocols\x0d\x0a" + "Upgrade: WebSocket\x0d\x0a" + "Connection: Upgrade\x0d\x0a" + "Sec-WebSocket-Accept: "); + strcpy(p, accept_buf); + p += accept_len; + + if (wsi->ietf_spec_revision == 4) { + LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Nonce: "); + + /* select the nonce */ + + n = libwebsockets_get_random(wsi->protocol->owning_server, + hash, 16); + if (n != 16) { + fprintf(stderr, "Unable to read random device %s %d\n", + SYSTEM_RANDOM_FILEPATH, n); + if (wsi->user_space) + free(wsi->user_space); + goto bail; + } + + /* encode the nonce */ + + nonce_len = lws_b64_encode_string((const char *)hash, 16, + nonce_buf, sizeof nonce_buf); + if (nonce_len < 0) { + fprintf(stderr, "Failed to base 64 encode the nonce\n"); + if (wsi->user_space) + free(wsi->user_space); + goto bail; + } + + /* apply the nonce */ + + strcpy(p, nonce_buf); + p += nonce_len; + } + + if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) { + LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: "); + LWS_CPYAPP_TOKEN(p, WSI_TOKEN_PROTOCOL); + } + + /* + * Figure out which extensions the client has that we want to + * enable on this connection, and give him back the list + */ + + if (wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token_len) { + + /* + * break down the list of client extensions + * and go through them + */ + + c = wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token; + debug("wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token = %s\n", + wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token); + wsi->count_active_extensions = 0; + n = 0; + while (more) { + + if (*c && (*c != ',' && *c != ' ' && *c != '\t')) { + ext_name[n] = *c++; + if (n < sizeof(ext_name) - 1) + n++; + continue; + } + ext_name[n] = '\0'; + if (!*c) + more = 0; + else { + c++; + if (!n) + continue; + } + + /* check a client's extension against our support */ + + ext = wsi->protocol->owning_server->extensions; + + while (ext && ext->callback) { + + if (strcmp(ext_name, ext->name)) { + ext++; + continue; + } + + /* + * oh, we do support this one he + * asked for... but let's ask user + * code if it's OK to apply it on this + * particular connection + protocol + */ + + n = wsi->protocol->owning_server-> + protocols[0].callback( + wsi->protocol->owning_server, + wsi, + LWS_CALLBACK_CONFIRM_EXTENSION_OKAY, + wsi->user_space, ext_name, 0); + + /* + * zero return from callback means + * go ahead and allow the extension, + * it's what we get if the callback is + * unhandled + */ + + if (n) { + ext++; + continue; + } + + /* apply it */ + + if (ext_count) + *p++ = ','; + else + LWS_CPYAPP(p, + "\x0d\x0aSec-WebSocket-Extensions: "); + p += sprintf(p, "%s", ext_name); + ext_count++; + + /* instantiate the extension on this conn */ + + wsi->active_extensions_user[ + wsi->count_active_extensions] = + malloc(ext->per_session_data_size); + memset(wsi->active_extensions_user[ + wsi->count_active_extensions], 0, + ext->per_session_data_size); + + wsi->active_extensions[ + wsi->count_active_extensions] = ext; + + /* allow him to construct his context */ + + ext->callback(wsi->protocol->owning_server, + ext, wsi, + LWS_EXT_CALLBACK_CONSTRUCT, + wsi->active_extensions_user[ + wsi->count_active_extensions], NULL, 0); + + wsi->count_active_extensions++; + debug("wsi->count_active_extensions <- %d", + wsi->count_active_extensions); + + ext++; + } + + n = 0; + } + } + + /* end of response packet */ + + LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a"); + + if (wsi->ietf_spec_revision == 4) { + + /* + * precompute the masking key the client will use from the SHA1 + * hash of ( base 64 client key we were sent, concatenated with + * the bse 64 nonce we sent, concatenated with a magic constant + * guid specified by the 04 standard ) + * + * We store the hash in the connection's wsi ready to use with + * undoing the masking the client has done on framed data it + * sends (we send our data to the client in clear). + */ + + strcpy(mask_summing_buf, wsi->utf8_token[WSI_TOKEN_KEY].token); + m += wsi->utf8_token[WSI_TOKEN_KEY].token_len; + strcpy(m, nonce_buf); + m += nonce_len; + strcpy(m, websocket_magic_guid_04_masking); + m += strlen(websocket_magic_guid_04_masking); + + SHA1((unsigned char *)mask_summing_buf, m - mask_summing_buf, + wsi->masking_key_04); + } + + if (!lws_any_extension_handled(context, wsi, + LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX, + response, p - response)) { + + /* okay send the handshake response accepting the connection */ + + debug("issuing response packet %d len\n", (int)(p - response)); + #ifdef DEBUG + fwrite(response, 1, p - response, stderr); + #endif + n = libwebsocket_write(wsi, (unsigned char *)response, + p - response, LWS_WRITE_HTTP); + if (n < 0) { + fprintf(stderr, "ERROR writing to socket"); + goto bail; + } + + } + + /* alright clean up and set ourselves into established state */ + + free(response); + wsi->state = WSI_STATE_ESTABLISHED; + wsi->lws_rx_parse_state = LWS_RXPS_NEW; + wsi->rx_packet_length = 0; + + /* notify user code that we're ready to roll */ + + if (wsi->protocol->callback) + wsi->protocol->callback(wsi->protocol->owning_server, + wsi, LWS_CALLBACK_ESTABLISHED, + wsi->user_space, NULL, 0); + + return 0; + + +bail: + return -1; +} + + +/* + * -04 of the protocol (actually the 80th version) has a radically different + * handshake. The 04 spec gives the following idea + * + * The handshake from the client looks as follows: + * + * GET /chat HTTP/1.1 + * Host: server.example.com + * Upgrade: websocket + * Connection: Upgrade + * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== + * Sec-WebSocket-Origin: http://example.com + * Sec-WebSocket-Protocol: chat, superchat + * Sec-WebSocket-Version: 4 + * + * The handshake from the server looks as follows: + * + * HTTP/1.1 101 Switching Protocols + * Upgrade: websocket + * Connection: Upgrade + * Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo= + * Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC== + * Sec-WebSocket-Protocol: chat + */ + +/* + * We have to take care about parsing because the headers may be split + * into multiple fragments. They may contain unknown headers with arbitrary + * argument lengths. So, we parse using a single-character at a time state + * machine that is completely independent of packet size. + */ + +int +libwebsocket_read(struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned char * buf, size_t len) +{ + size_t n; + + switch (wsi->state) { + case WSI_STATE_HTTP: + wsi->state = WSI_STATE_HTTP_HEADERS; + wsi->parser_state = WSI_TOKEN_NAME_PART; + /* fallthru */ + case WSI_STATE_HTTP_HEADERS: + + debug("issuing %d bytes to parser\n", (int)len); +#ifdef DEBUG + fwrite(buf, 1, len, stderr); +#endif + + switch (wsi->mode) { + case LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY: + case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE: + case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY: + case LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT: + case LWS_CONNMODE_WS_CLIENT: + for (n = 0; n < len; n++) + libwebsocket_client_rx_sm(wsi, *buf++); + + return 0; + default: + break; + } + + /* LWS_CONNMODE_WS_SERVING */ + + for (n = 0; n < len; n++) + libwebsocket_parse(wsi, *buf++); + + if (wsi->parser_state != WSI_PARSING_COMPLETE) + break; + + debug("seem to be serving, mode is %d\n", wsi->mode); + + debug("libwebsocket_parse sees parsing complete\n"); + + /* is this websocket protocol or normal http 1.0? */ + + if (!wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len || + !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len) { + wsi->state = WSI_STATE_HTTP; + if (wsi->protocol->callback) + (wsi->protocol->callback)(context, wsi, + LWS_CALLBACK_HTTP, wsi->user_space, + wsi->utf8_token[WSI_TOKEN_GET_URI].token, 0); + return 0; + } + + if (!wsi->protocol) + fprintf(stderr, "NULL protocol at libwebsocket_read\n"); + + /* + * It's websocket + * + * Make sure user side is happy about protocol + */ + + while (wsi->protocol->callback) { + + if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token == NULL) { + if (wsi->protocol->name == NULL) + break; + } else + if (wsi->protocol->name && strcmp( + wsi->utf8_token[WSI_TOKEN_PROTOCOL].token, + wsi->protocol->name) == 0) + break; + + wsi->protocol++; + } + + /* we didn't find a protocol he wanted? */ + + if (wsi->protocol->callback == NULL) { + if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token == NULL) + fprintf(stderr, "[no protocol] " + "not supported (use NULL .name)\n"); + else + fprintf(stderr, "Requested protocol %s " + "not supported\n", + wsi->utf8_token[WSI_TOKEN_PROTOCOL].token); + goto bail; + } + + /* + * find out which spec version the client is using + * if this header is not given, we default to 00 (aka 76) + */ + + if (wsi->utf8_token[WSI_TOKEN_VERSION].token_len) + wsi->ietf_spec_revision = + atoi(wsi->utf8_token[WSI_TOKEN_VERSION].token); + + /* + * Give the user code a chance to study the request and + * have the opportunity to deny it + */ + + if ((wsi->protocol->callback)(wsi->protocol->owning_server, wsi, + LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION, + &wsi->utf8_token[0], NULL, 0)) { + fprintf(stderr, "User code denied connection\n"); + goto bail; + } + + + /* + * Perform the handshake according to the protocol version the + * client announced + */ + + switch (wsi->ietf_spec_revision) { + case 0: /* applies to 76 and 00 */ + wsi->xor_mask = xor_no_mask; + if (handshake_00(context, wsi)) + goto bail; + break; + case 4: /* 04 */ + wsi->xor_mask = xor_mask_04; + debug("libwebsocket_parse calling handshake_04\n"); + if (handshake_0405(context, wsi)) + goto bail; + break; + case 5: + case 6: + case 7: + case 8: + case 13: + wsi->xor_mask = xor_mask_05; + debug("libwebsocket_parse calling handshake_04\n"); + if (handshake_0405(context, wsi)) + goto bail; + break; + + default: + fprintf(stderr, "Unknown client spec version %d\n", + wsi->ietf_spec_revision); + goto bail; + } + + debug("accepted v%02d connection\n", + wsi->ietf_spec_revision); + + break; + + case WSI_STATE_AWAITING_CLOSE_ACK: + case WSI_STATE_ESTABLISHED: + switch (wsi->mode) { + case LWS_CONNMODE_WS_CLIENT: + for (n = 0; n < len; n++) + if (libwebsocket_client_rx_sm(wsi, *buf++) < 0) + goto bail; + + return 0; + default: + break; + } + + /* LWS_CONNMODE_WS_SERVING */ + + if (libwebsocket_interpret_incoming_packet(wsi, buf, len) < 0) + goto bail; + + break; + default: + break; + } + + return 0; + +bail: + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); + + return -1; +} diff --git a/libs/libwebsockets/lib/libwebsockets.c b/libs/libwebsockets/lib/libwebsockets.c new file mode 100644 index 0000000000..03147e16fd --- /dev/null +++ b/libs/libwebsockets/lib/libwebsockets.c @@ -0,0 +1,3183 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "private-libwebsockets.h" + +#ifdef WIN32 + +#else +#include +#include +#include +#include +#endif + +#ifdef LWS_OPENSSL_SUPPORT +int openssl_websocket_private_data_index; +#endif + +#ifdef __MINGW32__ +#include "../win32port/win32helpers/websock-w32.c" +#else +#ifdef __MINGW64__ +#include "../win32port/win32helpers/websock-w32.c" +#endif +#endif + +/* + * In-place str to lower case + */ + +static void +strtolower(char *s) +{ + while (*s) { + *s = tolower(*s); + s++; + } +} + +/* file descriptor hash management */ + +struct libwebsocket * +wsi_from_fd(struct libwebsocket_context *context, int fd) +{ + int h = LWS_FD_HASH(fd); + int n = 0; + + for (n = 0; n < context->fd_hashtable[h].length; n++) + if (context->fd_hashtable[h].wsi[n]->sock == fd) + return context->fd_hashtable[h].wsi[n]; + + return NULL; +} + +int +insert_wsi(struct libwebsocket_context *context, struct libwebsocket *wsi) +{ + int h = LWS_FD_HASH(wsi->sock); + + if (context->fd_hashtable[h].length == MAX_CLIENTS - 1) { + fprintf(stderr, "hash table overflow\n"); + return 1; + } + + context->fd_hashtable[h].wsi[context->fd_hashtable[h].length++] = wsi; + + return 0; +} + +int +delete_from_fd(struct libwebsocket_context *context, int fd) +{ + int h = LWS_FD_HASH(fd); + int n = 0; + + for (n = 0; n < context->fd_hashtable[h].length; n++) + if (context->fd_hashtable[h].wsi[n]->sock == fd) { + while (n < context->fd_hashtable[h].length) { + context->fd_hashtable[h].wsi[n] = + context->fd_hashtable[h].wsi[n + 1]; + n++; + } + context->fd_hashtable[h].length--; + + return 0; + } + + fprintf(stderr, "Failed to find fd %d requested for " + "delete in hashtable\n", fd); + return 1; +} + +#ifdef LWS_OPENSSL_SUPPORT +static void +libwebsockets_decode_ssl_error(void) +{ + char buf[256]; + u_long err; + + while ((err = ERR_get_error()) != 0) { + ERR_error_string_n(err, buf, sizeof(buf)); + fprintf(stderr, "*** %s\n", buf); + } +} +#endif + + +static int +interface_to_sa(const char *ifname, struct sockaddr_in *addr, size_t addrlen) +{ + int rc = -1; +#ifdef WIN32 + /* TODO */ +#else + struct ifaddrs *ifr; + struct ifaddrs *ifc; + struct sockaddr_in *sin; + + getifaddrs(&ifr); + for (ifc = ifr; ifc != NULL; ifc = ifc->ifa_next) { + if (strcmp(ifc->ifa_name, ifname)) + continue; + if (ifc->ifa_addr == NULL) + continue; + sin = (struct sockaddr_in *)ifc->ifa_addr; + if (sin->sin_family != AF_INET) + continue; + memcpy(addr, sin, addrlen); + rc = 0; + } + + freeifaddrs(ifr); +#endif + return rc; +} + +void +libwebsocket_close_and_free_session(struct libwebsocket_context *context, + struct libwebsocket *wsi, enum lws_close_status reason) +{ + int n; + int old_state; + unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 2 + + LWS_SEND_BUFFER_POST_PADDING]; + int ret; + int m; + struct lws_tokens eff_buf; + struct libwebsocket_extension *ext; + + if (!wsi) + return; + + old_state = wsi->state; + + if (old_state == WSI_STATE_DEAD_SOCKET) + return; + + wsi->close_reason = reason; + + /* + * are his extensions okay with him closing? Eg he might be a mux + * parent and just his ch1 aspect is closing? + */ + + + for (n = 0; n < wsi->count_active_extensions; n++) { + if (!wsi->active_extensions[n]->callback) + continue; + + m = wsi->active_extensions[n]->callback(context, + wsi->active_extensions[n], wsi, + LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE, + wsi->active_extensions_user[n], NULL, 0); + + /* + * if somebody vetoed actually closing him at this time.... + * up to the extension to track the attempted close, let's + * just bail + */ + + if (m) { + debug("extension vetoed close\n"); + return; + } + } + + + + /* + * flush any tx pending from extensions, since we may send close packet + * if there are problems with send, just nuke the connection + */ + + ret = 1; + while (ret == 1) { + + /* default to nobody has more to spill */ + + ret = 0; + eff_buf.token = NULL; + eff_buf.token_len = 0; + + /* show every extension the new incoming data */ + + for (n = 0; n < wsi->count_active_extensions; n++) { + m = wsi->active_extensions[n]->callback( + wsi->protocol->owning_server, + wsi->active_extensions[n], wsi, + LWS_EXT_CALLBACK_FLUSH_PENDING_TX, + wsi->active_extensions_user[n], &eff_buf, 0); + if (m < 0) { + fprintf(stderr, "Extension reports " + "fatal error\n"); + goto just_kill_connection; + } + if (m) + /* + * at least one extension told us he has more + * to spill, so we will go around again after + */ + ret = 1; + } + + /* assuming they left us something to send, send it */ + + if (eff_buf.token_len) + if (lws_issue_raw(wsi, (unsigned char *)eff_buf.token, + eff_buf.token_len)) + goto just_kill_connection; + } + + /* + * signal we are closing, libsocket_write will + * add any necessary version-specific stuff. If the write fails, + * no worries we are closing anyway. If we didn't initiate this + * close, then our state has been changed to + * WSI_STATE_RETURNED_CLOSE_ALREADY and we will skip this. + * + * Likewise if it's a second call to close this connection after we + * sent the close indication to the peer already, we are in state + * WSI_STATE_AWAITING_CLOSE_ACK and will skip doing this a second time. + */ + + if (old_state == WSI_STATE_ESTABLISHED && + reason != LWS_CLOSE_STATUS_NOSTATUS) { + + debug("sending close indication...\n"); + + n = libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], + 0, LWS_WRITE_CLOSE); + if (!n) { + /* + * we have sent a nice protocol level indication we + * now wish to close, we should not send anything more + */ + + wsi->state = WSI_STATE_AWAITING_CLOSE_ACK; + + /* and we should wait for a reply for a bit */ + + libwebsocket_set_timeout(wsi, + PENDING_TIMEOUT_CLOSE_ACK, 5); + + debug("sent close indication, awaiting ack\n"); + + return; + } + + /* else, the send failed and we should just hang up */ + } + +just_kill_connection: + + debug("libwebsocket_close_and_free_session: just_kill_connection\n"); + + /* + * we won't be servicing or receiving anything further from this guy + * remove this fd from wsi mapping hashtable + */ + + if (wsi->sock) + delete_from_fd(context, wsi->sock); + + /* delete it from the internal poll list if still present */ + + for (n = 0; n < context->fds_count; n++) { + if (context->fds[n].fd != wsi->sock) + continue; + while (n < context->fds_count - 1) { + context->fds[n] = context->fds[n + 1]; + n++; + } + context->fds_count--; + /* we only have to deal with one */ + n = context->fds_count; + } + + /* remove also from external POLL support via protocol 0 */ + if (wsi->sock) + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_DEL_POLL_FD, (void *)(long)wsi->sock, NULL, 0); + + wsi->state = WSI_STATE_DEAD_SOCKET; + + /* tell the user it's all over for this guy */ + + if (wsi->protocol && wsi->protocol->callback && + ((old_state == WSI_STATE_ESTABLISHED) || + (old_state == WSI_STATE_RETURNED_CLOSE_ALREADY) || + (old_state == WSI_STATE_AWAITING_CLOSE_ACK))) { + debug("calling back CLOSED\n"); + wsi->protocol->callback(context, wsi, LWS_CALLBACK_CLOSED, + wsi->user_space, NULL, 0); + } else + debug("not calling back closed, old_state=%d\n", old_state); + + /* deallocate any active extension contexts */ + + for (n = 0; n < wsi->count_active_extensions; n++) { + if (!wsi->active_extensions[n]->callback) + continue; + + wsi->active_extensions[n]->callback(context, + wsi->active_extensions[n], wsi, + LWS_EXT_CALLBACK_DESTROY, + wsi->active_extensions_user[n], NULL, 0); + + free(wsi->active_extensions_user[n]); + } + + /* + * inform all extensions in case they tracked this guy out of band + * even though not active on him specifically + */ + + ext = context->extensions; + while (ext && ext->callback) { + ext->callback(context, ext, wsi, + LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING, + NULL, NULL, 0); + ext++; + } + + /* free up his parsing allocations */ + + for (n = 0; n < WSI_TOKEN_COUNT; n++) + if (wsi->utf8_token[n].token) + free(wsi->utf8_token[n].token); + + if (wsi->c_address) + free(wsi->c_address); + +/* fprintf(stderr, "closing fd=%d\n", wsi->sock); */ + +#ifdef LWS_OPENSSL_SUPPORT + if (wsi->ssl) { + n = SSL_get_fd(wsi->ssl); + SSL_shutdown(wsi->ssl); +#ifdef WIN32 + closesocket(n); +#else + close(n); +#endif + SSL_free(wsi->ssl); + } else { +#endif + shutdown(wsi->sock, SHUT_RDWR); +#ifdef WIN32 + if (wsi->sock) + closesocket(wsi->sock); +#else + if (wsi->sock) + close(wsi->sock); +#endif +#ifdef LWS_OPENSSL_SUPPORT + } +#endif + if (wsi->protocol && wsi->protocol->per_session_data_size && wsi->user_space) /* user code may own */ + free(wsi->user_space); + + free(wsi); +} + +/** + * libwebsockets_hangup_on_client() - Server calls to terminate client + * connection + * @context: libwebsockets context + * @fd: Connection socket descriptor + */ + +void +libwebsockets_hangup_on_client(struct libwebsocket_context *context, int fd) +{ + struct libwebsocket *wsi = wsi_from_fd(context, fd); + + if (wsi == NULL) + return; + + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); +} + + +/** + * libwebsockets_get_peer_addresses() - Get client address information + * @fd: Connection socket descriptor + * @name: Buffer to take client address name + * @name_len: Length of client address name buffer + * @rip: Buffer to take client address IP qotted quad + * @rip_len: Length of client address IP buffer + * + * This function fills in @name and @rip with the name and IP of + * the client connected with socket descriptor @fd. Names may be + * truncated if there is not enough room. If either cannot be + * determined, they will be returned as valid zero-length strings. + */ + +void +libwebsockets_get_peer_addresses(int fd, char *name, int name_len, + char *rip, int rip_len) +{ + unsigned int len; + struct sockaddr_in sin; + struct hostent *host; + struct hostent *host1; + char ip[128]; + unsigned char *p; + int n; + struct sockaddr_un *un; + + rip[0] = '\0'; + name[0] = '\0'; + + len = sizeof sin; + if (getpeername(fd, (struct sockaddr *) &sin, &len) < 0) { + perror("getpeername"); + return; + } + + host = gethostbyaddr((char *) &sin.sin_addr, sizeof sin.sin_addr, + AF_INET); + if (host == NULL) { + perror("gethostbyaddr"); + return; + } + + strncpy(name, host->h_name, name_len); + name[name_len - 1] = '\0'; + + host1 = gethostbyname(host->h_name); + if (host1 == NULL) + return; + p = (unsigned char *)host1; + n = 0; + while (p != NULL) { + p = (unsigned char *)host1->h_addr_list[n++]; + if (p == NULL) + continue; + if ((host1->h_addrtype != AF_INET) +#ifdef AF_LOCAL + && (host1->h_addrtype != AF_LOCAL) +#endif + ) + continue; + + if (host1->h_addrtype == AF_INET) + sprintf(ip, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]); +#ifdef AF_LOCAL + else { + un = (struct sockaddr_un *)p; + strncpy(ip, un->sun_path, sizeof(ip) - 1); + ip[sizeof(ip) - 1] = '\0'; + } +#endif + p = NULL; + strncpy(rip, ip, rip_len); + rip[rip_len - 1] = '\0'; + } +} + +int libwebsockets_get_random(struct libwebsocket_context *context, + void *buf, int len) +{ + int n; + char *p = buf; + +#ifdef WIN32 + for (n = 0; n < len; n++) + p[n] = (unsigned char)rand(); +#else + n = read(context->fd_random, p, len); +#endif + + return n; +} + +unsigned char * +libwebsockets_SHA1(const unsigned char *d, size_t n, unsigned char *md) +{ + return SHA1(d, n, md); +} + +void libwebsockets_00_spaceout(char *key, int spaces, int seed) +{ + char *p; + + key++; + while (spaces--) { + if (*key && (seed & 1)) + key++; + seed >>= 1; + + p = key + strlen(key); + while (p >= key) { + p[1] = p[0]; + p--; + } + *key++ = ' '; + } +} + +void libwebsockets_00_spam(char *key, int count, int seed) +{ + char *p; + + key++; + while (count--) { + + if (*key && (seed & 1)) + key++; + seed >>= 1; + + p = key + strlen(key); + while (p >= key) { + p[1] = p[0]; + p--; + } + *key++ = 0x21 + ((seed & 0xffff) % 15); + /* 4 would use it up too fast.. not like it matters */ + seed >>= 1; + } +} + +int lws_send_pipe_choked(struct libwebsocket *wsi) +{ + struct pollfd fds; + + fds.fd = wsi->sock; + fds.events = POLLOUT; + fds.revents = 0; + + if (poll(&fds, 1, 0) != 1) + return 1; + + if ((fds.revents & POLLOUT) == 0) + return 1; + + /* okay to send another packet without blocking */ + + return 0; +} + +int +lws_handle_POLLOUT_event(struct libwebsocket_context *context, + struct libwebsocket *wsi, struct pollfd *pollfd) +{ + struct lws_tokens eff_buf; + int n; + int ret; + int m; + int handled = 0; + + for (n = 0; n < wsi->count_active_extensions; n++) { + if (!wsi->active_extensions[n]->callback) + continue; + + m = wsi->active_extensions[n]->callback(context, + wsi->active_extensions[n], wsi, + LWS_EXT_CALLBACK_IS_WRITEABLE, + wsi->active_extensions_user[n], NULL, 0); + if (m > handled) + handled = m; + } + + if (handled == 1) + goto notify_action; + + if (!wsi->extension_data_pending || handled == 2) + goto user_service; + + /* + * check in on the active extensions, see if they + * had pending stuff to spill... they need to get the + * first look-in otherwise sequence will be disordered + * + * NULL, zero-length eff_buf means just spill pending + */ + + ret = 1; + while (ret == 1) { + + /* default to nobody has more to spill */ + + ret = 0; + eff_buf.token = NULL; + eff_buf.token_len = 0; + + /* give every extension a chance to spill */ + + for (n = 0; n < wsi->count_active_extensions; n++) { + m = wsi->active_extensions[n]->callback( + wsi->protocol->owning_server, + wsi->active_extensions[n], wsi, + LWS_EXT_CALLBACK_PACKET_TX_PRESEND, + wsi->active_extensions_user[n], &eff_buf, 0); + if (m < 0) { + fprintf(stderr, "ext reports fatal error\n"); + return -1; + } + if (m) + /* + * at least one extension told us he has more + * to spill, so we will go around again after + */ + ret = 1; + } + + /* assuming they gave us something to send, send it */ + + if (eff_buf.token_len) { + if (lws_issue_raw(wsi, (unsigned char *)eff_buf.token, + eff_buf.token_len)) + return -1; + } else + continue; + + /* no extension has more to spill */ + + if (!ret) + continue; + + /* + * There's more to spill from an extension, but we just sent + * something... did that leave the pipe choked? + */ + + if (!lws_send_pipe_choked(wsi)) + /* no we could add more */ + continue; + + debug("choked in POLLOUT service\n"); + + /* + * Yes, he's choked. Leave the POLLOUT masked on so we will + * come back here when he is unchoked. Don't call the user + * callback to enforce ordering of spilling, he'll get called + * when we come back here and there's nothing more to spill. + */ + + return 0; + } + + wsi->extension_data_pending = 0; + +user_service: + /* one shot */ + + if (pollfd) { + pollfd->events &= ~POLLOUT; + + /* external POLL support via protocol 0 */ + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_CLEAR_MODE_POLL_FD, + (void *)(long)wsi->sock, NULL, POLLOUT); + } + +notify_action: + + if (wsi->mode == LWS_CONNMODE_WS_CLIENT) + n = LWS_CALLBACK_CLIENT_WRITEABLE; + else + n = LWS_CALLBACK_SERVER_WRITEABLE; + + wsi->protocol->callback(context, wsi, n, wsi->user_space, NULL, 0); + + return 0; +} + + + +void +libwebsocket_service_timeout_check(struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned int sec) +{ + int n; + + /* + * if extensions want in on it (eg, we are a mux parent) + * give them a chance to service child timeouts + */ + + for (n = 0; n < wsi->count_active_extensions; n++) + wsi->active_extensions[n]->callback( + context, wsi->active_extensions[n], + wsi, LWS_EXT_CALLBACK_1HZ, + wsi->active_extensions_user[n], NULL, sec); + + if (!wsi->pending_timeout) + return; + + /* + * if we went beyond the allowed time, kill the + * connection + */ + + if (sec > wsi->pending_timeout_limit) { + debug("TIMEDOUT WAITING\n"); + libwebsocket_close_and_free_session(context, + wsi, LWS_CLOSE_STATUS_NOSTATUS); + } +} + +struct libwebsocket * +libwebsocket_create_new_server_wsi(struct libwebsocket_context *context) +{ + struct libwebsocket *new_wsi; + int n; + + new_wsi = malloc(sizeof(struct libwebsocket)); + if (new_wsi == NULL) { + fprintf(stderr, "Out of memory for new connection\n"); + return NULL; + } + + memset(new_wsi, 0, sizeof(struct libwebsocket)); + new_wsi->count_active_extensions = 0; + new_wsi->pending_timeout = NO_PENDING_TIMEOUT; + + /* intialize the instance struct */ + + new_wsi->state = WSI_STATE_HTTP; + new_wsi->name_buffer_pos = 0; + new_wsi->mode = LWS_CONNMODE_WS_SERVING; + + for (n = 0; n < WSI_TOKEN_COUNT; n++) { + new_wsi->utf8_token[n].token = NULL; + new_wsi->utf8_token[n].token_len = 0; + } + + /* + * these can only be set once the protocol is known + * we set an unestablished connection's protocol pointer + * to the start of the supported list, so it can look + * for matching ones during the handshake + */ + new_wsi->protocol = context->protocols; + new_wsi->user_space = NULL; + + /* + * Default protocol is 76 / 00 + * After 76, there's a header specified to inform which + * draft the client wants, when that's seen we modify + * the individual connection's spec revision accordingly + */ + new_wsi->ietf_spec_revision = 0; + + return new_wsi; +} + +char * +libwebsockets_generate_client_handshake(struct libwebsocket_context *context, + struct libwebsocket *wsi, char *pkt) +{ + char hash[20]; + char *p = pkt; + int n; + struct libwebsocket_extension *ext; + struct libwebsocket_extension *ext1; + int ext_count = 0; + unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1 + + MAX_BROADCAST_PAYLOAD + LWS_SEND_BUFFER_POST_PADDING]; + static const char magic_websocket_guid[] = + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + + /* + * create the random key + */ + + n = libwebsockets_get_random(context, hash, 16); + if (n != 16) { + fprintf(stderr, "Unable to read from random dev %s\n", + SYSTEM_RANDOM_FILEPATH); + free(wsi->c_path); + free(wsi->c_host); + if (wsi->c_origin) + free(wsi->c_origin); + if (wsi->c_protocol) + free(wsi->c_protocol); + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); + return NULL; + } + + lws_b64_encode_string(hash, 16, wsi->key_b64, + sizeof wsi->key_b64); + + /* + * 00 example client handshake + * + * GET /socket.io/websocket HTTP/1.1 + * Upgrade: WebSocket + * Connection: Upgrade + * Host: 127.0.0.1:9999 + * Origin: http://127.0.0.1 + * Sec-WebSocket-Key1: 1 0 2#0W 9 89 7 92 ^ + * Sec-WebSocket-Key2: 7 7Y 4328 B2v[8(z1 + * Cookie: socketio=websocket + * + * (îÄ0¶†≥ + * + * 04 example client handshake + * + * GET /chat HTTP/1.1 + * Host: server.example.com + * Upgrade: websocket + * Connection: Upgrade + * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== + * Sec-WebSocket-Origin: http://example.com + * Sec-WebSocket-Protocol: chat, superchat + * Sec-WebSocket-Version: 4 + */ + + p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a", wsi->c_path); + + if (wsi->ietf_spec_revision == 0) { + unsigned char spaces_1, spaces_2; + unsigned int max_1, max_2; + unsigned int num_1, num_2; + unsigned long product_1, product_2; + char key_1[40]; + char key_2[40]; + unsigned int seed; + unsigned int count; + char challenge[16]; + + libwebsockets_get_random(context, &spaces_1, sizeof(char)); + libwebsockets_get_random(context, &spaces_2, sizeof(char)); + + spaces_1 = (spaces_1 % 12) + 1; + spaces_2 = (spaces_2 % 12) + 1; + + max_1 = 4294967295 / spaces_1; + max_2 = 4294967295 / spaces_2; + + libwebsockets_get_random(context, &num_1, sizeof(int)); + libwebsockets_get_random(context, &num_2, sizeof(int)); + + num_1 = (num_1 % max_1); + num_2 = (num_2 % max_2); + + challenge[0] = num_1 >> 24; + challenge[1] = num_1 >> 16; + challenge[2] = num_1 >> 8; + challenge[3] = num_1; + challenge[4] = num_2 >> 24; + challenge[5] = num_2 >> 16; + challenge[6] = num_2 >> 8; + challenge[7] = num_2; + + product_1 = num_1 * spaces_1; + product_2 = num_2 * spaces_2; + + sprintf(key_1, "%lu", product_1); + sprintf(key_2, "%lu", product_2); + + libwebsockets_get_random(context, &seed, sizeof(int)); + libwebsockets_get_random(context, &count, sizeof(int)); + + libwebsockets_00_spam(key_1, (count % 12) + 1, seed); + + libwebsockets_get_random(context, &seed, sizeof(int)); + libwebsockets_get_random(context, &count, sizeof(int)); + + libwebsockets_00_spam(key_2, (count % 12) + 1, seed); + + libwebsockets_get_random(context, &seed, sizeof(int)); + + libwebsockets_00_spaceout(key_1, spaces_1, seed); + libwebsockets_00_spaceout(key_2, spaces_2, seed >> 16); + + p += sprintf(p, "Upgrade: WebSocket\x0d\x0a" + "Connection: Upgrade\x0d\x0aHost: %s\x0d\x0a", + wsi->c_host); + if (wsi->c_origin) + p += sprintf(p, "Origin: %s\x0d\x0a", wsi->c_origin); + + if (wsi->c_protocol) + p += sprintf(p, "Sec-WebSocket-Protocol: %s" + "\x0d\x0a", wsi->c_protocol); + + p += sprintf(p, "Sec-WebSocket-Key1: %s\x0d\x0a", key_1); + p += sprintf(p, "Sec-WebSocket-Key2: %s\x0d\x0a", key_2); + + /* give userland a chance to append, eg, cookies */ + + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, + NULL, &p, (pkt + sizeof(pkt)) - p - 12); + + p += sprintf(p, "\x0d\x0a"); + + if (libwebsockets_get_random(context, p, 8) != 8) + return NULL; + memcpy(&challenge[8], p, 8); + p += 8; + + /* precompute what we want to see from the server */ + + MD5((unsigned char *)challenge, 16, + (unsigned char *)wsi->initial_handshake_hash_base64); + + goto issue_hdr; + } + + p += sprintf(p, "Host: %s\x0d\x0a", wsi->c_host); + p += sprintf(p, "Upgrade: websocket\x0d\x0a"); + p += sprintf(p, "Connection: Upgrade\x0d\x0a" + "Sec-WebSocket-Key: "); + strcpy(p, wsi->key_b64); + p += strlen(wsi->key_b64); + p += sprintf(p, "\x0d\x0a"); + if (wsi->c_origin) + p += sprintf(p, "Sec-WebSocket-Origin: %s\x0d\x0a", + wsi->c_origin); + if (wsi->c_protocol) + p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a", + wsi->c_protocol); + + /* tell the server what extensions we could support */ + + p += sprintf(p, "Sec-WebSocket-Extensions: "); + + ext = context->extensions; + while (ext && ext->callback) { + + n = 0; + ext1 = context->extensions; + + while (ext1 && ext1->callback) { + n |= ext1->callback(context, ext1, wsi, + LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION, + NULL, (char *)ext->name, 0); + + ext1++; + } + + if (n) { /* an extension vetos us */ + debug("ext %s vetoed\n", (char *)ext->name); + ext++; + continue; + } + + n = context->protocols[0].callback(context, wsi, + LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED, + wsi->user_space, (char *)ext->name, 0); + + /* + * zero return from callback means + * go ahead and allow the extension, + * it's what we get if the callback is + * unhandled + */ + + if (n) { + ext++; + continue; + } + + /* apply it */ + + if (ext_count) + *p++ = ','; + p += sprintf(p, "%s", ext->name); + ext_count++; + + ext++; + } + + p += sprintf(p, "\x0d\x0a"); + + if (wsi->ietf_spec_revision) + p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a", + wsi->ietf_spec_revision); + + /* give userland a chance to append, eg, cookies */ + + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, + NULL, &p, (pkt + sizeof(pkt)) - p - 12); + + p += sprintf(p, "\x0d\x0a"); + + /* prepare the expected server accept response */ + + strcpy((char *)buf, wsi->key_b64); + strcpy((char *)&buf[strlen((char *)buf)], magic_websocket_guid); + + SHA1(buf, strlen((char *)buf), (unsigned char *)hash); + + lws_b64_encode_string(hash, 20, + wsi->initial_handshake_hash_base64, + sizeof wsi->initial_handshake_hash_base64); + +issue_hdr: + +#if 0 + puts(pkt); +#endif + + /* done with these now */ + + free(wsi->c_path); + free(wsi->c_host); + if (wsi->c_origin) + free(wsi->c_origin); + + return p; +} + +int +lws_client_interpret_server_handshake(struct libwebsocket_context *context, + struct libwebsocket *wsi) +{ + unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1 + + MAX_BROADCAST_PAYLOAD + LWS_SEND_BUFFER_POST_PADDING]; + char pkt[1024]; + char *p = &pkt[0]; + const char *pc; + const char *c; + int more = 1; + int okay = 0; + char ext_name[128]; + struct libwebsocket_extension *ext; + void *v; + int len = 0; + int n; + static const char magic_websocket_04_masking_guid[] = + "61AC5F19-FBBA-4540-B96F-6561F1AB40A8"; + + /* + * 00 / 76 --> + * + * HTTP/1.1 101 WebSocket Protocol Handshake + * Upgrade: WebSocket + * Connection: Upgrade + * Sec-WebSocket-Origin: http://127.0.0.1 + * Sec-WebSocket-Location: ws://127.0.0.1:9999/socket.io/websocket + * + * xxxxxxxxxxxxxxxx + */ + + if (wsi->ietf_spec_revision == 0) { + if (!wsi->utf8_token[WSI_TOKEN_HTTP].token_len || + !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len || + !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len || + !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len || + (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len && + wsi->c_protocol != NULL)) { + debug("libwebsocket_client_handshake " + "missing required header(s)\n"); + pkt[len] = '\0'; + debug("%s", pkt); + goto bail3; + } + + strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token); + if (strncmp(wsi->utf8_token[WSI_TOKEN_HTTP].token, "101", 3)) { + fprintf(stderr, "libwebsocket_client_handshake " + "server sent bad HTTP response '%s'\n", + wsi->utf8_token[WSI_TOKEN_HTTP].token); + goto bail3; + } + + if (wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len < 16) { + fprintf(stderr, "libwebsocket_client_handshake " + "challenge reply too short %d\n", + wsi->utf8_token[ + WSI_TOKEN_CHALLENGE].token_len); + pkt[len] = '\0'; + debug("%s", pkt); + goto bail3; + + } + + goto select_protocol; + } + + /* + * well, what the server sent looked reasonable for syntax. + * Now let's confirm it sent all the necessary headers + */ +#if 0 + fprintf(stderr, "WSI_TOKEN_HTTP: %d\n", + wsi->utf8_token[WSI_TOKEN_HTTP].token_len); + fprintf(stderr, "WSI_TOKEN_UPGRADE: %d\n", + wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len); + fprintf(stderr, "WSI_TOKEN_CONNECTION: %d\n", + wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len); + fprintf(stderr, "WSI_TOKEN_ACCEPT: %d\n", + wsi->utf8_token[WSI_TOKEN_ACCEPT].token_len); + fprintf(stderr, "WSI_TOKEN_NONCE: %d\n", + wsi->utf8_token[WSI_TOKEN_NONCE].token_len); + fprintf(stderr, "WSI_TOKEN_PROTOCOL: %d\n", + wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len); +#endif + if (!wsi->utf8_token[WSI_TOKEN_HTTP].token_len || + !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len || + !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len || + !wsi->utf8_token[WSI_TOKEN_ACCEPT].token_len || + (!wsi->utf8_token[WSI_TOKEN_NONCE].token_len && + wsi->ietf_spec_revision == 4) || + (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len && + wsi->c_protocol != NULL)) { + debug("libwebsocket_client_handshake " + "missing required header(s)\n"); + pkt[len] = '\0'; + debug("%s", pkt); + goto bail3; + } + + /* + * Everything seems to be there, now take a closer look at what + * is in each header + */ + + strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token); + if (strncmp(wsi->utf8_token[WSI_TOKEN_HTTP].token, "101", 3)) { + fprintf(stderr, "libwebsocket_client_handshake " + "server sent bad HTTP response '%s'\n", + wsi->utf8_token[WSI_TOKEN_HTTP].token); + goto bail3; + } + + strtolower(wsi->utf8_token[WSI_TOKEN_UPGRADE].token); + if (strcmp(wsi->utf8_token[WSI_TOKEN_UPGRADE].token, + "websocket")) { + fprintf(stderr, "libwebsocket_client_handshake server " + "sent bad Upgrade header '%s'\n", + wsi->utf8_token[WSI_TOKEN_UPGRADE].token); + goto bail3; + } + + strtolower(wsi->utf8_token[WSI_TOKEN_CONNECTION].token); + if (strcmp(wsi->utf8_token[WSI_TOKEN_CONNECTION].token, + "upgrade")) { + fprintf(stderr, "libwebsocket_client_handshake server " + "sent bad Connection hdr '%s'\n", + wsi->utf8_token[WSI_TOKEN_CONNECTION].token); + goto bail3; + } + +select_protocol: + pc = wsi->c_protocol; + if (pc == NULL) + fprintf(stderr, "lws_client_interpret_server_handshake: " + "NULL c_protocol\n"); + else + debug("lws_client_interpret_server_handshake: " + "cPprotocol='%s'\n", pc); + + /* + * confirm the protocol the server wants to talk was in the list + * of protocols we offered + */ + + if (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len) { + + fprintf(stderr, "lws_client_interpret_server_handshake " + "WSI_TOKEN_PROTOCOL is null\n"); + /* + * no protocol name to work from, + * default to first protocol + */ + wsi->protocol = &context->protocols[0]; + wsi->c_callback = wsi->protocol->callback; + free(wsi->c_protocol); + + goto check_accept; + } + + while (*pc && !okay) { + if ((!strncmp(pc, wsi->utf8_token[WSI_TOKEN_PROTOCOL].token, + wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len)) && + (pc[wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len] == ',' || + pc[wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len] == '\0')) { + okay = 1; + continue; + } + while (*pc && *pc != ',') + pc++; + while (*pc && *pc != ' ') + pc++; + } + + /* done with him now */ + + if (wsi->c_protocol) + free(wsi->c_protocol); + + if (!okay) { + fprintf(stderr, "libwebsocket_client_handshake server " + "sent bad protocol '%s'\n", + wsi->utf8_token[WSI_TOKEN_PROTOCOL].token); + goto bail2; + } + + /* + * identify the selected protocol struct and set it + */ + n = 0; + wsi->protocol = NULL; + while (context->protocols[n].callback && !wsi->protocol) { /* Stop after finding first one?? */ + if (strcmp(wsi->utf8_token[WSI_TOKEN_PROTOCOL].token, + context->protocols[n].name) == 0) { + wsi->protocol = &context->protocols[n]; + wsi->c_callback = wsi->protocol->callback; + } + n++; + } + + if (wsi->protocol == NULL) { + fprintf(stderr, "libwebsocket_client_handshake server " + "requested protocol '%s', which we " + "said we supported but we don't!\n", + wsi->utf8_token[WSI_TOKEN_PROTOCOL].token); + goto bail2; + } + + + /* instantiate the accepted extensions */ + + if (!wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token_len) { + debug("no client extenstions allowed by server\n"); + goto check_accept; + } + + /* + * break down the list of server accepted extensions + * and go through matching them or identifying bogons + */ + + c = wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token; + n = 0; + while (more) { + + if (*c && (*c != ',' && *c != ' ' && *c != '\t')) { + ext_name[n] = *c++; + if (n < sizeof(ext_name) - 1) + n++; + continue; + } + ext_name[n] = '\0'; + if (!*c) + more = 0; + else { + c++; + if (!n) + continue; + } + + /* check we actually support it */ + + debug("checking client ext %s\n", ext_name); + + n = 0; + ext = wsi->protocol->owning_server->extensions; + while (ext && ext->callback) { + + if (strcmp(ext_name, ext->name)) { + ext++; + continue; + } + + n = 1; + + debug("instantiating client ext %s\n", ext_name); + + /* instantiate the extension on this conn */ + + wsi->active_extensions_user[ + wsi->count_active_extensions] = + malloc(ext->per_session_data_size); + memset(wsi->active_extensions_user[ + wsi->count_active_extensions], 0, + ext->per_session_data_size); + wsi->active_extensions[ + wsi->count_active_extensions] = ext; + + /* allow him to construct his context */ + + ext->callback(wsi->protocol->owning_server, + ext, wsi, + LWS_EXT_CALLBACK_CLIENT_CONSTRUCT, + wsi->active_extensions_user[ + wsi->count_active_extensions], + NULL, 0); + + wsi->count_active_extensions++; + + ext++; + } + + if (n == 0) { + fprintf(stderr, "Server said we should use" + "an unknown extension '%s'!\n", ext_name); + goto bail2; + } + + n = 0; + } + + +check_accept: + + if (wsi->ietf_spec_revision == 0) { + + if (memcmp(wsi->initial_handshake_hash_base64, + wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 16)) { + fprintf(stderr, "libwebsocket_client_handshake " + "failed 00 challenge compare\n"); + pkt[len] = '\0'; + fprintf(stderr, "%s", pkt); + goto bail2; + } + + goto accept_ok; + } + + /* + * Confirm his accept token is the one we precomputed + */ + + if (strcmp(wsi->utf8_token[WSI_TOKEN_ACCEPT].token, + wsi->initial_handshake_hash_base64)) { + fprintf(stderr, "libwebsocket_client_handshake server " + "sent bad ACCEPT '%s' vs computed '%s'\n", + wsi->utf8_token[WSI_TOKEN_ACCEPT].token, + wsi->initial_handshake_hash_base64); + goto bail2; + } + + if (wsi->ietf_spec_revision == 4) { + /* + * Calculate the 04 masking key to use when + * sending data to server + */ + + strcpy((char *)buf, wsi->key_b64); + p = (char *)buf + strlen(wsi->key_b64); + strcpy(p, wsi->utf8_token[WSI_TOKEN_NONCE].token); + p += wsi->utf8_token[WSI_TOKEN_NONCE].token_len; + strcpy(p, magic_websocket_04_masking_guid); + SHA1(buf, strlen((char *)buf), wsi->masking_key_04); + } +accept_ok: + + /* allocate the per-connection user memory (if any) */ + if (wsi->protocol->per_session_data_size && + !libwebsocket_ensure_user_space(wsi)) + goto bail2; + + /* clear his proxy connection timeout */ + + libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); + + /* mark him as being alive */ + + wsi->state = WSI_STATE_ESTABLISHED; + wsi->mode = LWS_CONNMODE_WS_CLIENT; + + debug("handshake OK for protocol %s\n", wsi->protocol->name); + + /* call him back to inform him he is up */ + + wsi->protocol->callback(context, wsi, + LWS_CALLBACK_CLIENT_ESTABLISHED, + wsi->user_space, NULL, 0); + + /* + * inform all extensions, not just active ones since they + * already know + */ + + ext = context->extensions; + + while (ext && ext->callback) { + v = NULL; + for (n = 0; n < wsi->count_active_extensions; n++) + if (wsi->active_extensions[n] == ext) + v = wsi->active_extensions_user[n]; + + ext->callback(context, ext, wsi, + LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED, v, NULL, 0); + ext++; + } + + return 0; + +bail3: + if (wsi->c_protocol) + free(wsi->c_protocol); + +bail2: + if (wsi->c_callback) wsi->c_callback(context, wsi, + LWS_CALLBACK_CLIENT_CONNECTION_ERROR, + wsi->user_space, + NULL, 0); + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); // But this should be LWS_CLOSE_STATUS_PROTOCOL_ERR + + return 1; +} + + + +/** + * libwebsocket_service_fd() - Service polled socket with something waiting + * @context: Websocket context + * @pollfd: The pollfd entry describing the socket fd and which events + * happened. + * + * This function closes any active connections and then frees the + * context. After calling this, any further use of the context is + * undefined. + */ + +int +libwebsocket_service_fd(struct libwebsocket_context *context, + struct pollfd *pollfd) +{ + unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1 + + MAX_BROADCAST_PAYLOAD + LWS_SEND_BUFFER_POST_PADDING]; + struct libwebsocket *wsi; + struct libwebsocket *new_wsi; + int n; + int m; + ssize_t len; + int accept_fd; + unsigned int clilen; + struct sockaddr_in cli_addr; + struct timeval tv; + char pkt[1024]; + char *p = &pkt[0]; + int more = 1; + struct lws_tokens eff_buf; + int opt = 1; + char c; + +#ifdef LWS_OPENSSL_SUPPORT + char ssl_err_buf[512]; +#endif + /* + * you can call us with pollfd = NULL to just allow the once-per-second + * global timeout checks; if less than a second since the last check + * it returns immediately then. + */ + + gettimeofday(&tv, NULL); + + if (context->last_timeout_check_s != tv.tv_sec) { + context->last_timeout_check_s = tv.tv_sec; + + /* global timeout check once per second */ + + for (n = 0; n < context->fds_count; n++) { + wsi = wsi_from_fd(context, context->fds[n].fd); + + libwebsocket_service_timeout_check(context, wsi, + tv.tv_sec); + } + } + + /* just here for timeout management? */ + + if (pollfd == NULL) + return 0; + + /* no, here to service a socket descriptor */ + + wsi = wsi_from_fd(context, pollfd->fd); + + if (wsi == NULL) + return 1; + + switch (wsi->mode) { + case LWS_CONNMODE_SERVER_LISTENER: + + /* pollin means a client has connected to us then */ + + if (!pollfd->revents & POLLIN) + break; + + if (context->fds_count >= MAX_CLIENTS) { + fprintf(stderr, "too busy to accept new client\n"); + break; + } + + /* listen socket got an unencrypted connection... */ + + clilen = sizeof(cli_addr); + accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr, + &clilen); + if (accept_fd < 0) { + debug("ERROR on accept\n"); + return -1; + } + + /* Disable Nagle */ + opt = 1; + setsockopt(accept_fd, IPPROTO_TCP, TCP_NODELAY, + (const void *)&opt, sizeof(opt)); + + /* + * look at who we connected to and give user code a chance + * to reject based on client IP. There's no protocol selected + * yet so we issue this to protocols[0] + */ + + if ((context->protocols[0].callback)(context, wsi, + LWS_CALLBACK_FILTER_NETWORK_CONNECTION, + (void *)(long)accept_fd, NULL, 0)) { + debug("Callback denied network connection\n"); +#ifdef WIN32 + closesocket(accept_fd); +#else + close(accept_fd); +#endif + break; + } + + /* accepting connection to main listener */ + + new_wsi = libwebsocket_create_new_server_wsi(context); + if (new_wsi == NULL) + break; + + new_wsi->sock = accept_fd; + + +#ifdef LWS_OPENSSL_SUPPORT + new_wsi->ssl = NULL; + + if (context->use_ssl) { + + new_wsi->ssl = SSL_new(context->ssl_ctx); + if (new_wsi->ssl == NULL) { + fprintf(stderr, "SSL_new failed: %s\n", + ERR_error_string(SSL_get_error( + new_wsi->ssl, 0), NULL)); + libwebsockets_decode_ssl_error(); + free(new_wsi); + break; + } + + SSL_set_fd(new_wsi->ssl, accept_fd); + + n = SSL_accept(new_wsi->ssl); + if (n != 1) { + /* + * browsers seem to probe with various + * ssl params which fail then retry + * and succeed + */ + debug("SSL_accept failed skt %u: %s\n", + pollfd->fd, + ERR_error_string(SSL_get_error( + new_wsi->ssl, n), NULL)); + SSL_free( + new_wsi->ssl); + free(new_wsi); + break; + } + + debug("accepted new SSL conn " + "port %u on fd=%d SSL ver %s\n", + ntohs(cli_addr.sin_port), accept_fd, + SSL_get_version(new_wsi->ssl)); + + } else +#endif + debug("accepted new conn port %u on fd=%d\n", + ntohs(cli_addr.sin_port), accept_fd); + + insert_wsi(context, new_wsi); + + /* + * make sure NO events are seen yet on this new socket + * (otherwise we inherit old fds[client].revents from + * previous socket there and die mysteriously! ) + */ + context->fds[context->fds_count].revents = 0; + + context->fds[context->fds_count].events = POLLIN; + context->fds[context->fds_count++].fd = accept_fd; + + /* external POLL support via protocol 0 */ + context->protocols[0].callback(context, new_wsi, + LWS_CALLBACK_ADD_POLL_FD, + (void *)(long)accept_fd, NULL, POLLIN); + + break; + + case LWS_CONNMODE_BROADCAST_PROXY_LISTENER: + + /* as we are listening, POLLIN means accept() is needed */ + + if (!pollfd->revents & POLLIN) + break; + + /* listen socket got an unencrypted connection... */ + + clilen = sizeof(cli_addr); + accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr, + &clilen); + if (accept_fd < 0) { + debug("ERROR on accept\n"); + return -1; + } + + if (context->fds_count >= MAX_CLIENTS) { + fprintf(stderr, "too busy to accept new broadcast " + "proxy client\n"); +#ifdef WIN32 + closesocket(accept_fd); +#else + close(accept_fd); +#endif + break; + } + + /* create a dummy wsi for the connection and add it */ + + new_wsi = malloc(sizeof(struct libwebsocket)); + memset(new_wsi, 0, sizeof(struct libwebsocket)); + new_wsi->sock = accept_fd; + new_wsi->mode = LWS_CONNMODE_BROADCAST_PROXY; + new_wsi->state = WSI_STATE_ESTABLISHED; + new_wsi->count_active_extensions = 0; + /* note which protocol we are proxying */ + new_wsi->protocol_index_for_broadcast_proxy = + wsi->protocol_index_for_broadcast_proxy; + insert_wsi(context, new_wsi); + + /* add connected socket to internal poll array */ + + context->fds[context->fds_count].revents = 0; + context->fds[context->fds_count].events = POLLIN; + context->fds[context->fds_count++].fd = accept_fd; + + /* external POLL support via protocol 0 */ + context->protocols[0].callback(context, new_wsi, + LWS_CALLBACK_ADD_POLL_FD, + (void *)(long)accept_fd, NULL, POLLIN); + + break; + + case LWS_CONNMODE_BROADCAST_PROXY: + + /* handle session socket closed */ + + if (pollfd->revents & (POLLERR | POLLHUP)) { + + debug("Session Socket %p (fd=%d) dead\n", + (void *)wsi, pollfd->fd); + + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NORMAL); + return 1; + } + + /* + * either extension code with stuff to spill, or the user code, + * requested a callback when it was OK to write + */ + + if (pollfd->revents & POLLOUT) + if (lws_handle_POLLOUT_event(context, wsi, + pollfd) < 0) { + libwebsocket_close_and_free_session( + context, wsi, LWS_CLOSE_STATUS_NORMAL); + return 1; + } + + /* any incoming data ready? */ + + if (!(pollfd->revents & POLLIN)) + break; + + /* get the issued broadcast payload from the socket */ + + len = read(pollfd->fd, buf + LWS_SEND_BUFFER_PRE_PADDING, + MAX_BROADCAST_PAYLOAD); + if (len < 0) { + fprintf(stderr, "Error reading broadcast payload\n"); + break; + } + + /* broadcast it to all guys with this protocol index */ + + for (n = 0; n < FD_HASHTABLE_MODULUS; n++) { + + for (m = 0; m < context->fd_hashtable[n].length; m++) { + + new_wsi = context->fd_hashtable[n].wsi[m]; + + /* only to clients we are serving to */ + + if (new_wsi->mode != LWS_CONNMODE_WS_SERVING) + continue; + + /* + * never broadcast to non-established + * connection + */ + + if (new_wsi->state != WSI_STATE_ESTABLISHED) + continue; + + /* + * only broadcast to connections using + * the requested protocol + */ + + if (new_wsi->protocol->protocol_index != + wsi->protocol_index_for_broadcast_proxy) + continue; + + /* broadcast it to this connection */ + + new_wsi->protocol->callback(context, new_wsi, + LWS_CALLBACK_BROADCAST, + new_wsi->user_space, + buf + LWS_SEND_BUFFER_PRE_PADDING, len); + } + } + break; + + case LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY: + + /* handle proxy hung up on us */ + + if (pollfd->revents & (POLLERR | POLLHUP)) { + + fprintf(stderr, "Proxy connection %p (fd=%d) dead\n", + (void *)wsi, pollfd->fd); + + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); + return 1; + } + + n = recv(wsi->sock, pkt, sizeof pkt, 0); + if (n < 0) { + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); + fprintf(stderr, "ERROR reading from proxy socket\n"); + return 1; + } + + pkt[13] = '\0'; + if (strcmp(pkt, "HTTP/1.0 200 ") != 0) { + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); + fprintf(stderr, "ERROR from proxy: %s\n", pkt); + return 1; + } + + /* clear his proxy connection timeout */ + + libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); + + /* fallthru */ + + case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE: + + #ifdef LWS_OPENSSL_SUPPORT + if (wsi->use_ssl && !wsi->ssl) { + + wsi->ssl = SSL_new(context->ssl_client_ctx); + wsi->client_bio = BIO_new_socket(wsi->sock, + BIO_NOCLOSE); + SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio); + + SSL_set_ex_data(wsi->ssl, + openssl_websocket_private_data_index, + context); + } + + if (wsi->use_ssl) { + if (SSL_connect(wsi->ssl) <= 0) { + + /* + * retry if new data comes until we + * run into the connection timeout or win + */ + + fprintf(stderr, "SSL connect error %s\n", + ERR_error_string(ERR_get_error(), + ssl_err_buf)); + return 0; + } + + n = SSL_get_verify_result(wsi->ssl); + if ((n != X509_V_OK) && ( + n != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || + wsi->use_ssl != 2)) { + + fprintf(stderr, "server's cert didn't " + "look good %d\n", n); + libwebsocket_close_and_free_session(context, + wsi, LWS_CLOSE_STATUS_NOSTATUS); + return 1; + } + } else + wsi->ssl = NULL; + #endif + + p = libwebsockets_generate_client_handshake(context, wsi, p); + if (p == NULL) + return 1; + + /* send our request to the server */ + + #ifdef LWS_OPENSSL_SUPPORT + if (wsi->use_ssl) + n = SSL_write(wsi->ssl, pkt, p - pkt); + else + #endif + n = send(wsi->sock, pkt, p - pkt, 0); + + if (n < 0) { + fprintf(stderr, "ERROR writing to client socket\n"); + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); + return 1; + } + + wsi->parser_state = WSI_TOKEN_NAME_PART; + wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY; + libwebsocket_set_timeout(wsi, + PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE, 5); + + break; + + case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY: + + /* handle server hung up on us */ + + if (pollfd->revents & (POLLERR | POLLHUP)) { + + fprintf(stderr, "Server connection %p (fd=%d) dead\n", + (void *)wsi, pollfd->fd); + + goto bail3; + } + + + /* interpret the server response */ + + /* + * HTTP/1.1 101 Switching Protocols + * Upgrade: websocket + * Connection: Upgrade + * Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo= + * Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC== + * Sec-WebSocket-Protocol: chat + */ + + /* + * we have to take some care here to only take from the + * socket bytewise. The browser may (and has been seen to + * in the case that onopen() performs websocket traffic) + * coalesce both handshake response and websocket traffic + * in one packet, since at that point the connection is + * definitively ready from browser pov. + */ + + len = 1; + while (wsi->parser_state != WSI_PARSING_COMPLETE && len > 0) { +#ifdef LWS_OPENSSL_SUPPORT + if (wsi->use_ssl) + len = SSL_read(wsi->ssl, &c, 1); + else +#endif + len = recv(wsi->sock, &c, 1, 0); + + libwebsocket_parse(wsi, c); + } + + /* + * hs may also be coming in multiple packets, there is a 5-sec + * libwebsocket timeout still active here too, so if parsing did + * not complete just wait for next packet coming in this state + */ + + if (wsi->parser_state != WSI_PARSING_COMPLETE) + break; + + /* + * otherwise deal with the handshake. If there's any + * packet traffic already arrived we'll trigger poll() again + * right away and deal with it that way + */ + + return lws_client_interpret_server_handshake(context, wsi); + +bail3: + if (wsi->c_protocol) + free(wsi->c_protocol); + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); + return 1; + + case LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT: + fprintf(stderr, + "LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT\n"); + break; + + case LWS_CONNMODE_WS_CLIENT_PENDING_CANDIDATE_CHILD: + fprintf(stderr, + "LWS_CONNMODE_WS_CLIENT_PENDING_CANDIDATE_CHILD\n"); + break; + + + case LWS_CONNMODE_WS_SERVING: + case LWS_CONNMODE_WS_CLIENT: + + /* handle session socket closed */ + + if (pollfd->revents & (POLLERR | POLLHUP)) { + + fprintf(stderr, "Session Socket %p (fd=%d) dead\n", + (void *)wsi, pollfd->fd); + + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); + return 1; + } + + /* the guy requested a callback when it was OK to write */ + + if ((pollfd->revents & POLLOUT) && + wsi->state == WSI_STATE_ESTABLISHED) + if (lws_handle_POLLOUT_event(context, wsi, + pollfd) < 0) { + libwebsocket_close_and_free_session( + context, wsi, LWS_CLOSE_STATUS_NORMAL); + return 1; + } + + + /* any incoming data ready? */ + + if (!(pollfd->revents & POLLIN)) + break; + +#ifdef LWS_OPENSSL_SUPPORT + if (wsi->ssl) + eff_buf.token_len = SSL_read(wsi->ssl, buf, sizeof buf); + else +#endif + eff_buf.token_len = + recv(pollfd->fd, buf, sizeof buf, 0); + + if (eff_buf.token_len < 0) { + fprintf(stderr, "Socket read returned %d\n", + eff_buf.token_len); + if (errno != EINTR) + libwebsocket_close_and_free_session(context, + wsi, LWS_CLOSE_STATUS_NOSTATUS); + return 1; + } + if (!eff_buf.token_len) { + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); + return 1; + } + + /* + * give any active extensions a chance to munge the buffer + * before parse. We pass in a pointer to an lws_tokens struct + * prepared with the default buffer and content length that's in + * there. Rather than rewrite the default buffer, extensions + * that expect to grow the buffer can adapt .token to + * point to their own per-connection buffer in the extension + * user allocation. By default with no extensions or no + * extension callback handling, just the normal input buffer is + * used then so it is efficient. + */ + + eff_buf.token = (char *)buf; + + more = 1; + while (more) { + + more = 0; + + for (n = 0; n < wsi->count_active_extensions; n++) { + m = wsi->active_extensions[n]->callback(context, + wsi->active_extensions[n], wsi, + LWS_EXT_CALLBACK_PACKET_RX_PREPARSE, + wsi->active_extensions_user[n], + &eff_buf, 0); + if (m < 0) { + fprintf(stderr, + "Extension reports fatal error\n"); + libwebsocket_close_and_free_session( + context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); + return 1; + } + if (m) + more = 1; + } + + /* service incoming data */ + + if (eff_buf.token_len) { + n = libwebsocket_read(context, wsi, + (unsigned char *)eff_buf.token, + eff_buf.token_len); + if (n < 0) + /* we closed wsi */ + return 1; + } + + eff_buf.token = NULL; + eff_buf.token_len = 0; + } + break; + } + + return 0; +} + + +/** + * libwebsocket_context_destroy() - Destroy the websocket context + * @context: Websocket context + * + * This function closes any active connections and then frees the + * context. After calling this, any further use of the context is + * undefined. + */ +void +libwebsocket_context_destroy(struct libwebsocket_context *context) +{ + int n; + int m; + struct libwebsocket *wsi; + struct libwebsocket_extension *ext; + + for (n = 0; n < FD_HASHTABLE_MODULUS; n++) + for (m = 0; m < context->fd_hashtable[n].length; m++) { + wsi = context->fd_hashtable[n].wsi[m]; + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_GOINGAWAY); + } + + /* + * give all extensions a chance to clean up any per-context + * allocations they might have made + */ + + ext = context->extensions; + m = LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT; + if (context->listen_port) + m = LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT; + while (ext && ext->callback) { + ext->callback(context, ext, NULL, m, NULL, NULL, 0); + ext++; + } + +#ifdef WIN32 +#else + close(context->fd_random); +#endif + +#ifdef LWS_OPENSSL_SUPPORT + if (context->ssl_ctx) + SSL_CTX_free(context->ssl_ctx); + if (context->ssl_client_ctx) + SSL_CTX_free(context->ssl_client_ctx); +#endif + + free(context); + +#ifdef WIN32 + WSACleanup(); +#endif +} + +/** + * libwebsocket_service() - Service any pending websocket activity + * @context: Websocket context + * @timeout_ms: Timeout for poll; 0 means return immediately if nothing needed + * service otherwise block and service immediately, returning + * after the timeout if nothing needed service. + * + * This function deals with any pending websocket traffic, for three + * kinds of event. It handles these events on both server and client + * types of connection the same. + * + * 1) Accept new connections to our context's server + * + * 2) Perform pending broadcast writes initiated from other forked + * processes (effectively serializing asynchronous broadcasts) + * + * 3) Call the receive callback for incoming frame data received by + * server or client connections. + * + * You need to call this service function periodically to all the above + * functions to happen; if your application is single-threaded you can + * just call it in your main event loop. + * + * Alternatively you can fork a new process that asynchronously handles + * calling this service in a loop. In that case you are happy if this + * call blocks your thread until it needs to take care of something and + * would call it with a large nonzero timeout. Your loop then takes no + * CPU while there is nothing happening. + * + * If you are calling it in a single-threaded app, you don't want it to + * wait around blocking other things in your loop from happening, so you + * would call it with a timeout_ms of 0, so it returns immediately if + * nothing is pending, or as soon as it services whatever was pending. + */ + + +int +libwebsocket_service(struct libwebsocket_context *context, int timeout_ms) +{ + int n; + + /* stay dead once we are dead */ + + if (context == NULL) + return 1; + + /* wait for something to need service */ + + n = poll(context->fds, context->fds_count, timeout_ms); + if (n == 0) /* poll timeout */ + return 0; + + if (n < 0) { + /* + fprintf(stderr, "Listen Socket dead\n"); + */ + return -1; + } + + /* handle accept on listening socket? */ + + for (n = 0; n < context->fds_count; n++) + if (context->fds[n].revents) + if (libwebsocket_service_fd(context, + &context->fds[n]) < 0) + return -1; + return 0; +} + +int +lws_any_extension_handled(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons r, + void *v, size_t len) +{ + int n; + int handled = 0; + + /* maybe an extension will take care of it for us */ + + for (n = 0; n < wsi->count_active_extensions && !handled; n++) { + if (!wsi->active_extensions[n]->callback) + continue; + + handled |= wsi->active_extensions[n]->callback(context, + wsi->active_extensions[n], wsi, + r, wsi->active_extensions_user[n], v, len); + } + + return handled; +} + + +void * +lws_get_extension_user_matching_ext(struct libwebsocket *wsi, + struct libwebsocket_extension *ext) +{ + int n = 0; + + if (wsi == NULL) + return NULL; + + while (n < wsi->count_active_extensions) { + if (wsi->active_extensions[n] != ext) { + n++; + continue; + } + return wsi->active_extensions_user[n]; + } + + return NULL; +} + +/** + * libwebsocket_callback_on_writable() - Request a callback when this socket + * becomes able to be written to without + * blocking + * + * @context: libwebsockets context + * @wsi: Websocket connection instance to get callback for + */ + +int +libwebsocket_callback_on_writable(struct libwebsocket_context *context, + struct libwebsocket *wsi) +{ + int n; + int handled = 0; + + /* maybe an extension will take care of it for us */ + + for (n = 0; n < wsi->count_active_extensions; n++) { + if (!wsi->active_extensions[n]->callback) + continue; + + handled |= wsi->active_extensions[n]->callback(context, + wsi->active_extensions[n], wsi, + LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE, + wsi->active_extensions_user[n], NULL, 0); + } + + if (handled) + return 1; + + for (n = 0; n < context->fds_count; n++) + if (context->fds[n].fd == wsi->sock) { + context->fds[n].events |= POLLOUT; + n = context->fds_count + 1; + } + + if (n == context->fds_count) + fprintf(stderr, "libwebsocket_callback_on_writable: " + "failed to find socket %d\n", wsi->sock); + + /* external POLL support via protocol 0 */ + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_SET_MODE_POLL_FD, + (void *)(long)wsi->sock, NULL, POLLOUT); + + return 1; +} + +/** + * libwebsocket_callback_on_writable_all_protocol() - Request a callback for + * all connections using the given protocol when it + * becomes possible to write to each socket without + * blocking in turn. + * + * @protocol: Protocol whose connections will get callbacks + */ + +int +libwebsocket_callback_on_writable_all_protocol( + const struct libwebsocket_protocols *protocol) +{ + struct libwebsocket_context *context = protocol->owning_server; + int n; + int m; + struct libwebsocket *wsi; + + for (n = 0; n < FD_HASHTABLE_MODULUS; n++) { + + for (m = 0; m < context->fd_hashtable[n].length; m++) { + + wsi = context->fd_hashtable[n].wsi[m]; + + if (wsi->protocol == protocol) + libwebsocket_callback_on_writable(context, wsi); + } + } + + return 0; +} + +/** + * libwebsocket_set_timeout() - marks the wsi as subject to a timeout + * + * You will not need this unless you are doing something special + * + * @wsi: Websocket connection instance + * @reason: timeout reason + * @secs: how many seconds + */ + +void +libwebsocket_set_timeout(struct libwebsocket *wsi, + enum pending_timeout reason, int secs) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + + wsi->pending_timeout_limit = tv.tv_sec + secs; + wsi->pending_timeout = reason; +} + + +/** + * libwebsocket_get_socket_fd() - returns the socket file descriptor + * + * You will not need this unless you are doing something special + * + * @wsi: Websocket connection instance + */ + +int +libwebsocket_get_socket_fd(struct libwebsocket *wsi) +{ + return wsi->sock; +} + +/** + * libwebsocket_rx_flow_control() - Enable and disable socket servicing for + * receieved packets. + * + * If the output side of a server process becomes choked, this allows flow + * control for the input side. + * + * @wsi: Websocket connection instance to get callback for + * @enable: 0 = disable read servicing for this connection, 1 = enable + */ + +int +libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable) +{ + struct libwebsocket_context *context = wsi->protocol->owning_server; + int n; + + for (n = 0; n < context->fds_count; n++) + if (context->fds[n].fd == wsi->sock) { + if (enable) + context->fds[n].events |= POLLIN; + else + context->fds[n].events &= ~POLLIN; + + return 0; + } + + if (enable) + /* external POLL support via protocol 0 */ + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_SET_MODE_POLL_FD, + (void *)(long)wsi->sock, NULL, POLLIN); + else + /* external POLL support via protocol 0 */ + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_CLEAR_MODE_POLL_FD, + (void *)(long)wsi->sock, NULL, POLLIN); + +#if 0 + fprintf(stderr, "libwebsocket_rx_flow_control " + "unable to find socket\n"); +#endif + return 1; +} + +/** + * libwebsocket_canonical_hostname() - returns this host's hostname + * + * This is typically used by client code to fill in the host parameter + * when making a client connection. You can only call it after the context + * has been created. + * + * @context: Websocket context + */ + + +extern const char * +libwebsocket_canonical_hostname(struct libwebsocket_context *context) +{ + return (const char *)context->canonical_hostname; +} + + +static void sigpipe_handler(int x) +{ +} + +#ifdef LWS_OPENSSL_SUPPORT +static int +OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) +{ + + SSL *ssl; + int n; + struct libwebsocket_context *context; + + ssl = X509_STORE_CTX_get_ex_data(x509_ctx, + SSL_get_ex_data_X509_STORE_CTX_idx()); + + /* + * !!! nasty openssl requires the index to come as a library-scope + * static + */ + context = SSL_get_ex_data(ssl, openssl_websocket_private_data_index); + + n = context->protocols[0].callback(NULL, NULL, + LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION, + x509_ctx, ssl, preverify_ok); + + /* convert return code from 0 = OK to 1 = OK */ + + if (!n) + n = 1; + else + n = 0; + + return n; +} +#endif + + +/** + * libwebsocket_create_context() - Create the websocket handler + * @port: Port to listen on... you can use 0 to suppress listening on + * any port, that's what you want if you are not running a + * websocket server at all but just using it as a client + * @interf: NULL to bind the listen socket to all interfaces, or the + * interface name, eg, "eth2" + * @protocols: Array of structures listing supported protocols and a protocol- + * specific callback for each one. The list is ended with an + * entry that has a NULL callback pointer. + * It's not const because we write the owning_server member + * @extensions: NULL or array of libwebsocket_extension structs listing the + * extensions this context supports + * @ssl_cert_filepath: If libwebsockets was compiled to use ssl, and you want + * to listen using SSL, set to the filepath to fetch the + * server cert from, otherwise NULL for unencrypted + * @ssl_private_key_filepath: filepath to private key if wanting SSL mode, + * else ignored + * @gid: group id to change to after setting listen socket, or -1. + * @uid: user id to change to after setting listen socket, or -1. + * @options: 0, or LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK + * + * This function creates the listening socket and takes care + * of all initialization in one step. + * + * After initialization, it returns a struct libwebsocket_context * that + * represents this server. After calling, user code needs to take care + * of calling libwebsocket_service() with the context pointer to get the + * server's sockets serviced. This can be done in the same process context + * or a forked process, or another thread, + * + * The protocol callback functions are called for a handful of events + * including http requests coming in, websocket connections becoming + * established, and data arriving; it's also called periodically to allow + * async transmission. + * + * HTTP requests are sent always to the FIRST protocol in @protocol, since + * at that time websocket protocol has not been negotiated. Other + * protocols after the first one never see any HTTP callack activity. + * + * The server created is a simple http server by default; part of the + * websocket standard is upgrading this http connection to a websocket one. + * + * This allows the same server to provide files like scripts and favicon / + * images or whatever over http and dynamic data over websockets all in + * one place; they're all handled in the user callback. + */ + +struct libwebsocket_context * +libwebsocket_create_context(int port, const char *interf, + struct libwebsocket_protocols *protocols, + struct libwebsocket_extension *extensions, + const char *ssl_cert_filepath, + const char *ssl_private_key_filepath, + int gid, int uid, unsigned int options) +{ + int n; + int m; + int sockfd = 0; + int fd; + struct sockaddr_in serv_addr, cli_addr; + int opt = 1; + struct libwebsocket_context *context = NULL; + unsigned int slen; + char *p; + char hostname[1024] = ""; +// struct hostent *he; + struct libwebsocket *wsi; + struct sockaddr sa; + +#ifdef LWS_OPENSSL_SUPPORT + SSL_METHOD *method; + char ssl_err_buf[512]; +#endif + +#ifdef _WIN32 + { + WORD wVersionRequested; + WSADATA wsaData; + int err; + HMODULE wsdll; + + /* Use the MAKEWORD(lowbyte, highbyte) macro from Windef.h */ + wVersionRequested = MAKEWORD(2, 2); + + err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) { + /* Tell the user that we could not find a usable */ + /* Winsock DLL. */ + fprintf(stderr, "WSAStartup failed with error: %d\n", + err); + return NULL; + } + + /* default to a poll() made out of select() */ + poll = emulated_poll; + + /* if windows socket lib available, use his WSAPoll */ + wsdll = GetModuleHandle("Ws2_32.dll"); + if (wsdll) + poll = (PFNWSAPOLL)GetProcAddress(wsdll, "WSAPoll"); + } +#endif + + + context = malloc(sizeof(struct libwebsocket_context)); + if (!context) { + fprintf(stderr, "No memory for websocket context\n"); + return NULL; + } + context->protocols = protocols; + context->listen_port = port; + context->http_proxy_port = 0; + context->http_proxy_address[0] = '\0'; + context->options = options; + context->fds_count = 0; + context->extensions = extensions; + context->last_timeout_check_s = 0; + +#ifdef WIN32 + context->fd_random = 0; +#else + context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY); + if (context->fd_random < 0) { + fprintf(stderr, "Unable to open random device %s %d\n", + SYSTEM_RANDOM_FILEPATH, context->fd_random); + return NULL; + } +#endif + +#ifdef LWS_OPENSSL_SUPPORT + context->use_ssl = 0; + context->ssl_ctx = NULL; + context->ssl_client_ctx = NULL; + openssl_websocket_private_data_index = 0; +#endif + /* find canonical hostname */ + + hostname[(sizeof hostname) - 1] = '\0'; + memset(&sa, 0, sizeof(sa)); + sa.sa_family = AF_INET; + sa.sa_data[(sizeof sa.sa_data) - 1] = '\0'; + gethostname(hostname, (sizeof hostname) - 1); + + n = 0; + + if (strlen(hostname) < sizeof(sa.sa_data) - 1) { + strcpy(sa.sa_data, hostname); +// fprintf(stderr, "my host name is %s\n", sa.sa_data); + n = getnameinfo(&sa, sizeof(sa), hostname, + (sizeof hostname) - 1, NULL, 0, 0); + } + + if (!n) { + strncpy(context->canonical_hostname, hostname, + sizeof context->canonical_hostname - 1); + context->canonical_hostname[ + sizeof context->canonical_hostname - 1] = '\0'; + } else + strncpy(context->canonical_hostname, hostname, + sizeof context->canonical_hostname - 1); + +// fprintf(stderr, "context->canonical_hostname = %s\n", +// context->canonical_hostname); + + /* split the proxy ads:port if given */ + + p = getenv("http_proxy"); + if (p) { + strncpy(context->http_proxy_address, p, + sizeof context->http_proxy_address - 1); + context->http_proxy_address[ + sizeof context->http_proxy_address - 1] = '\0'; + + p = strchr(context->http_proxy_address, ':'); + if (p == NULL) { + fprintf(stderr, "http_proxy needs to be ads:port\n"); + return NULL; + } + *p = '\0'; + context->http_proxy_port = atoi(p + 1); + + fprintf(stderr, "Using proxy %s:%u\n", + context->http_proxy_address, + context->http_proxy_port); + } + + if (port) { + +#ifdef LWS_OPENSSL_SUPPORT + context->use_ssl = ssl_cert_filepath != NULL && + ssl_private_key_filepath != NULL; + if (context->use_ssl) + fprintf(stderr, " Compiled with SSL support, " + "using it\n"); + else + fprintf(stderr, " Compiled with SSL support, " + "not using it\n"); + +#else + if (ssl_cert_filepath != NULL && + ssl_private_key_filepath != NULL) { + fprintf(stderr, " Not compiled for OpenSSl support!\n"); + return NULL; + } + fprintf(stderr, " Compiled without SSL support, " + "serving unencrypted\n"); +#endif + } + + /* ignore SIGPIPE */ +#ifdef WIN32 +#else + signal(SIGPIPE, sigpipe_handler); +#endif + + +#ifdef LWS_OPENSSL_SUPPORT + + /* basic openssl init */ + + SSL_library_init(); + + OpenSSL_add_all_algorithms(); + SSL_load_error_strings(); + + openssl_websocket_private_data_index = + SSL_get_ex_new_index(0, "libwebsockets", NULL, NULL, NULL); + + /* + * Firefox insists on SSLv23 not SSLv3 + * Konq disables SSLv2 by default now, SSLv23 works + */ + + method = (SSL_METHOD *)SSLv23_server_method(); + if (!method) { + fprintf(stderr, "problem creating ssl method: %s\n", + ERR_error_string(ERR_get_error(), ssl_err_buf)); + return NULL; + } + context->ssl_ctx = SSL_CTX_new(method); /* create context */ + if (!context->ssl_ctx) { + fprintf(stderr, "problem creating ssl context: %s\n", + ERR_error_string(ERR_get_error(), ssl_err_buf)); + return NULL; + } + + /* client context */ + + if (port == CONTEXT_PORT_NO_LISTEN) { + method = (SSL_METHOD *)SSLv23_client_method(); + if (!method) { + fprintf(stderr, "problem creating ssl method: %s\n", + ERR_error_string(ERR_get_error(), ssl_err_buf)); + return NULL; + } + /* create context */ + context->ssl_client_ctx = SSL_CTX_new(method); + if (!context->ssl_client_ctx) { + fprintf(stderr, "problem creating ssl context: %s\n", + ERR_error_string(ERR_get_error(), ssl_err_buf)); + return NULL; + } + + /* openssl init for cert verification (for client sockets) */ + + if (!SSL_CTX_load_verify_locations( + context->ssl_client_ctx, NULL, + LWS_OPENSSL_CLIENT_CERTS)) + fprintf(stderr, + "Unable to load SSL Client certs from %s " + "(set by --with-client-cert-dir= in configure) -- " + " client ssl isn't going to work", + LWS_OPENSSL_CLIENT_CERTS); + + /* + * callback allowing user code to load extra verification certs + * helping the client to verify server identity + */ + + context->protocols[0].callback(context, NULL, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS, + context->ssl_client_ctx, NULL, 0); + } + + /* as a server, are we requiring clients to identify themselves? */ + + if (options & LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT) { + + /* absolutely require the client cert */ + + SSL_CTX_set_verify(context->ssl_ctx, + SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + OpenSSL_verify_callback); + + /* + * give user code a chance to load certs into the server + * allowing it to verify incoming client certs + */ + + context->protocols[0].callback(context, NULL, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, + context->ssl_ctx, NULL, 0); + } + + if (context->use_ssl) { + + /* openssl init for server sockets */ + + /* set the local certificate from CertFile */ + n = SSL_CTX_use_certificate_file(context->ssl_ctx, + ssl_cert_filepath, SSL_FILETYPE_PEM); + if (n != 1) { + fprintf(stderr, "problem getting cert '%s': %s\n", + ssl_cert_filepath, + ERR_error_string(ERR_get_error(), ssl_err_buf)); + return NULL; + } + /* set the private key from KeyFile */ + if (SSL_CTX_use_PrivateKey_file(context->ssl_ctx, + ssl_private_key_filepath, SSL_FILETYPE_PEM) != 1) { + fprintf(stderr, "ssl problem getting key '%s': %s\n", + ssl_private_key_filepath, + ERR_error_string(ERR_get_error(), ssl_err_buf)); + return NULL; + } + /* verify private key */ + if (!SSL_CTX_check_private_key(context->ssl_ctx)) { + fprintf(stderr, "Private SSL key doesn't match cert\n"); + return NULL; + } + + /* SSL is happy and has a cert it's content with */ + } +#endif + + /* selftest */ + + if (lws_b64_selftest()) + return NULL; + + /* fd hashtable init */ + + for (n = 0; n < FD_HASHTABLE_MODULUS; n++) + context->fd_hashtable[n].length = 0; + + /* set up our external listening socket we serve on */ + + if (port) { + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + fprintf(stderr, "ERROR opening socket"); + return NULL; + } + + /* allow us to restart even if old sockets in TIME_WAIT */ + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, + (const void *)&opt, sizeof(opt)); + + /* Disable Nagle */ + opt = 1; + setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, + (const void *)&opt, sizeof(opt)); + + bzero((char *) &serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + if (interf == NULL) + serv_addr.sin_addr.s_addr = INADDR_ANY; + else + interface_to_sa(interf, &serv_addr, + sizeof(serv_addr)); + serv_addr.sin_port = htons(port); + + n = bind(sockfd, (struct sockaddr *) &serv_addr, + sizeof(serv_addr)); + if (n < 0) { + fprintf(stderr, "ERROR on binding to port %d (%d %d)\n", + port, n, errno); + return NULL; + } + + wsi = malloc(sizeof(struct libwebsocket)); + memset(wsi, 0, sizeof(struct libwebsocket)); + wsi->sock = sockfd; + wsi->count_active_extensions = 0; + wsi->mode = LWS_CONNMODE_SERVER_LISTENER; + insert_wsi(context, wsi); + + listen(sockfd, 5); + fprintf(stderr, " Listening on port %d\n", port); + + /* list in the internal poll array */ + + context->fds[context->fds_count].fd = sockfd; + context->fds[context->fds_count++].events = POLLIN; + + /* external POLL support via protocol 0 */ + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_ADD_POLL_FD, + (void *)(long)sockfd, NULL, POLLIN); + + } + + /* + * drop any root privs for this process + * to listen on port < 1023 we would have needed root, but now we are + * listening, we don't want the power for anything else + */ +#ifdef WIN32 +#else + if (gid != -1) + if (setgid(gid)) + fprintf(stderr, "setgid: %s\n", strerror(errno)); + if (uid != -1) + if (setuid(uid)) + fprintf(stderr, "setuid: %s\n", strerror(errno)); +#endif + + /* set up our internal broadcast trigger sockets per-protocol */ + + for (context->count_protocols = 0; + protocols[context->count_protocols].callback; + context->count_protocols++) { + + debug(" Protocol: %s\n", protocols[context->count_protocols].name); + + protocols[context->count_protocols].owning_server = context; + protocols[context->count_protocols].protocol_index = + context->count_protocols; + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + fprintf(stderr, "ERROR opening socket"); + return NULL; + } + + /* allow us to restart even if old sockets in TIME_WAIT */ + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, + sizeof(opt)); + + bzero((char *) &serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + serv_addr.sin_port = 0; /* pick the port for us */ + + n = bind(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); + if (n < 0) { + fprintf(stderr, "ERROR on binding to port %d (%d %d)\n", + port, n, errno); + return NULL; + } + + slen = sizeof cli_addr; + n = getsockname(fd, (struct sockaddr *)&cli_addr, &slen); + if (n < 0) { + fprintf(stderr, "getsockname failed\n"); + return NULL; + } + protocols[context->count_protocols].broadcast_socket_port = + ntohs(cli_addr.sin_port); + listen(fd, 5); + + debug(" Protocol %s broadcast socket %d\n", + protocols[context->count_protocols].name, + ntohs(cli_addr.sin_port)); + + /* dummy wsi per broadcast proxy socket */ + + wsi = malloc(sizeof(struct libwebsocket)); + memset(wsi, 0, sizeof(struct libwebsocket)); + wsi->sock = fd; + wsi->mode = LWS_CONNMODE_BROADCAST_PROXY_LISTENER; + wsi->count_active_extensions = 0; + /* note which protocol we are proxying */ + wsi->protocol_index_for_broadcast_proxy = + context->count_protocols; + insert_wsi(context, wsi); + + /* list in internal poll array */ + + context->fds[context->fds_count].fd = fd; + context->fds[context->fds_count].events = POLLIN; + context->fds[context->fds_count].revents = 0; + context->fds_count++; + + /* external POLL support via protocol 0 */ + context->protocols[0].callback(context, wsi, + LWS_CALLBACK_ADD_POLL_FD, + (void *)(long)fd, NULL, POLLIN); + } + + /* + * give all extensions a chance to create any per-context + * allocations they need + */ + + m = LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT; + if (port) + m = LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT; + + if (extensions) { + while (extensions->callback) { + debug(" Extension: %s\n", extensions->name); + extensions->callback(context, extensions, + NULL, m, NULL, NULL, 0); + extensions++; + } + } + + return context; +} + + +#ifndef LWS_NO_FORK + +/** + * libwebsockets_fork_service_loop() - Optional helper function forks off + * a process for the websocket server loop. + * You don't have to use this but if not, you + * have to make sure you are calling + * libwebsocket_service periodically to service + * the websocket traffic + * @context: server context returned by creation function + */ + +int +libwebsockets_fork_service_loop(struct libwebsocket_context *context) +{ + int fd; + struct sockaddr_in cli_addr; + int n; + int p; + + n = fork(); + if (n < 0) + return n; + + if (!n) { + + /* main process context */ + + /* + * set up the proxy sockets to allow broadcast from + * service process context + */ + + for (p = 0; p < context->count_protocols; p++) { + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + fprintf(stderr, "Unable to create socket\n"); + return -1; + } + cli_addr.sin_family = AF_INET; + cli_addr.sin_port = htons( + context->protocols[p].broadcast_socket_port); + cli_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + n = connect(fd, (struct sockaddr *)&cli_addr, + sizeof cli_addr); + if (n < 0) { + fprintf(stderr, "Unable to connect to " + "broadcast socket %d, %s\n", + n, strerror(errno)); + return -1; + } + + context->protocols[p].broadcast_socket_user_fd = fd; + } + + return 0; + } + +#ifdef HAVE_SYS_PRCTL_H + /* we want a SIGHUP when our parent goes down */ + prctl(PR_SET_PDEATHSIG, SIGHUP); +#endif + + /* in this forked process, sit and service websocket connections */ + + while (1) { + if (libwebsocket_service(context, 1000)) + break; +#ifndef HAVE_SYS_PRCTL_H +/* + * on systems without prctl() (i.e. anything but linux) we can notice that our + * parent is dead if getppid() returns 1. FIXME apparently this is not true for + * solaris, could remember ppid right after fork and wait for it to change. + */ + + if (getppid() == 1) + break; +#endif + } + + + return 1; +} + +#endif + +/** + * libwebsockets_get_protocol() - Returns a protocol pointer from a websocket + * connection. + * @wsi: pointer to struct websocket you want to know the protocol of + * + * + * This is useful to get the protocol to broadcast back to from inside + * the callback. + */ + +const struct libwebsocket_protocols * +libwebsockets_get_protocol(struct libwebsocket *wsi) +{ + return wsi->protocol; +} + +/** + * libwebsockets_broadcast() - Sends a buffer to the callback for all active + * connections of the given protocol. + * @protocol: pointer to the protocol you will broadcast to all members of + * @buf: buffer containing the data to be broadcase. NOTE: this has to be + * allocated with LWS_SEND_BUFFER_PRE_PADDING valid bytes before + * the pointer and LWS_SEND_BUFFER_POST_PADDING afterwards in the + * case you are calling this function from callback context. + * @len: length of payload data in buf, starting from buf. + * + * This function allows bulk sending of a packet to every connection using + * the given protocol. It does not send the data directly; instead it calls + * the callback with a reason type of LWS_CALLBACK_BROADCAST. If the callback + * wants to actually send the data for that connection, the callback itself + * should call libwebsocket_write(). + * + * libwebsockets_broadcast() can be called from another fork context without + * having to take any care about data visibility between the processes, it'll + * "just work". + */ + + +int +libwebsockets_broadcast(const struct libwebsocket_protocols *protocol, + unsigned char *buf, size_t len) +{ + struct libwebsocket_context *context = protocol->owning_server; + int n; + int m; + struct libwebsocket *wsi; + + if (!protocol->broadcast_socket_user_fd) { + /* + * We are either running unforked / flat, or we are being + * called from poll thread context + * eg, from a callback. In that case don't use sockets for + * broadcast IPC (since we can't open a socket connection to + * a socket listening on our own thread) but directly do the + * send action. + * + * Locking is not needed because we are by definition being + * called in the poll thread context and are serialized. + */ + + for (n = 0; n < FD_HASHTABLE_MODULUS; n++) { + + for (m = 0; m < context->fd_hashtable[n].length; m++) { + + wsi = context->fd_hashtable[n].wsi[m]; + + if (wsi->mode != LWS_CONNMODE_WS_SERVING) + continue; + + /* + * never broadcast to + * non-established connections + */ + if (wsi->state != WSI_STATE_ESTABLISHED) + continue; + + /* only broadcast to guys using + * requested protocol + */ + if (wsi->protocol != protocol) + continue; + + wsi->protocol->callback(context, wsi, + LWS_CALLBACK_BROADCAST, + wsi->user_space, + buf, len); + } + } + + return 0; + } + + /* + * We're being called from a different process context than the server + * loop. Instead of broadcasting directly, we send our + * payload on a socket to do the IPC; the server process will serialize + * the broadcast action in its main poll() loop. + * + * There's one broadcast socket listening for each protocol supported + * set up when the websocket server initializes + */ + + n = send(protocol->broadcast_socket_user_fd, buf, len, MSG_NOSIGNAL); + + return n; +} + +int +libwebsocket_is_final_fragment(struct libwebsocket *wsi) +{ + return wsi->final; +} + +void * +libwebsocket_ensure_user_space(struct libwebsocket *wsi) +{ + /* allocate the per-connection user memory (if any) */ + + if (wsi->protocol->per_session_data_size && !wsi->user_space) { + wsi->user_space = malloc( + wsi->protocol->per_session_data_size); + if (wsi->user_space == NULL) { + fprintf(stderr, "Out of memory for " + "conn user space\n"); + return NULL; + } + memset(wsi->user_space, 0, + wsi->protocol->per_session_data_size); + } + return wsi->user_space; +} diff --git a/libs/libwebsockets/lib/libwebsockets.h b/libs/libwebsockets/lib/libwebsockets.h new file mode 100644 index 0000000000..60e7468cdc --- /dev/null +++ b/libs/libwebsockets/lib/libwebsockets.h @@ -0,0 +1,731 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef __LIBWEBSOCKET_H__ +#define __LIBWEBSOCKET_H__ + +#ifdef __cplusplus +extern "C" { +#include +#endif + +#ifdef WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include +#include "../win32port/win32helpers/websock-w32.h" + +#include "../win32port/win32helpers/gettimeofday.h" + +#define strcasecmp stricmp + +typedef int ssize_t; + +#ifdef LWS_DLL +#ifdef LWS_INTERNAL +#define LWS_EXTERN extern __declspec(dllexport) +#else +#define LWS_EXTERN extern __declspec(dllimport) +#endif +#endif + +#else +#include +#endif + +#ifndef LWS_EXTERN +#define LWS_EXTERN extern +#endif + +#define CONTEXT_PORT_NO_LISTEN 0 +#define MAX_MUX_RECURSION 2 + +enum libwebsocket_context_options { + LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK = 1, + LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT = 2, +}; + +enum libwebsocket_callback_reasons { + LWS_CALLBACK_ESTABLISHED, + LWS_CALLBACK_CLIENT_CONNECTION_ERROR, + LWS_CALLBACK_CLIENT_ESTABLISHED, + LWS_CALLBACK_CLOSED, + LWS_CALLBACK_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE_PONG, + LWS_CALLBACK_CLIENT_WRITEABLE, + LWS_CALLBACK_SERVER_WRITEABLE, + LWS_CALLBACK_HTTP, + LWS_CALLBACK_BROADCAST, + LWS_CALLBACK_FILTER_NETWORK_CONNECTION, + LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION, + LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, + LWS_CALLBACK_CONFIRM_EXTENSION_OKAY, + LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED, + /* external poll() management support */ + LWS_CALLBACK_ADD_POLL_FD, + LWS_CALLBACK_DEL_POLL_FD, + LWS_CALLBACK_SET_MODE_POLL_FD, + LWS_CALLBACK_CLEAR_MODE_POLL_FD, +}; + +enum libwebsocket_extension_callback_reasons { + LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONSTRUCT, + LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE, + LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION, + LWS_EXT_CALLBACK_DESTROY, + LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING, + LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED, + LWS_EXT_CALLBACK_PACKET_RX_PREPARSE, + LWS_EXT_CALLBACK_PACKET_TX_PRESEND, + LWS_EXT_CALLBACK_PACKET_TX_DO_SEND, + LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX, + LWS_EXT_CALLBACK_FLUSH_PENDING_TX, + LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX, + LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION, + LWS_EXT_CALLBACK_1HZ, + LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE, + LWS_EXT_CALLBACK_IS_WRITEABLE, +}; + +enum libwebsocket_write_protocol { + LWS_WRITE_TEXT, + LWS_WRITE_BINARY, + LWS_WRITE_CONTINUATION, + LWS_WRITE_HTTP, + + /* special 04+ opcodes */ + + LWS_WRITE_CLOSE, + LWS_WRITE_PING, + LWS_WRITE_PONG, + + /* flags */ + + LWS_WRITE_NO_FIN = 0x40, + /* + * client packet payload goes out on wire unmunged + * only useful for security tests since normal servers cannot + * decode the content if used + */ + LWS_WRITE_CLIENT_IGNORE_XOR_MASK = 0x80 +}; + +/* + * you need these to look at headers that have been parsed if using the + * LWS_CALLBACK_FILTER_CONNECTION callback. If a header from the enum + * list below is absent, .token = NULL and token_len = 0. Otherwise .token + * points to .token_len chars containing that header content. + */ + +struct lws_tokens { + char *token; + int token_len; +}; + +enum lws_token_indexes { + WSI_TOKEN_GET_URI, + WSI_TOKEN_HOST, + WSI_TOKEN_CONNECTION, + WSI_TOKEN_KEY1, + WSI_TOKEN_KEY2, + WSI_TOKEN_PROTOCOL, + WSI_TOKEN_UPGRADE, + WSI_TOKEN_ORIGIN, + WSI_TOKEN_DRAFT, + WSI_TOKEN_CHALLENGE, + + /* new for 04 */ + WSI_TOKEN_KEY, + WSI_TOKEN_VERSION, + WSI_TOKEN_SWORIGIN, + + /* new for 05 */ + WSI_TOKEN_EXTENSIONS, + + /* client receives these */ + WSI_TOKEN_ACCEPT, + WSI_TOKEN_NONCE, + WSI_TOKEN_HTTP, + WSI_TOKEN_MUXURL, + + /* always last real token index*/ + WSI_TOKEN_COUNT, + /* parser state additions */ + WSI_TOKEN_NAME_PART, + WSI_TOKEN_SKIPPING, + WSI_TOKEN_SKIPPING_SAW_CR, + WSI_PARSING_COMPLETE, + WSI_INIT_TOKEN_MUXURL, +}; + +/* + * From 06 spec + 1000 + + 1000 indicates a normal closure, meaning whatever purpose the + connection was established for has been fulfilled. + + 1001 + + 1001 indicates that an endpoint is "going away", such as a server + going down, or a browser having navigated away from a page. + + 1002 + + 1002 indicates that an endpoint is terminating the connection due + to a protocol error. + + 1003 + + 1003 indicates that an endpoint is terminating the connection + because it has received a type of data it cannot accept (e.g. an + endpoint that understands only text data may send this if it + receives a binary message.) + + 1004 + + 1004 indicates that an endpoint is terminating the connection + because it has received a message that is too large. +*/ + +enum lws_close_status { + LWS_CLOSE_STATUS_NOSTATUS = 0, + LWS_CLOSE_STATUS_NORMAL = 1000, + LWS_CLOSE_STATUS_GOINGAWAY = 1001, + LWS_CLOSE_STATUS_PROTOCOL_ERR = 1002, + LWS_CLOSE_STATUS_UNACCEPTABLE_OPCODE = 1003, + LWS_CLOSE_STATUS_PAYLOAD_TOO_LARGE = 1004, +}; + +struct libwebsocket; +struct libwebsocket_context; +struct libwebsocket_extension; + +/** + * callback_function() - User server actions + * @context: Websockets context + * @wsi: Opaque websocket instance pointer + * @reason: The reason for the call + * @user: Pointer to per-session user data allocated by library + * @in: Pointer used for some callback reasons + * @len: Length set for some callback reasons + * + * This callback is the way the user controls what is served. All the + * protocol detail is hidden and handled by the library. + * + * For each connection / session there is user data allocated that is + * pointed to by "user". You set the size of this user data area when + * the library is initialized with libwebsocket_create_server. + * + * You get an opportunity to initialize user data when called back with + * LWS_CALLBACK_ESTABLISHED reason. + * + * LWS_CALLBACK_ESTABLISHED: after the server completes a handshake with + * an incoming client + * + * LWS_CALLBACK_CLIENT_CONNECTION_ERROR: the request client connection has + * been unable to complete a handshake with the remote server + * + * LWS_CALLBACK_CLIENT_ESTABLISHED: after your client connection completed + * a handshake with the remote server + * + * LWS_CALLBACK_CLOSED: when the websocket session ends + * + * LWS_CALLBACK_BROADCAST: signal to send to client (you would use + * libwebsocket_write() taking care about the + * special buffer requirements + * + * LWS_CALLBACK_RECEIVE: data has appeared for this server endpoint from a + * remote client, it can be found at *in and is + * len bytes long + * + * LWS_CALLBACK_CLIENT_RECEIVE_PONG: if you elected to see PONG packets, + * they appear with this callback reason. PONG + * packets only exist in 04+ protocol + * + * LWS_CALLBACK_CLIENT_RECEIVE: data has appeared from the server for the + * client connection, it can be found at *in and + * is len bytes long + * + * LWS_CALLBACK_HTTP: an http request has come from a client that is not + * asking to upgrade the connection to a websocket + * one. This is a chance to serve http content, + * for example, to send a script to the client + * which will then open the websockets connection. + * @in points to the URI path requested and + * libwebsockets_serve_http_file() makes it very + * simple to send back a file to the client. + * + * LWS_CALLBACK_CLIENT_WRITEABLE: + * LWS_CALLBACK_SERVER_WRITEABLE: If you call + * libwebsocket_callback_on_writable() on a connection, you will + * get one of these callbacks coming when the connection socket + * is able to accept another write packet without blocking. + * If it already was able to take another packet without blocking, + * you'll get this callback at the next call to the service loop + * function. Notice that CLIENTs get LWS_CALLBACK_CLIENT_WRITEABLE + * and servers get LWS_CALLBACK_SERVER_WRITEABLE. + * + * LWS_CALLBACK_FILTER_NETWORK_CONNECTION: called when a client connects to + * the server at network level; the connection is accepted but then + * passed to this callback to decide whether to hang up immediately + * or not, based on the client IP. @user contains the connection + * socket's descriptor. Return non-zero to terminate + * the connection before sending or receiving anything. + * Because this happens immediately after the network connection + * from the client, there's no websocket protocol selected yet so + * this callback is issued only to protocol 0. + * + * LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: called when the handshake has + * been received and parsed from the client, but the response is + * not sent yet. Return non-zero to disallow the connection. + * @user is a pointer to an array of struct lws_tokens, you can + * use the header enums lws_token_indexes from libwebsockets.h + * to check for and read the supported header presence and + * content before deciding to allow the handshake to proceed or + * to kill the connection. + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to perform extra SSL_CTX_load_verify_locations() or similar + * calls to direct OpenSSL where to find certificates the client + * can use to confirm the remote server identity. @user is the + * OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to load extra certifcates into the server which allow it to + * verify the validity of certificates returned by clients. @user + * is the server's OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: if the + * libwebsockets context was created with the option + * LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this + * callback is generated during OpenSSL verification of the cert + * sent from the client. It is sent to protocol[0] callback as + * no protocol has been negotiated on the connection yet. + * Notice that the libwebsockets context and wsi are both NULL + * during this callback. See + * http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html + * to understand more detail about the OpenSSL callback that + * generates this libwebsockets callback and the meanings of the + * arguments passed. In this callback, @user is the x509_ctx, + * @in is the ssl pointer and @len is preverify_ok + * Notice that this callback maintains libwebsocket return + * conventions, return 0 to mean the cert is OK or 1 to fail it. + * This also means that if you don't handle this callback then + * the default callback action of returning 0 allows the client + * certificates. + * + * LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: this callback happens + * when a client handshake is being compiled. @user is NULL, + * @in is a char **, it's pointing to a char * which holds the + * next location in the header buffer where you can add + * headers, and @len is the remaining space in the header buffer, + * which is typically some hundreds of bytes. So, to add a canned + * cookie, your handler code might look similar to: + * + * char **p = (char **)in; + * + * if (len < 100) + * return 1; + * + * *p += sprintf(*p, "Cookie: a=b\x0d\x0a"); + * + * return 0; + * + * Notice if you add anything, you just have to take care about + * the CRLF on the line you added. Obviously this callback is + * optional, if you don't handle it everything is fine. + * + * Notice the callback is coming to protocols[0] all the time, + * because there is no specific protocol handshook yet. + * + * LWS_CALLBACK_CONFIRM_EXTENSION_OKAY: When the server handshake code + * sees that it does support a requested extension, before + * accepting the extension by additing to the list sent back to + * the client it gives this callback just to check that it's okay + * to use that extension. It calls back to the requested protocol + * and with @in being the extension name, @len is 0 and @user is + * valid. Note though at this time the ESTABLISHED callback hasn't + * happened yet so if you initialize @user content there, @user + * content during this callback might not be useful for anything. + * Notice this callback comes to protocols[0]. + * + * LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: When a client + * connection is being prepared to start a handshake to a server, + * each supported extension is checked with protocols[0] callback + * with this reason, giving the user code a chance to suppress the + * claim to support that extension by returning non-zero. If + * unhandled, by default 0 will be returned and the extension + * support included in the header to the server. Notice this + * callback comes to protocols[0]. + * + * The next four reasons are optional and only need taking care of if you + * will be integrating libwebsockets sockets into an external polling + * array. + * + * LWS_CALLBACK_ADD_POLL_FD: libwebsocket deals with its poll() loop + * internally, but in the case you are integrating with another + * server you will need to have libwebsocket sockets share a + * polling array with the other server. This and the other + * POLL_FD related callbacks let you put your specialized + * poll array interface code in the callback for protocol 0, the + * first protocol you support, usually the HTTP protocol in the + * serving case. This callback happens when a socket needs to be + * added to the polling loop: @user contains the fd, and + * @len is the events bitmap (like, POLLIN). If you are using the + * internal polling loop (the "service" callback), you can just + * ignore these callbacks. + * + * LWS_CALLBACK_DEL_POLL_FD: This callback happens when a socket descriptor + * needs to be removed from an external polling array. @user is + * the socket desricptor. If you are using the internal polling + * loop, you can just ignore it. + * + * LWS_CALLBACK_SET_MODE_POLL_FD: This callback happens when libwebsockets + * wants to modify the events for the socket descriptor in @user. + * The handler should OR @len on to the events member of the pollfd + * struct for this socket descriptor. If you are using the + * internal polling loop, you can just ignore it. + * + * LWS_CALLBACK_CLEAR_MODE_POLL_FD: This callback occurs when libwebsockets + * wants to modify the events for the socket descriptor in @user. + * The handler should AND ~@len on to the events member of the + * pollfd struct for this socket descriptor. If you are using the + * internal polling loop, you can just ignore it. + */ +LWS_EXTERN int callback(struct libwebsocket_context * context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +typedef int (callback_function)(struct libwebsocket_context * context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + + +/** + * extension_callback_function() - Hooks to allow extensions to operate + * @context: Websockets context + * @ext: This extension + * @wsi: Opaque websocket instance pointer + * @reason: The reason for the call + * @user: Pointer to per-session user data allocated by library + * @in: Pointer used for some callback reasons + * @len: Length set for some callback reasons + * + * Each extension that is active on a particular connection receives + * callbacks during the connection lifetime to allow the extension to + * operate on websocket data and manage itself. + * + * Libwebsockets takes care of allocating and freeing "user" memory for + * each active extension on each connection. That is what is pointed to + * by the @user parameter. + * + * LWS_EXT_CALLBACK_CONSTRUCT: called when the server has decided to + * select this extension from the list provided by the client, + * just before the server will send back the handshake accepting + * the connection with this extension active. This gives the + * extension a chance to initialize its connection context found + * in @user. + * + * LWS_EXT_CALLBACK_CLIENT_CONSTRUCT: same as LWS_EXT_CALLBACK_CONSTRUCT + * but called when client is instantiating this extension. Some + * extensions will work the same on client and server side and then + * you can just merge handlers for both CONSTRUCTS. + * + * LWS_EXT_CALLBACK_DESTROY: called when the connection the extension was + * being used on is about to be closed and deallocated. It's the + * last chance for the extension to deallocate anything it has + * allocated in the user data (pointed to by @user) before the + * user data is deleted. This same callback is used whether you + * are in client or server instantiation context. + * + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE: when this extension was active on + * a connection, and a packet of data arrived at the connection, + * it is passed to this callback to give the extension a chance to + * change the data, eg, decompress it. @user is pointing to the + * extension's private connection context data, @in is pointing + * to an lws_tokens struct, it consists of a char * pointer called + * token, and an int called token_len. At entry, these are + * set to point to the received buffer and set to the content + * length. If the extension will grow the content, it should use + * a new buffer allocated in its private user context data and + * set the pointed-to lws_tokens members to point to its buffer. + * + * LWS_EXT_CALLBACK_PACKET_TX_PRESEND: this works the same way as + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE above, except it gives the + * extension a chance to change websocket data just before it will + * be sent out. Using the same lws_token pointer scheme in @in, + * the extension can change the buffer and the length to be + * transmitted how it likes. Again if it wants to grow the + * buffer safely, it should copy the data into its own buffer and + * set the lws_tokens token pointer to it. + */ +LWS_EXTERN int extension_callback(struct libwebsocket_context * context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, void *user, + void *in, size_t len); + +typedef int (extension_callback_function)(struct libwebsocket_context * context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, void *user, + void *in, size_t len); + +/** + * struct libwebsocket_protocols - List of protocols and handlers server + * supports. + * @name: Protocol name that must match the one given in the client + * Javascript new WebSocket(url, 'protocol') name + * @callback: The service callback used for this protocol. It allows the + * service action for an entire protocol to be encapsulated in + * the protocol-specific callback + * @per_session_data_size: Each new connection using this protocol gets + * this much memory allocated on connection establishment and + * freed on connection takedown. A pointer to this per-connection + * allocation is passed into the callback in the 'user' parameter + * @owning_server: the server init call fills in this opaque pointer when + * registering this protocol with the server. + * @broadcast_socket_port: the server init call fills this in with the + * localhost port number used to forward broadcasts for this + * protocol + * @broadcast_socket_user_fd: the server init call fills this in ... the main() + * process context can write to this socket to perform broadcasts + * (use the libwebsockets_broadcast() api to do this instead, + * it works from any process context) + * @protocol_index: which protocol we are starting from zero + * + * This structure represents one protocol supported by the server. An + * array of these structures is passed to libwebsocket_create_server() + * allows as many protocols as you like to be handled by one server. + */ + +struct libwebsocket_protocols { + const char *name; + callback_function *callback; + size_t per_session_data_size; + + /* + * below are filled in on server init and can be left uninitialized, + * no need for user to use them directly either + */ + + struct libwebsocket_context *owning_server; + int broadcast_socket_port; + int broadcast_socket_user_fd; + int protocol_index; +}; + +/** + * struct libwebsocket_extension - An extension we know how to cope with + * + * @name: Formal extension name, eg, "deflate-stream" + * @callback: Service callback + * @per_session_data_size: Libwebsockets will auto-malloc this much + * memory for the use of the extension, a pointer + * to it comes in the @user callback parameter + * @per_context_private_data: Optional storage for this externsion that + * is per-context, so it can track stuff across + * all sessions, etc, if it wants + */ + +struct libwebsocket_extension { + const char *name; + extension_callback_function *callback; + size_t per_session_data_size; + void * per_context_private_data; +}; + + + +LWS_EXTERN struct libwebsocket_context * +libwebsocket_create_context(int port, const char * interf, + struct libwebsocket_protocols *protocols, + struct libwebsocket_extension *extensions, + const char *ssl_cert_filepath, + const char *ssl_private_key_filepath, int gid, int uid, + unsigned int options); + +LWS_EXTERN void +libwebsocket_context_destroy(struct libwebsocket_context *context); + +LWS_EXTERN int +libwebsockets_fork_service_loop(struct libwebsocket_context *context); + +LWS_EXTERN int +libwebsocket_service(struct libwebsocket_context *context, int timeout_ms); + +LWS_EXTERN int +libwebsocket_service_fd(struct libwebsocket_context *context, + struct pollfd *pollfd); + +/* + * IMPORTANT NOTICE! + * + * When sending with websocket protocol (LWS_WRITE_TEXT or LWS_WRITE_BINARY) + * the send buffer has to have LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE + * buf, and LWS_SEND_BUFFER_POST_PADDING bytes valid AFTER (buf + len). + * + * This allows us to add protocol info before and after the data, and send as + * one packet on the network without payload copying, for maximum efficiency. + * + * So for example you need this kind of code to use libwebsocket_write with a + * 128-byte payload + * + * char buf[LWS_SEND_BUFFER_PRE_PADDING + 128 + LWS_SEND_BUFFER_POST_PADDING]; + * + * // fill your part of the buffer... for example here it's all zeros + * memset(&buf[LWS_SEND_BUFFER_PRE_PADDING], 0, 128); + * + * libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], 128); + * + * When sending LWS_WRITE_HTTP, there is no protocol addition and you can just + * use the whole buffer without taking care of the above. + */ + +/* + * this is the frame nonce plus two header plus 8 length + * there's an additional two for mux extension per mux nesting level + * 2 byte prepend on close will already fit because control frames cannot use + * the big length style + */ + +#define LWS_SEND_BUFFER_PRE_PADDING (4 + 10 + (2 * MAX_MUX_RECURSION)) +#define LWS_SEND_BUFFER_POST_PADDING 1 + +LWS_EXTERN int +libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, size_t len, + enum libwebsocket_write_protocol protocol); + +LWS_EXTERN int +libwebsockets_serve_http_file(struct libwebsocket *wsi, const char *file, + const char *content_type); + +/* notice - you need the pre- and post- padding allocation for buf below */ + +LWS_EXTERN int +libwebsockets_broadcast(const struct libwebsocket_protocols *protocol, + unsigned char *buf, size_t len); + +LWS_EXTERN const struct libwebsocket_protocols * +libwebsockets_get_protocol(struct libwebsocket *wsi); + +LWS_EXTERN int +libwebsocket_callback_on_writable(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_EXTERN int +libwebsocket_callback_on_writable_all_protocol( + const struct libwebsocket_protocols *protocol); + +LWS_EXTERN int +libwebsocket_get_socket_fd(struct libwebsocket *wsi); + +LWS_EXTERN int +libwebsocket_is_final_fragment(struct libwebsocket *wsi); + +LWS_EXTERN void * +libwebsocket_ensure_user_space(struct libwebsocket *wsi); + +LWS_EXTERN int +libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable); + +LWS_EXTERN size_t +libwebsockets_remaining_packet_payload(struct libwebsocket *wsi); + +LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one); + +LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect_extended(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one, + void *userdata); + +LWS_EXTERN const char * +libwebsocket_canonical_hostname(struct libwebsocket_context *context); + + +LWS_EXTERN void +libwebsockets_get_peer_addresses(int fd, char *name, int name_len, + char *rip, int rip_len); + +LWS_EXTERN void +libwebsockets_hangup_on_client(struct libwebsocket_context *context, int fd); + +LWS_EXTERN void +libwebsocket_close_and_free_session(struct libwebsocket_context *context, + struct libwebsocket *wsi, enum lws_close_status); + +LWS_EXTERN int +libwebsockets_get_random(struct libwebsocket_context *context, + void *buf, int len); + +LWS_EXTERN int +lws_send_pipe_choked(struct libwebsocket *wsi); + +LWS_EXTERN unsigned char * +libwebsockets_SHA1(const unsigned char *d, size_t n, unsigned char *md); + +LWS_EXTERN int +lws_b64_encode_string(const char *in, int in_len, char *out, int out_size); + +LWS_EXTERN int +lws_b64_decode_string(const char *in, char *out, int out_size); + +LWS_EXTERN struct libwebsocket_extension libwebsocket_internal_extensions[]; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libwebsockets/lib/md5.c b/libs/libwebsockets/lib/md5.c new file mode 100644 index 0000000000..042db3b8e4 --- /dev/null +++ b/libs/libwebsockets/lib/md5.c @@ -0,0 +1,217 @@ +/* + * Modified from Polarssl here + * http://polarssl.org/show_source?file=md5 + * under GPL2 or later + */ + +#include +#include + + +#define GET_ULONG_LE(n, b, i) \ +{ \ + (n) = ((unsigned long)(b)[i]) \ + | ((unsigned long)(b)[(i) + 1] << 8) \ + | ((unsigned long)(b)[(i) + 2] << 16) \ + | ((unsigned long)(b)[(i) + 3] << 24); \ +} + +#define PUT_ULONG_LE(n, b, i) \ +{ \ + (b)[i] = (unsigned char)(n); \ + (b)[(i) + 1] = (unsigned char)((n) >> 8); \ + (b)[(i) + 2] = (unsigned char)((n) >> 16); \ + (b)[(i) + 3] = (unsigned char)((n) >> 24); \ +} + +static const unsigned char md5_padding[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const unsigned long state_init[] = { + 0, 0, 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476 +}; + +static void +md5_process(unsigned long *state, const unsigned char *data) +{ + unsigned long X[16], A, B, C, D; + int v; + + for (v = 0; v < 16; v++) + GET_ULONG_LE(X[v], data, v << 2); + +#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define P(a, b, c, d, k, s, t) { a += F(b, c, d) + X[k] + t; a = S(a, s) + b; } + + A = state[0]; + B = state[1]; + C = state[2]; + D = state[3]; + +#define F(x, y, z) (z ^ (x & (y ^ z))) + + P(A, B, C, D, 0, 7, 0xD76AA478); + P(D, A, B, C, 1, 12, 0xE8C7B756); + P(C, D, A, B, 2, 17, 0x242070DB); + P(B, C, D, A, 3, 22, 0xC1BDCEEE); + P(A, B, C, D, 4, 7, 0xF57C0FAF); + P(D, A, B, C, 5, 12, 0x4787C62A); + P(C, D, A, B, 6, 17, 0xA8304613); + P(B, C, D, A, 7, 22, 0xFD469501); + P(A, B, C, D, 8, 7, 0x698098D8); + P(D, A, B, C, 9, 12, 0x8B44F7AF); + P(C, D, A, B, 10, 17, 0xFFFF5BB1); + P(B, C, D, A, 11, 22, 0x895CD7BE); + P(A, B, C, D, 12, 7, 0x6B901122); + P(D, A, B, C, 13, 12, 0xFD987193); + P(C, D, A, B, 14, 17, 0xA679438E); + P(B, C, D, A, 15, 22, 0x49B40821); + +#undef F + +#define F(x, y, z) (y ^ (z & (x ^ y))) + + P(A, B, C, D, 1, 5, 0xF61E2562); + P(D, A, B, C, 6, 9, 0xC040B340); + P(C, D, A, B, 11, 14, 0x265E5A51); + P(B, C, D, A, 0, 20, 0xE9B6C7AA); + P(A, B, C, D, 5, 5, 0xD62F105D); + P(D, A, B, C, 10, 9, 0x02441453); + P(C, D, A, B, 15, 14, 0xD8A1E681); + P(B, C, D, A, 4, 20, 0xE7D3FBC8); + P(A, B, C, D, 9, 5, 0x21E1CDE6); + P(D, A, B, C, 14, 9, 0xC33707D6); + P(C, D, A, B, 3, 14, 0xF4D50D87); + P(B, C, D, A, 8, 20, 0x455A14ED); + P(A, B, C, D, 13, 5, 0xA9E3E905); + P(D, A, B, C, 2, 9, 0xFCEFA3F8); + P(C, D, A, B, 7, 14, 0x676F02D9); + P(B, C, D, A, 12, 20, 0x8D2A4C8A); + +#undef F + +#define F(x, y, z) (x ^ y ^ z) + + P(A, B, C, D, 5, 4, 0xFFFA3942); + P(D, A, B, C, 8, 11, 0x8771F681); + P(C, D, A, B, 11, 16, 0x6D9D6122); + P(B, C, D, A, 14, 23, 0xFDE5380C); + P(A, B, C, D, 1, 4, 0xA4BEEA44); + P(D, A, B, C, 4, 11, 0x4BDECFA9); + P(C, D, A, B, 7, 16, 0xF6BB4B60); + P(B, C, D, A, 10, 23, 0xBEBFBC70); + P(A, B, C, D, 13, 4, 0x289B7EC6); + P(D, A, B, C, 0, 11, 0xEAA127FA); + P(C, D, A, B, 3, 16, 0xD4EF3085); + P(B, C, D, A, 6, 23, 0x04881D05); + P(A, B, C, D, 9, 4, 0xD9D4D039); + P(D, A, B, C, 12, 11, 0xE6DB99E5); + P(C, D, A, B, 15, 16, 0x1FA27CF8); + P(B, C, D, A, 2, 23, 0xC4AC5665); + +#undef F + +#define F(x, y, z) (y ^ (x | ~z)) + + P(A, B, C, D, 0, 6, 0xF4292244); + P(D, A, B, C, 7, 10, 0x432AFF97); + P(C, D, A, B, 14, 15, 0xAB9423A7); + P(B, C, D, A, 5, 21, 0xFC93A039); + P(A, B, C, D, 12, 6, 0x655B59C3); + P(D, A, B, C, 3, 10, 0x8F0CCC92); + P(C, D, A, B, 10, 15, 0xFFEFF47D); + P(B, C, D, A, 1, 21, 0x85845DD1); + P(A, B, C, D, 8, 6, 0x6FA87E4F); + P(D, A, B, C, 15, 10, 0xFE2CE6E0); + P(C, D, A, B, 6, 15, 0xA3014314); + P(B, C, D, A, 13, 21, 0x4E0811A1); + P(A, B, C, D, 4, 6, 0xF7537E82); + P(D, A, B, C, 11, 10, 0xBD3AF235); + P(C, D, A, B, 2, 15, 0x2AD7D2BB); + P(B, C, D, A, 9, 21, 0xEB86D391); + +#undef F + + state[0] += A; + state[1] += B; + state[2] += C; + state[3] += D; +} + +static +void md5_update(unsigned long *state, unsigned char *buffer, + const unsigned char *input, int ilen) +{ + int fill; + unsigned long left; + + if (ilen <= 0) + return; + + left = state[0] & 0x3F; + fill = 64 - left; + + state[0] += ilen; + state[0] &= 0xFFFFFFFF; + + if (state[0] < (unsigned long)ilen) + state[1]++; + + if (left && ilen >= fill) { + memcpy(buffer + left, input, fill); + md5_process(&state[2], buffer); + input += fill; + ilen -= fill; + left = 0; + } + + while (ilen >= 64) { + md5_process(&state[2], input); + input += 64; + ilen -= 64; + } + + if (ilen > 0) + memcpy(buffer + left, input, ilen); +} + +void +MD5(const unsigned char *input, int ilen, unsigned char *output) +{ + unsigned long last, padn; + unsigned long high, low; + unsigned char msglen[8]; + unsigned long state[6]; + unsigned char buffer[64]; + + memcpy(&state[0], &state_init[0], sizeof(state_init)); + + md5_update(state, buffer, input, ilen); + + high = (state[0] >> 29) | (state[1] << 3); + low = state[0] << 3; + + PUT_ULONG_LE(low, msglen, 0); + PUT_ULONG_LE(high, msglen, 4); + + last = state[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + md5_update(state, buffer, md5_padding, padn); + md5_update(state, buffer, msglen, 8); + + PUT_ULONG_LE(state[2], output, 0); + PUT_ULONG_LE(state[3], output, 4); + PUT_ULONG_LE(state[4], output, 8); + PUT_ULONG_LE(state[5], output, 12); +} + diff --git a/libs/libwebsockets/lib/parsers.c b/libs/libwebsockets/lib/parsers.c new file mode 100644 index 0000000000..a185971610 --- /dev/null +++ b/libs/libwebsockets/lib/parsers.c @@ -0,0 +1,1967 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "private-libwebsockets.h" + +const struct lws_tokens lws_tokens[WSI_TOKEN_COUNT] = { + + /* win32 can't do C99 */ + +/* [WSI_TOKEN_GET_URI] = */{ "GET ", 4 }, +/* [WSI_TOKEN_HOST] = */{ "Host:", 5 }, +/* [WSI_TOKEN_CONNECTION] = */{ "Connection:", 11 }, +/* [WSI_TOKEN_KEY1] = */{ "Sec-WebSocket-Key1:", 19 }, +/* [WSI_TOKEN_KEY2] = */{ "Sec-WebSocket-Key2:", 19 }, +/* [WSI_TOKEN_PROTOCOL] = */{ "Sec-WebSocket-Protocol:", 23 }, +/* [WSI_TOKEN_UPGRADE] = */{ "Upgrade:", 8 }, +/* [WSI_TOKEN_ORIGIN] = */{ "Origin:", 7 }, +/* [WSI_TOKEN_DRAFT] = */{ "Sec-WebSocket-Draft:", 20 }, +/* [WSI_TOKEN_CHALLENGE] = */{ "\x0d\x0a", 2 }, + +/* [WSI_TOKEN_KEY] = */{ "Sec-WebSocket-Key:", 18 }, +/* [WSI_TOKEN_VERSION] = */{ "Sec-WebSocket-Version:", 22 }, +/* [WSI_TOKEN_SWORIGIN]= */{ "Sec-WebSocket-Origin:", 21 }, + +/* [WSI_TOKEN_EXTENSIONS] = */{ "Sec-WebSocket-Extensions:", 25 }, + +/* [WSI_TOKEN_ACCEPT] = */{ "Sec-WebSocket-Accept:", 21 }, +/* [WSI_TOKEN_NONCE] = */{ "Sec-WebSocket-Nonce:", 20 }, +/* [WSI_TOKEN_HTTP] = */{ "HTTP/1.1 ", 9 }, +/* [WSI_TOKEN_MUXURL] = */{ "", -1 }, + +}; + +int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c) +{ + int n; + + switch (wsi->parser_state) { + case WSI_TOKEN_GET_URI: + case WSI_TOKEN_HOST: + case WSI_TOKEN_CONNECTION: + case WSI_TOKEN_KEY1: + case WSI_TOKEN_KEY2: + case WSI_TOKEN_PROTOCOL: + case WSI_TOKEN_UPGRADE: + case WSI_TOKEN_ORIGIN: + case WSI_TOKEN_SWORIGIN: + case WSI_TOKEN_DRAFT: + case WSI_TOKEN_CHALLENGE: + case WSI_TOKEN_KEY: + case WSI_TOKEN_VERSION: + case WSI_TOKEN_ACCEPT: + case WSI_TOKEN_NONCE: + case WSI_TOKEN_EXTENSIONS: + case WSI_TOKEN_HTTP: + case WSI_TOKEN_MUXURL: + + debug("WSI_TOKEN_(%d) '%c'\n", wsi->parser_state, c); + + /* collect into malloc'd buffers */ + /* optional space swallow */ + if (!wsi->utf8_token[wsi->parser_state].token_len && c == ' ') + break; + + /* special case space terminator for get-uri */ + if (wsi->parser_state == WSI_TOKEN_GET_URI && c == ' ') { + wsi->utf8_token[wsi->parser_state].token[ + wsi->utf8_token[wsi->parser_state].token_len] = '\0'; + wsi->parser_state = WSI_TOKEN_SKIPPING; + break; + } + + /* allocate appropriate memory */ + if (wsi->utf8_token[wsi->parser_state].token_len == + wsi->current_alloc_len - 1) { + /* need to extend */ + wsi->current_alloc_len += LWS_ADDITIONAL_HDR_ALLOC; + if (wsi->current_alloc_len >= LWS_MAX_HEADER_LEN) { + /* it's waaay to much payload, fail it */ + strcpy(wsi->utf8_token[wsi->parser_state].token, + "!!! Length exceeded maximum supported !!!"); + wsi->parser_state = WSI_TOKEN_SKIPPING; + break; + } + wsi->utf8_token[wsi->parser_state].token = + realloc(wsi->utf8_token[wsi->parser_state].token, + wsi->current_alloc_len); + } + + /* bail at EOL */ + if (wsi->parser_state != WSI_TOKEN_CHALLENGE && c == '\x0d') { + wsi->utf8_token[wsi->parser_state].token[ + wsi->utf8_token[wsi->parser_state].token_len] = '\0'; + wsi->parser_state = WSI_TOKEN_SKIPPING_SAW_CR; + debug("*\n"); + break; + } + + wsi->utf8_token[wsi->parser_state].token[ + wsi->utf8_token[wsi->parser_state].token_len++] = c; + + /* per-protocol end of headers management */ + + if (wsi->parser_state != WSI_TOKEN_CHALLENGE) + break; + + /* -76 has no version header ... server */ + if (!wsi->utf8_token[WSI_TOKEN_VERSION].token_len && + wsi->mode != LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY && + wsi->utf8_token[wsi->parser_state].token_len != 8) + break; + + /* -76 has no version header ... client */ + if (!wsi->utf8_token[WSI_TOKEN_VERSION].token_len && + wsi->mode == LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY && + wsi->utf8_token[wsi->parser_state].token_len != 16) + break; + + /* <= 03 has old handshake with version header needs 8 bytes */ + if (wsi->utf8_token[WSI_TOKEN_VERSION].token_len && + atoi(wsi->utf8_token[WSI_TOKEN_VERSION].token) < 4 && + wsi->utf8_token[wsi->parser_state].token_len != 8) + break; + + /* no payload challenge in 01 + */ + + if (wsi->utf8_token[WSI_TOKEN_VERSION].token_len && + atoi(wsi->utf8_token[WSI_TOKEN_VERSION].token) > 0) { + wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len = 0; + free(wsi->utf8_token[WSI_TOKEN_CHALLENGE].token); + wsi->utf8_token[WSI_TOKEN_CHALLENGE].token = NULL; + } + + /* For any supported protocol we have enough payload */ + + debug("Setting WSI_PARSING_COMPLETE\n"); + wsi->parser_state = WSI_PARSING_COMPLETE; + break; + + case WSI_INIT_TOKEN_MUXURL: + wsi->parser_state = WSI_TOKEN_MUXURL; + wsi->current_alloc_len = LWS_INITIAL_HDR_ALLOC; + + wsi->utf8_token[wsi->parser_state].token = + malloc(wsi->current_alloc_len); + wsi->utf8_token[wsi->parser_state].token_len = 0; + break; + + /* collecting and checking a name part */ + case WSI_TOKEN_NAME_PART: + debug("WSI_TOKEN_NAME_PART '%c'\n", c); + + if (wsi->name_buffer_pos == sizeof(wsi->name_buffer) - 1) { + /* name bigger than we can handle, skip until next */ + wsi->parser_state = WSI_TOKEN_SKIPPING; + break; + } + wsi->name_buffer[wsi->name_buffer_pos++] = c; + wsi->name_buffer[wsi->name_buffer_pos] = '\0'; + + for (n = 0; n < WSI_TOKEN_COUNT; n++) { + if (wsi->name_buffer_pos != lws_tokens[n].token_len) + continue; + if (strcasecmp(lws_tokens[n].token, wsi->name_buffer)) + continue; + debug("known hdr '%s'\n", wsi->name_buffer); + + /* + * WSORIGIN is protocol equiv to ORIGIN, + * JWebSocket likes to send it, map to ORIGIN + */ + if (n == WSI_TOKEN_SWORIGIN) + n = WSI_TOKEN_ORIGIN; + + wsi->parser_state = WSI_TOKEN_GET_URI + n; + + n = WSI_TOKEN_COUNT; + + /* If the header has been seen already, just append */ + if (wsi->utf8_token[wsi->parser_state].token) + continue; + + wsi->current_alloc_len = LWS_INITIAL_HDR_ALLOC; + wsi->utf8_token[wsi->parser_state].token = + malloc(wsi->current_alloc_len); + wsi->utf8_token[wsi->parser_state].token_len = 0; + } + + /* colon delimiter means we just don't know this name */ + + if (wsi->parser_state == WSI_TOKEN_NAME_PART && c == ':') { + debug("skipping unknown header '%s'\n", + wsi->name_buffer); + wsi->parser_state = WSI_TOKEN_SKIPPING; + break; + } + + if (wsi->parser_state != WSI_TOKEN_CHALLENGE) + break; + + /* don't look for payload when it can just be http headers */ + + if (!wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len) { + /* they're HTTP headers, not websocket upgrade! */ + debug("Setting WSI_PARSING_COMPLETE " + "from http headers\n"); + wsi->parser_state = WSI_PARSING_COMPLETE; + } + + /* 04 version has no packet content after end of hdrs */ + + if (wsi->utf8_token[WSI_TOKEN_VERSION].token_len && + atoi(wsi->utf8_token[WSI_TOKEN_VERSION].token) >= 4) { + debug("04 header completed\n"); + wsi->parser_state = WSI_PARSING_COMPLETE; + wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len = 0; + free(wsi->utf8_token[WSI_TOKEN_CHALLENGE].token); + wsi->utf8_token[WSI_TOKEN_CHALLENGE].token = NULL; + } + + /* client parser? */ + + if (wsi->ietf_spec_revision >= 4) { + debug("04 header completed\n"); + wsi->parser_state = WSI_PARSING_COMPLETE; + } + + break; + + /* skipping arg part of a name we didn't recognize */ + case WSI_TOKEN_SKIPPING: + debug("WSI_TOKEN_SKIPPING '%c'\n", c); + if (c == '\x0d') + wsi->parser_state = WSI_TOKEN_SKIPPING_SAW_CR; + break; + case WSI_TOKEN_SKIPPING_SAW_CR: + debug("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c); + if (c == '\x0a') + wsi->parser_state = WSI_TOKEN_NAME_PART; + else + wsi->parser_state = WSI_TOKEN_SKIPPING; + wsi->name_buffer_pos = 0; + break; + /* we're done, ignore anything else */ + case WSI_PARSING_COMPLETE: + debug("WSI_PARSING_COMPLETE '%c'\n", c); + break; + + default: /* keep gcc happy */ + break; + } + + return 0; +} + +unsigned char +xor_no_mask(struct libwebsocket *wsi, unsigned char c) +{ + return c; +} + +unsigned char +xor_mask_04(struct libwebsocket *wsi, unsigned char c) +{ + c ^= wsi->masking_key_04[wsi->frame_mask_index++]; + if (wsi->frame_mask_index == 20) + wsi->frame_mask_index = 0; + + return c; +} + +unsigned char +xor_mask_05(struct libwebsocket *wsi, unsigned char c) +{ + return c ^ wsi->frame_masking_nonce_04[(wsi->frame_mask_index++) & 3]; +} + + + +int +libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c) +{ + int n; + unsigned char buf[20 + 4]; + struct lws_tokens eff_buf; + int handled; + int m; + +#if 0 + fprintf(stderr, "RX: %02X ", c); +#endif + + switch (wsi->lws_rx_parse_state) { + case LWS_RXPS_NEW: + + switch (wsi->ietf_spec_revision) { + /* Firefox 4.0b6 likes this as of 30 Oct 2010 */ + case 0: + if (c == 0xff) + wsi->lws_rx_parse_state = LWS_RXPS_SEEN_76_FF; + if (c == 0) { + wsi->lws_rx_parse_state = + LWS_RXPS_EAT_UNTIL_76_FF; + wsi->rx_user_buffer_head = 0; + } + break; + case 4: + case 5: + case 6: + wsi->all_zero_nonce = 1; + wsi->frame_masking_nonce_04[0] = c; + if (c) + wsi->all_zero_nonce = 0; + wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_1; + break; + case 7: + case 8: + case 13: + /* + * no prepended frame key any more + */ + wsi->all_zero_nonce = 1; + goto handle_first; + + default: + fprintf(stderr, "libwebsocket_rx_sm doesn't know " + "about spec version %d\n", wsi->ietf_spec_revision); + break; + } + break; + case LWS_RXPS_04_MASK_NONCE_1: + wsi->frame_masking_nonce_04[1] = c; + if (c) + wsi->all_zero_nonce = 0; + wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_2; + break; + case LWS_RXPS_04_MASK_NONCE_2: + wsi->frame_masking_nonce_04[2] = c; + if (c) + wsi->all_zero_nonce = 0; + wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_3; + break; + case LWS_RXPS_04_MASK_NONCE_3: + wsi->frame_masking_nonce_04[3] = c; + if (c) + wsi->all_zero_nonce = 0; + + if (wsi->protocol->owning_server->options & + LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK) + goto post_mask; + + if (wsi->ietf_spec_revision > 4) + goto post_sha1; + + /* + * we are able to compute the frame key now + * it's a SHA1 of ( frame nonce we were just sent, concatenated + * with the connection masking key we computed at handshake + * time ) -- yeah every frame from the client invokes a SHA1 + * for no real reason so much for lightweight. + */ + + buf[0] = wsi->frame_masking_nonce_04[0]; + buf[1] = wsi->frame_masking_nonce_04[1]; + buf[2] = wsi->frame_masking_nonce_04[2]; + buf[3] = wsi->frame_masking_nonce_04[3]; + + memcpy(buf + 4, wsi->masking_key_04, 20); + + /* + * wsi->frame_mask_04 will be our recirculating 20-byte XOR key + * for this frame + */ + + SHA1((unsigned char *)buf, 4 + 20, wsi->frame_mask_04); + +post_sha1: + + /* + * start from the zero'th byte in the XOR key buffer since + * this is the start of a frame with a new key + */ + + wsi->frame_mask_index = 0; + +post_mask: + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_1; + break; + + /* + * 04 logical framing from the spec (all this is masked when incoming + * and has to be unmasked) + * + * We ignore the possibility of extension data because we don't + * negotiate any extensions at the moment. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-------+-+-------------+-------------------------------+ + * |F|R|R|R| opcode|R| Payload len | Extended payload length | + * |I|S|S|S| (4) |S| (7) | (16/63) | + * |N|V|V|V| |V| | (if payload len==126/127) | + * | |1|2|3| |4| | | + * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + * | Extended payload length continued, if payload len == 127 | + * + - - - - - - - - - - - - - - - +-------------------------------+ + * | | Extension data | + * +-------------------------------+ - - - - - - - - - - - - - - - + + * : : + * +---------------------------------------------------------------+ + * : Application data : + * +---------------------------------------------------------------+ + * + * We pass payload through to userland as soon as we get it, ignoring + * FIN. It's up to userland to buffer it up if it wants to see a + * whole unfragmented block of the original size (which may be up to + * 2^63 long!) + */ + + case LWS_RXPS_04_FRAME_HDR_1: +handle_first: + + /* + * 04 spec defines the opcode like this: (1, 2, and 3 are + * "control frame" opcodes which may not be fragmented or + * have size larger than 126) + * + * frame-opcode = + * %x0 ; continuation frame + * / %x1 ; connection close + * / %x2 ; ping + * / %x3 ; pong + * / %x4 ; text frame + * / %x5 ; binary frame + * / %x6-F ; reserved + * + * FIN (b7) + */ + + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); + + if (c & 0x70) + fprintf(stderr, + "Frame has unknown extension bits set 1 %02X\n", c); + + /* translate all incoming opcodes into v7+ map */ + if (wsi->ietf_spec_revision < 7) + switch (c & 0xf) { + case LWS_WS_OPCODE_04__CONTINUATION: + wsi->opcode = LWS_WS_OPCODE_07__CONTINUATION; + break; + case LWS_WS_OPCODE_04__CLOSE: + wsi->opcode = LWS_WS_OPCODE_07__CLOSE; + break; + case LWS_WS_OPCODE_04__PING: + wsi->opcode = LWS_WS_OPCODE_07__PING; + break; + case LWS_WS_OPCODE_04__PONG: + wsi->opcode = LWS_WS_OPCODE_07__PONG; + break; + case LWS_WS_OPCODE_04__TEXT_FRAME: + wsi->opcode = LWS_WS_OPCODE_07__TEXT_FRAME; + break; + case LWS_WS_OPCODE_04__BINARY_FRAME: + wsi->opcode = LWS_WS_OPCODE_07__BINARY_FRAME; + break; + default: + fprintf(stderr, "reserved opcodes not " + "usable pre v7 protocol\n"); + return -1; + } + else + wsi->opcode = c & 0xf; + + wsi->final = !!((c >> 7) & 1); + + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN: + + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); + + if ((c & 0x80) && wsi->ietf_spec_revision < 7) { + fprintf(stderr, "Frame has extensions " + "set illegally 2\n"); + /* kill the connection */ + return -1; + } + + wsi->this_frame_masked = !!(c & 0x80); + + switch (c & 0x7f) { + case 126: + /* control frames are not allowed to have big lengths */ + if (wsi->opcode & 8) + goto illegal_ctl_length; + + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2; + break; + case 127: + /* control frames are not allowed to have big lengths */ + if (wsi->opcode & 8) + goto illegal_ctl_length; + + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8; + break; + default: + wsi->rx_packet_length = c & 0x7f; + if (wsi->this_frame_masked) + wsi->lws_rx_parse_state = + LWS_RXPS_07_COLLECT_FRAME_KEY_1; + else + wsi->lws_rx_parse_state = + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; + break; + } + break; + + case LWS_RXPS_04_FRAME_HDR_LEN16_2: + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); + + wsi->rx_packet_length = c << 8; + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN16_1: + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); + + wsi->rx_packet_length |= c; + if (wsi->this_frame_masked) + wsi->lws_rx_parse_state = + LWS_RXPS_07_COLLECT_FRAME_KEY_1; + else + wsi->lws_rx_parse_state = + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_8: + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); + if (c & 0x80) { + fprintf(stderr, "b63 of length must be zero\n"); + /* kill the connection */ + return -1; + } +#if defined __LP64__ + wsi->rx_packet_length = ((size_t)c) << 56; +#else + wsi->rx_packet_length = 0; +#endif + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_7: + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); +#if defined __LP64__ + wsi->rx_packet_length |= ((size_t)c) << 48; +#endif + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_6: + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); +#if defined __LP64__ + wsi->rx_packet_length |= ((size_t)c) << 40; +#endif + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_5: + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); +#if defined __LP64__ + wsi->rx_packet_length |= ((size_t)c) << 32; +#endif + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_4: + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); + wsi->rx_packet_length |= ((size_t)c) << 24; + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_3: + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); + wsi->rx_packet_length |= ((size_t)c) << 16; + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_2: + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); + wsi->rx_packet_length |= ((size_t)c) << 8; + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_1: + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); + wsi->rx_packet_length |= ((size_t)c); + if (wsi->this_frame_masked) + wsi->lws_rx_parse_state = + LWS_RXPS_07_COLLECT_FRAME_KEY_1; + else + wsi->lws_rx_parse_state = + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; + break; + + case LWS_RXPS_EAT_UNTIL_76_FF: + if (c == 0xff) { + wsi->lws_rx_parse_state = LWS_RXPS_NEW; + goto issue; + } + wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + + (wsi->rx_user_buffer_head++)] = c; + + if (wsi->rx_user_buffer_head != MAX_USER_RX_BUFFER) + break; +issue: + if (wsi->protocol->callback) + wsi->protocol->callback(wsi->protocol->owning_server, + wsi, LWS_CALLBACK_RECEIVE, + wsi->user_space, + &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING], + wsi->rx_user_buffer_head); + wsi->rx_user_buffer_head = 0; + break; + case LWS_RXPS_SEEN_76_FF: + if (c) + break; + + debug("Seen that client is requesting " + "a v76 close, sending ack\n"); + buf[0] = 0xff; + buf[1] = 0; + n = libwebsocket_write(wsi, buf, 2, LWS_WRITE_HTTP); + if (n < 0) { + fprintf(stderr, "ERROR writing to socket"); + return -1; + } + debug(" v76 close ack sent, server closing skt\n"); + /* returning < 0 will get it closed in parent */ + return -1; + + case LWS_RXPS_PULLING_76_LENGTH: + break; + + + case LWS_RXPS_07_COLLECT_FRAME_KEY_1: + wsi->frame_masking_nonce_04[0] = c; + if (c) + wsi->all_zero_nonce = 0; + wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2; + break; + + case LWS_RXPS_07_COLLECT_FRAME_KEY_2: + wsi->frame_masking_nonce_04[1] = c; + if (c) + wsi->all_zero_nonce = 0; + wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3; + break; + + case LWS_RXPS_07_COLLECT_FRAME_KEY_3: + wsi->frame_masking_nonce_04[2] = c; + if (c) + wsi->all_zero_nonce = 0; + wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4; + break; + + case LWS_RXPS_07_COLLECT_FRAME_KEY_4: + wsi->frame_masking_nonce_04[3] = c; + if (c) + wsi->all_zero_nonce = 0; + wsi->lws_rx_parse_state = + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; + wsi->frame_mask_index = 0; + break; + + + case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED: + if (wsi->ietf_spec_revision < 4 || + (wsi->all_zero_nonce && wsi->ietf_spec_revision >= 5)) + wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + + (wsi->rx_user_buffer_head++)] = c; + else + wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + + (wsi->rx_user_buffer_head++)] = + wsi->xor_mask(wsi, c); + + if (--wsi->rx_packet_length == 0) { + wsi->lws_rx_parse_state = LWS_RXPS_NEW; + goto spill; + } + if (wsi->rx_user_buffer_head != MAX_USER_RX_BUFFER) + break; +spill: + /* + * is this frame a control packet we should take care of at this + * layer? If so service it and hide it from the user callback + */ + + debug("spill on %s\n", wsi->protocol->name); + + switch (wsi->opcode) { + case LWS_WS_OPCODE_07__CLOSE: + /* is this an acknowledgement of our close? */ + if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) { + /* + * fine he has told us he is closing too, let's + * finish our close + */ + debug("seen client close ack\n"); + return -1; + } + debug("server sees client close packet\n"); + /* parrot the close packet payload back */ + n = libwebsocket_write(wsi, (unsigned char *) + &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING], + wsi->rx_user_buffer_head, LWS_WRITE_CLOSE); + wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY; + /* close the connection */ + return -1; + + case LWS_WS_OPCODE_07__PING: + /* parrot the ping packet payload back as a pong */ + n = libwebsocket_write(wsi, (unsigned char *) + &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING], + wsi->rx_user_buffer_head, LWS_WRITE_PONG); + /* ... then just drop it */ + wsi->rx_user_buffer_head = 0; + return 0; + + case LWS_WS_OPCODE_07__PONG: + /* keep the statistics... */ + wsi->pings_vs_pongs--; + /* ... then just drop it */ + wsi->rx_user_buffer_head = 0; + return 0; + + case LWS_WS_OPCODE_07__TEXT_FRAME: + case LWS_WS_OPCODE_07__BINARY_FRAME: + break; + + default: + + debug("passing opcode %x up to exts\n", wsi->opcode); + + /* + * It's something special we can't understand here. + * Pass the payload up to the extension's parsing + * state machine. + */ + + eff_buf.token = &wsi->rx_user_buffer[ + LWS_SEND_BUFFER_PRE_PADDING]; + eff_buf.token_len = wsi->rx_user_buffer_head; + + handled = 0; + for (n = 0; n < wsi->count_active_extensions; n++) { + m = wsi->active_extensions[n]->callback( + wsi->protocol->owning_server, + wsi->active_extensions[n], wsi, + LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX, + wsi->active_extensions_user[n], + &eff_buf, 0); + if (m) + handled = 1; + } + + if (!handled) + fprintf(stderr, "Unhandled extended opcode " + "0x%x - ignoring frame\n", wsi->opcode); + + wsi->rx_user_buffer_head = 0; + return 0; + } + + /* + * No it's real payload, pass it up to the user callback. + * It's nicely buffered with the pre-padding taken care of + * so it can be sent straight out again using libwebsocket_write + */ + + wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + + wsi->rx_user_buffer_head] = '\0'; + + if (wsi->protocol->callback) + wsi->protocol->callback(wsi->protocol->owning_server, + wsi, LWS_CALLBACK_RECEIVE, + wsi->user_space, + &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING], + wsi->rx_user_buffer_head); + else + fprintf(stderr, "No callback on payload spill!\n"); + + wsi->rx_user_buffer_head = 0; + break; + } + + return 0; + +illegal_ctl_length: + + fprintf(stderr, "Control frame asking for " + "extended length is illegal\n"); + /* kill the connection */ + return -1; +} + + +int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c) +{ + int n; + unsigned char buf[20 + 4]; + int callback_action = LWS_CALLBACK_CLIENT_RECEIVE; + int handled; + struct lws_tokens eff_buf; + int m; + + debug(" CRX: %02X %d\n", c, wsi->lws_rx_parse_state); + + switch (wsi->lws_rx_parse_state) { + case LWS_RXPS_NEW: + + switch (wsi->ietf_spec_revision) { + /* Firefox 4.0b6 likes this as of 30 Oct */ + case 0: + if (c == 0xff) + wsi->lws_rx_parse_state = LWS_RXPS_SEEN_76_FF; + if (c == 0) { + wsi->lws_rx_parse_state = + LWS_RXPS_EAT_UNTIL_76_FF; + wsi->rx_user_buffer_head = 0; + } + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 13: + /* + * 04 logical framing from the spec (all this is masked when + * incoming and has to be unmasked) + * + * We ignore the possibility of extension data because we don't + * negotiate any extensions at the moment. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-------+-+-------------+-------------------------------+ + * |F|R|R|R| opcode|R| Payload len | Extended payload length | + * |I|S|S|S| (4) |S| (7) | (16/63) | + * |N|V|V|V| |V| | (if payload len==126/127) | + * | |1|2|3| |4| | | + * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + * | Extended payload length continued, if payload len == 127 | + * + - - - - - - - - - - - - - - - +-------------------------------+ + * | | Extension data | + * +-------------------------------+ - - - - - - - - - - - - - - - + + * : : + * +---------------------------------------------------------------+ + * : Application data : + * +---------------------------------------------------------------+ + * + * We pass payload through to userland as soon as we get it, ignoring + * FIN. It's up to userland to buffer it up if it wants to see a + * whole unfragmented block of the original size (which may be up to + * 2^63 long!) + * + * Notice in v7 RSV4 is set to indicate 32-bit frame key is coming in + * after length, unlike extension data which is now deprecated, this + * does not impact the payload length calculation. + */ + + /* + * 04 spec defines the opcode like this: (1, 2, and 3 are + * "control frame" opcodes which may not be fragmented or + * have size larger than 126) + * + * frame-opcode = + * %x0 ; continuation frame + * / %x1 ; connection close + * / %x2 ; ping + * / %x3 ; pong + * / %x4 ; text frame + * / %x5 ; binary frame + * / %x6-F ; reserved + * + * FIN (b7) + */ + + if (c & 0x70) + fprintf(stderr, "Frame has unknown extension " + "bits set on first framing byte %02X\n", c); + + if (wsi->ietf_spec_revision < 7) + switch (c & 0xf) { + case LWS_WS_OPCODE_04__CONTINUATION: + wsi->opcode = + LWS_WS_OPCODE_07__CONTINUATION; + break; + case LWS_WS_OPCODE_04__CLOSE: + wsi->opcode = LWS_WS_OPCODE_07__CLOSE; + break; + case LWS_WS_OPCODE_04__PING: + wsi->opcode = LWS_WS_OPCODE_07__PING; + break; + case LWS_WS_OPCODE_04__PONG: + wsi->opcode = LWS_WS_OPCODE_07__PONG; + break; + case LWS_WS_OPCODE_04__TEXT_FRAME: + wsi->opcode = + LWS_WS_OPCODE_07__TEXT_FRAME; + break; + case LWS_WS_OPCODE_04__BINARY_FRAME: + wsi->opcode = + LWS_WS_OPCODE_07__BINARY_FRAME; + break; + default: + fprintf(stderr, "reserved opcodes not " + "usable pre v7 protocol\n"); + return -1; + } + else + wsi->opcode = c & 0xf; + + wsi->final = !!((c >> 7) & 1); + + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN; + break; + + default: + fprintf(stderr, "client_rx_sm doesn't know how " + "to handle spec version %02d\n", + wsi->ietf_spec_revision); + break; + } + break; + + + case LWS_RXPS_04_FRAME_HDR_LEN: + + if ((c & 0x80) && wsi->ietf_spec_revision < 7) { + fprintf(stderr, + "Frame has extensions set illegally 4\n"); + /* kill the connection */ + return -1; + } + + wsi->this_frame_masked = !!(c & 0x80); + + switch (c & 0x7f) { + case 126: + /* control frames are not allowed to have big lengths */ + if (wsi->opcode & 8) + goto illegal_ctl_length; + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2; + break; + case 127: + /* control frames are not allowed to have big lengths */ + if (wsi->opcode & 8) + goto illegal_ctl_length; + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8; + break; + default: + wsi->rx_packet_length = c; + if (wsi->this_frame_masked) + wsi->lws_rx_parse_state = + LWS_RXPS_07_COLLECT_FRAME_KEY_1; + else { + if (c) + wsi->lws_rx_parse_state = + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; + else { + wsi->lws_rx_parse_state = LWS_RXPS_NEW; + goto spill; + } + } + break; + } + break; + + case LWS_RXPS_04_FRAME_HDR_LEN16_2: + wsi->rx_packet_length = c << 8; + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN16_1: + wsi->rx_packet_length |= c; + if (wsi->this_frame_masked) + wsi->lws_rx_parse_state = + LWS_RXPS_07_COLLECT_FRAME_KEY_1; + else { + if (wsi->rx_packet_length) + wsi->lws_rx_parse_state = + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; + else { + wsi->lws_rx_parse_state = LWS_RXPS_NEW; + goto spill; + } + } + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_8: + if (c & 0x80) { + fprintf(stderr, "b63 of length must be zero\n"); + /* kill the connection */ + return -1; + } +#if defined __LP64__ + wsi->rx_packet_length = ((size_t)c) << 56; +#else + wsi->rx_packet_length = 0; +#endif + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_7: +#if defined __LP64__ + wsi->rx_packet_length |= ((size_t)c) << 48; +#endif + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_6: +#if defined __LP64__ + wsi->rx_packet_length |= ((size_t)c) << 40; +#endif + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_5: +#if defined __LP64__ + wsi->rx_packet_length |= ((size_t)c) << 32; +#endif + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_4: + wsi->rx_packet_length |= ((size_t)c) << 24; + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_3: + wsi->rx_packet_length |= ((size_t)c) << 16; + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_2: + wsi->rx_packet_length |= ((size_t)c) << 8; + wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1; + break; + + case LWS_RXPS_04_FRAME_HDR_LEN64_1: + wsi->rx_packet_length |= (size_t)c; + if (wsi->this_frame_masked) + wsi->lws_rx_parse_state = + LWS_RXPS_07_COLLECT_FRAME_KEY_1; + else { + if (wsi->rx_packet_length) + wsi->lws_rx_parse_state = + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; + else { + wsi->lws_rx_parse_state = LWS_RXPS_NEW; + goto spill; + } + } + break; + + case LWS_RXPS_07_COLLECT_FRAME_KEY_1: + wsi->frame_masking_nonce_04[0] = c; + if (c) + wsi->all_zero_nonce = 0; + wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2; + break; + + case LWS_RXPS_07_COLLECT_FRAME_KEY_2: + wsi->frame_masking_nonce_04[1] = c; + if (c) + wsi->all_zero_nonce = 0; + wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3; + break; + + case LWS_RXPS_07_COLLECT_FRAME_KEY_3: + wsi->frame_masking_nonce_04[2] = c; + if (c) + wsi->all_zero_nonce = 0; + wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4; + break; + + case LWS_RXPS_07_COLLECT_FRAME_KEY_4: + wsi->frame_masking_nonce_04[3] = c; + if (c) + wsi->all_zero_nonce = 0; + + if (wsi->rx_packet_length) + wsi->lws_rx_parse_state = + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; + else { + wsi->lws_rx_parse_state = LWS_RXPS_NEW; + goto spill; + } + break; + + case LWS_RXPS_EAT_UNTIL_76_FF: + if (c == 0xff) { + wsi->lws_rx_parse_state = LWS_RXPS_NEW; + goto issue; + } + wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + + (wsi->rx_user_buffer_head++)] = c; + + if (wsi->rx_user_buffer_head != MAX_USER_RX_BUFFER) + break; +issue: + if (wsi->protocol->callback) + wsi->protocol->callback(wsi->protocol->owning_server, + wsi, + LWS_CALLBACK_CLIENT_RECEIVE, + wsi->user_space, + &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING], + wsi->rx_user_buffer_head); + wsi->rx_user_buffer_head = 0; + break; + case LWS_RXPS_SEEN_76_FF: + if (c) + break; + + debug("Seen that client is requesting " + "a v76 close, sending ack\n"); + buf[0] = 0xff; + buf[1] = 0; + n = libwebsocket_write(wsi, buf, 2, LWS_WRITE_HTTP); + if (n < 0) { + fprintf(stderr, "ERROR writing to socket"); + return -1; + } + debug(" v76 close ack sent, server closing skt\n"); + /* returning < 0 will get it closed in parent */ + return -1; + + case LWS_RXPS_PULLING_76_LENGTH: + break; + + case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED: + if ((!wsi->this_frame_masked) || wsi->all_zero_nonce) + wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + + (wsi->rx_user_buffer_head++)] = c; + else + wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + + (wsi->rx_user_buffer_head++)] = + wsi->xor_mask(wsi, c); + + if (--wsi->rx_packet_length == 0) { + wsi->lws_rx_parse_state = LWS_RXPS_NEW; + goto spill; + } + if (wsi->rx_user_buffer_head != MAX_USER_RX_BUFFER) + break; +spill: + + handled = 0; + + /* + * is this frame a control packet we should take care of at this + * layer? If so service it and hide it from the user callback + */ + + switch (wsi->opcode) { + case LWS_WS_OPCODE_07__CLOSE: + /* is this an acknowledgement of our close? */ + if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) { + /* + * fine he has told us he is closing too, let's + * finish our close + */ + debug("seen server's close ack\n"); + return -1; + } + debug("client sees server close packet len = %d\n", wsi->rx_user_buffer_head); + /* parrot the close packet payload back */ + n = libwebsocket_write(wsi, (unsigned char *) + &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING], + wsi->rx_user_buffer_head, LWS_WRITE_CLOSE); + debug("client writing close ack returned %d\n", n); + wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY; + /* close the connection */ + return -1; + + case LWS_WS_OPCODE_07__PING: + /* parrot the ping packet payload back as a pong*/ + n = libwebsocket_write(wsi, (unsigned char *) + &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING], + wsi->rx_user_buffer_head, LWS_WRITE_PONG); + handled = 1; + break; + + case LWS_WS_OPCODE_07__PONG: + /* keep the statistics... */ + wsi->pings_vs_pongs--; + + /* issue it */ + callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG; + break; + + case LWS_WS_OPCODE_07__CONTINUATION: + case LWS_WS_OPCODE_07__TEXT_FRAME: + case LWS_WS_OPCODE_07__BINARY_FRAME: + break; + + default: + + debug("Reserved opcode 0x%2X\n", wsi->opcode); + /* + * It's something special we can't understand here. + * Pass the payload up to the extension's parsing + * state machine. + */ + + eff_buf.token = &wsi->rx_user_buffer[ + LWS_SEND_BUFFER_PRE_PADDING]; + eff_buf.token_len = wsi->rx_user_buffer_head; + + for (n = 0; n < wsi->count_active_extensions; n++) { + m = wsi->active_extensions[n]->callback( + wsi->protocol->owning_server, + wsi->active_extensions[n], wsi, + LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX, + wsi->active_extensions_user[n], + &eff_buf, 0); + if (m) + handled = 1; + } + + if (!handled) { + fprintf(stderr, "Unhandled extended opcode " + "0x%x - ignoring frame\n", wsi->opcode); + wsi->rx_user_buffer_head = 0; + + return 0; + } + + break; + } + + /* + * No it's real payload, pass it up to the user callback. + * It's nicely buffered with the pre-padding taken care of + * so it can be sent straight out again using libwebsocket_write + */ + + if (!handled && wsi->protocol->callback) + wsi->protocol->callback(wsi->protocol->owning_server, + wsi, callback_action, + wsi->user_space, + &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING], + wsi->rx_user_buffer_head); + wsi->rx_user_buffer_head = 0; + break; + default: + fprintf(stderr, "client rx illegal state\n"); + return 1; + } + + return 0; + +illegal_ctl_length: + + fprintf(stderr, "Control frame asking for " + "extended length is illegal\n"); + /* kill the connection */ + return -1; + +} + + + +int libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi, + unsigned char *buf, size_t len) +{ + int n; + +#ifdef DEBUG + fprintf(stderr, "received %d byte packet\n", (int)len); + for (n = 0; n < len; n++) + fprintf(stderr, "%02X ", buf[n]); + fprintf(stderr, "\n"); +#endif + + /* let the rx protocol state machine have as much as it needs */ + + n = 0; + while (n < len) + if (libwebsocket_rx_sm(wsi, buf[n++]) < 0) + return -1; + + return 0; +} + + +static int +libwebsocket_0405_frame_mask_generate(struct libwebsocket *wsi) +{ + char buf[4 + 20]; + int n; + + /* fetch the per-frame nonce */ + + n = libwebsockets_get_random(wsi->protocol->owning_server, + wsi->frame_masking_nonce_04, 4); + if (n != 4) { + fprintf(stderr, "Unable to read from random device %s %d\n", + SYSTEM_RANDOM_FILEPATH, n); + return 1; + } + + /* start masking from first byte of masking key buffer */ + wsi->frame_mask_index = 0; + + if (wsi->ietf_spec_revision != 4) + return 0; + + /* 04 only does SHA-1 more complex key */ + + /* + * the frame key is the frame nonce (4 bytes) followed by the + * connection masking key, hashed by SHA1 + */ + + memcpy(buf, wsi->frame_masking_nonce_04, 4); + + memcpy(buf + 4, wsi->masking_key_04, 20); + + /* concatenate the nonce with the connection key then hash it */ + + SHA1((unsigned char *)buf, 4 + 20, wsi->frame_mask_04); + + return 0; +} + +void lws_stderr_hexdump(unsigned char *buf, size_t len) +{ + int n; + int m; + int start; + + fprintf(stderr, "\n"); + + for (n = 0; n < len;) { + start = n; + + fprintf(stderr, "%04X: ", start); + + for (m = 0; m < 16 && n < len; m++) + fprintf(stderr, "%02X ", buf[n++]); + while (m++ < 16) + fprintf(stderr, " "); + + fprintf(stderr, " "); + + for (m = 0; m < 16 && (start + m) < len; m++) { + if (buf[start + m] >= ' ' && buf[start + m] <= 127) + fprintf(stderr, "%c", buf[start + m]); + else + fprintf(stderr, "."); + } + while (m++ < 16) + fprintf(stderr, " "); + + fprintf(stderr, "\n"); + } + fprintf(stderr, "\n"); +} + +int lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len) +{ + int n; + int m; + + /* + * one of the extensions is carrying our data itself? Like mux? + */ + + for (n = 0; n < wsi->count_active_extensions; n++) { + /* + * there can only be active extensions after handshake completed + * so we can rely on protocol being set already in here + */ + m = wsi->active_extensions[n]->callback( + wsi->protocol->owning_server, + wsi->active_extensions[n], wsi, + LWS_EXT_CALLBACK_PACKET_TX_DO_SEND, + wsi->active_extensions_user[n], &buf, len); + if (m < 0) { + fprintf(stderr, "Extension reports fatal error\n"); + return -1; + } + if (m) /* handled */ { +/* fprintf(stderr, "ext sent it\n"); */ + return 0; + } + } + + if (!wsi->sock) + fprintf(stderr, "** error 0 sock but expected to send\n"); + + /* + * nope, send it on the socket directly + */ + +#if 0 + fprintf(stderr, " TX: "); + lws_stderr_hexdump(buf, len); +#endif + +#ifdef LWS_OPENSSL_SUPPORT + if (wsi->ssl) { + n = SSL_write(wsi->ssl, buf, len); + if (n < 0) { + fprintf(stderr, + "ERROR writing to socket\n"); + return -1; + } + } else { +#endif + n = send(wsi->sock, buf, len, MSG_NOSIGNAL); + if (n < 0) { + fprintf(stderr, + "ERROR writing to socket\n"); + return -1; + } +#ifdef LWS_OPENSSL_SUPPORT + } +#endif + return 0; +} + +int +lws_issue_raw_ext_access(struct libwebsocket *wsi, + unsigned char *buf, size_t len) +{ + int ret; + struct lws_tokens eff_buf; + int m; + int n; + + eff_buf.token = (char *)buf; + eff_buf.token_len = len; + + /* + * while we have original buf to spill ourselves, or extensions report + * more in their pipeline + */ + + ret = 1; + while (ret == 1) { + + /* default to nobody has more to spill */ + + ret = 0; + + /* show every extension the new incoming data */ + + for (n = 0; n < wsi->count_active_extensions; n++) { + m = wsi->active_extensions[n]->callback( + wsi->protocol->owning_server, + wsi->active_extensions[n], wsi, + LWS_EXT_CALLBACK_PACKET_TX_PRESEND, + wsi->active_extensions_user[n], &eff_buf, 0); + if (m < 0) { + fprintf(stderr, "Extension: fatal error\n"); + return -1; + } + if (m) + /* + * at least one extension told us he has more + * to spill, so we will go around again after + */ + ret = 1; + } + + /* assuming they left us something to send, send it */ + + if (eff_buf.token_len) + if (lws_issue_raw(wsi, (unsigned char *)eff_buf.token, + eff_buf.token_len)) + return -1; + + /* we used up what we had */ + + eff_buf.token = NULL; + eff_buf.token_len = 0; + + /* + * Did that leave the pipe choked? + */ + + if (!lws_send_pipe_choked(wsi)) + /* no we could add more */ + continue; + + debug("choked\n"); + + /* + * Yes, he's choked. Don't spill the rest now get a callback + * when he is ready to send and take care of it there + */ + libwebsocket_callback_on_writable( + wsi->protocol->owning_server, wsi); + wsi->extension_data_pending = 1; + ret = 0; + } + + debug("written %d bytes to client\n", eff_buf.token_len); + + return 0; +} + +/** + * libwebsocket_write() - Apply protocol then write data to client + * @wsi: Websocket instance (available from user callback) + * @buf: The data to send. For data being sent on a websocket + * connection (ie, not default http), this buffer MUST have + * LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE the pointer + * and an additional LWS_SEND_BUFFER_POST_PADDING bytes valid + * in the buffer after (buf + len). This is so the protocol + * header and trailer data can be added in-situ. + * @len: Count of the data bytes in the payload starting from buf + * @protocol: Use LWS_WRITE_HTTP to reply to an http connection, and one + * of LWS_WRITE_BINARY or LWS_WRITE_TEXT to send appropriate + * data on a websockets connection. Remember to allow the extra + * bytes before and after buf if LWS_WRITE_BINARY or LWS_WRITE_TEXT + * are used. + * + * This function provides the way to issue data back to the client + * for both http and websocket protocols. + * + * In the case of sending using websocket protocol, be sure to allocate + * valid storage before and after buf as explained above. This scheme + * allows maximum efficiency of sending data and protocol in a single + * packet while not burdening the user code with any protocol knowledge. + */ + +int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, + size_t len, enum libwebsocket_write_protocol protocol) +{ + int n; + int pre = 0; + int post = 0; + int shift = 7; + int masked7 = wsi->mode == LWS_CONNMODE_WS_CLIENT && + wsi->xor_mask != xor_no_mask; + unsigned char *dropmask = NULL; + unsigned char is_masked_bit = 0; + + if (len == 0 && protocol != LWS_WRITE_CLOSE) { + fprintf(stderr, "zero length libwebsocket_write attempt\n"); + return 0; + } + + if (protocol == LWS_WRITE_HTTP) + goto send_raw; + + /* websocket protocol, either binary or text */ + + if (wsi->state != WSI_STATE_ESTABLISHED) + return -1; + + switch (wsi->ietf_spec_revision) { + /* chrome likes this as of 30 Oct 2010 */ + /* Firefox 4.0b6 likes this as of 30 Oct 2010 */ + case 0: + if ((protocol & 0xf) == LWS_WRITE_BINARY) { + /* in binary mode we send 7-bit used length blocks */ + pre = 1; + while (len & (127 << shift)) { + pre++; + shift += 7; + } + n = 0; + shift -= 7; + while (shift >= 0) { + if (shift) + buf[0 - pre + n] = + ((len >> shift) & 127) | 0x80; + else + buf[0 - pre + n] = + ((len >> shift) & 127); + n++; + shift -= 7; + } + break; + } + + /* frame type = text, length-free spam mode */ + + pre = 1; + buf[-pre] = 0; + buf[len] = 0xff; /* EOT marker */ + post = 1; + break; + + case 7: + case 8: + case 13: + if (masked7) { + pre += 4; + dropmask = &buf[0 - pre]; + is_masked_bit = 0x80; + } + /* fallthru */ + case 4: + case 5: + case 6: + switch (protocol & 0xf) { + case LWS_WRITE_TEXT: + if (wsi->ietf_spec_revision < 7) + n = LWS_WS_OPCODE_04__TEXT_FRAME; + else + n = LWS_WS_OPCODE_07__TEXT_FRAME; + break; + case LWS_WRITE_BINARY: + if (wsi->ietf_spec_revision < 7) + n = LWS_WS_OPCODE_04__BINARY_FRAME; + else + n = LWS_WS_OPCODE_07__BINARY_FRAME; + break; + case LWS_WRITE_CONTINUATION: + if (wsi->ietf_spec_revision < 7) + n = LWS_WS_OPCODE_04__CONTINUATION; + else + n = LWS_WS_OPCODE_07__CONTINUATION; + break; + + case LWS_WRITE_CLOSE: + if (wsi->ietf_spec_revision < 7) + n = LWS_WS_OPCODE_04__CLOSE; + else + n = LWS_WS_OPCODE_07__CLOSE; + + /* + * v5 mandates the first byte of close packet + * in both client and server directions + */ + + switch (wsi->ietf_spec_revision) { + case 0: + case 4: + break; + case 5: + /* we can do this because we demand post-buf */ + + if (len < 1) + len = 1; + + switch (wsi->mode) { + case LWS_CONNMODE_WS_SERVING: + /* + fprintf(stderr, "LWS_WRITE_CLOSE S\n"); + */ + buf[0] = 'S'; + break; + case LWS_CONNMODE_WS_CLIENT: + /* + fprintf(stderr, "LWS_WRITE_CLOSE C\n"); + */ + buf[0] = 'C'; + break; + default: + break; + } + break; + default: + /* + * 06 has a 2-byte status code in network order + * we can do this because we demand post-buf + */ + + if (wsi->close_reason) { + /* reason codes count as data bytes */ + buf -= 2; + buf[0] = wsi->close_reason >> 8; + buf[1] = wsi->close_reason; + len += 2; + } + break; + } + break; + case LWS_WRITE_PING: + if (wsi->ietf_spec_revision < 7) + n = LWS_WS_OPCODE_04__PING; + else + n = LWS_WS_OPCODE_07__PING; + + wsi->pings_vs_pongs++; + break; + case LWS_WRITE_PONG: + if (wsi->ietf_spec_revision < 7) + n = LWS_WS_OPCODE_04__PONG; + else + n = LWS_WS_OPCODE_07__PONG; + break; + default: + fprintf(stderr, "libwebsocket_write: unknown write " + "opcode / protocol\n"); + return -1; + } + + if (!(protocol & LWS_WRITE_NO_FIN)) + n |= 1 << 7; + + if (len < 126) { + pre += 2; + buf[-pre] = n; + buf[-pre + 1] = len | is_masked_bit; + } else { + if (len < 65536) { + pre += 4; + buf[-pre] = n; + buf[-pre + 1] = 126 | is_masked_bit; + buf[-pre + 2] = len >> 8; + buf[-pre + 3] = len; + } else { + pre += 10; + buf[-pre] = n; + buf[-pre + 1] = 127 | is_masked_bit; +#if defined __LP64__ + buf[-pre + 2] = (len >> 56) & 0x7f; + buf[-pre + 3] = len >> 48; + buf[-pre + 4] = len >> 40; + buf[-pre + 5] = len >> 32; +#else + buf[-pre + 2] = 0; + buf[-pre + 3] = 0; + buf[-pre + 4] = 0; + buf[-pre + 5] = 0; +#endif + buf[-pre + 6] = len >> 24; + buf[-pre + 7] = len >> 16; + buf[-pre + 8] = len >> 8; + buf[-pre + 9] = len; + } + } + break; + } + + /* + * Deal with masking if we are in client -> server direction and + * the protocol demands it + */ + + if (wsi->mode == LWS_CONNMODE_WS_CLIENT && + wsi->ietf_spec_revision >= 4) { + + /* + * this is only useful for security tests where it's required + * to control the raw packet payload content + */ + + if (!(protocol & LWS_WRITE_CLIENT_IGNORE_XOR_MASK) && + wsi->xor_mask != xor_no_mask) { + + if (libwebsocket_0405_frame_mask_generate(wsi)) { + fprintf(stderr, "libwebsocket_write: " + "frame mask generation failed\n"); + return 1; + } + + + if (wsi->ietf_spec_revision < 7) + /* + * use the XOR masking against everything we + * send past the frame key + */ + for (n = -pre; n < ((int)len + post); n++) + buf[n] = wsi->xor_mask(wsi, buf[n]); + else + /* + * in v7, just mask the payload + */ + for (n = 0; n < (int)len; n++) + dropmask[n + 4] = + wsi->xor_mask(wsi, dropmask[n + 4]); + + + if (wsi->ietf_spec_revision < 7) { + /* make space for the frame nonce in clear */ + pre += 4; + + dropmask = &buf[0 - pre]; + } + + if (dropmask) + /* copy the frame nonce into place */ + memcpy(dropmask, + wsi->frame_masking_nonce_04, 4); + + } else { + if (wsi->ietf_spec_revision < 7) { + + /* make space for the frame nonce in clear */ + pre += 4; + + buf[0 - pre] = 0; + buf[1 - pre] = 0; + buf[2 - pre] = 0; + buf[3 - pre] = 0; + } else { + if (dropmask && wsi->xor_mask != xor_no_mask) { + dropmask[0] = 0; + dropmask[1] = 0; + dropmask[2] = 0; + dropmask[3] = 0; + } + } + } + + } + +send_raw: + +#if 0 + fprintf(stderr, "send %ld: ", len + post); + for (n = -pre; n < ((int)len + post); n++) + fprintf(stderr, "%02X ", buf[n]); + + fprintf(stderr, "\n"); +#endif + + if (protocol == LWS_WRITE_HTTP) { + if (lws_issue_raw(wsi, (unsigned char *)buf - pre, + len + pre + post)) + return -1; + + return 0; + } + + /* + * give any active extensions a chance to munge the buffer + * before send. We pass in a pointer to an lws_tokens struct + * prepared with the default buffer and content length that's in + * there. Rather than rewrite the default buffer, extensions + * that expect to grow the buffer can adapt .token to + * point to their own per-connection buffer in the extension + * user allocation. By default with no extensions or no + * extension callback handling, just the normal input buffer is + * used then so it is efficient. + * + * callback returns 1 in case it wants to spill more buffers + */ + + return lws_issue_raw_ext_access(wsi, buf - pre, len + pre + post); +} + + +/** + * libwebsockets_serve_http_file() - Send a file back to the client using http + * @wsi: Websocket instance (available from user callback) + * @file: The file to issue over http + * @content_type: The http content type, eg, text/html + * + * This function is intended to be called from the callback in response + * to http requests from the client. It allows the callback to issue + * local files down the http link in a single step. + */ + +int libwebsockets_serve_http_file(struct libwebsocket *wsi, const char *file, + const char *content_type) +{ + int fd; + struct stat stat_buf; + char buf[512]; + char *p = buf; + int n; + +#ifdef WIN32 + fd = open(file, O_RDONLY | _O_BINARY); +#else + fd = open(file, O_RDONLY); +#endif + if (fd < 1) { + p += sprintf(p, "HTTP/1.0 400 Bad\x0d\x0a" + "Server: libwebsockets\x0d\x0a" + "\x0d\x0a" + ); + libwebsocket_write(wsi, (unsigned char *)buf, p - buf, + LWS_WRITE_HTTP); + + return -1; + } + + fstat(fd, &stat_buf); + p += sprintf(p, "HTTP/1.0 200 OK\x0d\x0a" + "Server: libwebsockets\x0d\x0a" + "Content-Type: %s\x0d\x0a" + "Content-Length: %u\x0d\x0a" + "\x0d\x0a", content_type, + (unsigned int)stat_buf.st_size); + + libwebsocket_write(wsi, (unsigned char *)buf, p - buf, LWS_WRITE_HTTP); + + n = 1; + while (n > 0) { + n = read(fd, buf, 512); + if (n <= 0) + continue; + libwebsocket_write(wsi, (unsigned char *)buf, n, + LWS_WRITE_HTTP); + } + + close(fd); + + return 0; +} + + +/** + * libwebsockets_remaining_packet_payload() - Bytes to come before "overall" + * rx packet is complete + * @wsi: Websocket instance (available from user callback) + * + * This function is intended to be called from the callback if the + * user code is interested in "complete packets" from the client. + * libwebsockets just passes through payload as it comes and issues a buffer + * additionally when it hits a built-in limit. The LWS_CALLBACK_RECEIVE + * callback handler can use this API to find out if the buffer it has just + * been given is the last piece of a "complete packet" from the client -- + * when that is the case libwebsockets_remaining_packet_payload() will return + * 0. + * + * Many protocols won't care becuse their packets are always small. + */ + +size_t +libwebsockets_remaining_packet_payload(struct libwebsocket *wsi) +{ + return wsi->rx_packet_length; +} diff --git a/libs/libwebsockets/lib/private-libwebsockets.h b/libs/libwebsockets/lib/private-libwebsockets.h new file mode 100644 index 0000000000..3c9776fd86 --- /dev/null +++ b/libs/libwebsockets/lib/private-libwebsockets.h @@ -0,0 +1,445 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __MINGW64__ +#else +#ifdef __MINGW32__ +#else +#include +#endif +#endif +#include + +#include + +#ifdef WIN32 +#ifdef __MINGW64__ +#else +#ifdef __MINGW32__ +#else +#include +#endif +#endif +#include +#include +#include + +#else + +#include +#include +#ifndef LWS_NO_FORK +#ifdef HAVE_SYS_PRCTL_H +#include +#endif +#endif +#include +#include +#include + +#include +#include +#include + +#endif + +#ifdef LWS_OPENSSL_SUPPORT +#include +#include +#include +#include +#include +#endif + + +#include "libwebsockets.h" + +#if 0 +#define DEBUG +#endif + +#ifdef DEBUG +#ifdef WIN32 +static +#else +static inline +#endif +void debug(const char *format, ...) +{ + va_list ap; + va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); +} +#else +#ifdef WIN32 +static +#else +static inline +#endif +void debug(const char *format, ...) +{ +} +#endif + + +/* + * Mac OSX as well as iOS do not define the MSG_NOSIGNAL flag, + * but happily have something equivalent in the SO_NOSIGPIPE flag. + */ +#ifdef __APPLE__ +#define MSG_NOSIGNAL SO_NOSIGPIPE +#endif + + +#define FD_HASHTABLE_MODULUS 32 +#define MAX_CLIENTS 100 +#define LWS_MAX_HEADER_NAME_LENGTH 64 +#define LWS_MAX_HEADER_LEN 4096 +#define LWS_INITIAL_HDR_ALLOC 256 +#define LWS_ADDITIONAL_HDR_ALLOC 64 +#define MAX_USER_RX_BUFFER 4096 +#define MAX_BROADCAST_PAYLOAD 2048 +#define LWS_MAX_PROTOCOLS 10 +#define LWS_MAX_EXTENSIONS_ACTIVE 10 +#define SPEC_LATEST_SUPPORTED 13 + +#define MAX_WEBSOCKET_04_KEY_LEN 128 +#define SYSTEM_RANDOM_FILEPATH "/dev/urandom" + +enum lws_websocket_opcodes_04 { + LWS_WS_OPCODE_04__CONTINUATION = 0, + LWS_WS_OPCODE_04__CLOSE = 1, + LWS_WS_OPCODE_04__PING = 2, + LWS_WS_OPCODE_04__PONG = 3, + LWS_WS_OPCODE_04__TEXT_FRAME = 4, + LWS_WS_OPCODE_04__BINARY_FRAME = 5, + + LWS_WS_OPCODE_04__RESERVED_6 = 6, + LWS_WS_OPCODE_04__RESERVED_7 = 7, + LWS_WS_OPCODE_04__RESERVED_8 = 8, + LWS_WS_OPCODE_04__RESERVED_9 = 9, + LWS_WS_OPCODE_04__RESERVED_A = 0xa, + LWS_WS_OPCODE_04__RESERVED_B = 0xb, + LWS_WS_OPCODE_04__RESERVED_C = 0xc, + LWS_WS_OPCODE_04__RESERVED_D = 0xd, + LWS_WS_OPCODE_04__RESERVED_E = 0xe, + LWS_WS_OPCODE_04__RESERVED_F = 0xf, +}; + +enum lws_websocket_opcodes_07 { + LWS_WS_OPCODE_07__CONTINUATION = 0, + LWS_WS_OPCODE_07__TEXT_FRAME = 1, + LWS_WS_OPCODE_07__BINARY_FRAME = 2, + + LWS_WS_OPCODE_07__NOSPEC__MUX = 7, + + /* control extensions 8+ */ + + LWS_WS_OPCODE_07__CLOSE = 8, + LWS_WS_OPCODE_07__PING = 9, + LWS_WS_OPCODE_07__PONG = 0xa, +}; + + +enum lws_connection_states { + WSI_STATE_HTTP, + WSI_STATE_HTTP_HEADERS, + WSI_STATE_DEAD_SOCKET, + WSI_STATE_ESTABLISHED, + WSI_STATE_CLIENT_UNCONNECTED, + WSI_STATE_RETURNED_CLOSE_ALREADY, + WSI_STATE_AWAITING_CLOSE_ACK, +}; + +enum lws_rx_parse_state { + LWS_RXPS_NEW, + + LWS_RXPS_SEEN_76_FF, + LWS_RXPS_PULLING_76_LENGTH, + LWS_RXPS_EAT_UNTIL_76_FF, + + LWS_RXPS_04_MASK_NONCE_1, + LWS_RXPS_04_MASK_NONCE_2, + LWS_RXPS_04_MASK_NONCE_3, + + LWS_RXPS_04_FRAME_HDR_1, + LWS_RXPS_04_FRAME_HDR_LEN, + LWS_RXPS_04_FRAME_HDR_LEN16_2, + LWS_RXPS_04_FRAME_HDR_LEN16_1, + LWS_RXPS_04_FRAME_HDR_LEN64_8, + LWS_RXPS_04_FRAME_HDR_LEN64_7, + LWS_RXPS_04_FRAME_HDR_LEN64_6, + LWS_RXPS_04_FRAME_HDR_LEN64_5, + LWS_RXPS_04_FRAME_HDR_LEN64_4, + LWS_RXPS_04_FRAME_HDR_LEN64_3, + LWS_RXPS_04_FRAME_HDR_LEN64_2, + LWS_RXPS_04_FRAME_HDR_LEN64_1, + + LWS_RXPS_07_COLLECT_FRAME_KEY_1, + LWS_RXPS_07_COLLECT_FRAME_KEY_2, + LWS_RXPS_07_COLLECT_FRAME_KEY_3, + LWS_RXPS_07_COLLECT_FRAME_KEY_4, + + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED +}; + + +enum connection_mode { + LWS_CONNMODE_WS_SERVING, + LWS_CONNMODE_WS_CLIENT, + + /* transient modes */ + LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY, + LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE, + LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY, + LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT, + LWS_CONNMODE_WS_CLIENT_PENDING_CANDIDATE_CHILD, + + /* special internal types */ + LWS_CONNMODE_SERVER_LISTENER, + LWS_CONNMODE_BROADCAST_PROXY_LISTENER, + LWS_CONNMODE_BROADCAST_PROXY +}; + + +#define LWS_FD_HASH(fd) ((fd ^ (fd >> 8) ^ (fd >> 16)) % FD_HASHTABLE_MODULUS) + +struct libwebsocket_fd_hashtable { + struct libwebsocket *wsi[MAX_CLIENTS + 1]; + int length; +}; + +struct libwebsocket_protocols; + +struct libwebsocket_context { + struct libwebsocket_fd_hashtable fd_hashtable[FD_HASHTABLE_MODULUS]; + struct pollfd fds[MAX_CLIENTS * FD_HASHTABLE_MODULUS + 1]; + int fds_count; + int listen_port; + char http_proxy_address[256]; + char canonical_hostname[1024]; + unsigned int http_proxy_port; + unsigned int options; + unsigned long last_timeout_check_s; + + int fd_random; + +#ifdef LWS_OPENSSL_SUPPORT + int use_ssl; + SSL_CTX *ssl_ctx; + SSL_CTX *ssl_client_ctx; +#endif + struct libwebsocket_protocols *protocols; + int count_protocols; + struct libwebsocket_extension *extensions; +}; + + +enum pending_timeout { + NO_PENDING_TIMEOUT = 0, + PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, + PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, + PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE, + PENDING_TIMEOUT_AWAITING_PING, + PENDING_TIMEOUT_CLOSE_ACK, + PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, +}; + + +/* + * This is totally opaque to code using the library. It's exported as a + * forward-reference pointer-only declaration; the user can use the pointer with + * other APIs to get information out of it. + */ + +struct libwebsocket { + const struct libwebsocket_protocols *protocol; + struct libwebsocket_extension * + active_extensions[LWS_MAX_EXTENSIONS_ACTIVE]; + void *active_extensions_user[LWS_MAX_EXTENSIONS_ACTIVE]; + int count_active_extensions; + + enum lws_connection_states state; + + char name_buffer[LWS_MAX_HEADER_NAME_LENGTH]; + int name_buffer_pos; + int current_alloc_len; + enum lws_token_indexes parser_state; + struct lws_tokens utf8_token[WSI_TOKEN_COUNT]; + int ietf_spec_revision; + char rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + MAX_USER_RX_BUFFER + + LWS_SEND_BUFFER_POST_PADDING]; + int rx_user_buffer_head; + enum libwebsocket_write_protocol rx_frame_type; + int protocol_index_for_broadcast_proxy; + enum pending_timeout pending_timeout; + unsigned long pending_timeout_limit; + + int sock; + + enum lws_rx_parse_state lws_rx_parse_state; + char extension_data_pending; + struct libwebsocket *candidate_children_list; + struct libwebsocket *extension_handles; + + /* 04 protocol specific */ + + char key_b64[150]; + unsigned char masking_key_04[20]; + unsigned char frame_masking_nonce_04[4]; + unsigned char frame_mask_04[20]; + unsigned char frame_mask_index; + size_t rx_packet_length; + unsigned char opcode; + unsigned char final; + + int pings_vs_pongs; + unsigned char (*xor_mask)(struct libwebsocket *, unsigned char); + char all_zero_nonce; + + enum lws_close_status close_reason; + + /* 07 specific */ + char this_frame_masked; + + /* client support */ + char initial_handshake_hash_base64[30]; + enum connection_mode mode; + char *c_path; + char *c_host; + char *c_origin; + char *c_protocol; + callback_function *c_callback; + + char *c_address; + int c_port; + + +#ifdef LWS_OPENSSL_SUPPORT + SSL *ssl; + BIO *client_bio; + int use_ssl; +#endif + + void *user_space; +}; + +extern int +libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c); + +extern int +libwebsocket_parse(struct libwebsocket *wsi, unsigned char c); + +extern int +libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi, + unsigned char *buf, size_t len); + +extern int +libwebsocket_read(struct libwebsocket_context *context, + struct libwebsocket *wsi, + unsigned char *buf, size_t len); + +extern int +lws_b64_selftest(void); + +extern unsigned char +xor_no_mask(struct libwebsocket *wsi, unsigned char c); + +extern unsigned char +xor_mask_04(struct libwebsocket *wsi, unsigned char c); + +extern unsigned char +xor_mask_05(struct libwebsocket *wsi, unsigned char c); + +extern struct libwebsocket * +wsi_from_fd(struct libwebsocket_context *context, int fd); + +extern int +insert_wsi(struct libwebsocket_context *context, struct libwebsocket *wsi); + +extern int +delete_from_fd(struct libwebsocket_context *context, int fd); + +extern void +libwebsocket_set_timeout(struct libwebsocket *wsi, + enum pending_timeout reason, int secs); + +extern int +lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len); + + +extern void +libwebsocket_service_timeout_check(struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned int sec); + +extern struct libwebsocket * +__libwebsocket_client_connect_2(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +extern struct libwebsocket * +libwebsocket_create_new_server_wsi(struct libwebsocket_context *context); + +extern char * +libwebsockets_generate_client_handshake(struct libwebsocket_context *context, + struct libwebsocket *wsi, char *pkt); + +extern int +lws_handle_POLLOUT_event(struct libwebsocket_context *context, + struct libwebsocket *wsi, struct pollfd *pollfd); + +extern int +lws_any_extension_handled(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons r, + void *v, size_t len); + +extern void * +lws_get_extension_user_matching_ext(struct libwebsocket *wsi, + struct libwebsocket_extension *ext); + +extern int +lws_client_interpret_server_handshake(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +extern int +libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c); + +extern int +lws_issue_raw_ext_access(struct libwebsocket *wsi, + unsigned char *buf, size_t len); + +#ifndef LWS_OPENSSL_SUPPORT + +unsigned char * +SHA1(const unsigned char *d, size_t n, unsigned char *md); + +void +MD5(const unsigned char *input, int ilen, unsigned char *output); + +#endif diff --git a/libs/libwebsockets/lib/sha-1.c b/libs/libwebsockets/lib/sha-1.c new file mode 100644 index 0000000000..f30f3ed63b --- /dev/null +++ b/libs/libwebsockets/lib/sha-1.c @@ -0,0 +1,326 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * FIPS pub 180-1: Secure Hash Algorithm (SHA-1) + * based on: http://csrc.nist.gov/fips/fip180-1.txt + * implemented by Jun-ichiro itojun Itoh + */ + +#include +#ifdef WIN32 + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 /* to show byte order (taken from gcc) */ +#endif +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif +#ifndef BYTE_ORDER +#define BYTE_ORDER LITTLE_ENDIAN +#endif + +typedef unsigned __int64 u_int64_t; + +#undef __P +#ifndef __P +#if __STDC__ +#define __P(protos) protos +#else +#define __P(protos) () +#endif +#endif + +#define bzero(b, len) (memset((b), '\0', (len)), (void) 0) + +#else +#include +#include +#include +#endif + +#include + +struct sha1_ctxt { + union { + unsigned char b8[20]; + unsigned int b32[5]; + } h; + union { + unsigned char b8[8]; + u_int64_t b64[1]; + } c; + union { + unsigned char b8[64]; + unsigned int b32[16]; + } m; + unsigned char count; +}; + +/* sanity check */ +#if BYTE_ORDER != BIG_ENDIAN +# if BYTE_ORDER != LITTLE_ENDIAN +# define unsupported 1 +# endif +#endif + +#ifndef unsupported + +/* constant table */ +static unsigned int _K[] = { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 }; +#define K(t) _K[(t) / 20] + +#define F0(b, c, d) (((b) & (c)) | ((~(b)) & (d))) +#define F1(b, c, d) (((b) ^ (c)) ^ (d)) +#define F2(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) +#define F3(b, c, d) (((b) ^ (c)) ^ (d)) + +#define S(n, x) (((x) << (n)) | ((x) >> (32 - n))) + +#define H(n) (ctxt->h.b32[(n)]) +#define COUNT (ctxt->count) +#define BCOUNT (ctxt->c.b64[0] / 8) +#define W(n) (ctxt->m.b32[(n)]) + +#define PUTBYTE(x) { \ + ctxt->m.b8[(COUNT % 64)] = (x); \ + COUNT++; \ + COUNT %= 64; \ + ctxt->c.b64[0] += 8; \ + if (COUNT % 64 == 0) \ + sha1_step(ctxt); \ + } + +#define PUTPAD(x) { \ + ctxt->m.b8[(COUNT % 64)] = (x); \ + COUNT++; \ + COUNT %= 64; \ + if (COUNT % 64 == 0) \ + sha1_step(ctxt); \ + } + +static void sha1_step __P((struct sha1_ctxt *)); + +static void +sha1_step(struct sha1_ctxt *ctxt) +{ + unsigned int a, b, c, d, e, tmp; + size_t t, s; + +#if BYTE_ORDER == LITTLE_ENDIAN + struct sha1_ctxt tctxt; + + memcpy(&tctxt.m.b8[0], &ctxt->m.b8[0], 64); + ctxt->m.b8[0] = tctxt.m.b8[3]; ctxt->m.b8[1] = tctxt.m.b8[2]; + ctxt->m.b8[2] = tctxt.m.b8[1]; ctxt->m.b8[3] = tctxt.m.b8[0]; + ctxt->m.b8[4] = tctxt.m.b8[7]; ctxt->m.b8[5] = tctxt.m.b8[6]; + ctxt->m.b8[6] = tctxt.m.b8[5]; ctxt->m.b8[7] = tctxt.m.b8[4]; + ctxt->m.b8[8] = tctxt.m.b8[11]; ctxt->m.b8[9] = tctxt.m.b8[10]; + ctxt->m.b8[10] = tctxt.m.b8[9]; ctxt->m.b8[11] = tctxt.m.b8[8]; + ctxt->m.b8[12] = tctxt.m.b8[15]; ctxt->m.b8[13] = tctxt.m.b8[14]; + ctxt->m.b8[14] = tctxt.m.b8[13]; ctxt->m.b8[15] = tctxt.m.b8[12]; + ctxt->m.b8[16] = tctxt.m.b8[19]; ctxt->m.b8[17] = tctxt.m.b8[18]; + ctxt->m.b8[18] = tctxt.m.b8[17]; ctxt->m.b8[19] = tctxt.m.b8[16]; + ctxt->m.b8[20] = tctxt.m.b8[23]; ctxt->m.b8[21] = tctxt.m.b8[22]; + ctxt->m.b8[22] = tctxt.m.b8[21]; ctxt->m.b8[23] = tctxt.m.b8[20]; + ctxt->m.b8[24] = tctxt.m.b8[27]; ctxt->m.b8[25] = tctxt.m.b8[26]; + ctxt->m.b8[26] = tctxt.m.b8[25]; ctxt->m.b8[27] = tctxt.m.b8[24]; + ctxt->m.b8[28] = tctxt.m.b8[31]; ctxt->m.b8[29] = tctxt.m.b8[30]; + ctxt->m.b8[30] = tctxt.m.b8[29]; ctxt->m.b8[31] = tctxt.m.b8[28]; + ctxt->m.b8[32] = tctxt.m.b8[35]; ctxt->m.b8[33] = tctxt.m.b8[34]; + ctxt->m.b8[34] = tctxt.m.b8[33]; ctxt->m.b8[35] = tctxt.m.b8[32]; + ctxt->m.b8[36] = tctxt.m.b8[39]; ctxt->m.b8[37] = tctxt.m.b8[38]; + ctxt->m.b8[38] = tctxt.m.b8[37]; ctxt->m.b8[39] = tctxt.m.b8[36]; + ctxt->m.b8[40] = tctxt.m.b8[43]; ctxt->m.b8[41] = tctxt.m.b8[42]; + ctxt->m.b8[42] = tctxt.m.b8[41]; ctxt->m.b8[43] = tctxt.m.b8[40]; + ctxt->m.b8[44] = tctxt.m.b8[47]; ctxt->m.b8[45] = tctxt.m.b8[46]; + ctxt->m.b8[46] = tctxt.m.b8[45]; ctxt->m.b8[47] = tctxt.m.b8[44]; + ctxt->m.b8[48] = tctxt.m.b8[51]; ctxt->m.b8[49] = tctxt.m.b8[50]; + ctxt->m.b8[50] = tctxt.m.b8[49]; ctxt->m.b8[51] = tctxt.m.b8[48]; + ctxt->m.b8[52] = tctxt.m.b8[55]; ctxt->m.b8[53] = tctxt.m.b8[54]; + ctxt->m.b8[54] = tctxt.m.b8[53]; ctxt->m.b8[55] = tctxt.m.b8[52]; + ctxt->m.b8[56] = tctxt.m.b8[59]; ctxt->m.b8[57] = tctxt.m.b8[58]; + ctxt->m.b8[58] = tctxt.m.b8[57]; ctxt->m.b8[59] = tctxt.m.b8[56]; + ctxt->m.b8[60] = tctxt.m.b8[63]; ctxt->m.b8[61] = tctxt.m.b8[62]; + ctxt->m.b8[62] = tctxt.m.b8[61]; ctxt->m.b8[63] = tctxt.m.b8[60]; +#endif + + a = H(0); b = H(1); c = H(2); d = H(3); e = H(4); + + for (t = 0; t < 20; t++) { + s = t & 0x0f; + if (t >= 16) + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ + W((s+2) & 0x0f) ^ W(s)); + + tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + for (t = 20; t < 40; t++) { + s = t & 0x0f; + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ + W((s+2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + for (t = 40; t < 60; t++) { + s = t & 0x0f; + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ + W((s+2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + for (t = 60; t < 80; t++) { + s = t & 0x0f; + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ + W((s+2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + + H(0) = H(0) + a; + H(1) = H(1) + b; + H(2) = H(2) + c; + H(3) = H(3) + d; + H(4) = H(4) + e; + + bzero(&ctxt->m.b8[0], 64); +} + +/*------------------------------------------------------------*/ + +void +sha1_init(struct sha1_ctxt *ctxt) +{ + bzero(ctxt, sizeof(struct sha1_ctxt)); + H(0) = 0x67452301; + H(1) = 0xefcdab89; + H(2) = 0x98badcfe; + H(3) = 0x10325476; + H(4) = 0xc3d2e1f0; +} + +void +sha1_pad(struct sha1_ctxt *ctxt) +{ + size_t padlen; /*pad length in bytes*/ + size_t padstart; + + PUTPAD(0x80); + + padstart = COUNT % 64; + padlen = 64 - padstart; + if (padlen < 8) { + bzero(&ctxt->m.b8[padstart], padlen); + COUNT += padlen; + COUNT %= 64; + sha1_step(ctxt); + padstart = COUNT % 64; /* should be 0 */ + padlen = 64 - padstart; /* should be 64 */ + } + bzero(&ctxt->m.b8[padstart], padlen - 8); + COUNT += (padlen - 8); + COUNT %= 64; +#if BYTE_ORDER == BIG_ENDIAN + PUTPAD(ctxt->c.b8[0]); PUTPAD(ctxt->c.b8[1]); + PUTPAD(ctxt->c.b8[2]); PUTPAD(ctxt->c.b8[3]); + PUTPAD(ctxt->c.b8[4]); PUTPAD(ctxt->c.b8[5]); + PUTPAD(ctxt->c.b8[6]); PUTPAD(ctxt->c.b8[7]); +#else + PUTPAD(ctxt->c.b8[7]); PUTPAD(ctxt->c.b8[6]); + PUTPAD(ctxt->c.b8[5]); PUTPAD(ctxt->c.b8[4]); + PUTPAD(ctxt->c.b8[3]); PUTPAD(ctxt->c.b8[2]); + PUTPAD(ctxt->c.b8[1]); PUTPAD(ctxt->c.b8[0]); +#endif +} + +void +sha1_loop(struct sha1_ctxt *ctxt, const unsigned char *input, size_t len) +{ + size_t gaplen; + size_t gapstart; + size_t off; + size_t copysiz; + + off = 0; + + while (off < len) { + gapstart = COUNT % 64; + gaplen = 64 - gapstart; + + copysiz = (gaplen < len - off) ? gaplen : len - off; + memcpy(&ctxt->m.b8[gapstart], &input[off], copysiz); + COUNT += copysiz; + COUNT %= 64; + ctxt->c.b64[0] += copysiz * 8; + if (COUNT % 64 == 0) + sha1_step(ctxt); + off += copysiz; + } +} + +void +sha1_result(struct sha1_ctxt *ctxt, void *digest0) +{ + unsigned char *digest; + + digest = (unsigned char *)digest0; + sha1_pad(ctxt); +#if BYTE_ORDER == BIG_ENDIAN + memcpy(digest, &ctxt->h.b8[0], 20); +#else + digest[0] = ctxt->h.b8[3]; digest[1] = ctxt->h.b8[2]; + digest[2] = ctxt->h.b8[1]; digest[3] = ctxt->h.b8[0]; + digest[4] = ctxt->h.b8[7]; digest[5] = ctxt->h.b8[6]; + digest[6] = ctxt->h.b8[5]; digest[7] = ctxt->h.b8[4]; + digest[8] = ctxt->h.b8[11]; digest[9] = ctxt->h.b8[10]; + digest[10] = ctxt->h.b8[9]; digest[11] = ctxt->h.b8[8]; + digest[12] = ctxt->h.b8[15]; digest[13] = ctxt->h.b8[14]; + digest[14] = ctxt->h.b8[13]; digest[15] = ctxt->h.b8[12]; + digest[16] = ctxt->h.b8[19]; digest[17] = ctxt->h.b8[18]; + digest[18] = ctxt->h.b8[17]; digest[19] = ctxt->h.b8[16]; +#endif +} + +/* + * This should look and work like the libcrypto implementation + */ + +unsigned char * +SHA1(const unsigned char *d, size_t n, unsigned char *md) +{ + struct sha1_ctxt ctx; + + sha1_init(&ctx); + sha1_loop(&ctx, d, n); + sha1_result(&ctx, (void *)md); + + return md; +} + +#endif /*unsupported*/ diff --git a/libs/libwebsockets/libwebsockets-api-doc.html b/libs/libwebsockets/libwebsockets-api-doc.html new file mode 100644 index 0000000000..18b1620e50 --- /dev/null +++ b/libs/libwebsockets/libwebsockets-api-doc.html @@ -0,0 +1,933 @@ +

libwebsockets_hangup_on_client - Server calls to terminate client connection

+void +libwebsockets_hangup_on_client +(struct libwebsocket_context * context, +int fd) +

Arguments

+
+
context +
libwebsockets context +
fd +
Connection socket descriptor +
+
+

libwebsockets_get_peer_addresses - Get client address information

+void +libwebsockets_get_peer_addresses +(int fd, +char * name, +int name_len, +char * rip, +int rip_len) +

Arguments

+
+
fd +
Connection socket descriptor +
name +
Buffer to take client address name +
name_len +
Length of client address name buffer +
rip +
Buffer to take client address IP qotted quad +
rip_len +
Length of client address IP buffer +
+

Description

+
+This function fills in name and rip with the name and IP of +the client connected with socket descriptor fd. Names may be +truncated if there is not enough room. If either cannot be +determined, they will be returned as valid zero-length strings. +
+
+

libwebsocket_service_fd - Service polled socket with something waiting

+int +libwebsocket_service_fd +(struct libwebsocket_context * context, +struct pollfd * pollfd) +

Arguments

+
+
context +
Websocket context +
pollfd +
The pollfd entry describing the socket fd and which events +happened. +
+

Description

+
+This function closes any active connections and then frees the +context. After calling this, any further use of the context is +undefined. +
+
+

libwebsocket_context_destroy - Destroy the websocket context

+void +libwebsocket_context_destroy +(struct libwebsocket_context * context) +

Arguments

+
+
context +
Websocket context +
+

Description

+
+This function closes any active connections and then frees the +context. After calling this, any further use of the context is +undefined. +
+
+

libwebsocket_service - Service any pending websocket activity

+int +libwebsocket_service +(struct libwebsocket_context * context, +int timeout_ms) +

Arguments

+
+
context +
Websocket context +
timeout_ms +
Timeout for poll; 0 means return immediately if nothing needed +service otherwise block and service immediately, returning +after the timeout if nothing needed service. +
+

Description

+
+This function deals with any pending websocket traffic, for three +kinds of event. It handles these events on both server and client +types of connection the same. +

+1) Accept new connections to our context's server +

+2) Perform pending broadcast writes initiated from other forked +processes (effectively serializing asynchronous broadcasts) +

+3) Call the receive callback for incoming frame data received by +server or client connections. +

+You need to call this service function periodically to all the above +functions to happen; if your application is single-threaded you can +just call it in your main event loop. +

+Alternatively you can fork a new process that asynchronously handles +calling this service in a loop. In that case you are happy if this +call blocks your thread until it needs to take care of something and +would call it with a large nonzero timeout. Your loop then takes no +CPU while there is nothing happening. +

+If you are calling it in a single-threaded app, you don't want it to +wait around blocking other things in your loop from happening, so you +would call it with a timeout_ms of 0, so it returns immediately if +nothing is pending, or as soon as it services whatever was pending. +

+
+

libwebsocket_callback_on_writable - Request a callback when this socket becomes able to be written to without blocking

+int +libwebsocket_callback_on_writable +(struct libwebsocket_context * context, +struct libwebsocket * wsi) +

Arguments

+
+
context +
libwebsockets context +
wsi +
Websocket connection instance to get callback for +
+
+

libwebsocket_callback_on_writable_all_protocol - Request a callback for all connections using the given protocol when it becomes possible to write to each socket without blocking in turn.

+int +libwebsocket_callback_on_writable_all_protocol +(const struct libwebsocket_protocols * protocol) +

Arguments

+
+
protocol +
Protocol whose connections will get callbacks +
+
+

libwebsocket_set_timeout - marks the wsi as subject to a timeout

+void +libwebsocket_set_timeout +(struct libwebsocket * wsi, +enum pending_timeout reason, +int secs) +

Arguments

+
+
wsi +
Websocket connection instance +
reason +
timeout reason +
secs +
how many seconds +
+

Description

+
+

+You will not need this unless you are doing something special +

+
+

libwebsocket_get_socket_fd - returns the socket file descriptor

+int +libwebsocket_get_socket_fd +(struct libwebsocket * wsi) +

Arguments

+
+
wsi +
Websocket connection instance +
+

Description

+
+

+You will not need this unless you are doing something special +

+
+

libwebsocket_rx_flow_control - Enable and disable socket servicing for receieved packets.

+int +libwebsocket_rx_flow_control +(struct libwebsocket * wsi, +int enable) +

Arguments

+
+
wsi +
Websocket connection instance to get callback for +
enable +
0 = disable read servicing for this connection, 1 = enable +
+

Description

+
+

+If the output side of a server process becomes choked, this allows flow +control for the input side. +

+
+

libwebsocket_canonical_hostname - returns this host's hostname

+const char * +libwebsocket_canonical_hostname +(struct libwebsocket_context * context) +

Arguments

+
+
context +
Websocket context +
+

Description

+
+

+This is typically used by client code to fill in the host parameter +when making a client connection. You can only call it after the context +has been created. +

+
+

libwebsocket_create_context - Create the websocket handler

+struct libwebsocket_context * +libwebsocket_create_context +(int port, +const char * interf, +struct libwebsocket_protocols * protocols, +struct libwebsocket_extension * extensions, +const char * ssl_cert_filepath, +const char * ssl_private_key_filepath, +int gid, +int uid, +unsigned int options) +

Arguments

+
+
port +
Port to listen on... you can use 0 to suppress listening on +any port, that's what you want if you are not running a +websocket server at all but just using it as a client +
interf +
NULL to bind the listen socket to all interfaces, or the +interface name, eg, "eth2" +
protocols +
Array of structures listing supported protocols and a protocol- +specific callback for each one. The list is ended with an +entry that has a NULL callback pointer. +It's not const because we write the owning_server member +
extensions +
NULL or array of libwebsocket_extension structs listing the +extensions this context supports +
ssl_cert_filepath +
If libwebsockets was compiled to use ssl, and you want +to listen using SSL, set to the filepath to fetch the +server cert from, otherwise NULL for unencrypted +
ssl_private_key_filepath +
filepath to private key if wanting SSL mode, +else ignored +
gid +
group id to change to after setting listen socket, or -1. +
uid +
user id to change to after setting listen socket, or -1. +
options +
0, or LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK +
+

Description

+
+This function creates the listening socket and takes care +of all initialization in one step. +

+After initialization, it returns a struct libwebsocket_context * that +represents this server. After calling, user code needs to take care +of calling libwebsocket_service with the context pointer to get the +server's sockets serviced. This can be done in the same process context +or a forked process, or another thread, +

+The protocol callback functions are called for a handful of events +including http requests coming in, websocket connections becoming +established, and data arriving; it's also called periodically to allow +async transmission. +

+HTTP requests are sent always to the FIRST protocol in protocol, since +at that time websocket protocol has not been negotiated. Other +protocols after the first one never see any HTTP callack activity. +

+The server created is a simple http server by default; part of the +websocket standard is upgrading this http connection to a websocket one. +

+This allows the same server to provide files like scripts and favicon / +images or whatever over http and dynamic data over websockets all in +one place; they're all handled in the user callback. +

+
+

libwebsockets_fork_service_loop - Optional helper function forks off a process for the websocket server loop. You don't have to use this but if not, you have to make sure you are calling libwebsocket_service periodically to service the websocket traffic

+int +libwebsockets_fork_service_loop +(struct libwebsocket_context * context) +

Arguments

+
+
context +
server context returned by creation function +
+
+

libwebsockets_get_protocol - Returns a protocol pointer from a websocket connection.

+const struct libwebsocket_protocols * +libwebsockets_get_protocol +(struct libwebsocket * wsi) +

Arguments

+
+
wsi +
pointer to struct websocket you want to know the protocol of +
+

Description

+
+

+This is useful to get the protocol to broadcast back to from inside +the callback. +

+
+

libwebsockets_broadcast - Sends a buffer to the callback for all active connections of the given protocol.

+int +libwebsockets_broadcast +(const struct libwebsocket_protocols * protocol, +unsigned char * buf, +size_t len) +

Arguments

+
+
protocol +
pointer to the protocol you will broadcast to all members of +
buf +
buffer containing the data to be broadcase. NOTE: this has to be +allocated with LWS_SEND_BUFFER_PRE_PADDING valid bytes before +the pointer and LWS_SEND_BUFFER_POST_PADDING afterwards in the +case you are calling this function from callback context. +
len +
length of payload data in buf, starting from buf. +
+

Description

+
+This function allows bulk sending of a packet to every connection using +the given protocol. It does not send the data directly; instead it calls +the callback with a reason type of LWS_CALLBACK_BROADCAST. If the callback +wants to actually send the data for that connection, the callback itself +should call libwebsocket_write. +

+libwebsockets_broadcast can be called from another fork context without +having to take any care about data visibility between the processes, it'll +"just work". +

+
+

libwebsocket_write - Apply protocol then write data to client

+int +libwebsocket_write +(struct libwebsocket * wsi, +unsigned char * buf, +size_t len, +enum libwebsocket_write_protocol protocol) +

Arguments

+
+
wsi +
Websocket instance (available from user callback) +
buf +
The data to send. For data being sent on a websocket +connection (ie, not default http), this buffer MUST have +LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE the pointer +and an additional LWS_SEND_BUFFER_POST_PADDING bytes valid +in the buffer after (buf + len). This is so the protocol +header and trailer data can be added in-situ. +
len +
Count of the data bytes in the payload starting from buf +
protocol +
Use LWS_WRITE_HTTP to reply to an http connection, and one +of LWS_WRITE_BINARY or LWS_WRITE_TEXT to send appropriate +data on a websockets connection. Remember to allow the extra +bytes before and after buf if LWS_WRITE_BINARY or LWS_WRITE_TEXT +are used. +
+

Description

+
+This function provides the way to issue data back to the client +for both http and websocket protocols. +

+In the case of sending using websocket protocol, be sure to allocate +valid storage before and after buf as explained above. This scheme +allows maximum efficiency of sending data and protocol in a single +packet while not burdening the user code with any protocol knowledge. +

+
+

libwebsockets_serve_http_file - Send a file back to the client using http

+int +libwebsockets_serve_http_file +(struct libwebsocket * wsi, +const char * file, +const char * content_type) +

Arguments

+
+
wsi +
Websocket instance (available from user callback) +
file +
The file to issue over http +
content_type +
The http content type, eg, text/html +
+

Description

+
+This function is intended to be called from the callback in response +to http requests from the client. It allows the callback to issue +local files down the http link in a single step. +
+
+

libwebsockets_remaining_packet_payload - Bytes to come before "overall" rx packet is complete

+size_t +libwebsockets_remaining_packet_payload +(struct libwebsocket * wsi) +

Arguments

+
+
wsi +
Websocket instance (available from user callback) +
+

Description

+
+This function is intended to be called from the callback if the +user code is interested in "complete packets" from the client. +libwebsockets just passes through payload as it comes and issues a buffer +additionally when it hits a built-in limit. The LWS_CALLBACK_RECEIVE +callback handler can use this API to find out if the buffer it has just +been given is the last piece of a "complete packet" from the client -- +when that is the case libwebsockets_remaining_packet_payload will return +0. +

+Many protocols won't care becuse their packets are always small. +

+
+

libwebsocket_client_connect - Connect to another websocket server

+struct libwebsocket * +libwebsocket_client_connect +(struct libwebsocket_context * context, +const char * address, +int port, +int ssl_connection, +const char * path, +const char * host, +const char * origin, +const char * protocol, +int ietf_version_or_minus_one) +

Arguments

+
+
context +
Websocket context +
address +
Remote server address, eg, "myserver.com" +
port +
Port to connect to on the remote server, eg, 80 +
ssl_connection +
0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self +signed certs +
path +
Websocket path on server +
host +
Hostname on server +
origin +
Socket origin name +
protocol +
Comma-separated list of protocols being asked for from +the server, or just one. The server will pick the one it +likes best. +
ietf_version_or_minus_one +
-1 to ask to connect using the default, latest +protocol supported, or the specific protocol ordinal +
+

Description

+
+This function creates a connection to a remote server +
+
+

libwebsocket_client_connect_extended - Connect to another websocket server

+struct libwebsocket * +libwebsocket_client_connect_extended +(struct libwebsocket_context * context, +const char * address, +int port, +int ssl_connection, +const char * path, +const char * host, +const char * origin, +const char * protocol, +int ietf_version_or_minus_one, +void * userdata) +

Arguments

+
+
context +
Websocket context +
address +
Remote server address, eg, "myserver.com" +
port +
Port to connect to on the remote server, eg, 80 +
ssl_connection +
0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self +signed certs +
path +
Websocket path on server +
host +
Hostname on server +
origin +
Socket origin name +
protocol +
Comma-separated list of protocols being asked for from +the server, or just one. The server will pick the one it +likes best. +
ietf_version_or_minus_one +
-1 to ask to connect using the default, latest +protocol supported, or the specific protocol ordinal +
userdata +
Pre-allocated user data +
+

Description

+
+This function creates a connection to a remote server +
+
+

callback - User server actions

+LWS_EXTERN int +callback +(struct libwebsocket_context * context, +struct libwebsocket * wsi, +enum libwebsocket_callback_reasons reason, +void * user, +void * in, +size_t len) +

Arguments

+
+
context +
Websockets context +
wsi +
Opaque websocket instance pointer +
reason +
The reason for the call +
user +
Pointer to per-session user data allocated by library +
in +
Pointer used for some callback reasons +
len +
Length set for some callback reasons +
+

Description

+
+This callback is the way the user controls what is served. All the +protocol detail is hidden and handled by the library. +

+For each connection / session there is user data allocated that is +pointed to by "user". You set the size of this user data area when +the library is initialized with libwebsocket_create_server. +

+You get an opportunity to initialize user data when called back with +LWS_CALLBACK_ESTABLISHED reason. +

+

LWS_CALLBACK_ESTABLISHED

+
+after the server completes a handshake with +an incoming client +
+

LWS_CALLBACK_CLIENT_CONNECTION_ERROR

+
+the request client connection has +been unable to complete a handshake with the remote server +
+

LWS_CALLBACK_CLIENT_ESTABLISHED

+
+after your client connection completed +a handshake with the remote server +
+

LWS_CALLBACK_CLOSED

+
+when the websocket session ends +
+

LWS_CALLBACK_BROADCAST

+
+signal to send to client (you would use +libwebsocket_write taking care about the +special buffer requirements +
+

LWS_CALLBACK_RECEIVE

+
+data has appeared for this server endpoint from a +remote client, it can be found at *in and is +len bytes long +
+

LWS_CALLBACK_CLIENT_RECEIVE_PONG

+
+if you elected to see PONG packets, +they appear with this callback reason. PONG +packets only exist in 04+ protocol +
+

LWS_CALLBACK_CLIENT_RECEIVE

+
+data has appeared from the server for the +client connection, it can be found at *in and +is len bytes long +
+

LWS_CALLBACK_HTTP

+
+an http request has come from a client that is not +asking to upgrade the connection to a websocket +one. This is a chance to serve http content, +for example, to send a script to the client +which will then open the websockets connection. +in points to the URI path requested and +libwebsockets_serve_http_file makes it very +simple to send back a file to the client. +
+

LWS_CALLBACK_SERVER_WRITEABLE

+
+If you call +libwebsocket_callback_on_writable on a connection, you will +get one of these callbacks coming when the connection socket +is able to accept another write packet without blocking. +If it already was able to take another packet without blocking, +you'll get this callback at the next call to the service loop +function. Notice that CLIENTs get LWS_CALLBACK_CLIENT_WRITEABLE +and servers get LWS_CALLBACK_SERVER_WRITEABLE. +
+

LWS_CALLBACK_FILTER_NETWORK_CONNECTION

+
+called when a client connects to +the server at network level; the connection is accepted but then +passed to this callback to decide whether to hang up immediately +or not, based on the client IP. user contains the connection +socket's descriptor. Return non-zero to terminate +the connection before sending or receiving anything. +Because this happens immediately after the network connection +from the client, there's no websocket protocol selected yet so +this callback is issued only to protocol 0. +
+

LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION

+
+called when the handshake has +been received and parsed from the client, but the response is +not sent yet. Return non-zero to disallow the connection. +user is a pointer to an array of struct lws_tokens, you can +use the header enums lws_token_indexes from libwebsockets.h +to check for and read the supported header presence and +content before deciding to allow the handshake to proceed or +to kill the connection. +
+

LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS

+
+if configured for +including OpenSSL support, this callback allows your user code +to perform extra SSL_CTX_load_verify_locations or similar +calls to direct OpenSSL where to find certificates the client +can use to confirm the remote server identity. user is the +OpenSSL SSL_CTX* +
+

LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS

+
+if configured for +including OpenSSL support, this callback allows your user code +to load extra certifcates into the server which allow it to +verify the validity of certificates returned by clients. user +is the server's OpenSSL SSL_CTX* +
+

LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION

+
+if the +libwebsockets context was created with the option +LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this +callback is generated during OpenSSL verification of the cert +sent from the client. It is sent to protocol[0] callback as +no protocol has been negotiated on the connection yet. +Notice that the libwebsockets context and wsi are both NULL +during this callback. See +
+

http

+
+//www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +to understand more detail about the OpenSSL callback that +generates this libwebsockets callback and the meanings of the +arguments passed. In this callback, user is the x509_ctx, +in is the ssl pointer and len is preverify_ok +Notice that this callback maintains libwebsocket return +conventions, return 0 to mean the cert is OK or 1 to fail it. +This also means that if you don't handle this callback then +the default callback action of returning 0 allows the client +certificates. +
+

LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER

+
+this callback happens +when a client handshake is being compiled. user is NULL, +in is a char **, it's pointing to a char * which holds the +next location in the header buffer where you can add +headers, and len is the remaining space in the header buffer, +which is typically some hundreds of bytes. So, to add a canned +cookie, your handler code might look similar to: +

+char **p = (char **)in; +

+if (len < 100) +return 1; +

+*p += sprintf(*p, "Cookie: a=b\x0d\x0a"); +

+return 0; +

+Notice if you add anything, you just have to take care about +the CRLF on the line you added. Obviously this callback is +optional, if you don't handle it everything is fine. +

+Notice the callback is coming to protocols[0] all the time, +because there is no specific protocol handshook yet. +

+

LWS_CALLBACK_CONFIRM_EXTENSION_OKAY

+
+When the server handshake code +sees that it does support a requested extension, before +accepting the extension by additing to the list sent back to +the client it gives this callback just to check that it's okay +to use that extension. It calls back to the requested protocol +and with in being the extension name, len is 0 and user is +valid. Note though at this time the ESTABLISHED callback hasn't +happened yet so if you initialize user content there, user +content during this callback might not be useful for anything. +Notice this callback comes to protocols[0]. +
+

LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED

+
+When a client +connection is being prepared to start a handshake to a server, +each supported extension is checked with protocols[0] callback +with this reason, giving the user code a chance to suppress the +claim to support that extension by returning non-zero. If +unhandled, by default 0 will be returned and the extension +support included in the header to the server. Notice this +callback comes to protocols[0]. +

+The next four reasons are optional and only need taking care of if you +will be integrating libwebsockets sockets into an external polling +array. +

+

LWS_CALLBACK_ADD_POLL_FD

+
+libwebsocket deals with its poll loop +internally, but in the case you are integrating with another +server you will need to have libwebsocket sockets share a +polling array with the other server. This and the other +POLL_FD related callbacks let you put your specialized +poll array interface code in the callback for protocol 0, the +first protocol you support, usually the HTTP protocol in the +serving case. This callback happens when a socket needs to be +
+

added to the polling loop

+
+user contains the fd, and +len is the events bitmap (like, POLLIN). If you are using the +internal polling loop (the "service" callback), you can just +ignore these callbacks. +
+

LWS_CALLBACK_DEL_POLL_FD

+
+This callback happens when a socket descriptor +needs to be removed from an external polling array. user is +the socket desricptor. If you are using the internal polling +loop, you can just ignore it. +
+

LWS_CALLBACK_SET_MODE_POLL_FD

+
+This callback happens when libwebsockets +wants to modify the events for the socket descriptor in user. +The handler should OR len on to the events member of the pollfd +struct for this socket descriptor. If you are using the +internal polling loop, you can just ignore it. +
+

LWS_CALLBACK_CLEAR_MODE_POLL_FD

+
+This callback occurs when libwebsockets +wants to modify the events for the socket descriptor in user. +The handler should AND ~len on to the events member of the +pollfd struct for this socket descriptor. If you are using the +internal polling loop, you can just ignore it. +
+
+

extension_callback - Hooks to allow extensions to operate

+LWS_EXTERN int +extension_callback +(struct libwebsocket_context * context, +struct libwebsocket_extension * ext, +struct libwebsocket * wsi, +enum libwebsocket_extension_callback_reasons reason, +void * user, +void * in, +size_t len) +

Arguments

+
+
context +
Websockets context +
ext +
This extension +
wsi +
Opaque websocket instance pointer +
reason +
The reason for the call +
user +
Pointer to per-session user data allocated by library +
in +
Pointer used for some callback reasons +
len +
Length set for some callback reasons +
+

Description

+
+Each extension that is active on a particular connection receives +callbacks during the connection lifetime to allow the extension to +operate on websocket data and manage itself. +

+Libwebsockets takes care of allocating and freeing "user" memory for +each active extension on each connection. That is what is pointed to +by the user parameter. +

+

LWS_EXT_CALLBACK_CONSTRUCT

+
+called when the server has decided to +select this extension from the list provided by the client, +just before the server will send back the handshake accepting +the connection with this extension active. This gives the +extension a chance to initialize its connection context found +in user. +
+

LWS_EXT_CALLBACK_CLIENT_CONSTRUCT

+
+same as LWS_EXT_CALLBACK_CONSTRUCT +but called when client is instantiating this extension. Some +extensions will work the same on client and server side and then +you can just merge handlers for both CONSTRUCTS. +
+

LWS_EXT_CALLBACK_DESTROY

+
+called when the connection the extension was +being used on is about to be closed and deallocated. It's the +last chance for the extension to deallocate anything it has +allocated in the user data (pointed to by user) before the +user data is deleted. This same callback is used whether you +are in client or server instantiation context. +
+

LWS_EXT_CALLBACK_PACKET_RX_PREPARSE

+
+when this extension was active on +a connection, and a packet of data arrived at the connection, +it is passed to this callback to give the extension a chance to +change the data, eg, decompress it. user is pointing to the +extension's private connection context data, in is pointing +to an lws_tokens struct, it consists of a char * pointer called +token, and an int called token_len. At entry, these are +set to point to the received buffer and set to the content +length. If the extension will grow the content, it should use +a new buffer allocated in its private user context data and +set the pointed-to lws_tokens members to point to its buffer. +
+

LWS_EXT_CALLBACK_PACKET_TX_PRESEND

+
+this works the same way as +LWS_EXT_CALLBACK_PACKET_RX_PREPARSE above, except it gives the +extension a chance to change websocket data just before it will +be sent out. Using the same lws_token pointer scheme in in, +the extension can change the buffer and the length to be +transmitted how it likes. Again if it wants to grow the +buffer safely, it should copy the data into its own buffer and +set the lws_tokens token pointer to it. +
+
+

struct libwebsocket_protocols - List of protocols and handlers server supports.

+struct libwebsocket_protocols {
+    const char * name;
+    callback_function * callback;
+    size_t per_session_data_size;
+    struct libwebsocket_context * owning_server;
+    int broadcast_socket_port;
+    int broadcast_socket_user_fd;
+    int protocol_index;
+};
+

Members

+
+
name +
Protocol name that must match the one given in the client +Javascript new WebSocket(url, 'protocol') name +
callback +
The service callback used for this protocol. It allows the +service action for an entire protocol to be encapsulated in +the protocol-specific callback +
per_session_data_size +
Each new connection using this protocol gets +this much memory allocated on connection establishment and +freed on connection takedown. A pointer to this per-connection +allocation is passed into the callback in the 'user' parameter +
owning_server +
the server init call fills in this opaque pointer when +registering this protocol with the server. +
broadcast_socket_port +
the server init call fills this in with the +localhost port number used to forward broadcasts for this +protocol +
broadcast_socket_user_fd +
the server init call fills this in ... the main +process context can write to this socket to perform broadcasts +(use the libwebsockets_broadcast api to do this instead, +it works from any process context) +
protocol_index +
which protocol we are starting from zero +
+

Description

+
+This structure represents one protocol supported by the server. An +array of these structures is passed to libwebsocket_create_server +allows as many protocols as you like to be handled by one server. +
+
+

struct libwebsocket_extension - An extension we know how to cope with

+struct libwebsocket_extension {
+    const char * name;
+    extension_callback_function * callback;
+    size_t per_session_data_size;
+    void * per_context_private_data;
+};
+

Members

+
+
name +
Formal extension name, eg, "deflate-stream" +
callback +
Service callback +
per_session_data_size +
Libwebsockets will auto-malloc this much +memory for the use of the extension, a pointer +to it comes in the user callback parameter +
per_context_private_data +
Optional storage for this externsion that +is per-context, so it can track stuff across +all sessions, etc, if it wants +
+
diff --git a/libs/libwebsockets/libwebsockets.spec b/libs/libwebsockets/libwebsockets.spec new file mode 100644 index 0000000000..18e4b82f14 --- /dev/null +++ b/libs/libwebsockets/libwebsockets.spec @@ -0,0 +1,63 @@ +Name: libwebsockets +Version: 0.1 +Release: 45.gmaster_f1d2113d%{?dist} +Summary: Websocket Server Library + +Group: System +License: GPL +URL: http://warmcat.com +Source0: %{name}-%{version}.tar.gz +BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) + +BuildRequires: openssl-devel +Requires: openssl-devel + +%description +Webserver server library + +%package devel +Summary: Development files for libwebsockets +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} +Requires: openssl-devel + +%description devel +Development files for libwebsockets + +%prep +%setup -q + +%build +./configure --prefix=/usr --libdir=%{_libdir} --enable-openssl +make + + +%install +rm -rf $RPM_BUILD_ROOT +make install DESTDIR=$RPM_BUILD_ROOT + + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root,-) +%attr(755,root,root) /usr/bin/libwebsockets-test-server +%attr(755,root,root) +/%{_libdir}/libwebsockets.so.0.0.3 +/%{_libdir}/libwebsockets.so.0 +/%{_libdir}/libwebsockets.so +/%{_libdir}/libwebsockets.la +%attr(755,root,root) /usr/share/libwebsockets-test-server +%attr(755,root,root) /usr/share/libwebsockets-test-server-extpoll +%attr(755,root,root) /usr/share/libwebsockets-test-client +%attr(755,root,root) /usr/share/libwebsockets-test-ping +%doc +%files devel +%defattr(-,root,root,-) +/usr/include/* +%attr(755,root,root) +/%{_libdir}/libwebsockets.a + +%changelog + diff --git a/libs/libwebsockets/scripts/kernel-doc b/libs/libwebsockets/scripts/kernel-doc new file mode 100755 index 0000000000..241310e59c --- /dev/null +++ b/libs/libwebsockets/scripts/kernel-doc @@ -0,0 +1,2238 @@ +#!/usr/bin/perl -w + +use strict; + +## Copyright (c) 1998 Michael Zucchi, All Rights Reserved ## +## Copyright (C) 2000, 1 Tim Waugh ## +## Copyright (C) 2001 Simon Huggins ## +## Copyright (C) 2005-2009 Randy Dunlap ## +## ## +## #define enhancements by Armin Kuster ## +## Copyright (c) 2000 MontaVista Software, Inc. ## +## ## +## This software falls under the GNU General Public License. ## +## Please read the COPYING file for more information ## + +# w.o. 03-11-2000: added the '-filelist' option. + +# 18/01/2001 - Cleanups +# Functions prototyped as foo(void) same as foo() +# Stop eval'ing where we don't need to. +# -- huggie@earth.li + +# 27/06/2001 - Allowed whitespace after initial "/**" and +# allowed comments before function declarations. +# -- Christian Kreibich + +# Still to do: +# - add perldoc documentation +# - Look more closely at some of the scarier bits :) + +# 26/05/2001 - Support for separate source and object trees. +# Return error code. +# Keith Owens + +# 23/09/2001 - Added support for typedefs, structs, enums and unions +# Support for Context section; can be terminated using empty line +# Small fixes (like spaces vs. \s in regex) +# -- Tim Jansen + + +# +# This will read a 'c' file and scan for embedded comments in the +# style of gnome comments (+minor extensions - see below). +# + +# Note: This only supports 'c'. + +# usage: +# kernel-doc [ -docbook | -html | -text | -man ] [ -no-doc-sections ] +# [ -function funcname [ -function funcname ...] ] c file(s)s > outputfile +# or +# [ -nofunction funcname [ -function funcname ...] ] c file(s)s > outputfile +# +# Set output format using one of -docbook -html -text or -man. Default is man. +# +# -no-doc-sections +# Do not output DOC: sections +# +# -function funcname +# If set, then only generate documentation for the given function(s) or +# DOC: section titles. All other functions and DOC: sections are ignored. +# +# -nofunction funcname +# If set, then only generate documentation for the other function(s)/DOC: +# sections. Cannot be used together with -function (yes, that's a bug -- +# perl hackers can fix it 8)) +# +# c files - list of 'c' files to process +# +# All output goes to stdout, with errors to stderr. + +# +# format of comments. +# In the following table, (...)? signifies optional structure. +# (...)* signifies 0 or more structure elements +# /** +# * function_name(:)? (- short description)? +# (* @parameterx: (description of parameter x)?)* +# (* a blank line)? +# * (Description:)? (Description of function)? +# * (section header: (section description)? )* +# (*)?*/ +# +# So .. the trivial example would be: +# +# /** +# * my_function +# */ +# +# If the Description: header tag is omitted, then there must be a blank line +# after the last parameter specification. +# e.g. +# /** +# * my_function - does my stuff +# * @my_arg: its mine damnit +# * +# * Does my stuff explained. +# */ +# +# or, could also use: +# /** +# * my_function - does my stuff +# * @my_arg: its mine damnit +# * Description: Does my stuff explained. +# */ +# etc. +# +# Besides functions you can also write documentation for structs, unions, +# enums and typedefs. Instead of the function name you must write the name +# of the declaration; the struct/union/enum/typedef must always precede +# the name. Nesting of declarations is not supported. +# Use the argument mechanism to document members or constants. +# e.g. +# /** +# * struct my_struct - short description +# * @a: first member +# * @b: second member +# * +# * Longer description +# */ +# struct my_struct { +# int a; +# int b; +# /* private: */ +# int c; +# }; +# +# All descriptions can be multiline, except the short function description. +# +# You can also add additional sections. When documenting kernel functions you +# should document the "Context:" of the function, e.g. whether the functions +# can be called form interrupts. Unlike other sections you can end it with an +# empty line. +# Example-sections should contain the string EXAMPLE so that they are marked +# appropriately in DocBook. +# +# Example: +# /** +# * user_function - function that can only be called in user context +# * @a: some argument +# * Context: !in_interrupt() +# * +# * Some description +# * Example: +# * user_function(22); +# */ +# ... +# +# +# All descriptive text is further processed, scanning for the following special +# patterns, which are highlighted appropriately. +# +# 'funcname()' - function +# '$ENVVAR' - environmental variable +# '&struct_name' - name of a structure (up to two words including 'struct') +# '@parameter' - name of a parameter +# '%CONST' - name of a constant. + +my $errors = 0; +my $warnings = 0; +my $anon_struct_union = 0; + +# match expressions used to find embedded type information +my $type_constant = '\%([-_\w]+)'; +my $type_func = '(\w+)\(\)'; +my $type_param = '\@(\w+)'; +my $type_struct = '\&((struct\s*)*[_\w]+)'; +my $type_struct_xml = '\\&((struct\s*)*[_\w]+)'; +my $type_env = '(\$\w+)'; + +# Output conversion substitutions. +# One for each output format + +# these work fairly well +my %highlights_html = ( $type_constant, "\$1", + $type_func, "\$1", + $type_struct_xml, "\$1", + $type_env, "\$1", + $type_param, "\$1" ); +my $local_lt = "\\\\\\\\lt:"; +my $local_gt = "\\\\\\\\gt:"; +my $blankline_html = $local_lt . "p" . $local_gt; # was "

" + +# XML, docbook format +my %highlights_xml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1\$2", + $type_constant, "\$1", + $type_func, "\$1", + $type_struct_xml, "\$1", + $type_env, "\$1", + $type_param, "\$1" ); +my $blankline_xml = $local_lt . "/para" . $local_gt . $local_lt . "para" . $local_gt . "\n"; + +# gnome, docbook format +my %highlights_gnome = ( $type_constant, "\$1", + $type_func, "\$1", + $type_struct, "\$1", + $type_env, "\$1", + $type_param, "\$1" ); +my $blankline_gnome = "\n"; + +# these are pretty rough +my %highlights_man = ( $type_constant, "\$1", + $type_func, "\\\\fB\$1\\\\fP", + $type_struct, "\\\\fI\$1\\\\fP", + $type_param, "\\\\fI\$1\\\\fP" ); +my $blankline_man = ""; + +# text-mode +my %highlights_text = ( $type_constant, "\$1", + $type_func, "\$1", + $type_struct, "\$1", + $type_param, "\$1" ); +my $blankline_text = ""; + + +sub usage { + print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man ] [ -no-doc-sections ]\n"; + print " [ -function funcname [ -function funcname ...] ]\n"; + print " [ -nofunction funcname [ -nofunction funcname ...] ]\n"; + print " c source file(s) > outputfile\n"; + print " -v : verbose output, more warnings & other info listed\n"; + exit 1; +} + +# read arguments +if ($#ARGV == -1) { + usage(); +} + +my $verbose = 0; +my $output_mode = "man"; +my $no_doc_sections = 0; +my %highlights = %highlights_man; +my $blankline = $blankline_man; +my $modulename = "Kernel API"; +my $function_only = 0; +my $man_date = ('January', 'February', 'March', 'April', 'May', 'June', + 'July', 'August', 'September', 'October', + 'November', 'December')[(localtime)[4]] . + " " . ((localtime)[5]+1900); + +# Essentially these are globals +# They probably want to be tidied up, made more localised or something. +# CAVEAT EMPTOR! Some of the others I localised may not want to be, which +# could cause "use of undefined value" or other bugs. +my ($function, %function_table, %parametertypes, $declaration_purpose); +my ($type, $declaration_name, $return_type); +my ($newsection, $newcontents, $prototype, $filelist, $brcount, %source_map); + +if (defined($ENV{'KBUILD_VERBOSE'})) { + $verbose = "$ENV{'KBUILD_VERBOSE'}"; +} + +# Generated docbook code is inserted in a template at a point where +# docbook v3.1 requires a non-zero sequence of RefEntry's; see: +# http://www.oasis-open.org/docbook/documentation/reference/html/refentry.html +# We keep track of number of generated entries and generate a dummy +# if needs be to ensure the expanded template can be postprocessed +# into html. +my $section_counter = 0; + +my $lineprefix=""; + +# states +# 0 - normal code +# 1 - looking for function name +# 2 - scanning field start. +# 3 - scanning prototype. +# 4 - documentation block +my $state; +my $in_doc_sect; + +#declaration types: can be +# 'function', 'struct', 'union', 'enum', 'typedef' +my $decl_type; + +my $doc_special = "\@\%\$\&"; + +my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start. +my $doc_end = '\*/'; +my $doc_com = '\s*\*\s*'; +my $doc_decl = $doc_com . '(\w+)'; +my $doc_sect = $doc_com . '([' . $doc_special . ']?[\w\s]+):(.*)'; +my $doc_content = $doc_com . '(.*)'; +my $doc_block = $doc_com . 'DOC:\s*(.*)?'; + +my %constants; +my %parameterdescs; +my @parameterlist; +my %sections; +my @sectionlist; +my $sectcheck; +my $struct_actual; + +my $contents = ""; +my $section_default = "Description"; # default section +my $section_intro = "Introduction"; +my $section = $section_default; +my $section_context = "Context"; + +my $undescribed = "-- undescribed --"; + +reset_state(); + +while ($ARGV[0] =~ m/^-(.*)/) { + my $cmd = shift @ARGV; + if ($cmd eq "-html") { + $output_mode = "html"; + %highlights = %highlights_html; + $blankline = $blankline_html; + } elsif ($cmd eq "-man") { + $output_mode = "man"; + %highlights = %highlights_man; + $blankline = $blankline_man; + } elsif ($cmd eq "-text") { + $output_mode = "text"; + %highlights = %highlights_text; + $blankline = $blankline_text; + } elsif ($cmd eq "-docbook") { + $output_mode = "xml"; + %highlights = %highlights_xml; + $blankline = $blankline_xml; + } elsif ($cmd eq "-gnome") { + $output_mode = "gnome"; + %highlights = %highlights_gnome; + $blankline = $blankline_gnome; + } elsif ($cmd eq "-module") { # not needed for XML, inherits from calling document + $modulename = shift @ARGV; + } elsif ($cmd eq "-function") { # to only output specific functions + $function_only = 1; + $function = shift @ARGV; + $function_table{$function} = 1; + } elsif ($cmd eq "-nofunction") { # to only output specific functions + $function_only = 2; + $function = shift @ARGV; + $function_table{$function} = 1; + } elsif ($cmd eq "-v") { + $verbose = 1; + } elsif (($cmd eq "-h") || ($cmd eq "--help")) { + usage(); + } elsif ($cmd eq '-filelist') { + $filelist = shift @ARGV; + } elsif ($cmd eq '-no-doc-sections') { + $no_doc_sections = 1; + } +} + +# get kernel version from env +sub get_kernel_version() { + my $version = 'unknown kernel version'; + + if (defined($ENV{'KERNELVERSION'})) { + $version = $ENV{'KERNELVERSION'}; + } + return $version; +} +my $kernelversion = get_kernel_version(); + +# generate a sequence of code that will splice in highlighting information +# using the s// operator. +my $dohighlight = ""; +foreach my $pattern (keys %highlights) { +# print STDERR "scanning pattern:$pattern, highlight:($highlights{$pattern})\n"; + $dohighlight .= "\$contents =~ s:$pattern:$highlights{$pattern}:gs;\n"; +} + +## +# dumps section contents to arrays/hashes intended for that purpose. +# +sub dump_section { + my $file = shift; + my $name = shift; + my $contents = join "\n", @_; + + if ($name =~ m/$type_constant/) { + $name = $1; +# print STDERR "constant section '$1' = '$contents'\n"; + $constants{$name} = $contents; + } elsif ($name =~ m/$type_param/) { +# print STDERR "parameter def '$1' = '$contents'\n"; + $name = $1; + $parameterdescs{$name} = $contents; + $sectcheck = $sectcheck . $name . " "; + } elsif ($name eq "@\.\.\.") { +# print STDERR "parameter def '...' = '$contents'\n"; + $name = "..."; + $parameterdescs{$name} = $contents; + $sectcheck = $sectcheck . $name . " "; + } else { +# print STDERR "other section '$name' = '$contents'\n"; + if (defined($sections{$name}) && ($sections{$name} ne "")) { + print STDERR "Error(${file}:$.): duplicate section name '$name'\n"; + ++$errors; + } + $sections{$name} = $contents; + push @sectionlist, $name; + } +} + +## +# dump DOC: section after checking that it should go out +# +sub dump_doc_section { + my $file = shift; + my $name = shift; + my $contents = join "\n", @_; + + if ($no_doc_sections) { + return; + } + + if (($function_only == 0) || + ( $function_only == 1 && defined($function_table{$name})) || + ( $function_only == 2 && !defined($function_table{$name}))) + { + dump_section($file, $name, $contents); + output_blockhead({'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'module' => $modulename, + 'content-only' => ($function_only != 0), }); + } +} + +## +# output function +# +# parameterdescs, a hash. +# function => "function name" +# parameterlist => @list of parameters +# parameterdescs => %parameter descriptions +# sectionlist => @list of sections +# sections => %section descriptions +# + +sub output_highlight { + my $contents = join "\n",@_; + my $line; + +# DEBUG +# if (!defined $contents) { +# use Carp; +# confess "output_highlight got called with no args?\n"; +# } + + if ($output_mode eq "html" || $output_mode eq "xml") { + $contents = local_unescape($contents); + # convert data read & converted thru xml_escape() into &xyz; format: + $contents =~ s/\\\\\\/&/g; + } +# print STDERR "contents b4:$contents\n"; + eval $dohighlight; + die $@ if $@; +# print STDERR "contents af:$contents\n"; + + foreach $line (split "\n", $contents) { + if ($line eq ""){ + print $lineprefix, local_unescape($blankline); + } else { + $line =~ s/\\\\\\/\&/g; + if ($output_mode eq "man" && substr($line, 0, 1) eq ".") { + print "\\&$line"; + } else { + print $lineprefix, $line; + } + } + print "\n"; + } +} + +#output sections in html +sub output_section_html(%) { + my %args = %{$_[0]}; + my $section; + + foreach $section (@{$args{'sectionlist'}}) { + print "

$section

\n"; + print "
\n"; + output_highlight($args{'sections'}{$section}); + print "
\n"; + } +} + +# output enum in html +sub output_enum_html(%) { + my %args = %{$_[0]}; + my ($parameter); + my $count; + print "

enum " . $args{'enum'} . "

\n"; + + print "enum " . $args{'enum'} . " {
\n"; + $count = 0; + foreach $parameter (@{$args{'parameterlist'}}) { + print " " . $parameter . ""; + if ($count != $#{$args{'parameterlist'}}) { + $count++; + print ",\n"; + } + print "
"; + } + print "};
\n"; + + print "

Constants

\n"; + print "
\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + print "
" . $parameter . "\n"; + print "
"; + output_highlight($args{'parameterdescs'}{$parameter}); + } + print "
\n"; + output_section_html(@_); + print "
\n"; +} + +# output typedef in html +sub output_typedef_html(%) { + my %args = %{$_[0]}; + my ($parameter); + my $count; + print "

typedef " . $args{'typedef'} . "

\n"; + + print "typedef " . $args{'typedef'} . "\n"; + output_section_html(@_); + print "
\n"; +} + +# output struct in html +sub output_struct_html(%) { + my %args = %{$_[0]}; + my ($parameter); + + print "

" . $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "

\n"; + print "" . $args{'type'} . " " . $args{'struct'} . " {
\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + if ($parameter =~ /^#/) { + print "$parameter
\n"; + next; + } + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { + # pointer-to-function + print "    $1$parameter) ($2);
\n"; + } elsif ($type =~ m/^(.*?)\s*(:.*)/) { + # bitfield + print "    $1 $parameter$2;
\n"; + } else { + print "    $type $parameter;
\n"; + } + } + print "};
\n"; + + print "

Members

\n"; + print "
\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + ($parameter =~ /^#/) && next; + + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + print "
" . $parameter . "\n"; + print "
"; + output_highlight($args{'parameterdescs'}{$parameter_name}); + } + print "
\n"; + output_section_html(@_); + print "
\n"; +} + +# output function in html +sub output_function_html(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $count; + + print "

" . $args{'function'} . " - " . $args{'purpose'} . "

\n"; + print "" . $args{'functiontype'} . "\n"; + print "" . $args{'function'} . "\n"; + print "("; + $count = 0; + foreach $parameter (@{$args{'parameterlist'}}) { + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { + # pointer-to-function + print "$1$parameter) ($2)"; + } else { + print "" . $type . " " . $parameter . ""; + } + if ($count != $#{$args{'parameterlist'}}) { + $count++; + print ",\n"; + } + } + print ")\n"; + + print "

Arguments

\n"; + print "
\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + print "
" . $parameter . "\n"; + print "
"; + output_highlight($args{'parameterdescs'}{$parameter_name}); + } + print "
\n"; + output_section_html(@_); + print "
\n"; +} + +# output DOC: block header in html +sub output_blockhead_html(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $count; + + foreach $section (@{$args{'sectionlist'}}) { + print "

$section

\n"; + print "
    \n"; + output_highlight($args{'sections'}{$section}); + print "
\n"; + } + print "
\n"; +} + +sub output_section_xml(%) { + my %args = %{$_[0]}; + my $section; + # print out each section + $lineprefix=" "; + foreach $section (@{$args{'sectionlist'}}) { + print "\n"; + print "$section\n"; + if ($section =~ m/EXAMPLE/i) { + print "\n"; + } else { + print "\n"; + } + output_highlight($args{'sections'}{$section}); + if ($section =~ m/EXAMPLE/i) { + print "\n"; + } else { + print "\n"; + } + print "\n"; + } +} + +# output function in XML DocBook +sub output_function_xml(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $count; + my $id; + + $id = "API-" . $args{'function'}; + $id =~ s/[^A-Za-z0-9]/-/g; + + print "\n"; + print "\n"; + print " LINUX\n"; + print " Kernel Hackers Manual\n"; + print " $man_date\n"; + print "\n"; + print "\n"; + print " " . $args{'function'} . "\n"; + print " 9\n"; + print " " . $kernelversion . "\n"; + print "\n"; + print "\n"; + print " " . $args{'function'} . "\n"; + print " \n"; + print " "; + output_highlight ($args{'purpose'}); + print " \n"; + print "\n"; + + print "\n"; + print " Synopsis\n"; + print " \n"; + print " " . $args{'functiontype'} . " "; + print "" . $args{'function'} . " \n"; + + $count = 0; + if ($#{$args{'parameterlist'}} >= 0) { + foreach $parameter (@{$args{'parameterlist'}}) { + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { + # pointer-to-function + print " $1$parameter)\n"; + print " $2\n"; + } else { + print " " . $type; + print " $parameter\n"; + } + } + } else { + print " \n"; + } + print " \n"; + print "\n"; + + # print parameters + print "\n Arguments\n"; + if ($#{$args{'parameterlist'}} >= 0) { + print " \n"; + foreach $parameter (@{$args{'parameterlist'}}) { + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + print " \n $parameter\n"; + print " \n \n"; + $lineprefix=" "; + output_highlight($args{'parameterdescs'}{$parameter_name}); + print " \n \n \n"; + } + print " \n"; + } else { + print " \n None\n \n"; + } + print "\n"; + + output_section_xml(@_); + print "\n\n"; +} + +# output struct in XML DocBook +sub output_struct_xml(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $id; + + $id = "API-struct-" . $args{'struct'}; + $id =~ s/[^A-Za-z0-9]/-/g; + + print "\n"; + print "\n"; + print " LINUX\n"; + print " Kernel Hackers Manual\n"; + print " $man_date\n"; + print "\n"; + print "\n"; + print " " . $args{'type'} . " " . $args{'struct'} . "\n"; + print " 9\n"; + print " " . $kernelversion . "\n"; + print "\n"; + print "\n"; + print " " . $args{'type'} . " " . $args{'struct'} . "\n"; + print " \n"; + print " "; + output_highlight ($args{'purpose'}); + print " \n"; + print "\n"; + + print "\n"; + print " Synopsis\n"; + print " \n"; + print $args{'type'} . " " . $args{'struct'} . " {\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + if ($parameter =~ /^#/) { + print "$parameter\n"; + next; + } + + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + defined($args{'parameterdescs'}{$parameter_name}) || next; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { + # pointer-to-function + print " $1 $parameter) ($2);\n"; + } elsif ($type =~ m/^(.*?)\s*(:.*)/) { + # bitfield + print " $1 $parameter$2;\n"; + } else { + print " " . $type . " " . $parameter . ";\n"; + } + } + print "};"; + print " \n"; + print "\n"; + + print " \n"; + print " Members\n"; + + if ($#{$args{'parameterlist'}} >= 0) { + print " \n"; + foreach $parameter (@{$args{'parameterlist'}}) { + ($parameter =~ /^#/) && next; + + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + defined($args{'parameterdescs'}{$parameter_name}) || next; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + print " "; + print " $parameter\n"; + print " \n"; + output_highlight($args{'parameterdescs'}{$parameter_name}); + print " \n"; + print " \n"; + } + print " \n"; + } else { + print " \n None\n \n"; + } + print " \n"; + + output_section_xml(@_); + + print "\n\n"; +} + +# output enum in XML DocBook +sub output_enum_xml(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $count; + my $id; + + $id = "API-enum-" . $args{'enum'}; + $id =~ s/[^A-Za-z0-9]/-/g; + + print "\n"; + print "\n"; + print " LINUX\n"; + print " Kernel Hackers Manual\n"; + print " $man_date\n"; + print "\n"; + print "\n"; + print " enum " . $args{'enum'} . "\n"; + print " 9\n"; + print " " . $kernelversion . "\n"; + print "\n"; + print "\n"; + print " enum " . $args{'enum'} . "\n"; + print " \n"; + print " "; + output_highlight ($args{'purpose'}); + print " \n"; + print "\n"; + + print "\n"; + print " Synopsis\n"; + print " \n"; + print "enum " . $args{'enum'} . " {\n"; + $count = 0; + foreach $parameter (@{$args{'parameterlist'}}) { + print " $parameter"; + if ($count != $#{$args{'parameterlist'}}) { + $count++; + print ","; + } + print "\n"; + } + print "};"; + print " \n"; + print "\n"; + + print "\n"; + print " Constants\n"; + print " \n"; + foreach $parameter (@{$args{'parameterlist'}}) { + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + print " "; + print " $parameter\n"; + print " \n"; + output_highlight($args{'parameterdescs'}{$parameter_name}); + print " \n"; + print " \n"; + } + print " \n"; + print "\n"; + + output_section_xml(@_); + + print "\n\n"; +} + +# output typedef in XML DocBook +sub output_typedef_xml(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $id; + + $id = "API-typedef-" . $args{'typedef'}; + $id =~ s/[^A-Za-z0-9]/-/g; + + print "\n"; + print "\n"; + print " LINUX\n"; + print " Kernel Hackers Manual\n"; + print " $man_date\n"; + print "\n"; + print "\n"; + print " typedef " . $args{'typedef'} . "\n"; + print " 9\n"; + print "\n"; + print "\n"; + print " typedef " . $args{'typedef'} . "\n"; + print " \n"; + print " "; + output_highlight ($args{'purpose'}); + print " \n"; + print "\n"; + + print "\n"; + print " Synopsis\n"; + print " typedef " . $args{'typedef'} . ";\n"; + print "\n"; + + output_section_xml(@_); + + print "\n\n"; +} + +# output in XML DocBook +sub output_blockhead_xml(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $count; + + my $id = $args{'module'}; + $id =~ s/[^A-Za-z0-9]/-/g; + + # print out each section + $lineprefix=" "; + foreach $section (@{$args{'sectionlist'}}) { + if (!$args{'content-only'}) { + print "\n $section\n"; + } + if ($section =~ m/EXAMPLE/i) { + print "\n"; + } else { + print "\n"; + } + output_highlight($args{'sections'}{$section}); + if ($section =~ m/EXAMPLE/i) { + print "\n"; + } else { + print ""; + } + if (!$args{'content-only'}) { + print "\n\n"; + } + } + + print "\n\n"; +} + +# output in XML DocBook +sub output_function_gnome { + my %args = %{$_[0]}; + my ($parameter, $section); + my $count; + my $id; + + $id = $args{'module'} . "-" . $args{'function'}; + $id =~ s/[^A-Za-z0-9]/-/g; + + print "\n"; + print " " . $args{'function'} . "\n"; + + print " \n"; + print " " . $args{'functiontype'} . " "; + print "" . $args{'function'} . " "; + print "\n"; + + $count = 0; + if ($#{$args{'parameterlist'}} >= 0) { + foreach $parameter (@{$args{'parameterlist'}}) { + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { + # pointer-to-function + print " $1 $parameter)\n"; + print " $2\n"; + } else { + print " " . $type; + print " $parameter\n"; + } + } + } else { + print " \n"; + } + print " \n"; + if ($#{$args{'parameterlist'}} >= 0) { + print " \n"; + print "\n"; + print "\n"; + print "\n"; + print "\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + print " $parameter\n"; + print " \n"; + $lineprefix=" "; + output_highlight($args{'parameterdescs'}{$parameter_name}); + print " \n"; + } + print " \n"; + } else { + print " \n None\n \n"; + } + + # print out each section + $lineprefix=" "; + foreach $section (@{$args{'sectionlist'}}) { + print "\n $section\n"; + if ($section =~ m/EXAMPLE/i) { + print "\n"; + } else { + } + print "\n"; + output_highlight($args{'sections'}{$section}); + print "\n"; + if ($section =~ m/EXAMPLE/i) { + print "\n"; + } else { + } + print " \n"; + } + + print "\n\n"; +} + +## +# output function in man +sub output_function_man(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $count; + + print ".TH \"$args{'function'}\" 9 \"$args{'function'}\" \"$man_date\" \"Kernel Hacker's Manual\" LINUX\n"; + + print ".SH NAME\n"; + print $args{'function'} . " \\- " . $args{'purpose'} . "\n"; + + print ".SH SYNOPSIS\n"; + if ($args{'functiontype'} ne "") { + print ".B \"" . $args{'functiontype'} . "\" " . $args{'function'} . "\n"; + } else { + print ".B \"" . $args{'function'} . "\n"; + } + $count = 0; + my $parenth = "("; + my $post = ","; + foreach my $parameter (@{$args{'parameterlist'}}) { + if ($count == $#{$args{'parameterlist'}}) { + $post = ");"; + } + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { + # pointer-to-function + print ".BI \"" . $parenth . $1 . "\" " . $parameter . " \") (" . $2 . ")" . $post . "\"\n"; + } else { + $type =~ s/([^\*])$/$1 /; + print ".BI \"" . $parenth . $type . "\" " . $parameter . " \"" . $post . "\"\n"; + } + $count++; + $parenth = ""; + } + + print ".SH ARGUMENTS\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + print ".IP \"" . $parameter . "\" 12\n"; + output_highlight($args{'parameterdescs'}{$parameter_name}); + } + foreach $section (@{$args{'sectionlist'}}) { + print ".SH \"", uc $section, "\"\n"; + output_highlight($args{'sections'}{$section}); + } +} + +## +# output enum in man +sub output_enum_man(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $count; + + print ".TH \"$args{'module'}\" 9 \"enum $args{'enum'}\" \"$man_date\" \"API Manual\" LINUX\n"; + + print ".SH NAME\n"; + print "enum " . $args{'enum'} . " \\- " . $args{'purpose'} . "\n"; + + print ".SH SYNOPSIS\n"; + print "enum " . $args{'enum'} . " {\n"; + $count = 0; + foreach my $parameter (@{$args{'parameterlist'}}) { + print ".br\n.BI \" $parameter\"\n"; + if ($count == $#{$args{'parameterlist'}}) { + print "\n};\n"; + last; + } + else { + print ", \n.br\n"; + } + $count++; + } + + print ".SH Constants\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + print ".IP \"" . $parameter . "\" 12\n"; + output_highlight($args{'parameterdescs'}{$parameter_name}); + } + foreach $section (@{$args{'sectionlist'}}) { + print ".SH \"$section\"\n"; + output_highlight($args{'sections'}{$section}); + } +} + +## +# output struct in man +sub output_struct_man(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + + print ".TH \"$args{'module'}\" 9 \"" . $args{'type'} . " " . $args{'struct'} . "\" \"$man_date\" \"API Manual\" LINUX\n"; + + print ".SH NAME\n"; + print $args{'type'} . " " . $args{'struct'} . " \\- " . $args{'purpose'} . "\n"; + + print ".SH SYNOPSIS\n"; + print $args{'type'} . " " . $args{'struct'} . " {\n.br\n"; + + foreach my $parameter (@{$args{'parameterlist'}}) { + if ($parameter =~ /^#/) { + print ".BI \"$parameter\"\n.br\n"; + next; + } + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { + # pointer-to-function + print ".BI \" " . $1 . "\" " . $parameter . " \") (" . $2 . ")" . "\"\n;\n"; + } elsif ($type =~ m/^(.*?)\s*(:.*)/) { + # bitfield + print ".BI \" " . $1 . "\ \" " . $parameter . $2 . " \"" . "\"\n;\n"; + } else { + $type =~ s/([^\*])$/$1 /; + print ".BI \" " . $type . "\" " . $parameter . " \"" . "\"\n;\n"; + } + print "\n.br\n"; + } + print "};\n.br\n"; + + print ".SH Members\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + ($parameter =~ /^#/) && next; + + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + print ".IP \"" . $parameter . "\" 12\n"; + output_highlight($args{'parameterdescs'}{$parameter_name}); + } + foreach $section (@{$args{'sectionlist'}}) { + print ".SH \"$section\"\n"; + output_highlight($args{'sections'}{$section}); + } +} + +## +# output typedef in man +sub output_typedef_man(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + + print ".TH \"$args{'module'}\" 9 \"$args{'typedef'}\" \"$man_date\" \"API Manual\" LINUX\n"; + + print ".SH NAME\n"; + print "typedef " . $args{'typedef'} . " \\- " . $args{'purpose'} . "\n"; + + foreach $section (@{$args{'sectionlist'}}) { + print ".SH \"$section\"\n"; + output_highlight($args{'sections'}{$section}); + } +} + +sub output_blockhead_man(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $count; + + print ".TH \"$args{'module'}\" 9 \"$args{'module'}\" \"$man_date\" \"API Manual\" LINUX\n"; + + foreach $section (@{$args{'sectionlist'}}) { + print ".SH \"$section\"\n"; + output_highlight($args{'sections'}{$section}); + } +} + +## +# output in text +sub output_function_text(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $start; + + print "Name:\n\n"; + print $args{'function'} . " - " . $args{'purpose'} . "\n"; + + print "\nSynopsis:\n\n"; + if ($args{'functiontype'} ne "") { + $start = $args{'functiontype'} . " " . $args{'function'} . " ("; + } else { + $start = $args{'function'} . " ("; + } + print $start; + + my $count = 0; + foreach my $parameter (@{$args{'parameterlist'}}) { + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { + # pointer-to-function + print $1 . $parameter . ") (" . $2; + } else { + print $type . " " . $parameter; + } + if ($count != $#{$args{'parameterlist'}}) { + $count++; + print ",\n"; + print " " x length($start); + } else { + print ");\n\n"; + } + } + + print "Arguments:\n\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + print $parameter . "\n\t" . $args{'parameterdescs'}{$parameter_name} . "\n"; + } + output_section_text(@_); +} + +#output sections in text +sub output_section_text(%) { + my %args = %{$_[0]}; + my $section; + + print "\n"; + foreach $section (@{$args{'sectionlist'}}) { + print "$section:\n\n"; + output_highlight($args{'sections'}{$section}); + } + print "\n\n"; +} + +# output enum in text +sub output_enum_text(%) { + my %args = %{$_[0]}; + my ($parameter); + my $count; + print "Enum:\n\n"; + + print "enum " . $args{'enum'} . " - " . $args{'purpose'} . "\n\n"; + print "enum " . $args{'enum'} . " {\n"; + $count = 0; + foreach $parameter (@{$args{'parameterlist'}}) { + print "\t$parameter"; + if ($count != $#{$args{'parameterlist'}}) { + $count++; + print ","; + } + print "\n"; + } + print "};\n\n"; + + print "Constants:\n\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + print "$parameter\n\t"; + print $args{'parameterdescs'}{$parameter} . "\n"; + } + + output_section_text(@_); +} + +# output typedef in text +sub output_typedef_text(%) { + my %args = %{$_[0]}; + my ($parameter); + my $count; + print "Typedef:\n\n"; + + print "typedef " . $args{'typedef'} . " - " . $args{'purpose'} . "\n"; + output_section_text(@_); +} + +# output struct as text +sub output_struct_text(%) { + my %args = %{$_[0]}; + my ($parameter); + + print $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "\n\n"; + print $args{'type'} . " " . $args{'struct'} . " {\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + if ($parameter =~ /^#/) { + print "$parameter\n"; + next; + } + + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { + # pointer-to-function + print "\t$1 $parameter) ($2);\n"; + } elsif ($type =~ m/^(.*?)\s*(:.*)/) { + # bitfield + print "\t$1 $parameter$2;\n"; + } else { + print "\t" . $type . " " . $parameter . ";\n"; + } + } + print "};\n\n"; + + print "Members:\n\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + ($parameter =~ /^#/) && next; + + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + print "$parameter\n\t"; + print $args{'parameterdescs'}{$parameter_name} . "\n"; + } + print "\n"; + output_section_text(@_); +} + +sub output_blockhead_text(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + + foreach $section (@{$args{'sectionlist'}}) { + print " $section:\n"; + print " -> "; + output_highlight($args{'sections'}{$section}); + } +} + +## +# generic output function for all types (function, struct/union, typedef, enum); +# calls the generated, variable output_ function name based on +# functype and output_mode +sub output_declaration { + no strict 'refs'; + my $name = shift; + my $functype = shift; + my $func = "output_${functype}_$output_mode"; + if (($function_only==0) || + ( $function_only == 1 && defined($function_table{$name})) || + ( $function_only == 2 && !defined($function_table{$name}))) + { + &$func(@_); + $section_counter++; + } +} + +## +# generic output function - calls the right one based on current output mode. +sub output_blockhead { + no strict 'refs'; + my $func = "output_blockhead_" . $output_mode; + &$func(@_); + $section_counter++; +} + +## +# takes a declaration (struct, union, enum, typedef) and +# invokes the right handler. NOT called for functions. +sub dump_declaration($$) { + no strict 'refs'; + my ($prototype, $file) = @_; + my $func = "dump_" . $decl_type; + &$func(@_); +} + +sub dump_union($$) { + dump_struct(@_); +} + +sub dump_struct($$) { + my $x = shift; + my $file = shift; + my $nested; + + if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) { + #my $decl_type = $1; + $declaration_name = $2; + my $members = $3; + + # ignore embedded structs or unions + $members =~ s/({.*})//g; + $nested = $1; + + # ignore members marked private: + $members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gos; + $members =~ s/\/\*\s*private:.*//gos; + # strip comments: + $members =~ s/\/\*.*?\*\///gos; + $nested =~ s/\/\*.*?\*\///gos; + # strip kmemcheck_bitfield_{begin,end}.*; + $members =~ s/kmemcheck_bitfield_.*?;//gos; + + create_parameterlist($members, ';', $file); + check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested); + + output_declaration($declaration_name, + 'struct', + {'struct' => $declaration_name, + 'module' => $modulename, + 'parameterlist' => \@parameterlist, + 'parameterdescs' => \%parameterdescs, + 'parametertypes' => \%parametertypes, + 'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'purpose' => $declaration_purpose, + 'type' => $decl_type + }); + } + else { + print STDERR "Error(${file}:$.): Cannot parse struct or union!\n"; + ++$errors; + } +} + +sub dump_enum($$) { + my $x = shift; + my $file = shift; + + $x =~ s@/\*.*?\*/@@gos; # strip comments. + if ($x =~ /enum\s+(\w+)\s*{(.*)}/) { + $declaration_name = $1; + my $members = $2; + + foreach my $arg (split ',', $members) { + $arg =~ s/^\s*(\w+).*/$1/; + push @parameterlist, $arg; + if (!$parameterdescs{$arg}) { + $parameterdescs{$arg} = $undescribed; + print STDERR "Warning(${file}:$.): Enum value '$arg' ". + "not described in enum '$declaration_name'\n"; + } + + } + + output_declaration($declaration_name, + 'enum', + {'enum' => $declaration_name, + 'module' => $modulename, + 'parameterlist' => \@parameterlist, + 'parameterdescs' => \%parameterdescs, + 'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'purpose' => $declaration_purpose + }); + } + else { + print STDERR "Error(${file}:$.): Cannot parse enum!\n"; + ++$errors; + } +} + +sub dump_typedef($$) { + my $x = shift; + my $file = shift; + + $x =~ s@/\*.*?\*/@@gos; # strip comments. + while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) { + $x =~ s/\(*.\)\s*;$/;/; + $x =~ s/\[*.\]\s*;$/;/; + } + + if ($x =~ /typedef.*\s+(\w+)\s*;/) { + $declaration_name = $1; + + output_declaration($declaration_name, + 'typedef', + {'typedef' => $declaration_name, + 'module' => $modulename, + 'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'purpose' => $declaration_purpose + }); + } + else { + print STDERR "Error(${file}:$.): Cannot parse typedef!\n"; + ++$errors; + } +} + +sub save_struct_actual($) { + my $actual = shift; + + # strip all spaces from the actual param so that it looks like one string item + $actual =~ s/\s*//g; + $struct_actual = $struct_actual . $actual . " "; +} + +sub create_parameterlist($$$) { + my $args = shift; + my $splitter = shift; + my $file = shift; + my $type; + my $param; + + # temporarily replace commas inside function pointer definition + while ($args =~ /(\([^\),]+),/) { + $args =~ s/(\([^\),]+),/$1#/g; + } + + foreach my $arg (split($splitter, $args)) { + # strip comments + $arg =~ s/\/\*.*\*\///; + # strip leading/trailing spaces + $arg =~ s/^\s*//; + $arg =~ s/\s*$//; + $arg =~ s/\s+/ /; + + if ($arg =~ /^#/) { + # Treat preprocessor directive as a typeless variable just to fill + # corresponding data structures "correctly". Catch it later in + # output_* subs. + push_parameter($arg, "", $file); + } elsif ($arg =~ m/\(.+\)\s*\(/) { + # pointer-to-function + $arg =~ tr/#/,/; + $arg =~ m/[^\(]+\(\*?\s*(\w*)\s*\)/; + $param = $1; + $type = $arg; + $type =~ s/([^\(]+\(\*?)\s*$param/$1/; + save_struct_actual($param); + push_parameter($param, $type, $file); + } elsif ($arg) { + $arg =~ s/\s*:\s*/:/g; + $arg =~ s/\s*\[/\[/g; + + my @args = split('\s*,\s*', $arg); + if ($args[0] =~ m/\*/) { + $args[0] =~ s/(\*+)\s*/ $1/; + } + + my @first_arg; + if ($args[0] =~ /^(.*\s+)(.*?\[.*\].*)$/) { + shift @args; + push(@first_arg, split('\s+', $1)); + push(@first_arg, $2); + } else { + @first_arg = split('\s+', shift @args); + } + + unshift(@args, pop @first_arg); + $type = join " ", @first_arg; + + foreach $param (@args) { + if ($param =~ m/^(\*+)\s*(.*)/) { + save_struct_actual($2); + push_parameter($2, "$type $1", $file); + } + elsif ($param =~ m/(.*?):(\d+)/) { + if ($type ne "") { # skip unnamed bit-fields + save_struct_actual($1); + push_parameter($1, "$type:$2", $file) + } + } + else { + save_struct_actual($param); + push_parameter($param, $type, $file); + } + } + } + } +} + +sub push_parameter($$$) { + my $param = shift; + my $type = shift; + my $file = shift; + + if (($anon_struct_union == 1) && ($type eq "") && + ($param eq "}")) { + return; # ignore the ending }; from anon. struct/union + } + + $anon_struct_union = 0; + my $param_name = $param; + $param_name =~ s/\[.*//; + + if ($type eq "" && $param =~ /\.\.\.$/) + { + if (!defined $parameterdescs{$param} || $parameterdescs{$param} eq "") { + $parameterdescs{$param} = "variable arguments"; + } + } + elsif ($type eq "" && ($param eq "" or $param eq "void")) + { + $param="void"; + $parameterdescs{void} = "no arguments"; + } + elsif ($type eq "" && ($param eq "struct" or $param eq "union")) + # handle unnamed (anonymous) union or struct: + { + $type = $param; + $param = "{unnamed_" . $param . "}"; + $parameterdescs{$param} = "anonymous\n"; + $anon_struct_union = 1; + } + + # warn if parameter has no description + # (but ignore ones starting with # as these are not parameters + # but inline preprocessor statements); + # also ignore unnamed structs/unions; + if (!$anon_struct_union) { + if (!defined $parameterdescs{$param_name} && $param_name !~ /^#/) { + + $parameterdescs{$param_name} = $undescribed; + + if (($type eq 'function') || ($type eq 'enum')) { + print STDERR "Warning(${file}:$.): Function parameter ". + "or member '$param' not " . + "described in '$declaration_name'\n"; + } + print STDERR "Warning(${file}:$.):" . + " No description found for parameter '$param'\n"; + ++$warnings; + } + } + + # strip spaces from $param so that it is one continous string + # on @parameterlist; + # this fixes a problem where check_sections() cannot find + # a parameter like "addr[6 + 2]" because it actually appears + # as "addr[6", "+", "2]" on the parameter list; + # but it's better to maintain the param string unchanged for output, + # so just weaken the string compare in check_sections() to ignore + # "[blah" in a parameter string; + ###$param =~ s/\s*//g; + push @parameterlist, $param; + $parametertypes{$param} = $type; +} + +sub check_sections($$$$$$) { + my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck, $nested) = @_; + my @sects = split ' ', $sectcheck; + my @prms = split ' ', $prmscheck; + my $err; + my ($px, $sx); + my $prm_clean; # strip trailing "[array size]" and/or beginning "*" + + foreach $sx (0 .. $#sects) { + $err = 1; + foreach $px (0 .. $#prms) { + $prm_clean = $prms[$px]; + $prm_clean =~ s/\[.*\]//; + $prm_clean =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//; + # ignore array size in a parameter string; + # however, the original param string may contain + # spaces, e.g.: addr[6 + 2] + # and this appears in @prms as "addr[6" since the + # parameter list is split at spaces; + # hence just ignore "[..." for the sections check; + $prm_clean =~ s/\[.*//; + + ##$prm_clean =~ s/^\**//; + if ($prm_clean eq $sects[$sx]) { + $err = 0; + last; + } + } + if ($err) { + if ($decl_type eq "function") { + print STDERR "Warning(${file}:$.): " . + "Excess function parameter " . + "'$sects[$sx]' " . + "description in '$decl_name'\n"; + ++$warnings; + } else { + if ($nested !~ m/\Q$sects[$sx]\E/) { + print STDERR "Warning(${file}:$.): " . + "Excess struct/union/enum/typedef member " . + "'$sects[$sx]' " . + "description in '$decl_name'\n"; + ++$warnings; + } + } + } + } +} + +## +# takes a function prototype and the name of the current file being +# processed and spits out all the details stored in the global +# arrays/hashes. +sub dump_function($$) { + my $prototype = shift; + my $file = shift; + + $prototype =~ s/^static +//; + $prototype =~ s/^extern +//; + $prototype =~ s/^asmlinkage +//; + $prototype =~ s/^inline +//; + $prototype =~ s/^__inline__ +//; + $prototype =~ s/^__inline +//; + $prototype =~ s/^__always_inline +//; + $prototype =~ s/^noinline +//; + $prototype =~ s/__devinit +//; + $prototype =~ s/__init +//; + $prototype =~ s/^#\s*define\s+//; #ak added + $prototype =~ s/__attribute__\s*\(\([a-z,]*\)\)//; + + # Yes, this truly is vile. We are looking for: + # 1. Return type (may be nothing if we're looking at a macro) + # 2. Function name + # 3. Function parameters. + # + # All the while we have to watch out for function pointer parameters + # (which IIRC is what the two sections are for), C types (these + # regexps don't even start to express all the possibilities), and + # so on. + # + # If you mess with these regexps, it's a good idea to check that + # the following functions' documentation still comes out right: + # - parport_register_device (function pointer parameters) + # - atomic_set (macro) + # - pci_match_device, __copy_to_user (long return type) + + if ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || + $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || + $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || + $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || + $prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || + $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || + $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || + $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || + $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || + $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || + $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || + $prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || + $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || + $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || + $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || + $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || + $prototype =~ m/^(\w+\s+\w+\s*\*\s*\w+\s*\*\s*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/) { + $return_type = $1; + $declaration_name = $2; + my $args = $3; + + create_parameterlist($args, ',', $file); + } else { + print STDERR "Error(${file}:$.): cannot understand prototype: '$prototype'\n"; + ++$errors; + return; + } + + my $prms = join " ", @parameterlist; + check_sections($file, $declaration_name, "function", $sectcheck, $prms, ""); + + output_declaration($declaration_name, + 'function', + {'function' => $declaration_name, + 'module' => $modulename, + 'functiontype' => $return_type, + 'parameterlist' => \@parameterlist, + 'parameterdescs' => \%parameterdescs, + 'parametertypes' => \%parametertypes, + 'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'purpose' => $declaration_purpose + }); +} + +sub process_file($); + +# Read the file that maps relative names to absolute names for +# separate source and object directories and for shadow trees. +if (open(SOURCE_MAP, "<.tmp_filelist.txt")) { + my ($relname, $absname); + while() { + chop(); + ($relname, $absname) = (split())[0..1]; + $relname =~ s:^/+::; + $source_map{$relname} = $absname; + } + close(SOURCE_MAP); +} + +if ($filelist) { + open(FLIST,"<$filelist") or die "Can't open file list $filelist"; + while() { + chop; + process_file($_); + } +} + +foreach (@ARGV) { + chomp; + process_file($_); +} +if ($verbose && $errors) { + print STDERR "$errors errors\n"; +} +if ($verbose && $warnings) { + print STDERR "$warnings warnings\n"; +} + +exit($errors); + +sub reset_state { + $function = ""; + %constants = (); + %parameterdescs = (); + %parametertypes = (); + @parameterlist = (); + %sections = (); + @sectionlist = (); + $sectcheck = ""; + $struct_actual = ""; + $prototype = ""; + + $state = 0; +} + +sub tracepoint_munge($) { + my $file = shift; + my $tracepointname = 0; + my $tracepointargs = 0; + + if ($prototype =~ m/TRACE_EVENT\((.*?),/) { + $tracepointname = $1; + } + if ($prototype =~ m/DEFINE_SINGLE_EVENT\((.*?),/) { + $tracepointname = $1; + } + if ($prototype =~ m/DEFINE_EVENT\((.*?),(.*?),/) { + $tracepointname = $2; + } + $tracepointname =~ s/^\s+//; #strip leading whitespace + if ($prototype =~ m/TP_PROTO\((.*?)\)/) { + $tracepointargs = $1; + } + if (($tracepointname eq 0) || ($tracepointargs eq 0)) { + print STDERR "Warning(${file}:$.): Unrecognized tracepoint format: \n". + "$prototype\n"; + } else { + $prototype = "static inline void trace_$tracepointname($tracepointargs)"; + } +} + +sub syscall_munge() { + my $void = 0; + + $prototype =~ s@[\r\n\t]+@ @gos; # strip newlines/CR's/tabs +## if ($prototype =~ m/SYSCALL_DEFINE0\s*\(\s*(a-zA-Z0-9_)*\s*\)/) { + if ($prototype =~ m/SYSCALL_DEFINE0/) { + $void = 1; +## $prototype = "long sys_$1(void)"; + } + + $prototype =~ s/SYSCALL_DEFINE.*\(/long sys_/; # fix return type & func name + if ($prototype =~ m/long (sys_.*?),/) { + $prototype =~ s/,/\(/; + } elsif ($void) { + $prototype =~ s/\)/\(void\)/; + } + + # now delete all of the odd-number commas in $prototype + # so that arg types & arg names don't have a comma between them + my $count = 0; + my $len = length($prototype); + if ($void) { + $len = 0; # skip the for-loop + } + for (my $ix = 0; $ix < $len; $ix++) { + if (substr($prototype, $ix, 1) eq ',') { + $count++; + if ($count % 2 == 1) { + substr($prototype, $ix, 1) = ' '; + } + } + } +} + +sub process_state3_function($$) { + my $x = shift; + my $file = shift; + + $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line + + if ($x =~ m#\s*/\*\s+MACDOC\s*#io || ($x =~ /^#/ && $x !~ /^#\s*define/)) { + # do nothing + } + elsif ($x =~ /([^\{]*)/) { + $prototype .= $1; + } + + if (($x =~ /\{/) || ($x =~ /\#\s*define/) || ($x =~ /;/)) { + $prototype =~ s@/\*.*?\*/@@gos; # strip comments. + $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's. + $prototype =~ s@^\s+@@gos; # strip leading spaces + if ($prototype =~ /SYSCALL_DEFINE/) { + syscall_munge(); + } + if ($prototype =~ /TRACE_EVENT/ || $prototype =~ /DEFINE_EVENT/ || + $prototype =~ /DEFINE_SINGLE_EVENT/) + { + tracepoint_munge($file); + } + dump_function($prototype, $file); + reset_state(); + } +} + +sub process_state3_type($$) { + my $x = shift; + my $file = shift; + + $x =~ s@[\r\n]+@ @gos; # strip newlines/cr's. + $x =~ s@^\s+@@gos; # strip leading spaces + $x =~ s@\s+$@@gos; # strip trailing spaces + $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line + + if ($x =~ /^#/) { + # To distinguish preprocessor directive from regular declaration later. + $x .= ";"; + } + + while (1) { + if ( $x =~ /([^{};]*)([{};])(.*)/ ) { + $prototype .= $1 . $2; + ($2 eq '{') && $brcount++; + ($2 eq '}') && $brcount--; + if (($2 eq ';') && ($brcount == 0)) { + dump_declaration($prototype, $file); + reset_state(); + last; + } + $x = $3; + } else { + $prototype .= $x; + last; + } + } +} + +# xml_escape: replace <, >, and & in the text stream; +# +# however, formatting controls that are generated internally/locally in the +# kernel-doc script are not escaped here; instead, they begin life like +# $blankline_html (4 of '\' followed by a mnemonic + ':'), then these strings +# are converted to their mnemonic-expected output, without the 4 * '\' & ':', +# just before actual output; (this is done by local_unescape()) +sub xml_escape($) { + my $text = shift; + if (($output_mode eq "text") || ($output_mode eq "man")) { + return $text; + } + $text =~ s/\&/\\\\\\amp;/g; + $text =~ s/\/\\\\\\gt;/g; + return $text; +} + +# convert local escape strings to html +# local escape strings look like: '\\\\menmonic:' (that's 4 backslashes) +sub local_unescape($) { + my $text = shift; + if (($output_mode eq "text") || ($output_mode eq "man")) { + return $text; + } + $text =~ s/\\\\\\\\lt://g; + return $text; +} + +sub process_file($) { + my $file; + my $identifier; + my $func; + my $descr; + my $in_purpose = 0; + my $initial_section_counter = $section_counter; + + if (defined($ENV{'SRCTREE'})) { + $file = "$ENV{'SRCTREE'}" . "/" . "@_"; + } + else { + $file = "@_"; + } + if (defined($source_map{$file})) { + $file = $source_map{$file}; + } + + if (!open(IN,"<$file")) { + print STDERR "Error: Cannot open file $file\n"; + ++$errors; + return; + } + + $section_counter = 0; + while () { + if ($state == 0) { + if (/$doc_start/o) { + $state = 1; # next line is always the function name + $in_doc_sect = 0; + } + } elsif ($state == 1) { # this line is the function name (always) + if (/$doc_block/o) { + $state = 4; + $contents = ""; + if ( $1 eq "" ) { + $section = $section_intro; + } else { + $section = $1; + } + } + elsif (/$doc_decl/o) { + $identifier = $1; + if (/\s*([\w\s]+?)\s*-/) { + $identifier = $1; + } + + $state = 2; + if (/-(.*)/) { + # strip leading/trailing/multiple spaces + $descr= $1; + $descr =~ s/^\s*//; + $descr =~ s/\s*$//; + $descr =~ s/\s+/ /; + $declaration_purpose = xml_escape($descr); + $in_purpose = 1; + } else { + $declaration_purpose = ""; + } + + if (($declaration_purpose eq "") && $verbose) { + print STDERR "Warning(${file}:$.): missing initial short description on line:\n"; + print STDERR $_; + ++$warnings; + } + + if ($identifier =~ m/^struct/) { + $decl_type = 'struct'; + } elsif ($identifier =~ m/^union/) { + $decl_type = 'union'; + } elsif ($identifier =~ m/^enum/) { + $decl_type = 'enum'; + } elsif ($identifier =~ m/^typedef/) { + $decl_type = 'typedef'; + } else { + $decl_type = 'function'; + } + + if ($verbose) { + print STDERR "Info(${file}:$.): Scanning doc for $identifier\n"; + } + } else { + print STDERR "Warning(${file}:$.): Cannot understand $_ on line $.", + " - I thought it was a doc line\n"; + ++$warnings; + $state = 0; + } + } elsif ($state == 2) { # look for head: lines, and include content + if (/$doc_sect/o) { + $newsection = $1; + $newcontents = $2; + + if (($contents ne "") && ($contents ne "\n")) { + if (!$in_doc_sect && $verbose) { + print STDERR "Warning(${file}:$.): contents before sections\n"; + ++$warnings; + } + dump_section($file, $section, xml_escape($contents)); + $section = $section_default; + } + + $in_doc_sect = 1; + $in_purpose = 0; + $contents = $newcontents; + if ($contents ne "") { + while ((substr($contents, 0, 1) eq " ") || + substr($contents, 0, 1) eq "\t") { + $contents = substr($contents, 1); + } + $contents .= "\n"; + } + $section = $newsection; + } elsif (/$doc_end/) { + + if ($contents ne "") { + dump_section($file, $section, xml_escape($contents)); + $section = $section_default; + $contents = ""; + } + # look for doc_com + + doc_end: + if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') { + print STDERR "Warning(${file}:$.): suspicious ending line: $_"; + ++$warnings; + } + + $prototype = ""; + $state = 3; + $brcount = 0; +# print STDERR "end of doc comment, looking for prototype\n"; + } elsif (/$doc_content/) { + # miguel-style comment kludge, look for blank lines after + # @parameter line to signify start of description + if ($1 eq "") { + if ($section =~ m/^@/ || $section eq $section_context) { + dump_section($file, $section, xml_escape($contents)); + $section = $section_default; + $contents = ""; + } else { + $contents .= "\n"; + } + $in_purpose = 0; + } elsif ($in_purpose == 1) { + # Continued declaration purpose + chomp($declaration_purpose); + $declaration_purpose .= " " . xml_escape($1); + } else { + $contents .= $1 . "\n"; + } + } else { + # i dont know - bad line? ignore. + print STDERR "Warning(${file}:$.): bad line: $_"; + ++$warnings; + } + } elsif ($state == 3) { # scanning for function '{' (end of prototype) + if ($decl_type eq 'function') { + process_state3_function($_, $file); + } else { + process_state3_type($_, $file); + } + } elsif ($state == 4) { + # Documentation block + if (/$doc_block/) { + dump_doc_section($file, $section, xml_escape($contents)); + $contents = ""; + $function = ""; + %constants = (); + %parameterdescs = (); + %parametertypes = (); + @parameterlist = (); + %sections = (); + @sectionlist = (); + $prototype = ""; + if ( $1 eq "" ) { + $section = $section_intro; + } else { + $section = $1; + } + } + elsif (/$doc_end/) + { + dump_doc_section($file, $section, xml_escape($contents)); + $contents = ""; + $function = ""; + %constants = (); + %parameterdescs = (); + %parametertypes = (); + @parameterlist = (); + %sections = (); + @sectionlist = (); + $prototype = ""; + $state = 0; + } + elsif (/$doc_content/) + { + if ( $1 eq "" ) + { + $contents .= $blankline; + } + else + { + $contents .= $1 . "\n"; + } + } + } + } + if ($initial_section_counter == $section_counter) { + print STDERR "Warning(${file}): no structured comments found\n"; + if ($output_mode eq "xml") { + # The template wants at least one RefEntry here; make one. + print "\n"; + print " \n"; + print " \n"; + print " ${file}\n"; + print " \n"; + print " \n"; + print " Document generation inconsistency\n"; + print " \n"; + print " \n"; + print " \n"; + print " \n"; + print " Oops\n"; + print " \n"; + print " \n"; + print " \n"; + print " The template for this document tried to insert\n"; + print " the structured comment from the file\n"; + print " ${file} at this point,\n"; + print " but none was found.\n"; + print " This dummy section is inserted to allow\n"; + print " generation to continue.\n"; + print " \n"; + print " \n"; + print " \n"; + print "\n"; + } + } +} diff --git a/libs/libwebsockets/test-server/Makefile.am b/libs/libwebsockets/test-server/Makefile.am new file mode 100644 index 0000000000..a74b0e6148 --- /dev/null +++ b/libs/libwebsockets/test-server/Makefile.am @@ -0,0 +1,61 @@ +bin_PROGRAMS=libwebsockets-test-server libwebsockets-test-client libwebsockets-test-server-extpoll libwebsockets-test-fraggle +libwebsockets_test_server_SOURCES=test-server.c +libwebsockets_test_server_LDADD=-L../lib -lwebsockets -lz +libwebsockets_test_client_SOURCES=test-client.c +libwebsockets_test_client_LDADD=-L../lib -lwebsockets -lz +libwebsockets_test_server_extpoll_SOURCES=test-server-extpoll.c +libwebsockets_test_server_extpoll_LDADD=-L../lib -lwebsockets -lz +libwebsockets_test_fraggle_SOURCES=test-fraggle.c +libwebsockets_test_fraggle_LDADD=-L../lib -lwebsockets -lz + +if MINGW +libwebsockets_test_server_CFLAGS:= -w -I../win32port/win32helpers +libwebsockets_test_client_CFLAGS:= -w -I../win32port/win32helpers +libwebsockets_test_server_extpoll_CFLAGS:= -w -I../win32port/win32helpers +libwebsockets_test_fraggle_CFLAGS:= -w -I../win32port/win32helpers + +libwebsockets_test_server_LDADD+= -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz +libwebsockets_test_client_LDADD+= -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz +libwebsockets_test_server_extpoll_LDADD+= -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz +libwebsockets_test_fraggle_LDADD+= -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz + +else +libwebsockets_test_server_CFLAGS:= -Werror +libwebsockets_test_client_CFLAGS:= -Werror +libwebsockets_test_server_extpoll_CFLAGS:= -Werror +libwebsockets_test_fraggle_CFLAGS:= -Werror +endif + +libwebsockets_test_server_CFLAGS+= -Wall -std=gnu99 -pedantic -DINSTALL_DATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" +libwebsockets_test_client_CFLAGS+= -Wall -std=gnu99 -pedantic -DINSTALL_DATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" +libwebsockets_test_server_extpoll_CFLAGS+= -Wall -std=gnu99 -pedantic -DINSTALL_DATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" +libwebsockets_test_fraggle_CFLAGS+= -Wall -std=gnu99 -pedantic -DINSTALL_DATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" + + +if NOPING +else +bin_PROGRAMS+=libwebsockets-test-ping +libwebsockets_test_ping_SOURCES=test-ping.c +libwebsockets_test_ping_LDADD=-L../lib -lwebsockets +libwebsockets_test_ping_CFLAGS:= -Wall -Werror -std=gnu99 -pedantic -DINSTALL_DATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" +endif + + +# +# cook a random test cert and key +# notice your real cert and key will want to be 0600 permissions +libwebsockets-test-server.pem libwebsockets-test-server.key.pem: + printf "GB\nErewhon\nAll around\nlibwebsockets-test\n\nlocalhost\nnone@invalid.org\n" | \ + openssl req -new -newkey rsa:1024 -days 10000 -nodes -x509 -keyout \ + ./libwebsockets-test-server.key.pem -out ./libwebsockets-test-server.pem >/dev/null 2>&1 && \ + chmod 644 ./libwebsockets-test-server.key.pem \ + ./libwebsockets-test-server.pem + +clean-local: + rm -f ./libwebsockets-test-server.key.pem ./libwebsockets-test-server.pem + +install-data-local:libwebsockets-test-server.key.pem libwebsockets-test-server.pem + mkdir -p $(DESTDIR)$(datadir)/libwebsockets-test-server + cp -a test.html favicon.ico libwebsockets-test-server.key.pem libwebsockets-test-server.pem \ + $(DESTDIR)$(datadir)/libwebsockets-test-server + diff --git a/libs/libwebsockets/test-server/Makefile.in b/libs/libwebsockets/test-server/Makefile.in new file mode 100644 index 0000000000..919c8aecc3 --- /dev/null +++ b/libs/libwebsockets/test-server/Makefile.in @@ -0,0 +1,722 @@ +# Makefile.in generated by automake 1.11.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = libwebsockets-test-server$(EXEEXT) \ + libwebsockets-test-client$(EXEEXT) \ + libwebsockets-test-server-extpoll$(EXEEXT) \ + libwebsockets-test-fraggle$(EXEEXT) $(am__EXEEXT_1) +@MINGW_TRUE@am__append_1 = -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz +@MINGW_TRUE@am__append_2 = -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz +@MINGW_TRUE@am__append_3 = -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz +@MINGW_TRUE@am__append_4 = -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz +@NOPING_FALSE@am__append_5 = libwebsockets-test-ping +subdir = test-server +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +@NOPING_FALSE@am__EXEEXT_1 = libwebsockets-test-ping$(EXEEXT) +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) +am_libwebsockets_test_client_OBJECTS = \ + libwebsockets_test_client-test-client.$(OBJEXT) +libwebsockets_test_client_OBJECTS = \ + $(am_libwebsockets_test_client_OBJECTS) +am__DEPENDENCIES_1 = +libwebsockets_test_client_DEPENDENCIES = $(am__DEPENDENCIES_1) +libwebsockets_test_client_LINK = $(LIBTOOL) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(libwebsockets_test_client_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_libwebsockets_test_fraggle_OBJECTS = \ + libwebsockets_test_fraggle-test-fraggle.$(OBJEXT) +libwebsockets_test_fraggle_OBJECTS = \ + $(am_libwebsockets_test_fraggle_OBJECTS) +libwebsockets_test_fraggle_DEPENDENCIES = $(am__DEPENDENCIES_1) +libwebsockets_test_fraggle_LINK = $(LIBTOOL) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(libwebsockets_test_fraggle_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__libwebsockets_test_ping_SOURCES_DIST = test-ping.c +@NOPING_FALSE@am_libwebsockets_test_ping_OBJECTS = \ +@NOPING_FALSE@ libwebsockets_test_ping-test-ping.$(OBJEXT) +libwebsockets_test_ping_OBJECTS = \ + $(am_libwebsockets_test_ping_OBJECTS) +libwebsockets_test_ping_DEPENDENCIES = +libwebsockets_test_ping_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(libwebsockets_test_ping_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_libwebsockets_test_server_OBJECTS = \ + libwebsockets_test_server-test-server.$(OBJEXT) +libwebsockets_test_server_OBJECTS = \ + $(am_libwebsockets_test_server_OBJECTS) +libwebsockets_test_server_DEPENDENCIES = $(am__DEPENDENCIES_1) +libwebsockets_test_server_LINK = $(LIBTOOL) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(libwebsockets_test_server_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_libwebsockets_test_server_extpoll_OBJECTS = libwebsockets_test_server_extpoll-test-server-extpoll.$(OBJEXT) +libwebsockets_test_server_extpoll_OBJECTS = \ + $(am_libwebsockets_test_server_extpoll_OBJECTS) +libwebsockets_test_server_extpoll_DEPENDENCIES = \ + $(am__DEPENDENCIES_1) +libwebsockets_test_server_extpoll_LINK = $(LIBTOOL) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(libwebsockets_test_server_extpoll_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libwebsockets_test_client_SOURCES) \ + $(libwebsockets_test_fraggle_SOURCES) \ + $(libwebsockets_test_ping_SOURCES) \ + $(libwebsockets_test_server_SOURCES) \ + $(libwebsockets_test_server_extpoll_SOURCES) +DIST_SOURCES = $(libwebsockets_test_client_SOURCES) \ + $(libwebsockets_test_fraggle_SOURCES) \ + $(am__libwebsockets_test_ping_SOURCES_DIST) \ + $(libwebsockets_test_server_SOURCES) \ + $(libwebsockets_test_server_extpoll_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +clientcertdir = @clientcertdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +libwebsockets_test_server_SOURCES = test-server.c +libwebsockets_test_server_LDADD = -L../lib -lwebsockets -lz \ + $(am__append_1) +libwebsockets_test_client_SOURCES = test-client.c +libwebsockets_test_client_LDADD = -L../lib -lwebsockets -lz \ + $(am__append_2) +libwebsockets_test_server_extpoll_SOURCES = test-server-extpoll.c +libwebsockets_test_server_extpoll_LDADD = -L../lib -lwebsockets -lz \ + $(am__append_3) +libwebsockets_test_fraggle_SOURCES = test-fraggle.c +libwebsockets_test_fraggle_LDADD = -L../lib -lwebsockets -lz \ + $(am__append_4) +@MINGW_FALSE@libwebsockets_test_server_CFLAGS := -Werror -Wall \ +@MINGW_FALSE@ -std=gnu99 -pedantic \ +@MINGW_FALSE@ -DINSTALL_DATADIR=\"@datadir@\" \ +@MINGW_FALSE@ -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" +@MINGW_TRUE@libwebsockets_test_server_CFLAGS := -w \ +@MINGW_TRUE@ -I../win32port/win32helpers -Wall -std=gnu99 \ +@MINGW_TRUE@ -pedantic -DINSTALL_DATADIR=\"@datadir@\" \ +@MINGW_TRUE@ -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" +@MINGW_FALSE@libwebsockets_test_client_CFLAGS := -Werror -Wall \ +@MINGW_FALSE@ -std=gnu99 -pedantic \ +@MINGW_FALSE@ -DINSTALL_DATADIR=\"@datadir@\" \ +@MINGW_FALSE@ -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" +@MINGW_TRUE@libwebsockets_test_client_CFLAGS := -w \ +@MINGW_TRUE@ -I../win32port/win32helpers -Wall -std=gnu99 \ +@MINGW_TRUE@ -pedantic -DINSTALL_DATADIR=\"@datadir@\" \ +@MINGW_TRUE@ -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" +@MINGW_FALSE@libwebsockets_test_server_extpoll_CFLAGS := -Werror -Wall \ +@MINGW_FALSE@ -std=gnu99 -pedantic \ +@MINGW_FALSE@ -DINSTALL_DATADIR=\"@datadir@\" \ +@MINGW_FALSE@ -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" +@MINGW_TRUE@libwebsockets_test_server_extpoll_CFLAGS := -w \ +@MINGW_TRUE@ -I../win32port/win32helpers -Wall -std=gnu99 \ +@MINGW_TRUE@ -pedantic -DINSTALL_DATADIR=\"@datadir@\" \ +@MINGW_TRUE@ -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" +@MINGW_FALSE@libwebsockets_test_fraggle_CFLAGS := -Werror -Wall \ +@MINGW_FALSE@ -std=gnu99 -pedantic \ +@MINGW_FALSE@ -DINSTALL_DATADIR=\"@datadir@\" \ +@MINGW_FALSE@ -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" +@MINGW_TRUE@libwebsockets_test_fraggle_CFLAGS := -w \ +@MINGW_TRUE@ -I../win32port/win32helpers -Wall -std=gnu99 \ +@MINGW_TRUE@ -pedantic -DINSTALL_DATADIR=\"@datadir@\" \ +@MINGW_TRUE@ -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" +@NOPING_FALSE@libwebsockets_test_ping_SOURCES = test-ping.c +@NOPING_FALSE@libwebsockets_test_ping_LDADD = -L../lib -lwebsockets +@NOPING_FALSE@libwebsockets_test_ping_CFLAGS := -Wall -Werror -std=gnu99 -pedantic -DINSTALL_DATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test-server/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign test-server/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +libwebsockets-test-client$(EXEEXT): $(libwebsockets_test_client_OBJECTS) $(libwebsockets_test_client_DEPENDENCIES) $(EXTRA_libwebsockets_test_client_DEPENDENCIES) + @rm -f libwebsockets-test-client$(EXEEXT) + $(libwebsockets_test_client_LINK) $(libwebsockets_test_client_OBJECTS) $(libwebsockets_test_client_LDADD) $(LIBS) +libwebsockets-test-fraggle$(EXEEXT): $(libwebsockets_test_fraggle_OBJECTS) $(libwebsockets_test_fraggle_DEPENDENCIES) $(EXTRA_libwebsockets_test_fraggle_DEPENDENCIES) + @rm -f libwebsockets-test-fraggle$(EXEEXT) + $(libwebsockets_test_fraggle_LINK) $(libwebsockets_test_fraggle_OBJECTS) $(libwebsockets_test_fraggle_LDADD) $(LIBS) +libwebsockets-test-ping$(EXEEXT): $(libwebsockets_test_ping_OBJECTS) $(libwebsockets_test_ping_DEPENDENCIES) $(EXTRA_libwebsockets_test_ping_DEPENDENCIES) + @rm -f libwebsockets-test-ping$(EXEEXT) + $(libwebsockets_test_ping_LINK) $(libwebsockets_test_ping_OBJECTS) $(libwebsockets_test_ping_LDADD) $(LIBS) +libwebsockets-test-server$(EXEEXT): $(libwebsockets_test_server_OBJECTS) $(libwebsockets_test_server_DEPENDENCIES) $(EXTRA_libwebsockets_test_server_DEPENDENCIES) + @rm -f libwebsockets-test-server$(EXEEXT) + $(libwebsockets_test_server_LINK) $(libwebsockets_test_server_OBJECTS) $(libwebsockets_test_server_LDADD) $(LIBS) +libwebsockets-test-server-extpoll$(EXEEXT): $(libwebsockets_test_server_extpoll_OBJECTS) $(libwebsockets_test_server_extpoll_DEPENDENCIES) $(EXTRA_libwebsockets_test_server_extpoll_DEPENDENCIES) + @rm -f libwebsockets-test-server-extpoll$(EXEEXT) + $(libwebsockets_test_server_extpoll_LINK) $(libwebsockets_test_server_extpoll_OBJECTS) $(libwebsockets_test_server_extpoll_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_test_client-test-client.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_test_fraggle-test-fraggle.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_test_ping-test-ping.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_test_server-test-server.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_test_server_extpoll-test-server-extpoll.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libwebsockets_test_client-test-client.o: test-client.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_client_CFLAGS) $(CFLAGS) -MT libwebsockets_test_client-test-client.o -MD -MP -MF $(DEPDIR)/libwebsockets_test_client-test-client.Tpo -c -o libwebsockets_test_client-test-client.o `test -f 'test-client.c' || echo '$(srcdir)/'`test-client.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_test_client-test-client.Tpo $(DEPDIR)/libwebsockets_test_client-test-client.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-client.c' object='libwebsockets_test_client-test-client.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_client_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_client-test-client.o `test -f 'test-client.c' || echo '$(srcdir)/'`test-client.c + +libwebsockets_test_client-test-client.obj: test-client.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_client_CFLAGS) $(CFLAGS) -MT libwebsockets_test_client-test-client.obj -MD -MP -MF $(DEPDIR)/libwebsockets_test_client-test-client.Tpo -c -o libwebsockets_test_client-test-client.obj `if test -f 'test-client.c'; then $(CYGPATH_W) 'test-client.c'; else $(CYGPATH_W) '$(srcdir)/test-client.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_test_client-test-client.Tpo $(DEPDIR)/libwebsockets_test_client-test-client.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-client.c' object='libwebsockets_test_client-test-client.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_client_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_client-test-client.obj `if test -f 'test-client.c'; then $(CYGPATH_W) 'test-client.c'; else $(CYGPATH_W) '$(srcdir)/test-client.c'; fi` + +libwebsockets_test_fraggle-test-fraggle.o: test-fraggle.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_fraggle_CFLAGS) $(CFLAGS) -MT libwebsockets_test_fraggle-test-fraggle.o -MD -MP -MF $(DEPDIR)/libwebsockets_test_fraggle-test-fraggle.Tpo -c -o libwebsockets_test_fraggle-test-fraggle.o `test -f 'test-fraggle.c' || echo '$(srcdir)/'`test-fraggle.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_test_fraggle-test-fraggle.Tpo $(DEPDIR)/libwebsockets_test_fraggle-test-fraggle.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-fraggle.c' object='libwebsockets_test_fraggle-test-fraggle.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_fraggle_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_fraggle-test-fraggle.o `test -f 'test-fraggle.c' || echo '$(srcdir)/'`test-fraggle.c + +libwebsockets_test_fraggle-test-fraggle.obj: test-fraggle.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_fraggle_CFLAGS) $(CFLAGS) -MT libwebsockets_test_fraggle-test-fraggle.obj -MD -MP -MF $(DEPDIR)/libwebsockets_test_fraggle-test-fraggle.Tpo -c -o libwebsockets_test_fraggle-test-fraggle.obj `if test -f 'test-fraggle.c'; then $(CYGPATH_W) 'test-fraggle.c'; else $(CYGPATH_W) '$(srcdir)/test-fraggle.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_test_fraggle-test-fraggle.Tpo $(DEPDIR)/libwebsockets_test_fraggle-test-fraggle.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-fraggle.c' object='libwebsockets_test_fraggle-test-fraggle.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_fraggle_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_fraggle-test-fraggle.obj `if test -f 'test-fraggle.c'; then $(CYGPATH_W) 'test-fraggle.c'; else $(CYGPATH_W) '$(srcdir)/test-fraggle.c'; fi` + +libwebsockets_test_ping-test-ping.o: test-ping.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_ping_CFLAGS) $(CFLAGS) -MT libwebsockets_test_ping-test-ping.o -MD -MP -MF $(DEPDIR)/libwebsockets_test_ping-test-ping.Tpo -c -o libwebsockets_test_ping-test-ping.o `test -f 'test-ping.c' || echo '$(srcdir)/'`test-ping.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_test_ping-test-ping.Tpo $(DEPDIR)/libwebsockets_test_ping-test-ping.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-ping.c' object='libwebsockets_test_ping-test-ping.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_ping_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_ping-test-ping.o `test -f 'test-ping.c' || echo '$(srcdir)/'`test-ping.c + +libwebsockets_test_ping-test-ping.obj: test-ping.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_ping_CFLAGS) $(CFLAGS) -MT libwebsockets_test_ping-test-ping.obj -MD -MP -MF $(DEPDIR)/libwebsockets_test_ping-test-ping.Tpo -c -o libwebsockets_test_ping-test-ping.obj `if test -f 'test-ping.c'; then $(CYGPATH_W) 'test-ping.c'; else $(CYGPATH_W) '$(srcdir)/test-ping.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_test_ping-test-ping.Tpo $(DEPDIR)/libwebsockets_test_ping-test-ping.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-ping.c' object='libwebsockets_test_ping-test-ping.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_ping_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_ping-test-ping.obj `if test -f 'test-ping.c'; then $(CYGPATH_W) 'test-ping.c'; else $(CYGPATH_W) '$(srcdir)/test-ping.c'; fi` + +libwebsockets_test_server-test-server.o: test-server.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_server_CFLAGS) $(CFLAGS) -MT libwebsockets_test_server-test-server.o -MD -MP -MF $(DEPDIR)/libwebsockets_test_server-test-server.Tpo -c -o libwebsockets_test_server-test-server.o `test -f 'test-server.c' || echo '$(srcdir)/'`test-server.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_test_server-test-server.Tpo $(DEPDIR)/libwebsockets_test_server-test-server.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-server.c' object='libwebsockets_test_server-test-server.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_server_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_server-test-server.o `test -f 'test-server.c' || echo '$(srcdir)/'`test-server.c + +libwebsockets_test_server-test-server.obj: test-server.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_server_CFLAGS) $(CFLAGS) -MT libwebsockets_test_server-test-server.obj -MD -MP -MF $(DEPDIR)/libwebsockets_test_server-test-server.Tpo -c -o libwebsockets_test_server-test-server.obj `if test -f 'test-server.c'; then $(CYGPATH_W) 'test-server.c'; else $(CYGPATH_W) '$(srcdir)/test-server.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_test_server-test-server.Tpo $(DEPDIR)/libwebsockets_test_server-test-server.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-server.c' object='libwebsockets_test_server-test-server.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_server_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_server-test-server.obj `if test -f 'test-server.c'; then $(CYGPATH_W) 'test-server.c'; else $(CYGPATH_W) '$(srcdir)/test-server.c'; fi` + +libwebsockets_test_server_extpoll-test-server-extpoll.o: test-server-extpoll.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_server_extpoll_CFLAGS) $(CFLAGS) -MT libwebsockets_test_server_extpoll-test-server-extpoll.o -MD -MP -MF $(DEPDIR)/libwebsockets_test_server_extpoll-test-server-extpoll.Tpo -c -o libwebsockets_test_server_extpoll-test-server-extpoll.o `test -f 'test-server-extpoll.c' || echo '$(srcdir)/'`test-server-extpoll.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_test_server_extpoll-test-server-extpoll.Tpo $(DEPDIR)/libwebsockets_test_server_extpoll-test-server-extpoll.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-server-extpoll.c' object='libwebsockets_test_server_extpoll-test-server-extpoll.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_server_extpoll_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_server_extpoll-test-server-extpoll.o `test -f 'test-server-extpoll.c' || echo '$(srcdir)/'`test-server-extpoll.c + +libwebsockets_test_server_extpoll-test-server-extpoll.obj: test-server-extpoll.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_server_extpoll_CFLAGS) $(CFLAGS) -MT libwebsockets_test_server_extpoll-test-server-extpoll.obj -MD -MP -MF $(DEPDIR)/libwebsockets_test_server_extpoll-test-server-extpoll.Tpo -c -o libwebsockets_test_server_extpoll-test-server-extpoll.obj `if test -f 'test-server-extpoll.c'; then $(CYGPATH_W) 'test-server-extpoll.c'; else $(CYGPATH_W) '$(srcdir)/test-server-extpoll.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_test_server_extpoll-test-server-extpoll.Tpo $(DEPDIR)/libwebsockets_test_server_extpoll-test-server-extpoll.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-server-extpoll.c' object='libwebsockets_test_server_extpoll-test-server-extpoll.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_server_extpoll_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_server_extpoll-test-server-extpoll.obj `if test -f 'test-server-extpoll.c'; then $(CYGPATH_W) 'test-server-extpoll.c'; else $(CYGPATH_W) '$(srcdir)/test-server-extpoll.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libtool clean-local \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-data-local + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool clean-local ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-data-local install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS + + +# +# cook a random test cert and key +# notice your real cert and key will want to be 0600 permissions +libwebsockets-test-server.pem libwebsockets-test-server.key.pem: + printf "GB\nErewhon\nAll around\nlibwebsockets-test\n\nlocalhost\nnone@invalid.org\n" | \ + openssl req -new -newkey rsa:1024 -days 10000 -nodes -x509 -keyout \ + ./libwebsockets-test-server.key.pem -out ./libwebsockets-test-server.pem >/dev/null 2>&1 && \ + chmod 644 ./libwebsockets-test-server.key.pem \ + ./libwebsockets-test-server.pem + +clean-local: + rm -f ./libwebsockets-test-server.key.pem ./libwebsockets-test-server.pem + +install-data-local:libwebsockets-test-server.key.pem libwebsockets-test-server.pem + mkdir -p $(DESTDIR)$(datadir)/libwebsockets-test-server + cp -a test.html favicon.ico libwebsockets-test-server.key.pem libwebsockets-test-server.pem \ + $(DESTDIR)$(datadir)/libwebsockets-test-server + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libs/libwebsockets/test-server/favicon.ico b/libs/libwebsockets/test-server/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c0cc2e3dff34012ba3d4a7848a7ed17579788ec5 GIT binary patch literal 1406 zcmZQzU<5(|0R}M0U}azs1F|%L7$l?s#Ec9aKoZP=&`9i!<^REA8>%80(yxAC$j<-A zkb5S8;qL6446ipNFl>5#fuVR6L=8goC~GtXMnhmYga9MSfQgBTk&TUw5$JocUP63y z3phA97+G0a8QIy{!BT|y==xb$SQt4uIT@LmnZZ(o_~`mk`Tv1M8w?+DXJCL~kQj^& JqOtKoVgQl$ETjMc literal 0 HcmV?d00001 diff --git a/libs/libwebsockets/test-server/test-client.c b/libs/libwebsockets/test-server/test-client.c new file mode 100644 index 0000000000..ffd636569b --- /dev/null +++ b/libs/libwebsockets/test-server/test-client.c @@ -0,0 +1,341 @@ +/* + * libwebsockets-test-client - libwebsockets test implementation + * + * Copyright (C) 2011 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include "../lib/libwebsockets.h" + +static unsigned int opts; +static int was_closed; +static int deny_deflate; +static int deny_mux; +static struct libwebsocket *wsi_mirror; + +/* + * This demo shows how to connect multiple websockets simultaneously to a + * websocket server (there is no restriction on their having to be the same + * server just it simplifies the demo). + * + * dumb-increment-protocol: we connect to the server and print the number + * we are given + * + * lws-mirror-protocol: draws random circles, which are mirrored on to every + * client (see them being drawn in every browser + * session also using the test server) + */ + +enum demo_protocols { + + PROTOCOL_DUMB_INCREMENT, + PROTOCOL_LWS_MIRROR, + + /* always last */ + DEMO_PROTOCOL_COUNT +}; + + +/* dumb_increment protocol */ + +static int +callback_dumb_increment(struct libwebsocket_context *this, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, + void *user, void *in, size_t len) +{ + switch (reason) { + + case LWS_CALLBACK_CLOSED: + fprintf(stderr, "LWS_CALLBACK_CLOSED\n"); + was_closed = 1; + break; + + case LWS_CALLBACK_CLIENT_RECEIVE: + ((char *)in)[len] = '\0'; + fprintf(stderr, "rx %d '%s'\n", (int)len, (char *)in); + break; + + /* because we are protocols[0] ... */ + + case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: + if ((strcmp(in, "deflate-stream") == 0) && deny_deflate) { + fprintf(stderr, "denied deflate-stream extension\n"); + return 1; + } + if ((strcmp(in, "x-google-mux") == 0) && deny_mux) { + fprintf(stderr, "denied x-google-mux extension\n"); + return 1; + } + + break; + + default: + break; + } + + return 0; +} + + +/* lws-mirror_protocol */ + + +static int +callback_lws_mirror(struct libwebsocket_context *this, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, + void *user, void *in, size_t len) +{ + unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 4096 + + LWS_SEND_BUFFER_POST_PADDING]; + int l; + + switch (reason) { + + case LWS_CALLBACK_CLOSED: + fprintf(stderr, "mirror: LWS_CALLBACK_CLOSED\n"); + wsi_mirror = NULL; + break; + + case LWS_CALLBACK_CLIENT_ESTABLISHED: + + /* + * start the ball rolling, + * LWS_CALLBACK_CLIENT_WRITEABLE will come next service + */ + + libwebsocket_callback_on_writable(this, wsi); + break; + + case LWS_CALLBACK_CLIENT_RECEIVE: +/* fprintf(stderr, "rx %d '%s'\n", (int)len, (char *)in); */ + break; + + case LWS_CALLBACK_CLIENT_WRITEABLE: + + l = sprintf((char *)&buf[LWS_SEND_BUFFER_PRE_PADDING], + "c #%06X %d %d %d;", + (int)random() & 0xffffff, + (int)random() % 500, + (int)random() % 250, + (int)random() % 24); + + libwebsocket_write(wsi, + &buf[LWS_SEND_BUFFER_PRE_PADDING], l, opts | LWS_WRITE_TEXT); + + /* get notified as soon as we can write again */ + + libwebsocket_callback_on_writable(this, wsi); + + /* + * without at least this delay, we choke the browser + * and the connection stalls, despite we now take care about + * flow control + */ + + usleep(200); + break; + + default: + break; + } + + return 0; +} + + +/* list of supported protocols and callbacks */ + +static struct libwebsocket_protocols protocols[] = { + { + "dumb-increment-protocol", + callback_dumb_increment, + 0, + }, + { + "lws-mirror-protocol", + callback_lws_mirror, + 0, + }, + { /* end of list */ + NULL, + NULL, + 0 + } +}; + +static struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "port", required_argument, NULL, 'p' }, + { "ssl", no_argument, NULL, 's' }, + { "killmask", no_argument, NULL, 'k' }, + { "version", required_argument, NULL, 'v' }, + { "undeflated", no_argument, NULL, 'u' }, + { "nomux", no_argument, NULL, 'n' }, + { NULL, 0, 0, 0 } +}; + + +int main(int argc, char **argv) +{ + int n = 0; + int port = 7681; + int use_ssl = 0; + struct libwebsocket_context *context; + const char *address; + struct libwebsocket *wsi_dumb; + int ietf_version = -1; /* latest */ + int mirror_lifetime = 0; + + fprintf(stderr, "libwebsockets test client\n" + "(C) Copyright 2010 Andy Green " + "licensed under LGPL2.1\n"); + + if (argc < 2) + goto usage; + + while (n >= 0) { + n = getopt_long(argc, argv, "nuv:khsp:", options, NULL); + if (n < 0) + continue; + switch (n) { + case 's': + use_ssl = 2; /* 2 = allow selfsigned */ + break; + case 'p': + port = atoi(optarg); + break; + case 'k': + opts = LWS_WRITE_CLIENT_IGNORE_XOR_MASK; + break; + case 'v': + ietf_version = atoi(optarg); + break; + case 'u': + deny_deflate = 1; + break; + case 'n': + deny_mux = 1; + break; + case 'h': + goto usage; + } + } + + if (optind >= argc) + goto usage; + + address = argv[optind]; + + /* + * create the websockets context. This tracks open connections and + * knows how to route any traffic and which protocol version to use, + * and if each connection is client or server side. + * + * For this client-only demo, we tell it to not listen on any port. + */ + + context = libwebsocket_create_context(CONTEXT_PORT_NO_LISTEN, NULL, + protocols, libwebsocket_internal_extensions, + NULL, NULL, -1, -1, 0); + if (context == NULL) { + fprintf(stderr, "Creating libwebsocket context failed\n"); + return 1; + } + + + /* create a client websocket using dumb increment protocol */ + + wsi_dumb = libwebsocket_client_connect(context, address, port, use_ssl, + "/", argv[optind], argv[optind], + protocols[PROTOCOL_DUMB_INCREMENT].name, ietf_version); + + if (wsi_dumb == NULL) { + fprintf(stderr, "libwebsocket dumb connect failed\n"); + return -1; + } + + fprintf(stderr, "Websocket connections opened\n"); + + /* + * sit there servicing the websocket context to handle incoming + * packets, and drawing random circles on the mirror protocol websocket + */ + + n = 0; + while (n >= 0 && !was_closed) { + n = libwebsocket_service(context, 1000); + + if (n < 0) + continue; + + if (wsi_mirror == NULL) { + + /* create a client websocket using mirror protocol */ + + wsi_mirror = libwebsocket_client_connect(context, + address, port, use_ssl, "/", + argv[optind], argv[optind], + protocols[PROTOCOL_LWS_MIRROR].name, + ietf_version); + + if (wsi_mirror == NULL) { + fprintf(stderr, "libwebsocket " + "dumb connect failed\n"); + return -1; + } + + mirror_lifetime = 10 + (random() & 1023); + + fprintf(stderr, "opened mirror connection with " + "%d lifetime\n", mirror_lifetime); + + } else { + + mirror_lifetime--; + if (mirror_lifetime == 0) { + fprintf(stderr, "closing mirror session\n"); + libwebsocket_close_and_free_session(context, + wsi_mirror, LWS_CLOSE_STATUS_GOINGAWAY); + + /* + * wsi_mirror will get set to NULL in + * callback when close completes + */ + } + } + } + + fprintf(stderr, "Exiting\n"); + + libwebsocket_context_destroy(context); + + return 0; + +usage: + fprintf(stderr, "Usage: libwebsockets-test-client " + " [--port=

] " + "[--ssl] [-k] [-v ]\n"); + return 1; +} diff --git a/libs/libwebsockets/test-server/test-fraggle.c b/libs/libwebsockets/test-server/test-fraggle.c new file mode 100644 index 0000000000..1c77d59fe8 --- /dev/null +++ b/libs/libwebsockets/test-server/test-fraggle.c @@ -0,0 +1,333 @@ +/* + * libwebsockets-test-fraggle - random fragmentation test + * + * Copyright (C) 2010-2011 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include + +#include "../lib/libwebsockets.h" + +#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server" + +static int client; +static int terminate; + +enum demo_protocols { + PROTOCOL_FRAGGLE, + + /* always last */ + DEMO_PROTOCOL_COUNT +}; + +/* fraggle protocol */ + +enum fraggle_states { + FRAGSTATE_START_MESSAGE, + FRAGSTATE_RANDOM_PAYLOAD, + FRAGSTATE_POST_PAYLOAD_SUM, +}; + +struct per_session_data__fraggle { + int packets_left; + int total_message; + unsigned long sum; + enum fraggle_states state; +}; + +static int +callback_fraggle(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, + void *user, void *in, size_t len) +{ + int n; + unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 2048 + + LWS_SEND_BUFFER_POST_PADDING]; + struct per_session_data__fraggle *psf = user; + int chunk; + int write_mode = LWS_WRITE_CONTINUATION; + unsigned long sum; + unsigned char *p = (unsigned char *)in; + unsigned char *bp = &buf[LWS_SEND_BUFFER_PRE_PADDING]; + + switch (reason) { + + case LWS_CALLBACK_ESTABLISHED: + + fprintf(stderr, "server sees client connect\n"); + psf->state = FRAGSTATE_START_MESSAGE; + /* start the ball rolling */ + libwebsocket_callback_on_writable(context, wsi); + break; + + case LWS_CALLBACK_CLIENT_ESTABLISHED: + + fprintf(stderr, "client connects to server\n"); + psf->state = FRAGSTATE_START_MESSAGE; + break; + + case LWS_CALLBACK_CLIENT_RECEIVE: + + switch (psf->state) { + + case FRAGSTATE_START_MESSAGE: + + psf->state = FRAGSTATE_RANDOM_PAYLOAD; + psf->sum = 0; + psf->total_message = 0; + psf->packets_left = 0; + + /* fallthru */ + + case FRAGSTATE_RANDOM_PAYLOAD: + + for (n = 0; n < len; n++) + psf->sum += p[n]; + + psf->total_message += len; + psf->packets_left++; + + if (libwebsocket_is_final_fragment(wsi)) + psf->state = FRAGSTATE_POST_PAYLOAD_SUM; + break; + + case FRAGSTATE_POST_PAYLOAD_SUM: + + sum = p[0] << 24; + sum |= p[1] << 16; + sum |= p[2] << 8; + sum |= p[3]; + if (sum == psf->sum) + fprintf(stderr, "EOM received %d correctly " + "from %d fragments\n", + psf->total_message, psf->packets_left); + else + fprintf(stderr, "**** ERROR at EOM: " + "length %d, rx sum = 0x%lX, " + "server says it sent 0x%lX\n", + psf->total_message, psf->sum, sum); + + psf->state = FRAGSTATE_START_MESSAGE; + break; + } + break; + + case LWS_CALLBACK_SERVER_WRITEABLE: + + switch (psf->state) { + + case FRAGSTATE_START_MESSAGE: + + psf->packets_left = (random() % 1024) + 1; + fprintf(stderr, "Spamming %d random fragments\n", + psf->packets_left); + psf->sum = 0; + psf->total_message = 0; + write_mode = LWS_WRITE_BINARY; + psf->state = FRAGSTATE_RANDOM_PAYLOAD; + + /* fallthru */ + + case FRAGSTATE_RANDOM_PAYLOAD: + + chunk = (random() % 2000) + 1; + psf->total_message += chunk; + + libwebsockets_get_random(context, bp, chunk); + for (n = 0; n < chunk; n++) + psf->sum += bp[n]; + + psf->packets_left--; + if (psf->packets_left) + write_mode |= LWS_WRITE_NO_FIN; + else + psf->state = FRAGSTATE_POST_PAYLOAD_SUM; + + n = libwebsocket_write(wsi, bp, chunk, write_mode); + + libwebsocket_callback_on_writable(context, wsi); + break; + + case FRAGSTATE_POST_PAYLOAD_SUM: + + fprintf(stderr, "Spamming session over, " + "len = %d. sum = 0x%lX\n", + psf->total_message, psf->sum); + + bp[0] = psf->sum >> 24; + bp[1] = psf->sum >> 16; + bp[2] = psf->sum >> 8; + bp[3] = psf->sum; + + n = libwebsocket_write(wsi, (unsigned char *)bp, + 4, LWS_WRITE_BINARY); + + psf->state = FRAGSTATE_START_MESSAGE; + + libwebsocket_callback_on_writable(context, wsi); + break; + } + break; + + case LWS_CALLBACK_CLOSED: + + terminate = 1; + break; + + /* because we are protocols[0] ... */ + + case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: + if (strcmp(in, "deflate-stream") == 0) { + fprintf(stderr, "denied deflate-stream extension\n"); + return 1; + } + break; + + default: + break; + } + + return 0; +} + + + +/* list of supported protocols and callbacks */ + +static struct libwebsocket_protocols protocols[] = { + { + "fraggle-protocol", + callback_fraggle, + sizeof(struct per_session_data__fraggle), + }, + { + NULL, NULL, 0 /* End of list */ + } +}; + +static struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "port", required_argument, NULL, 'p' }, + { "ssl", no_argument, NULL, 's' }, + { "killmask", no_argument, NULL, 'k' }, + { "interface", required_argument, NULL, 'i' }, + { "client", no_argument, NULL, 'c' }, + { NULL, 0, 0, 0 } +}; + +int main(int argc, char **argv) +{ + int n = 0; + const char *cert_path = + LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem"; + const char *key_path = + LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem"; + int port = 7681; + int use_ssl = 0; + struct libwebsocket_context *context; + int opts = 0; + char interface_name[128] = ""; + const char *interface = NULL; + struct libwebsocket *wsi; + const char *address; + int server_port = port; + + fprintf(stderr, "libwebsockets test fraggle\n" + "(C) Copyright 2010-2011 Andy Green " + "licensed under LGPL2.1\n"); + + while (n >= 0) { + n = getopt_long(argc, argv, "ci:khsp:", options, NULL); + if (n < 0) + continue; + switch (n) { + case 's': + use_ssl = 1; + break; + case 'k': + opts = LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK; + break; + case 'p': + port = atoi(optarg); + server_port = port; + break; + case 'i': + strncpy(interface_name, optarg, sizeof interface_name); + interface_name[(sizeof interface_name) - 1] = '\0'; + interface = interface_name; + break; + case 'c': + client = 1; + fprintf(stderr, " Client mode\n"); + break; + case 'h': + fprintf(stderr, "Usage: libwebsockets-test-fraggle " + "[--port=

] [--ssl] [--client]\n"); + exit(1); + } + } + + if (client) { + server_port = CONTEXT_PORT_NO_LISTEN; + if (optind >= argc) { + fprintf(stderr, "Must give address of server\n"); + return 1; + } + } + + if (!use_ssl) + cert_path = key_path = NULL; + + context = libwebsocket_create_context(server_port, interface, protocols, + libwebsocket_internal_extensions, + cert_path, key_path, -1, -1, opts); + if (context == NULL) { + fprintf(stderr, "libwebsocket init failed\n"); + return -1; + } + + if (client) { + address = argv[optind]; + fprintf(stderr, "Connecting to %s:%u\n", address, port); + wsi = libwebsocket_client_connect(context, address, + port, use_ssl, "/", address, + "origin", protocols[PROTOCOL_FRAGGLE].name, + -1); + if (wsi == NULL) { + fprintf(stderr, "Client connect to server failed\n"); + goto bail; + } + } + + n = 0; + while (!n && !terminate) + n = libwebsocket_service(context, 50); + + fprintf(stderr, "Terminating...\n"); + +bail: + libwebsocket_context_destroy(context); + + return 0; +} diff --git a/libs/libwebsockets/test-server/test-ping.c b/libs/libwebsockets/test-server/test-ping.c new file mode 100644 index 0000000000..672f62cc0d --- /dev/null +++ b/libs/libwebsockets/test-server/test-ping.c @@ -0,0 +1,512 @@ +/* + * libwebsockets-test-ping - libwebsockets floodping + * + * Copyright (C) 2011 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "../lib/libwebsockets.h" +#include + +/* + * this is specified in the 04 standard, control frames can only have small + * payload length styles + */ +#define MAX_PING_PAYLOAD 125 +#define MAX_MIRROR_PAYLOAD 4096 +#define MAX_PING_CLIENTS 256 +#define PING_RINGBUFFER_SIZE 256 + +static struct libwebsocket *ping_wsi[MAX_PING_CLIENTS]; +static unsigned int interval_us = 1000000; +static unsigned int size = 64; +static int flood; +static const char *address; +static unsigned char pingbuf[LWS_SEND_BUFFER_PRE_PADDING + MAX_MIRROR_PAYLOAD + + LWS_SEND_BUFFER_POST_PADDING]; +static char peer_name[128]; +static unsigned long started; +static int screen_width = 80; +static int use_mirror; +static unsigned int write_options; + +static unsigned long rtt_min = 100000000; +static unsigned long rtt_max; +static unsigned long rtt_avg; +static unsigned long global_rx_count; +static unsigned long global_tx_count; +static int clients = 1; +static unsigned long interrupted_time; + +struct ping { + unsigned long issue_timestamp; + unsigned long index; + unsigned int seen; +}; + +struct per_session_data__ping { + unsigned long ping_index; + + struct ping ringbuffer[PING_RINGBUFFER_SIZE]; + int ringbuffer_head; + int ringbuffer_tail; + + unsigned long rx_count; +}; + +/* + * uses the ping pong protocol features to provide an equivalent for the + * ping utility for 04+ websockets + */ + +enum demo_protocols { + + PROTOCOL_LWS_MIRROR, + + /* always last */ + DEMO_PROTOCOL_COUNT +}; + + +static int +callback_lws_mirror(struct libwebsocket_context * this, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, + void *user, void *in, size_t len) +{ + struct timeval tv; + unsigned char *p; + int shift; + unsigned long l; + unsigned long iv; + int n; + int match = 0; + struct per_session_data__ping *psd = user; + + switch (reason) { + case LWS_CALLBACK_CLOSED: + + fprintf(stderr, "LWS_CALLBACK_CLOSED on %p\n", (void *)wsi); + + /* remove closed guy */ + + for (n = 0; n < clients; n++) + if (ping_wsi[n] == wsi) { + clients--; + while (n < clients) { + ping_wsi[n] = ping_wsi[n + 1]; + n++; + } + } + + break; + + case LWS_CALLBACK_CLIENT_ESTABLISHED: + + psd->rx_count = 0; + psd->ping_index = 1; + psd->ringbuffer_head = 0; + psd->ringbuffer_tail = 0; + + /* + * start the ball rolling, + * LWS_CALLBACK_CLIENT_WRITEABLE will come next service + */ + + libwebsocket_callback_on_writable(this, wsi); + break; + + case LWS_CALLBACK_CLIENT_RECEIVE: + case LWS_CALLBACK_CLIENT_RECEIVE_PONG: + gettimeofday(&tv, NULL); + iv = (tv.tv_sec * 1000000) + tv.tv_usec; + + psd->rx_count++; + + shift = 56; + p = in; + l = 0; + + while (shift >= 0) { + l |= (*p++) << shift; + shift -= 8; + } + + /* find it in the ringbuffer, look backwards from head */ + n = psd->ringbuffer_head; + while (!match) { + + if (psd->ringbuffer[n].index == l) { + psd->ringbuffer[n].seen++; + match = 1; + continue; + } + + if (n == psd->ringbuffer_tail) { + match = -1; + continue; + } + + if (n == 0) + n = PING_RINGBUFFER_SIZE - 1; + else + n--; + } + + if (match < 1) { + + if (!flood) + fprintf(stderr, "%d bytes from %s: req=%ld " + "time=(unknown)\n", (int)len, address, l); + else + fprintf(stderr, "\b \b"); + + break; + } + + if (psd->ringbuffer[n].seen > 1) + fprintf(stderr, "DUP! "); + + if ((iv - psd->ringbuffer[n].issue_timestamp) < rtt_min) + rtt_min = iv - psd->ringbuffer[n].issue_timestamp; + + if ((iv - psd->ringbuffer[n].issue_timestamp) > rtt_max) + rtt_max = iv - psd->ringbuffer[n].issue_timestamp; + + rtt_avg += iv - psd->ringbuffer[n].issue_timestamp; + global_rx_count++; + + if (!flood) + fprintf(stderr, "%d bytes from %s: req=%ld " + "time=%lu.%lums\n", (int)len, address, l, + (iv - psd->ringbuffer[n].issue_timestamp) / 1000, + ((iv - psd->ringbuffer[n].issue_timestamp) / 100) % 10); + else + fprintf(stderr, "\b \b"); + break; + + case LWS_CALLBACK_CLIENT_WRITEABLE: + + shift = 56; + p = &pingbuf[LWS_SEND_BUFFER_PRE_PADDING]; + + /* 64-bit ping index in network byte order */ + + while (shift >= 0) { + *p++ = psd->ping_index >> shift; + shift -= 8; + } + + gettimeofday(&tv, NULL); + + psd->ringbuffer[psd->ringbuffer_head].issue_timestamp = + (tv.tv_sec * 1000000) + tv.tv_usec; + psd->ringbuffer[psd->ringbuffer_head].index = psd->ping_index++; + psd->ringbuffer[psd->ringbuffer_head].seen = 0; + + if (psd->ringbuffer_head == PING_RINGBUFFER_SIZE - 1) + psd->ringbuffer_head = 0; + else + psd->ringbuffer_head++; + + /* snip any re-used tail so we keep to the ring length */ + + if (psd->ringbuffer_tail == psd->ringbuffer_head) { + if (psd->ringbuffer_tail == PING_RINGBUFFER_SIZE - 1) + psd->ringbuffer_tail = 0; + else + psd->ringbuffer_tail++; + } + + global_tx_count++; + + if (use_mirror) + libwebsocket_write(wsi, + &pingbuf[LWS_SEND_BUFFER_PRE_PADDING], + size, write_options | LWS_WRITE_BINARY); + else + libwebsocket_write(wsi, + &pingbuf[LWS_SEND_BUFFER_PRE_PADDING], + size, write_options | LWS_WRITE_PING); + + if (flood && + (psd->ping_index - psd->rx_count) < (screen_width - 1)) + fprintf(stderr, "."); + break; + + default: + break; + } + + return 0; +} + + +/* list of supported protocols and callbacks */ + +static struct libwebsocket_protocols protocols[] = { + + [PROTOCOL_LWS_MIRROR] = { + .name = "lws-mirror-protocol", + .callback = callback_lws_mirror, + .per_session_data_size = sizeof (struct per_session_data__ping), + }, + [DEMO_PROTOCOL_COUNT] = { /* end of list */ + .callback = NULL + } +}; + +static struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "port", required_argument, NULL, 'p' }, + { "ssl", no_argument, NULL, 't' }, + { "interval", required_argument, NULL, 'i' }, + { "size", required_argument, NULL, 's' }, + { "protocol", required_argument, NULL, 'n' }, + { "flood", no_argument, NULL, 'f' }, + { "mirror", no_argument, NULL, 'm' }, + { "replicate", required_argument, NULL, 'r' }, + { "killmask", no_argument, NULL, 'k' }, + { "version", required_argument, NULL, 'v' }, + { NULL, 0, 0, 0 } +}; + + +static void +signal_handler(int sig, siginfo_t *si, void *v) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + interrupted_time = (tv.tv_sec * 1000000) + tv.tv_usec; +} + + +int main(int argc, char **argv) +{ + int n = 0; + int port = 7681; + int use_ssl = 0; + struct libwebsocket_context *context; + char protocol_name[256]; + char ip[30]; + struct sigaction sa; + struct timeval tv; + struct winsize w; + unsigned long oldus = 0; + unsigned long l; + int ietf_version = -1; + + if (argc < 2) + goto usage; + + address = argv[1]; + optind++; + + while (n >= 0) { + n = getopt_long(argc, argv, "v:kr:hmfts:n:i:p:", options, NULL); + if (n < 0) + continue; + switch (n) { + case 'm': + use_mirror = 1; + break; + case 't': + use_ssl = 2; /* 2 = allow selfsigned */ + break; + case 'p': + port = atoi(optarg); + break; + case 'n': + strncpy(protocol_name, optarg, sizeof protocol_name); + protocol_name[(sizeof protocol_name) - 1] = '\0'; + protocols[PROTOCOL_LWS_MIRROR].name = protocol_name; + break; + case 'i': + interval_us = 1000000.0 * atof(optarg); + break; + case 's': + size = atoi(optarg); + break; + case 'f': + flood = 1; + break; + case 'r': + clients = atoi(optarg); + if (clients > MAX_PING_CLIENTS || clients < 1) { + fprintf(stderr, "Max clients supportd = %d\n", + MAX_PING_CLIENTS); + return 1; + } + break; + case 'k': + write_options = LWS_WRITE_CLIENT_IGNORE_XOR_MASK; + break; + case 'v': + ietf_version = atoi(optarg); + break; + + case 'h': + goto usage; + } + } + + if (!use_mirror) { + if (size > MAX_PING_PAYLOAD) { + fprintf(stderr, "Max ping opcode payload size %d\n", + MAX_PING_PAYLOAD); + return 1; + } + } else { + if (size > MAX_MIRROR_PAYLOAD) { + fprintf(stderr, "Max mirror payload size %d\n", + MAX_MIRROR_PAYLOAD); + return 1; + } + } + + + if (isatty(STDOUT_FILENO)) + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) + if (w.ws_col > 0) + screen_width = w.ws_col; + + context = libwebsocket_create_context(CONTEXT_PORT_NO_LISTEN, NULL, + protocols, + libwebsocket_internal_extensions, + NULL, NULL, -1, -1, 0); + if (context == NULL) { + fprintf(stderr, "Creating libwebsocket context failed\n"); + return 1; + } + + /* create client websockets using dumb increment protocol */ + + for (n = 0; n < clients; n++) { + ping_wsi[n] = libwebsocket_client_connect(context, address, + port, use_ssl, "/", address, + "origin", protocols[PROTOCOL_LWS_MIRROR].name, + ietf_version); + if (ping_wsi[n] == NULL) { + fprintf(stderr, "client connnection %d failed to " + "connect\n", n); + return 1; + } + } + + libwebsockets_get_peer_addresses( + libwebsocket_get_socket_fd(ping_wsi[0]), + peer_name, sizeof peer_name, ip, sizeof ip); + + fprintf(stderr, "Websocket PING %s (%s) %d bytes of data.\n", + peer_name, ip, size); + + /* set the ^C handler */ + + sa.sa_sigaction = signal_handler; + sa.sa_flags = SA_SIGINFO; + sigemptyset(&sa.sa_mask); + sigaction(SIGINT, &sa, NULL); + + gettimeofday(&tv, NULL); + started = (tv.tv_sec * 1000000) + tv.tv_usec; + + /* service loop */ + + n = 0; + while (n >= 0) { + + gettimeofday(&tv, NULL); + l = (tv.tv_sec * 1000000) + tv.tv_usec; + + /* servers can hang up on us */ + + if (clients == 0) { + n = -1; + continue; + } + + if (!interrupted_time) { + if ((l - oldus) > interval_us) { + for (n = 0; n < clients; n++) + libwebsocket_callback_on_writable( + context, ping_wsi[n]); + oldus = l; + } + } else + + /* allow time for in-flight pongs to come */ + + if ((l - interrupted_time) > 250000) { + n = -1; + continue; + } + + if (!interval_us) + n = libwebsocket_service(context, 0); + else + n = libwebsocket_service(context, 1); + } + + /* stats */ + + fprintf(stderr, "\n--- %s websocket ping statistics " + "using %d connections ---\n" + "%lu packets transmitted, %lu received, " + "%lu%% packet loss, time %ldms\n" + "rtt min/avg/max = %0.3f/%0.3f/%0.3f ms\n" + "payload bandwidth average %0.3f KiBytes/sec\n", + peer_name, clients, global_tx_count, global_rx_count, + ((global_tx_count - global_rx_count) * 100) / global_tx_count, + (l - started) / 1000, + ((double)rtt_min) / 1000.0, + ((double)rtt_avg / global_rx_count) / 1000.0, + ((double)rtt_max) / 1000.0, + ((double)global_rx_count * (double)size) / + ((double)(l - started) / 1000000.0) / 1024.0); + + libwebsocket_context_destroy(context); + + return 0; + +usage: + fprintf(stderr, "Usage: libwebsockets-test-ping " + " [--port=

] " + "[--ssl] [--interval=] " + "[--size=] " + "[--protocol=] " + "[--mirror] " + "[--replicate=clients>]" + "[--version ]" + "\n"); + return 1; +} diff --git a/libs/libwebsockets/test-server/test-server-extpoll.c b/libs/libwebsockets/test-server/test-server-extpoll.c new file mode 100644 index 0000000000..8131412fe3 --- /dev/null +++ b/libs/libwebsockets/test-server/test-server-extpoll.c @@ -0,0 +1,553 @@ +/* + * libwebsockets-test-server-extpoll - libwebsockets external poll loop sample + * + * This acts the same as libwebsockets-test-server but works with the poll + * loop taken out of libwebsockets and into this app. It's an example of how + * you can integrate libwebsockets polling into an app that already has its + * own poll loop. + * + * Copyright (C) 2010-2011 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#ifdef __MINGW32__ +#include "../win32port/win32helpers/websock-w32.h" +#else +#ifdef __MINGW64__ +#include "../win32port/win32helpers/websock-w32.h" +#else +#include +#endif +#endif + +#include "../lib/libwebsockets.h" + + +/* + * This demo server shows how to use libwebsockets for one or more + * websocket protocols in the same server + * + * It defines the following websocket protocols: + * + * dumb-increment-protocol: once the socket is opened, an incrementing + * ascii string is sent down it every 50ms. + * If you send "reset\n" on the websocket, then + * the incrementing number is reset to 0. + * + * lws-mirror-protocol: copies any received packet to every connection also + * using this protocol, including the sender + */ + +#define MAX_POLL_ELEMENTS 100 +struct pollfd pollfds[100]; +int count_pollfds = 0; + + + +enum demo_protocols { + /* always first */ + PROTOCOL_HTTP = 0, + + PROTOCOL_DUMB_INCREMENT, + PROTOCOL_LWS_MIRROR, + + /* always last */ + DEMO_PROTOCOL_COUNT +}; + + +#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server" + +/* this protocol server (always the first one) just knows how to do HTTP */ + +static int callback_http(struct libwebsocket_context * this, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len) +{ + int n; + char client_name[128]; + char client_ip[128]; + + switch (reason) { + case LWS_CALLBACK_HTTP: + fprintf(stderr, "serving HTTP URI %s\n", (char *)in); + + if (in && strcmp(in, "/favicon.ico") == 0) { + if (libwebsockets_serve_http_file(wsi, + LOCAL_RESOURCE_PATH"/favicon.ico", "image/x-icon")) + fprintf(stderr, "Failed to send favicon\n"); + break; + } + + /* send the script... when it runs it'll start websockets */ + + if (libwebsockets_serve_http_file(wsi, + LOCAL_RESOURCE_PATH"/test.html", "text/html")) + fprintf(stderr, "Failed to send HTTP file\n"); + break; + + /* + * callback for confirming to continue with client IP appear in + * protocol 0 callback since no websocket protocol has been agreed + * yet. You can just ignore this if you won't filter on client IP + * since the default uhandled callback return is 0 meaning let the + * connection continue. + */ + + case LWS_CALLBACK_FILTER_NETWORK_CONNECTION: + + libwebsockets_get_peer_addresses((int)(long)user, client_name, + sizeof(client_name), client_ip, sizeof(client_ip)); + + fprintf(stderr, "Received network connect from %s (%s)\n", + client_name, client_ip); + + /* if we returned non-zero from here, we kill the connection */ + break; + + /* + * callbacks for managing the external poll() array appear in + * protocol 0 callback + */ + + case LWS_CALLBACK_ADD_POLL_FD: + pollfds[count_pollfds].fd = (int)(long)user; + pollfds[count_pollfds].events = (int)len; + pollfds[count_pollfds++].revents = 0; + break; + + case LWS_CALLBACK_DEL_POLL_FD: + for (n = 0; n < count_pollfds; n++) + if (pollfds[n].fd == (int)(long)user) + while (n < count_pollfds) { + pollfds[n] = pollfds[n + 1]; + n++; + } + count_pollfds--; + break; + + case LWS_CALLBACK_SET_MODE_POLL_FD: + for (n = 0; n < count_pollfds; n++) + if (pollfds[n].fd == (int)(long)user) + pollfds[n].events |= (int)(long)len; + break; + + case LWS_CALLBACK_CLEAR_MODE_POLL_FD: + for (n = 0; n < count_pollfds; n++) + if (pollfds[n].fd == (int)(long)user) + pollfds[n].events &= ~(int)(long)len; + break; + + default: + break; + } + + return 0; +} + +/* + * this is just an example of parsing handshake headers, you don't need this + * in your code unless you will filter allowing connections by the header + * content + */ + +static void +dump_handshake_info(struct lws_tokens *lwst) +{ + int n; + static const char *token_names[] = { + [WSI_TOKEN_GET_URI] = "GET URI", + [WSI_TOKEN_HOST] = "Host", + [WSI_TOKEN_CONNECTION] = "Connection", + [WSI_TOKEN_KEY1] = "key 1", + [WSI_TOKEN_KEY2] = "key 2", + [WSI_TOKEN_PROTOCOL] = "Protocol", + [WSI_TOKEN_UPGRADE] = "Upgrade", + [WSI_TOKEN_ORIGIN] = "Origin", + [WSI_TOKEN_DRAFT] = "Draft", + [WSI_TOKEN_CHALLENGE] = "Challenge", + + /* new for 04 */ + [WSI_TOKEN_KEY] = "Key", + [WSI_TOKEN_VERSION] = "Version", + [WSI_TOKEN_SWORIGIN] = "Sworigin", + + /* new for 05 */ + [WSI_TOKEN_EXTENSIONS] = "Extensions", + + /* client receives these */ + [WSI_TOKEN_ACCEPT] = "Accept", + [WSI_TOKEN_NONCE] = "Nonce", + [WSI_TOKEN_HTTP] = "Http", + [WSI_TOKEN_MUXURL] = "MuxURL", + }; + + for (n = 0; n < WSI_TOKEN_COUNT; n++) { + if (lwst[n].token == NULL) + continue; + + fprintf(stderr, " %s = %s\n", token_names[n], lwst[n].token); + } +} + +/* dumb_increment protocol */ + +/* + * one of these is auto-created for each connection and a pointer to the + * appropriate instance is passed to the callback in the user parameter + * + * for this example protocol we use it to individualize the count for each + * connection. + */ + +struct per_session_data__dumb_increment { + int number; +}; + +static int +callback_dumb_increment(struct libwebsocket_context * this, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, + void *user, void *in, size_t len) +{ + int n; + unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 + + LWS_SEND_BUFFER_POST_PADDING]; + unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING]; + struct per_session_data__dumb_increment *pss = user; + + switch (reason) { + + case LWS_CALLBACK_ESTABLISHED: + pss->number = 0; + break; + + /* + * in this protocol, we just use the broadcast action as the chance to + * send our own connection-specific data and ignore the broadcast info + * that is available in the 'in' parameter + */ + + case LWS_CALLBACK_BROADCAST: + n = sprintf((char *)p, "%d", pss->number++); + n = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT); + if (n < 0) { + fprintf(stderr, "ERROR writing to socket"); + return 1; + } + break; + + case LWS_CALLBACK_RECEIVE: + fprintf(stderr, "rx %d\n", (int)len); + if (len < 6) + break; + if (strcmp(in, "reset\n") == 0) + pss->number = 0; + break; + + /* + * this just demonstrates how to use the protocol filter. If you won't + * study and reject connections based on header content, you don't need + * to handle this callback + */ + + case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: + dump_handshake_info((struct lws_tokens *)(long)user); + /* you could return non-zero here and kill the connection */ + break; + + default: + break; + } + + return 0; +} + + +/* lws-mirror_protocol */ + +#define MAX_MESSAGE_QUEUE 64 + +struct per_session_data__lws_mirror { + struct libwebsocket *wsi; + int ringbuffer_tail; +}; + +struct a_message { + void *payload; + size_t len; +}; + +static struct a_message ringbuffer[MAX_MESSAGE_QUEUE]; +static int ringbuffer_head; + + +static int +callback_lws_mirror(struct libwebsocket_context * this, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, + void *user, void *in, size_t len) +{ + int n; + struct per_session_data__lws_mirror *pss = user; + + switch (reason) { + + case LWS_CALLBACK_ESTABLISHED: + pss->ringbuffer_tail = ringbuffer_head; + pss->wsi = wsi; + libwebsocket_callback_on_writable(this, wsi); + break; + + case LWS_CALLBACK_SERVER_WRITEABLE: + + if (pss->ringbuffer_tail != ringbuffer_head) { + + n = libwebsocket_write(wsi, (unsigned char *) + ringbuffer[pss->ringbuffer_tail].payload + + LWS_SEND_BUFFER_PRE_PADDING, + ringbuffer[pss->ringbuffer_tail].len, + LWS_WRITE_TEXT); + + if (n < 0) { + fprintf(stderr, "ERROR writing to socket"); + exit(1); + } + + if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1)) + pss->ringbuffer_tail = 0; + else + pss->ringbuffer_tail++; + + if (((ringbuffer_head - pss->ringbuffer_tail) % + MAX_MESSAGE_QUEUE) < (MAX_MESSAGE_QUEUE - 15)) + libwebsocket_rx_flow_control(wsi, 1); + + libwebsocket_callback_on_writable(this, wsi); + + } + break; + + case LWS_CALLBACK_BROADCAST: + n = libwebsocket_write(wsi, in, len, LWS_WRITE_TEXT); + if (n < 0) + fprintf(stderr, "mirror write failed\n"); + break; + + case LWS_CALLBACK_RECEIVE: + + if (ringbuffer[ringbuffer_head].payload) + free(ringbuffer[ringbuffer_head].payload); + + ringbuffer[ringbuffer_head].payload = + malloc(LWS_SEND_BUFFER_PRE_PADDING + len + + LWS_SEND_BUFFER_POST_PADDING); + ringbuffer[ringbuffer_head].len = len; + memcpy((char *)ringbuffer[ringbuffer_head].payload + + LWS_SEND_BUFFER_PRE_PADDING, in, len); + if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1)) + ringbuffer_head = 0; + else + ringbuffer_head++; + + if (((ringbuffer_head - pss->ringbuffer_tail) % + MAX_MESSAGE_QUEUE) > (MAX_MESSAGE_QUEUE - 10)) + libwebsocket_rx_flow_control(wsi, 0); + + libwebsocket_callback_on_writable_all_protocol( + libwebsockets_get_protocol(wsi)); + break; + + /* + * this just demonstrates how to use the protocol filter. If you won't + * study and reject connections based on header content, you don't need + * to handle this callback + */ + + case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: + dump_handshake_info((struct lws_tokens *)(long)user); + /* you could return non-zero here and kill the connection */ + break; + + default: + break; + } + + return 0; +} + + +/* list of supported protocols and callbacks */ + +static struct libwebsocket_protocols protocols[] = { + /* first protocol must always be HTTP handler */ + + { + "http-only", /* name */ + callback_http, /* callback */ + 0 /* per_session_data_size */ + }, + { + "dumb-increment-protocol", + callback_dumb_increment, + sizeof(struct per_session_data__dumb_increment), + }, + { + "lws-mirror-protocol", + callback_lws_mirror, + sizeof(struct per_session_data__lws_mirror) + }, + { + NULL, NULL, 0 /* End of list */ + } +}; + +static struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "port", required_argument, NULL, 'p' }, + { "ssl", no_argument, NULL, 's' }, + { "killmask", no_argument, NULL, 'k' }, + { "interface", required_argument, NULL, 'i' }, + { NULL, 0, 0, 0 } +}; + +int main(int argc, char **argv) +{ + int n = 0; + const char *cert_path = + LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem"; + const char *key_path = + LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem"; + unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1024 + + LWS_SEND_BUFFER_POST_PADDING]; + int port = 7681; + int use_ssl = 0; + struct libwebsocket_context *context; + int opts = 0; + unsigned int oldus = 0; + char interface_name[128] = ""; + const char *interface_ptr = NULL; + + fprintf(stderr, "libwebsockets test server with external poll()\n" + "(C) Copyright 2010-2011 Andy Green " + "licensed under LGPL2.1\n"); + + while (n >= 0) { + n = getopt_long(argc, argv, "i:khsp:", options, NULL); + if (n < 0) + continue; + switch (n) { + case 's': + use_ssl = 1; + break; + case 'k': + opts = LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK; + break; + case 'p': + port = atoi(optarg); + break; + case 'i': + strncpy(interface_name, optarg, sizeof interface_name); + interface_name[(sizeof interface_name) - 1] = '\0'; + interface_ptr = interface_name; + break; + case 'h': + fprintf(stderr, "Usage: test-server " + "[--port=

] [--ssl]\n"); + exit(1); + } + } + + if (!use_ssl) + cert_path = key_path = NULL; + + context = libwebsocket_create_context(port, interface_ptr, protocols, + libwebsocket_internal_extensions, + cert_path, key_path, -1, -1, opts); + if (context == NULL) { + fprintf(stderr, "libwebsocket init failed\n"); + return -1; + } + + buf[LWS_SEND_BUFFER_PRE_PADDING] = 'x'; + + /* + * This is an example of an existing application's explicit poll() + * loop that libwebsockets can integrate with. + */ + + while (1) { + struct timeval tv; + + /* + * this represents an existing server's single poll action + * which also includes libwebsocket sockets + */ + + n = poll(pollfds, count_pollfds, 25); + if (n < 0) + goto done; + + if (n) + for (n = 0; n < count_pollfds; n++) + if (pollfds[n].revents) + /* + * returns immediately if the fd does not + * match anything under libwebsockets + * control + */ + if (libwebsocket_service_fd(context, + &pollfds[n])) + goto done; + + /* do our broadcast periodically */ + + gettimeofday(&tv, NULL); + + /* + * This broadcasts to all dumb-increment-protocol connections + * at 20Hz. + * + * We're just sending a character 'x', in these examples the + * callbacks send their own per-connection content. + * + * You have to send something with nonzero length to get the + * callback actions delivered. + * + * We take care of pre-and-post padding allocation. + */ + + if (((unsigned int)tv.tv_usec - oldus) > 50000) { + libwebsockets_broadcast( + &protocols[PROTOCOL_DUMB_INCREMENT], + &buf[LWS_SEND_BUFFER_PRE_PADDING], 1); + oldus = tv.tv_usec; + } + } + +done: + libwebsocket_context_destroy(context); + + return 0; +} diff --git a/libs/libwebsockets/test-server/test-server.c b/libs/libwebsockets/test-server/test-server.c new file mode 100644 index 0000000000..516deff7bd --- /dev/null +++ b/libs/libwebsockets/test-server/test-server.c @@ -0,0 +1,551 @@ +/* + * libwebsockets-test-server - libwebsockets test implementation + * + * Copyright (C) 2010-2011 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include + +#include "../lib/libwebsockets.h" + +static int close_testing; + +/* + * This demo server shows how to use libwebsockets for one or more + * websocket protocols in the same server + * + * It defines the following websocket protocols: + * + * dumb-increment-protocol: once the socket is opened, an incrementing + * ascii string is sent down it every 50ms. + * If you send "reset\n" on the websocket, then + * the incrementing number is reset to 0. + * + * lws-mirror-protocol: copies any received packet to every connection also + * using this protocol, including the sender + */ + +enum demo_protocols { + /* always first */ + PROTOCOL_HTTP = 0, + + PROTOCOL_DUMB_INCREMENT, + PROTOCOL_LWS_MIRROR, + + /* always last */ + DEMO_PROTOCOL_COUNT +}; + + +#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server" + +/* this protocol server (always the first one) just knows how to do HTTP */ + +static int callback_http(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len) +{ + char client_name[128]; + char client_ip[128]; + + switch (reason) { + case LWS_CALLBACK_HTTP: + fprintf(stderr, "serving HTTP URI %s\n", (char *)in); + + if (in && strcmp(in, "/favicon.ico") == 0) { + if (libwebsockets_serve_http_file(wsi, + LOCAL_RESOURCE_PATH"/favicon.ico", "image/x-icon")) + fprintf(stderr, "Failed to send favicon\n"); + break; + } + + /* send the script... when it runs it'll start websockets */ + + if (libwebsockets_serve_http_file(wsi, + LOCAL_RESOURCE_PATH"/test.html", "text/html")) + fprintf(stderr, "Failed to send HTTP file\n"); + break; + + /* + * callback for confirming to continue with client IP appear in + * protocol 0 callback since no websocket protocol has been agreed + * yet. You can just ignore this if you won't filter on client IP + * since the default uhandled callback return is 0 meaning let the + * connection continue. + */ + + case LWS_CALLBACK_FILTER_NETWORK_CONNECTION: + + libwebsockets_get_peer_addresses((int)(long)user, client_name, + sizeof(client_name), client_ip, sizeof(client_ip)); + + fprintf(stderr, "Received network connect from %s (%s)\n", + client_name, client_ip); + + /* if we returned non-zero from here, we kill the connection */ + break; + + default: + break; + } + + return 0; +} + + +/* + * this is just an example of parsing handshake headers, you don't need this + * in your code unless you will filter allowing connections by the header + * content + */ + +static void +dump_handshake_info(struct lws_tokens *lwst) +{ + int n; + static const char *token_names[WSI_TOKEN_COUNT] = { + /*[WSI_TOKEN_GET_URI] =*/ "GET URI", + /*[WSI_TOKEN_HOST] =*/ "Host", + /*[WSI_TOKEN_CONNECTION] =*/ "Connection", + /*[WSI_TOKEN_KEY1] =*/ "key 1", + /*[WSI_TOKEN_KEY2] =*/ "key 2", + /*[WSI_TOKEN_PROTOCOL] =*/ "Protocol", + /*[WSI_TOKEN_UPGRADE] =*/ "Upgrade", + /*[WSI_TOKEN_ORIGIN] =*/ "Origin", + /*[WSI_TOKEN_DRAFT] =*/ "Draft", + /*[WSI_TOKEN_CHALLENGE] =*/ "Challenge", + + /* new for 04 */ + /*[WSI_TOKEN_KEY] =*/ "Key", + /*[WSI_TOKEN_VERSION] =*/ "Version", + /*[WSI_TOKEN_SWORIGIN] =*/ "Sworigin", + + /* new for 05 */ + /*[WSI_TOKEN_EXTENSIONS] =*/ "Extensions", + + /* client receives these */ + /*[WSI_TOKEN_ACCEPT] =*/ "Accept", + /*[WSI_TOKEN_NONCE] =*/ "Nonce", + /*[WSI_TOKEN_HTTP] =*/ "Http", + /*[WSI_TOKEN_MUXURL] =*/ "MuxURL", + }; + + for (n = 0; n < WSI_TOKEN_COUNT; n++) { + if (lwst[n].token == NULL) + continue; + + fprintf(stderr, " %s = %s\n", token_names[n], lwst[n].token); + } +} + +/* dumb_increment protocol */ + +/* + * one of these is auto-created for each connection and a pointer to the + * appropriate instance is passed to the callback in the user parameter + * + * for this example protocol we use it to individualize the count for each + * connection. + */ + +struct per_session_data__dumb_increment { + int number; +}; + +static int +callback_dumb_increment(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, + void *user, void *in, size_t len) +{ + int n; + unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 + + LWS_SEND_BUFFER_POST_PADDING]; + unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING]; + struct per_session_data__dumb_increment *pss = user; + + switch (reason) { + + case LWS_CALLBACK_ESTABLISHED: + fprintf(stderr, "callback_dumb_increment: " + "LWS_CALLBACK_ESTABLISHED\n"); + pss->number = 0; + break; + + /* + * in this protocol, we just use the broadcast action as the chance to + * send our own connection-specific data and ignore the broadcast info + * that is available in the 'in' parameter + */ + + case LWS_CALLBACK_BROADCAST: + n = sprintf((char *)p, "%d", pss->number++); + n = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT); + if (n < 0) { + fprintf(stderr, "ERROR writing to socket"); + return 1; + } + if (close_testing && pss->number == 50) { + fprintf(stderr, "close tesing limit, closing\n"); + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NORMAL); + } + break; + + case LWS_CALLBACK_RECEIVE: + fprintf(stderr, "rx %d\n", (int)len); + if (len < 6) + break; + if (strcmp(in, "reset\n") == 0) + pss->number = 0; + break; + /* + * this just demonstrates how to use the protocol filter. If you won't + * study and reject connections based on header content, you don't need + * to handle this callback + */ + + case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: + dump_handshake_info((struct lws_tokens *)(long)user); + /* you could return non-zero here and kill the connection */ + break; + + default: + break; + } + + return 0; +} + + +/* lws-mirror_protocol */ + +#define MAX_MESSAGE_QUEUE 64 + +struct per_session_data__lws_mirror { + struct libwebsocket *wsi; + int ringbuffer_tail; +}; + +struct a_message { + void *payload; + size_t len; +}; + +static struct a_message ringbuffer[MAX_MESSAGE_QUEUE]; +static int ringbuffer_head; + + +static int +callback_lws_mirror(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, + void *user, void *in, size_t len) +{ + int n; + struct per_session_data__lws_mirror *pss = user; + + switch (reason) { + + case LWS_CALLBACK_ESTABLISHED: + fprintf(stderr, "callback_lws_mirror: " + "LWS_CALLBACK_ESTABLISHED\n"); + pss->ringbuffer_tail = ringbuffer_head; + pss->wsi = wsi; + break; + + case LWS_CALLBACK_SERVER_WRITEABLE: + if (close_testing) + break; + if (pss->ringbuffer_tail != ringbuffer_head) { + + n = libwebsocket_write(wsi, (unsigned char *) + ringbuffer[pss->ringbuffer_tail].payload + + LWS_SEND_BUFFER_PRE_PADDING, + ringbuffer[pss->ringbuffer_tail].len, + LWS_WRITE_TEXT); + if (n < 0) { + fprintf(stderr, "ERROR writing to socket"); + exit(1); + } + + if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1)) + pss->ringbuffer_tail = 0; + else + pss->ringbuffer_tail++; + + if (((ringbuffer_head - pss->ringbuffer_tail) % + MAX_MESSAGE_QUEUE) < (MAX_MESSAGE_QUEUE - 15)) + libwebsocket_rx_flow_control(wsi, 1); + + libwebsocket_callback_on_writable(context, wsi); + + } + break; + + case LWS_CALLBACK_BROADCAST: + n = libwebsocket_write(wsi, in, len, LWS_WRITE_TEXT); + if (n < 0) + fprintf(stderr, "mirror write failed\n"); + break; + + case LWS_CALLBACK_RECEIVE: + + if (ringbuffer[ringbuffer_head].payload) + free(ringbuffer[ringbuffer_head].payload); + + ringbuffer[ringbuffer_head].payload = + malloc(LWS_SEND_BUFFER_PRE_PADDING + len + + LWS_SEND_BUFFER_POST_PADDING); + ringbuffer[ringbuffer_head].len = len; + memcpy((char *)ringbuffer[ringbuffer_head].payload + + LWS_SEND_BUFFER_PRE_PADDING, in, len); + if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1)) + ringbuffer_head = 0; + else + ringbuffer_head++; + + if (((ringbuffer_head - pss->ringbuffer_tail) % + MAX_MESSAGE_QUEUE) > (MAX_MESSAGE_QUEUE - 10)) + libwebsocket_rx_flow_control(wsi, 0); + + libwebsocket_callback_on_writable_all_protocol( + libwebsockets_get_protocol(wsi)); + break; + /* + * this just demonstrates how to use the protocol filter. If you won't + * study and reject connections based on header content, you don't need + * to handle this callback + */ + + case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: + dump_handshake_info((struct lws_tokens *)(long)user); + /* you could return non-zero here and kill the connection */ + break; + + default: + break; + } + + return 0; +} + + +/* list of supported protocols and callbacks */ + +static struct libwebsocket_protocols protocols[] = { + /* first protocol must always be HTTP handler */ + + { + "http-only", /* name */ + callback_http, /* callback */ + 0 /* per_session_data_size */ + }, + { + "dumb-increment-protocol", + callback_dumb_increment, + sizeof(struct per_session_data__dumb_increment), + }, + { + "lws-mirror-protocol", + callback_lws_mirror, + sizeof(struct per_session_data__lws_mirror) + }, + { + NULL, NULL, 0 /* End of list */ + } +}; + +static struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "port", required_argument, NULL, 'p' }, + { "ssl", no_argument, NULL, 's' }, + { "killmask", no_argument, NULL, 'k' }, + { "interface", required_argument, NULL, 'i' }, + { "closetest", no_argument, NULL, 'c' }, + { NULL, 0, 0, 0 } +}; + +int main(int argc, char **argv) +{ + int n = 0; + const char *cert_path = + LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem"; + const char *key_path = + LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem"; + unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1024 + + LWS_SEND_BUFFER_POST_PADDING]; + int port = 7681; + int use_ssl = 0; + struct libwebsocket_context *context; + int opts = 0; + char interface_name[128] = ""; + const char *interface = NULL; +#ifdef LWS_NO_FORK + unsigned int oldus = 0; +#endif + + fprintf(stderr, "libwebsockets test server\n" + "(C) Copyright 2010-2011 Andy Green " + "licensed under LGPL2.1\n"); + + while (n >= 0) { + n = getopt_long(argc, argv, "ci:khsp:", options, NULL); + if (n < 0) + continue; + switch (n) { + case 's': + use_ssl = 1; + break; + case 'k': + opts = LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK; + break; + case 'p': + port = atoi(optarg); + break; + case 'i': + strncpy(interface_name, optarg, sizeof interface_name); + interface_name[(sizeof interface_name) - 1] = '\0'; + interface = interface_name; + break; + case 'c': + close_testing = 1; + fprintf(stderr, " Close testing mode -- closes on " + "client after 50 dumb increments" + "and suppresses lws_mirror spam\n"); + break; + case 'h': + fprintf(stderr, "Usage: test-server " + "[--port=

] [--ssl]\n"); + exit(1); + } + } + + if (!use_ssl) + cert_path = key_path = NULL; + + context = libwebsocket_create_context(port, interface, protocols, + libwebsocket_internal_extensions, + cert_path, key_path, -1, -1, opts); + if (context == NULL) { + fprintf(stderr, "libwebsocket init failed\n"); + return -1; + } + + buf[LWS_SEND_BUFFER_PRE_PADDING] = 'x'; + +#ifdef LWS_NO_FORK + + /* + * This example shows how to work with no forked service loop + */ + + fprintf(stderr, " Using no-fork service loop\n"); + + n = 0; + while (n >= 0) { + struct timeval tv; + + gettimeofday(&tv, NULL); + + /* + * This broadcasts to all dumb-increment-protocol connections + * at 20Hz. + * + * We're just sending a character 'x', in these examples the + * callbacks send their own per-connection content. + * + * You have to send something with nonzero length to get the + * callback actions delivered. + * + * We take care of pre-and-post padding allocation. + */ + + if (((unsigned int)tv.tv_usec - oldus) > 50000) { + libwebsockets_broadcast( + &protocols[PROTOCOL_DUMB_INCREMENT], + &buf[LWS_SEND_BUFFER_PRE_PADDING], 1); + oldus = tv.tv_usec; + } + + /* + * This example server does not fork or create a thread for + * websocket service, it all runs in this single loop. So, + * we have to give the websockets an opportunity to service + * "manually". + * + * If no socket is needing service, the call below returns + * immediately and quickly. Negative return means we are + * in process of closing + */ + + n = libwebsocket_service(context, 50); + } + +#else + + /* + * This example shows how to work with the forked websocket service loop + */ + + fprintf(stderr, " Using forked service loop\n"); + + /* + * This forks the websocket service action into a subprocess so we + * don't have to take care about it. + */ + + n = libwebsockets_fork_service_loop(context); + if (n < 0) { + fprintf(stderr, "Unable to fork service loop %d\n", n); + return 1; + } + + while (1) { + + usleep(50000); + + /* + * This broadcasts to all dumb-increment-protocol connections + * at 20Hz. + * + * We're just sending a character 'x', in these examples the + * callbacks send their own per-connection content. + * + * You have to send something with nonzero length to get the + * callback actions delivered. + * + * We take care of pre-and-post padding allocation. + */ + + libwebsockets_broadcast(&protocols[PROTOCOL_DUMB_INCREMENT], + &buf[LWS_SEND_BUFFER_PRE_PADDING], 1); + } + +#endif + + libwebsocket_context_destroy(context); + + return 0; +} diff --git a/libs/libwebsockets/test-server/test.html b/libs/libwebsockets/test-server/test.html new file mode 100644 index 0000000000..99d6236b83 --- /dev/null +++ b/libs/libwebsockets/test-server/test.html @@ -0,0 +1,361 @@ + + + + + Minimal Websocket test app + + + +

Detected Browser:
...

+

libwebsockets "dumb-increment-protocol" test applet

+The incrementing number is coming from the server and is individual for +each connection to the server... try opening a second browser window. +Click the button to send the server a websocket message to +reset the number.

+ + + + + + + +
Not initialized
+ +

libwebsockets "lws-mirror-protocol" test applet

+Use the mouse to draw on the canvas below -- all other browser windows open +on this page see your drawing in realtime and you can see any of theirs as +well. +

+The lws-mirror protocol doesn't interpret what is being sent to it, it just +re-sends it to every other websocket it has a connection with using that +protocol, including the guy who sent the packet. +

libwebsockets-test-client spams circles on to this shared canvas when +run.

+

+ + + + + + + + + +
Drawing color: + +
Not initialized
+ + + + + diff --git a/libs/libwebsockets/win32port/client/client.vcxproj b/libs/libwebsockets/win32port/client/client.vcxproj new file mode 100644 index 0000000000..1192afc142 --- /dev/null +++ b/libs/libwebsockets/win32port/client/client.vcxproj @@ -0,0 +1,259 @@ + + + + + Debug static + Win32 + + + Debug + Win32 + + + Debug + x64 + + + Release DLL + Win32 + + + Release DLL + x64 + + + Release static + Win32 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + {332bf17e-fd30-4363-975a-aa731a827b4f} + + + {4156fc56-8443-2973-4fe2-a0bb2c621525} + + + + + + + + {6265650C-4799-451C-A687-94DE48759A8B} + Win32Proj + client + + + + Application + true + Unicode + + + Application + true + Unicode + + + Application + true + Unicode + + + Application + true + Unicode + + + Application + false + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../win32helpers + false + + + Console + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../win32helpers + MultiThreadedDebug + false + + + Console + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../win32helpers + + + Console + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../win32helpers + + + Console + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../win32helpers + MultiThreaded + false + + + Console + true + true + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../win32helpers + + + Console + true + true + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + false + ../win32helpers + WIN32;_CONSOLE + MultiThreaded + + + Ws2_32.lib;%(AdditionalDependencies) + + + + + false + MultiThreaded + false + ../win32helpers + WIN32;_CONSOLE;LWS_DLL + + + + + + \ No newline at end of file diff --git a/libs/libwebsockets/win32port/client/client.vcxproj.filters b/libs/libwebsockets/win32port/client/client.vcxproj.filters new file mode 100644 index 0000000000..76f11219e3 --- /dev/null +++ b/libs/libwebsockets/win32port/client/client.vcxproj.filters @@ -0,0 +1,39 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/libs/libwebsockets/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj b/libs/libwebsockets/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj new file mode 100644 index 0000000000..8c371f3ffe --- /dev/null +++ b/libs/libwebsockets/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj @@ -0,0 +1,274 @@ + + + + + Debug static + Win32 + + + Debug + Win32 + + + Debug + x64 + + + Release DLL + Win32 + + + Release DLL + x64 + + + Release static + Win32 + + + Release + Win32 + + + Release + x64 + + + + {332BF17E-FD30-4363-975A-AA731A827B4F} + Win32Proj + libwebsocketswin32 + + + + StaticLibrary + true + Unicode + + + StaticLibrary + true + Unicode + + + StaticLibrary + true + Unicode + + + StaticLibrary + true + Unicode + + + StaticLibrary + false + true + Unicode + + + StaticLibrary + false + true + Unicode + + + StaticLibrary + + + DynamicLibrary + true + + + + + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)..\output\ + D:\Libraries\libwebsockets\output\;$(LibraryPath) + libwebsockets_vc100-mt-sgd + + + D:\Libraries\libwebsockets\output\;$(LibraryPath) + + + D:\Libraries\libwebsockets\output\;$(LibraryPath) + + + libwebsockets_vc100-mt-s + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + ../win32helpers;../zlib + false + + + Windows + true + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + ../win32helpers;../zlib + MultiThreadedDebug + false + + + Windows + true + + + $(OutDir)libwebsockets_vc100-mt-sgd$(TargetExt) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + ../win32helpers;../zlib + + + Windows + true + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + ../win32helpers;../zlib + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + ../win32helpers;../zlib + MultiThreaded + false + + + Windows + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + ../win32helpers;../zlib + + + Windows + true + true + true + + + + + ../win32helpers;../zlib + WIN32 + false + MultiThreaded + + + $(OutDir)libwebsockets_vc100-mt-s.lib + + + + + ../win32helpers;../zlib + WIN32;LWS_INTERNAL;LWS_DLL + false + MultiThreaded + false + Speed + true + + + $(OutDir)libwebsockets_vc100-mt-s.lib + + + Ws2_32.lib;..\..\output\ZLib_vc100-mt-s.lib;%(AdditionalDependencies) + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/libwebsockets/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.filters b/libs/libwebsockets/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.filters new file mode 100644 index 0000000000..3c6edbb327 --- /dev/null +++ b/libs/libwebsockets/win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.filters @@ -0,0 +1,72 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Source Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/libwebsockets/win32port/server/server.vcxproj b/libs/libwebsockets/win32port/server/server.vcxproj new file mode 100644 index 0000000000..7fe50a8550 --- /dev/null +++ b/libs/libwebsockets/win32port/server/server.vcxproj @@ -0,0 +1,276 @@ + + + + + Debug static + Win32 + + + Debug + Win32 + + + Debug + x64 + + + Release DLL + Win32 + + + Release DLL + x64 + + + Release static + Win32 + + + Release + Win32 + + + Release + x64 + + + + + ../win32helpers + ../win32helpers + ../win32helpers + ../win32helpers + + + + + + + + + + + + + + + + {332bf17e-fd30-4363-975a-aa731a827b4f} + + + {4156fc56-8443-2973-4fe2-a0bb2c621525} + + + + {E585B64F-9365-4C58-9EF8-56393EB27F8B} + Win32Proj + server + + + + Application + true + Unicode + + + Application + true + Unicode + + + Application + true + Unicode + + + Application + true + Unicode + + + Application + false + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../win32helpers + false + + + Console + true + + + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../win32helpers + MultiThreadedDebug + false + + + Console + true + + + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../win32helpers + + + Console + true + + + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../win32helpers + + + Console + true + + + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../win32helpers + MultiThreaded + false + + + Console + true + true + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../win32helpers + + + Console + true + true + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + false + ../win32helpers + WIN32;_CONSOLE + MultiThreaded + + + Ws2_32.lib;%(AdditionalDependencies) + + + + + false + MultiThreaded + false + ../win32helpers + WIN32;_CONSOLE;LWS_DLL + + + + + + \ No newline at end of file diff --git a/libs/libwebsockets/win32port/server/server.vcxproj.filters b/libs/libwebsockets/win32port/server/server.vcxproj.filters new file mode 100644 index 0000000000..d4a9c7da53 --- /dev/null +++ b/libs/libwebsockets/win32port/server/server.vcxproj.filters @@ -0,0 +1,51 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/libs/libwebsockets/win32port/win32helpers/getopt.c b/libs/libwebsockets/win32port/win32helpers/getopt.c new file mode 100644 index 0000000000..2181f1cb12 --- /dev/null +++ b/libs/libwebsockets/win32port/win32helpers/getopt.c @@ -0,0 +1,153 @@ +/* $NetBSD: getopt.c,v 1.16 1999/12/02 13:15:56 kleink Exp $ */ + +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; +#endif + +#include +#include +#include +#include + +#define __P(x) x +#define _DIAGASSERT(x) assert(x) + +#ifdef __weak_alias +__weak_alias(getopt,_getopt); +#endif + + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +static char * _progname __P((char *)); +int getopt_internal __P((int, char * const *, const char *)); + +static char * +_progname(nargv0) + char * nargv0; +{ + char * tmp; + + _DIAGASSERT(nargv0 != NULL); + + tmp = strrchr(nargv0, '/'); + if (tmp) + tmp++; + else + tmp = nargv0; + return(tmp); +} + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(nargc, nargv, ostr) + int nargc; + char * const nargv[]; + const char *ostr; +{ + static char *__progname = 0; + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + __progname = __progname?__progname:_progname(*nargv); + + _DIAGASSERT(nargv != NULL); + _DIAGASSERT(ostr != NULL); + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-' /* found "--" */ + && place[1] == '\0') { + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __progname, optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname, optopt); + return (BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} + diff --git a/libs/libwebsockets/win32port/win32helpers/getopt.h b/libs/libwebsockets/win32port/win32helpers/getopt.h new file mode 100644 index 0000000000..5a88c2df6b --- /dev/null +++ b/libs/libwebsockets/win32port/win32helpers/getopt.h @@ -0,0 +1,33 @@ +#ifndef __GETOPT_H__ +#define __GETOPT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int opterr; /* if error message should be printed */ +extern int optind; /* index into parent argv vector */ +extern int optopt; /* character checked for validity */ +extern int optreset; /* reset getopt */ +extern char *optarg; /* argument associated with option */ + +struct option +{ + const char *name; + int has_arg; + int *flag; + int val; +}; + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +int getopt(int, char**, char*); +int getopt_long(int, char**, char*, struct option*, int*); + +#ifdef __cplusplus +} +#endif + +#endif /* __GETOPT_H__ */ diff --git a/libs/libwebsockets/win32port/win32helpers/getopt_long.c b/libs/libwebsockets/win32port/win32helpers/getopt_long.c new file mode 100644 index 0000000000..43a5cba79a --- /dev/null +++ b/libs/libwebsockets/win32port/win32helpers/getopt_long.c @@ -0,0 +1,237 @@ + +/* + * Copyright (c) 1987, 1993, 1994, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include "getopt.h" + +extern int opterr; /* if error message should be printed */ +extern int optind; /* index into parent argv vector */ +extern int optopt; /* character checked for validity */ +extern int optreset; /* reset getopt */ +extern char *optarg; /* argument associated with option */ + +#define __P(x) x +#define _DIAGASSERT(x) assert(x) + +static char * __progname __P((char *)); +int getopt_internal __P((int, char * const *, const char *)); + +static char * +__progname(nargv0) + char * nargv0; +{ + char * tmp; + + _DIAGASSERT(nargv0 != NULL); + + tmp = strrchr(nargv0, '/'); + if (tmp) + tmp++; + else + tmp = nargv0; + return(tmp); +} + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt_internal(nargc, nargv, ostr) + int nargc; + char * const *nargv; + const char *ostr; +{ + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + _DIAGASSERT(nargv != NULL); + _DIAGASSERT(ostr != NULL); + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + /* ++optind; */ + place = EMSG; + return (-2); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __progname(nargv[0]), optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if ((opterr) && (*ostr != ':')) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname(nargv[0]), optopt); + return (BADARG); + } else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} + +#if 0 +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt2(nargc, nargv, ostr) + int nargc; + char * const *nargv; + const char *ostr; +{ + int retval; + + if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) { + retval = -1; + ++optind; + } + return(retval); +} +#endif + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +getopt_long(nargc, nargv, options, long_options, index) + int nargc; + char ** nargv; + char * options; + struct option * long_options; + int * index; +{ + int retval; + + _DIAGASSERT(nargv != NULL); + _DIAGASSERT(options != NULL); + _DIAGASSERT(long_options != NULL); + /* index may be NULL */ + + if ((retval = getopt_internal(nargc, nargv, options)) == -2) { + char *current_argv = nargv[optind++] + 2, *has_equal; + int i, current_argv_len, match = -1; + + if (*current_argv == '\0') { + return(-1); + } + if ((has_equal = strchr(current_argv, '=')) != NULL) { + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + if (strncmp(current_argv, long_options[i].name, current_argv_len)) + continue; + + if (strlen(long_options[i].name) == (unsigned)current_argv_len) { + match = i; + break; + } + if (match == -1) + match = i; + } + if (match != -1) { + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else + optarg = nargv[optind++]; + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument, leading : + * indicates no error should be generated + */ + if ((opterr) && (*options != ':')) + (void)fprintf(stderr, + "%s: option requires an argument -- %s\n", + __progname(nargv[0]), current_argv); + return (BADARG); + } + } else { /* No matching argument */ + if ((opterr) && (*options != ':')) + (void)fprintf(stderr, + "%s: illegal option -- %s\n", __progname(nargv[0]), current_argv); + return (BADCH); + } + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + retval = 0; + } else + retval = long_options[match].val; + if (index) + *index = match; + } + return(retval); +} diff --git a/libs/libwebsockets/win32port/win32helpers/gettimeofday.c b/libs/libwebsockets/win32port/win32helpers/gettimeofday.c new file mode 100644 index 0000000000..a424db923b --- /dev/null +++ b/libs/libwebsockets/win32port/win32helpers/gettimeofday.c @@ -0,0 +1,48 @@ +#include < time.h > +#include //I've ommited context line. +#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 +#else + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL +#endif + +struct timezone +{ + int tz_minuteswest; /* minutes W of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + FILETIME ft; + unsigned __int64 tmpres = 0; + static int tzflag; + + if (NULL != tv) + { + GetSystemTimeAsFileTime(&ft); + + tmpres |= ft.dwHighDateTime; + tmpres <<= 32; + tmpres |= ft.dwLowDateTime; + + /*converting file time to unix epoch*/ + tmpres -= DELTA_EPOCH_IN_MICROSECS; + tmpres /= 10; /*convert into microseconds*/ + tv->tv_sec = (long)(tmpres / 1000000UL); + tv->tv_usec = (long)(tmpres % 1000000UL); + } + + if (NULL != tz) + { + if (!tzflag) + { + _tzset(); + tzflag++; + } + tz->tz_minuteswest = _timezone / 60; + tz->tz_dsttime = _daylight; + } + + return 0; +} diff --git a/libs/libwebsockets/win32port/win32helpers/gettimeofday.h b/libs/libwebsockets/win32port/win32helpers/gettimeofday.h new file mode 100644 index 0000000000..223ceeed8b --- /dev/null +++ b/libs/libwebsockets/win32port/win32helpers/gettimeofday.h @@ -0,0 +1,28 @@ +#ifndef _GET_TIME_OF_DAY_H +#define _GET_TIME_OF_DAY_H + +#ifdef __MINGW64__ +#else +#ifdef __MINGW32__ +#else +#include < time.h > +#endif +#endif + +#include //I've ommited context line. +#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 +#else + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL +#endif + +struct timezone +{ + int tz_minuteswest; /* minutes W of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +int gettimeofday(struct timeval *tv, struct timezone *tz); + + +#endif diff --git a/libs/libwebsockets/win32port/win32helpers/netdb.h b/libs/libwebsockets/win32port/win32helpers/netdb.h new file mode 100644 index 0000000000..45304b7673 --- /dev/null +++ b/libs/libwebsockets/win32port/win32helpers/netdb.h @@ -0,0 +1 @@ +// Left blank for win32 \ No newline at end of file diff --git a/libs/libwebsockets/win32port/win32helpers/strings.h b/libs/libwebsockets/win32port/win32helpers/strings.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libwebsockets/win32port/win32helpers/sys/time.h b/libs/libwebsockets/win32port/win32helpers/sys/time.h new file mode 100644 index 0000000000..258af63bcd --- /dev/null +++ b/libs/libwebsockets/win32port/win32helpers/sys/time.h @@ -0,0 +1 @@ +// left blank \ No newline at end of file diff --git a/libs/libwebsockets/win32port/win32helpers/unistd.h b/libs/libwebsockets/win32port/win32helpers/unistd.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libwebsockets/win32port/win32helpers/websock-w32.c b/libs/libwebsockets/win32port/win32helpers/websock-w32.c new file mode 100644 index 0000000000..bec150b179 --- /dev/null +++ b/libs/libwebsockets/win32port/win32helpers/websock-w32.c @@ -0,0 +1,104 @@ +#define FD_SETSIZE 256 + +#ifdef __MINGW32__ +#include +#else +#ifdef __MINGW64__ +#include +#else +#include +#endif +#endif + +#include +#include +#include "websock-w32.h" + +PFNWSAPOLL poll = NULL; + +INT WSAAPI emulated_poll(LPWSAPOLLFD fdarray, ULONG nfds, INT timeout) +{ + fd_set readfds; + fd_set writefds; + struct timeval tv; + struct timeval *ptv = &tv; + SOCKET max_socket = 0; + ULONG n = 0; + int waiting; + int pending = 0; + WSAPOLLFD * poll_fd = fdarray; + + if (NULL == fdarray) { + errno = EFAULT; + return -1; + } + + FD_ZERO(&readfds); + FD_ZERO(&writefds); + + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + + if (timeout < 0) + ptv = NULL; + + while (n < nfds) { + + poll_fd->revents = 0; + + if (poll_fd->fd < 0 || !poll_fd->events) + goto skip1; + + if (max_socket < poll_fd->fd) + max_socket = poll_fd->fd; + + if (poll_fd->events & POLLIN) + FD_SET(poll_fd->fd, &readfds); + + if (poll_fd->events & POLLOUT) + FD_SET(poll_fd->fd, &writefds); +skip1: + poll_fd++; + n++; + } + + waiting = select((int)max_socket + 1, &readfds, &writefds, NULL, ptv); + + if (waiting <= 0) + return waiting; + + poll_fd = fdarray; + + while (waiting && nfds--) { + + if (!poll_fd->events) + goto skip2; + + if (poll_fd->fd <= 0) { + poll_fd->revents = POLLNVAL; + goto skip2; + } + + if (FD_ISSET(poll_fd->fd, &readfds)) { + + /* defer POLLHUP / error detect to false read attempt */ + + poll_fd->revents |= POLLIN; + waiting--; + } + + if (FD_ISSET(poll_fd->fd, &writefds)) { + + poll_fd->revents |= poll_fd->events & POLLOUT; + waiting--; + } + + if (poll_fd->revents) + pending++; + +skip2: + poll_fd++; + } + + return pending; +} diff --git a/libs/libwebsockets/win32port/win32helpers/websock-w32.h b/libs/libwebsockets/win32port/win32helpers/websock-w32.h new file mode 100644 index 0000000000..dfd99ca917 --- /dev/null +++ b/libs/libwebsockets/win32port/win32helpers/websock-w32.h @@ -0,0 +1,64 @@ +#ifndef __WEB_SOCK_W32_H__ +#define __WEB_SOCK_W32_H__ + +// Windows uses _DEBUG and NDEBUG +#ifdef _DEBUG +#undef DEBUG +#define DEBUG 1 +#endif + +#pragma warning(disable : 4996) + +#define bzero(b,len) (memset((b), '\0', (len)), (void) 0) + +#define MSG_NOSIGNAL 0 +#define SHUT_RDWR SD_BOTH + +#define SOL_TCP IPPROTO_TCP + +#define random rand +#define usleep _sleep + +#ifdef __MINGW64__ +#define DEF_POLL_STUFF +#endif +#ifdef __MINGW32__ +#define DEF_POLL_STUFF +#endif + +#ifdef DEF_POLL_STUFF + +#include + +typedef struct pollfd { + SOCKET fd; + short events; + short revents; +} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD; + +#define POLLIN 0x0001 /* any readable data available */ +#define POLLOUT 0x0004 /* file descriptor is writeable */ +#define POLLERR 0x0008 /* some poll error occurred */ +#define POLLHUP 0x0010 /* file descriptor was "hung up" */ +#define POLLNVAL 0x0020 /* requested events "invalid" */ + +#endif + +typedef INT (WSAAPI *PFNWSAPOLL)(LPWSAPOLLFD fdarray, ULONG nfds, INT timeout); +extern PFNWSAPOLL poll; + +extern INT WSAAPI emulated_poll(LPWSAPOLLFD fdarray, ULONG nfds, INT timeout); + +/* override configure because we are not using Makefiles */ + +#define LWS_NO_FORK + +/* windows can't cope with this idea, needs assets in cwd */ + +#ifdef INSTALL_DATADIR +#undef INSTALL_DATADIR +#endif + +#define INSTALL_DATADIR "." + +#endif diff --git a/libs/libwebsockets/win32port/win32port.sln b/libs/libwebsockets/win32port/win32port.sln new file mode 100644 index 0000000000..fc7ca7c2eb --- /dev/null +++ b/libs/libwebsockets/win32port/win32port.sln @@ -0,0 +1,100 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual C++ Express 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "server", "server\server.vcxproj", "{E585B64F-9365-4C58-9EF8-56393EB27F8B}" + ProjectSection(ProjectDependencies) = postProject + {332BF17E-FD30-4363-975A-AA731A827B4F} = {332BF17E-FD30-4363-975A-AA731A827B4F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwebsocketswin32", "libwebsocketswin32\libwebsocketswin32.vcxproj", "{332BF17E-FD30-4363-975A-AA731A827B4F}" + ProjectSection(ProjectDependencies) = postProject + {4156FC56-8443-2973-4FE2-A0BB2C621525} = {4156FC56-8443-2973-4FE2-A0BB2C621525} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "client", "client\client.vcxproj", "{6265650C-4799-451C-A687-94DE48759A8B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZLib", "zlib\ZLib.vcxproj", "{4156FC56-8443-2973-4FE2-A0BB2C621525}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug static|Win32 = Debug static|Win32 + Debug static|x64 = Debug static|x64 + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release DLL|Win32 = Release DLL|Win32 + Release DLL|x64 = Release DLL|x64 + Release static|Win32 = Release static|Win32 + Release static|x64 = Release static|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {332BF17E-FD30-4363-975A-AA731A827B4F}.Debug static|Win32.ActiveCfg = Debug static|Win32 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Debug static|Win32.Build.0 = Debug static|Win32 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Debug static|x64.ActiveCfg = Debug static|Win32 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Debug|Win32.ActiveCfg = Debug|Win32 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Debug|Win32.Build.0 = Debug|Win32 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Debug|x64.ActiveCfg = Debug|Win32 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Release DLL|Win32.ActiveCfg = Release DLL|Win32 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Release DLL|Win32.Build.0 = Release DLL|Win32 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Release DLL|x64.ActiveCfg = Release DLL|x64 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Release DLL|x64.Build.0 = Release DLL|x64 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Release static|Win32.ActiveCfg = Release static|Win32 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Release static|Win32.Build.0 = Release static|Win32 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Release static|x64.ActiveCfg = Release static|Win32 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Release|Win32.ActiveCfg = Release|Win32 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Release|Win32.Build.0 = Release|Win32 + {332BF17E-FD30-4363-975A-AA731A827B4F}.Release|x64.ActiveCfg = Release|Win32 + {4156FC56-8443-2973-4FE2-A0BB2C621525}.Debug static|Win32.ActiveCfg = Debug static|Win32 + {4156FC56-8443-2973-4FE2-A0BB2C621525}.Debug static|Win32.Build.0 = Debug static|Win32 + {4156FC56-8443-2973-4FE2-A0BB2C621525}.Debug static|x64.ActiveCfg = Debug static|Win32 + {4156FC56-8443-2973-4FE2-A0BB2C621525}.Debug|Win32.ActiveCfg = Debug|Win32 + {4156FC56-8443-2973-4FE2-A0BB2C621525}.Debug|Win32.Build.0 = Debug|Win32 + {4156FC56-8443-2973-4FE2-A0BB2C621525}.Debug|x64.ActiveCfg = Debug|Win32 + {4156FC56-8443-2973-4FE2-A0BB2C621525}.Release DLL|Win32.ActiveCfg = Release DLL|Win32 + {4156FC56-8443-2973-4FE2-A0BB2C621525}.Release DLL|Win32.Build.0 = Release DLL|Win32 + {4156FC56-8443-2973-4FE2-A0BB2C621525}.Release DLL|x64.ActiveCfg = Release DLL|x64 + {4156FC56-8443-2973-4FE2-A0BB2C621525}.Release DLL|x64.Build.0 = Release DLL|x64 + {4156FC56-8443-2973-4FE2-A0BB2C621525}.Release static|Win32.ActiveCfg = Release static|Win32 + {4156FC56-8443-2973-4FE2-A0BB2C621525}.Release static|Win32.Build.0 = Release static|Win32 + {4156FC56-8443-2973-4FE2-A0BB2C621525}.Release static|x64.ActiveCfg = Release static|Win32 + {4156FC56-8443-2973-4FE2-A0BB2C621525}.Release|Win32.ActiveCfg = Release|Win32 + {4156FC56-8443-2973-4FE2-A0BB2C621525}.Release|Win32.Build.0 = Release|Win32 + {4156FC56-8443-2973-4FE2-A0BB2C621525}.Release|x64.ActiveCfg = Release|Win32 + {6265650C-4799-451C-A687-94DE48759A8B}.Debug static|Win32.ActiveCfg = Debug static|Win32 + {6265650C-4799-451C-A687-94DE48759A8B}.Debug static|Win32.Build.0 = Debug static|Win32 + {6265650C-4799-451C-A687-94DE48759A8B}.Debug static|x64.ActiveCfg = Debug static|Win32 + {6265650C-4799-451C-A687-94DE48759A8B}.Debug|Win32.ActiveCfg = Debug|Win32 + {6265650C-4799-451C-A687-94DE48759A8B}.Debug|Win32.Build.0 = Debug|Win32 + {6265650C-4799-451C-A687-94DE48759A8B}.Debug|x64.ActiveCfg = Debug|Win32 + {6265650C-4799-451C-A687-94DE48759A8B}.Release DLL|Win32.ActiveCfg = Release DLL|Win32 + {6265650C-4799-451C-A687-94DE48759A8B}.Release DLL|Win32.Build.0 = Release DLL|Win32 + {6265650C-4799-451C-A687-94DE48759A8B}.Release DLL|x64.ActiveCfg = Release DLL|x64 + {6265650C-4799-451C-A687-94DE48759A8B}.Release DLL|x64.Build.0 = Release DLL|x64 + {6265650C-4799-451C-A687-94DE48759A8B}.Release static|Win32.ActiveCfg = Release static|Win32 + {6265650C-4799-451C-A687-94DE48759A8B}.Release static|Win32.Build.0 = Release static|Win32 + {6265650C-4799-451C-A687-94DE48759A8B}.Release static|x64.ActiveCfg = Release static|Win32 + {6265650C-4799-451C-A687-94DE48759A8B}.Release|Win32.ActiveCfg = Release|Win32 + {6265650C-4799-451C-A687-94DE48759A8B}.Release|Win32.Build.0 = Release|Win32 + {6265650C-4799-451C-A687-94DE48759A8B}.Release|x64.ActiveCfg = Release|Win32 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Debug static|Win32.ActiveCfg = Debug static|Win32 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Debug static|Win32.Build.0 = Debug static|Win32 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Debug static|x64.ActiveCfg = Debug static|Win32 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Debug|Win32.ActiveCfg = Debug|Win32 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Debug|Win32.Build.0 = Debug|Win32 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Debug|x64.ActiveCfg = Debug|Win32 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Release DLL|Win32.ActiveCfg = Release DLL|Win32 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Release DLL|Win32.Build.0 = Release DLL|Win32 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Release DLL|x64.ActiveCfg = Release DLL|x64 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Release DLL|x64.Build.0 = Release DLL|x64 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Release static|Win32.ActiveCfg = Release static|Win32 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Release static|Win32.Build.0 = Release static|Win32 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Release static|x64.ActiveCfg = Release static|Win32 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Release|Win32.ActiveCfg = Release|Win32 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Release|Win32.Build.0 = Release|Win32 + {E585B64F-9365-4C58-9EF8-56393EB27F8B}.Release|x64.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/libs/libwebsockets/win32port/zlib/ZLib.vcxproj b/libs/libwebsockets/win32port/zlib/ZLib.vcxproj new file mode 100644 index 0000000000..0afc43c923 --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/ZLib.vcxproj @@ -0,0 +1,374 @@ + + + + + Debug static + Win32 + + + Debug + Win32 + + + Debug + x64 + + + Release DLL + Win32 + + + Release DLL + x64 + + + Release static + Win32 + + + Release + Win32 + + + Release + x64 + + + + {4156FC56-8443-2973-4FE2-A0BB2C621525} + + + + StaticLibrary + false + MultiByte + + + StaticLibrary + false + MultiByte + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + StaticLibrary + + + StaticLibrary + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DebugV10\ + DebugV10\ + + + $(SolutionDir)..\output\ + DebugV10\ + ZLib_vc100-mt-sgd + + + DebugV10\ + DebugV10\ + + + DebugV10\ + DebugV10\ + + + .\Release\ + .\Release\ + + + .\Release\ + .\Release\ + + + $(SolutionDir)..\output\ + ZLib_vc100-mt-s + + + $(SolutionDir)..\output\ + ZLib_vc100-mt-s + + + + MultiThreadedDebugDLL + Default + false + Disabled + true + Level3 + true + EditAndContinue + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + DebugV10\ + DebugV10\ZLib.pch + DebugV10\ + DebugV10\ + EnableFastChecks + false + false + + + 0x1c09 + _DEBUG;%(PreprocessorDefinitions) + + + true + DebugV10\ZLib.bsc + + + true + DebugV10\ZLib.lib + + + + + MultiThreadedDebug + Default + false + Disabled + true + Level3 + true + EditAndContinue + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + DebugV10\ + DebugV10\ZLib.pch + DebugV10\ + DebugV10\ + EnableFastChecks + false + false + + + 0x1c09 + _DEBUG;%(PreprocessorDefinitions) + + + true + DebugV10\ZLib.bsc + + + true + $(OutDir)ZLib_vc100-mt-sgd.lib + + + + + MultiThreadedDebugDLL + Default + false + Disabled + true + Level3 + ProgramDatabase + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + DebugV10\ + DebugV10\ZLib.pch + DebugV10\ + DebugV10\ + EnableFastChecks + false + + + 0x1c09 + _DEBUG;%(PreprocessorDefinitions) + + + true + DebugV10\ZLib.bsc + + + true + DebugV10\ZLib.lib + + + + + MultiThreadedDebugDLL + Default + false + Disabled + true + Level3 + ProgramDatabase + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + DebugV10\ + DebugV10\ZLib.pch + DebugV10\ + DebugV10\ + EnableFastChecks + false + + + 0x1c09 + _DEBUG;%(PreprocessorDefinitions) + + + true + DebugV10\ZLib.bsc + + + true + DebugV10\ZLib.lib + + + + + MultiThreaded + OnlyExplicitInline + true + true + MaxSpeed + true + Level3 + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + .\Release\ + .\Release\ZLib.pch + .\Release\ + .\Release\ + false + false + + + 0x1c09 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\ZLib.bsc + + + true + .\Release\ZLib.lib + + + + + MultiThreadedDLL + OnlyExplicitInline + true + true + MaxSpeed + true + Level3 + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + .\Release\ + .\Release\ZLib.pch + .\Release\ + .\Release\ + false + + + 0x1c09 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\ZLib.bsc + + + true + .\Release\ZLib.lib + + + + + $(OutDir)ZLib_vc100-mt-s.lib + + + MultiThreaded + false + + + + + $(OutDir)ZLib_vc100-mt-s.lib + true + + + MultiThreaded + false + false + true + Speed + WIN32 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/libwebsockets/win32port/zlib/ZLib.vcxproj.filters b/libs/libwebsockets/win32port/zlib/ZLib.vcxproj.filters new file mode 100644 index 0000000000..3e6c18da25 --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/ZLib.vcxproj.filters @@ -0,0 +1,95 @@ + + + + + {2e5deede-b2ef-40bd-950a-a7f7f0fc0413} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {85d35343-9068-43e8-875e-60b528a03c9b} + h;hpp;hxx;hm;inl + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/libwebsockets/win32port/zlib/adler32.c b/libs/libwebsockets/win32port/zlib/adler32.c new file mode 100644 index 0000000000..5f2bc6bf4f --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/adler32.c @@ -0,0 +1,169 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2007 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#define local static + +local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2); + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware */ +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD4(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +local uLong adler32_combine_(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 >= BASE) sum1 -= BASE; + if (sum1 >= BASE) sum1 -= BASE; + if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 >= BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} + +uLong ZEXPORT adler32_combine64(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} diff --git a/libs/libwebsockets/win32port/zlib/compress.c b/libs/libwebsockets/win32port/zlib/compress.c new file mode 100644 index 0000000000..c46727a416 --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/compress.c @@ -0,0 +1,80 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13; +} diff --git a/libs/libwebsockets/win32port/zlib/crc32.c b/libs/libwebsockets/win32port/zlib/crc32.c new file mode 100644 index 0000000000..8cb3d8fffd --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/crc32.c @@ -0,0 +1,442 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2006, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) ((((w)>>24)&0xff)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); +local uLong crc32_combine_(uLong crc1, uLong crc2, z_off64_t len2); + + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + uInt len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +local uLong crc32_combine_(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case (also disallow negative lengths) */ + if (len2 <= 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + return crc32_combine_(crc1, crc2, len2); +} + +uLong ZEXPORT crc32_combine64(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ + return crc32_combine_(crc1, crc2, len2); +} diff --git a/libs/libwebsockets/win32port/zlib/crc32.h b/libs/libwebsockets/win32port/zlib/crc32.h new file mode 100644 index 0000000000..5de49bc978 --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/libs/libwebsockets/win32port/zlib/deflate.c b/libs/libwebsockets/win32port/zlib/deflate.c new file mode 100644 index 0000000000..fa00181166 --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/deflate.c @@ -0,0 +1,1834 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.5 Copyright 1995-2010 Jean-loup Gailly and Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local block_state deflate_rle OF((deflate_state *s, int flush)); +local block_state deflate_huff OF((deflate_state *s, int flush)); +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->high_water = 0; /* nothing written to s->window yet */ + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > s->w_size) { + length = s->w_size; + dictionary += dictLength - length; /* use the tail of the dictionary */ + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if ((strategy != s->strategy || func != configuration_table[level].func) && + strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_BLOCK); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds for + * every combination of windowBits and memLevel. But even the conservative + * upper bound of about 14% expansion does not seem onerous for output buffer + * allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong complen, wraplen; + Bytef *str; + + /* conservative upper bound for compressed data */ + complen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; + + /* if can't get parameters, return conservative bound plus zlib wrapper */ + if (strm == Z_NULL || strm->state == Z_NULL) + return complen + 6; + + /* compute wrapper length */ + s = strm->state; + switch (s->wrap) { + case 0: /* raw deflate */ + wraplen = 0; + break; + case 1: /* zlib wrapper */ + wraplen = 6 + (s->strstart ? 4 : 0); + break; + case 2: /* gzip wrapper */ + wraplen = 18; + if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ + if (s->gzhead->extra != Z_NULL) + wraplen += 2 + s->gzhead->extra_len; + str = s->gzhead->name; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + str = s->gzhead->comment; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + if (s->gzhead->hcrc) + wraplen += 2; + } + break; + default: /* for compiler happiness */ + wraplen = 6; + } + + /* if not default parameters, return conservative bound */ + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return complen + wraplen; + + /* default settings: return tight bound for that case */ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13 - 6 + wraplen; +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_BLOCK || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == Z_NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != Z_NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != Z_NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != Z_NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != Z_NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : + (s->strategy == Z_RLE ? deflate_rle(s, flush) : + (*(configuration_table[s->level].func))(s, flush)); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + if (s->lookahead == 0) { + s->strstart = 0; + s->block_start = 0L; + } + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy(dest, source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy(ds, ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ + +#else /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for FASTEST only + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#endif /* FASTEST */ + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ + if (s->high_water < s->window_size) { + ulg curr = s->strstart + (ulg)(s->lookahead); + ulg init; + + if (s->high_water < curr) { + /* Previous high water mark below current data -- zero WIN_INIT + * bytes or up to end of window, whichever is less. + */ + init = s->window_size - curr; + if (init > WIN_INIT) + init = WIN_INIT; + zmemzero(s->window + curr, (unsigned)init); + s->high_water = curr + init; + } + else if (s->high_water < (ulg)curr + WIN_INIT) { + /* High water mark at or above current data, but below current data + * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + * to end of window, whichever is less. + */ + init = (ulg)curr + WIN_INIT - s->high_water; + if (init > s->window_size - s->high_water) + init = s->window_size - s->high_water; + zmemzero(s->window + s->high_water, (unsigned)init); + s->high_water += init; + } + } +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, last) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (last)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, last) { \ + FLUSH_BLOCK_ONLY(s, last); \ + if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ + +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt prev; /* byte at distance one to match */ + Bytef *scan, *strend; /* scan goes up to strend for length of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + s->match_length = 0; + if (s->lookahead >= MIN_MATCH && s->strstart > 0) { + scan = s->window + s->strstart - 1; + prev = *scan; + if (prev == *++scan && prev == *++scan && prev == *++scan) { + strend = s->window + s->strstart + MAX_MATCH; + do { + } while (prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + scan < strend); + s->match_length = MAX_MATCH - (int)(strend - scan); + if (s->match_length > s->lookahead) + s->match_length = s->lookahead; + } + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, s->match_length); + + _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + s->strstart += s->match_length; + s->match_length = 0; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +local block_state deflate_huff(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s->lookahead == 0) { + fill_window(s); + if (s->lookahead == 0) { + if (flush == Z_NO_FLUSH) + return need_more; + break; /* flush the current block */ + } + } + + /* Output a literal byte */ + s->match_length = 0; + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} diff --git a/libs/libwebsockets/win32port/zlib/deflate.h b/libs/libwebsockets/win32port/zlib/deflate.h new file mode 100644 index 0000000000..e9044c1da2 --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/deflate.h @@ -0,0 +1,342 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2010 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + ulg high_water; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + +#define WIN_INIT MAX_MATCH +/* Number of bytes after end of data in window to initialize in order to avoid + memory checker errors from longest match routines */ + + /* in trees.c */ +void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); +int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); +void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); +void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch ZLIB_INTERNAL _length_code[]; + extern uch ZLIB_INTERNAL _dist_code[]; +#else + extern const uch ZLIB_INTERNAL _length_code[]; + extern const uch ZLIB_INTERNAL _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/libs/libwebsockets/win32port/zlib/gzclose.c b/libs/libwebsockets/win32port/zlib/gzclose.c new file mode 100755 index 0000000000..cbf0db663b --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/gzclose.c @@ -0,0 +1,25 @@ +/* gzclose.c -- zlib gzclose() function + * Copyright (C) 2004, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* gzclose() is in a separate file so that it is linked in only if it is used. + That way the other gzclose functions can be used instead to avoid linking in + unneeded compression or decompression routines. */ +int ZEXPORT gzclose(file) + gzFile file; +{ +#ifndef NO_GZCOMPRESS + gz_statep state; + + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file); +#else + return gzclose_r(file); +#endif +} diff --git a/libs/libwebsockets/win32port/zlib/gzguts.h b/libs/libwebsockets/win32port/zlib/gzguts.h new file mode 100755 index 0000000000..7ff93a8dd8 --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/gzguts.h @@ -0,0 +1,132 @@ +/* gzguts.h -- zlib internal header definitions for gz* operations + * Copyright (C) 2004, 2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef _LARGEFILE64_SOURCE +# ifndef _LARGEFILE_SOURCE +# define _LARGEFILE_SOURCE 1 +# endif +# ifdef _FILE_OFFSET_BITS +# undef _FILE_OFFSET_BITS +# endif +#endif + +#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ) +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include +#include "zlib.h" +#ifdef STDC +# include +# include +# include +#endif +#include + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifdef _MSC_VER +# include +# define vsnprintf _vsnprintf +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +/* gz* functions always use library allocation functions */ +#ifndef STDC + extern voidp malloc OF((uInt size)); + extern void free OF((voidpf ptr)); +#endif + +/* get errno and strerror definition */ +#if defined UNDER_CE +# include +# define zstrerror() gz_strwinerror((DWORD)GetLastError()) +#else +# ifdef STDC +# include +# define zstrerror() strerror(errno) +# else +# define zstrerror() "stdio error (consult errno)" +# endif +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); +#endif + +/* default i/o buffer size -- double this for output when reading */ +#define GZBUFSIZE 8192 + +/* gzip modes, also provide a little integrity check on the passed structure */ +#define GZ_NONE 0 +#define GZ_READ 7247 +#define GZ_WRITE 31153 +#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ + +/* values for gz_state how */ +#define LOOK 0 /* look for a gzip header */ +#define COPY 1 /* copy input directly */ +#define GZIP 2 /* decompress a gzip stream */ + +/* internal gzip file state data structure */ +typedef struct { + /* used for both reading and writing */ + int mode; /* see gzip modes above */ + int fd; /* file descriptor */ + char *path; /* path or fd for error messages */ + z_off64_t pos; /* current position in uncompressed data */ + unsigned size; /* buffer size, zero if not allocated yet */ + unsigned want; /* requested buffer size, default is GZBUFSIZE */ + unsigned char *in; /* input buffer */ + unsigned char *out; /* output buffer (double-sized when reading) */ + unsigned char *next; /* next output data to deliver or write */ + /* just for reading */ + unsigned have; /* amount of output data unused at next */ + int eof; /* true if end of input file reached */ + z_off64_t start; /* where the gzip data started, for rewinding */ + z_off64_t raw; /* where the raw data started, for seeking */ + int how; /* 0: get header, 1: copy, 2: decompress */ + int direct; /* true if last read direct, false if gzip */ + /* just for writing */ + int level; /* compression level */ + int strategy; /* compression strategy */ + /* seek request */ + z_off64_t skip; /* amount to skip (already rewound if backwards) */ + int seek; /* true if seek request pending */ + /* error information */ + int err; /* error code */ + char *msg; /* error message */ + /* zlib inflate or deflate stream */ + z_stream strm; /* stream structure in-place (not a pointer) */ +} gz_state; +typedef gz_state FAR *gz_statep; + +/* shared functions */ +void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); +#if defined UNDER_CE +char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); +#endif + +/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t + value -- needed when comparing unsigned to z_off64_t, which is signed + (possible z_off64_t types off_t, off64_t, and long are all signed) */ +#ifdef INT_MAX +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) +#else +unsigned ZLIB_INTERNAL gz_intmax OF((void)); +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) +#endif diff --git a/libs/libwebsockets/win32port/zlib/gzio.c b/libs/libwebsockets/win32port/zlib/gzio.c new file mode 100644 index 0000000000..26f2da1e97 --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/gzio.c @@ -0,0 +1,1005 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id$ */ + +#include + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatiblity with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[20]; + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, + s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + int err; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + err = do_flush (file, Z_FINISH); + if (err != Z_OK) return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +/* =========================================================================== + Returns the error message for the last error which occured on the + given compressed file. errnum is set to zlib error number. If an + error occured in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/libs/libwebsockets/win32port/zlib/gzlib.c b/libs/libwebsockets/win32port/zlib/gzlib.c new file mode 100755 index 0000000000..65efced42a --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/gzlib.c @@ -0,0 +1,537 @@ +/* gzlib.c -- zlib functions common to reading and writing gzip files + * Copyright (C) 2004, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define LSEEK lseek64 +#else +# define LSEEK lseek +#endif + +/* Local functions */ +local void gz_reset OF((gz_statep)); +local gzFile gz_open OF((const char *, int, const char *)); + +#if defined UNDER_CE + +/* Map the Windows error number in ERROR to a locale-dependent error message + string and return a pointer to it. Typically, the values for ERROR come + from GetLastError. + + The string pointed to shall not be modified by the application, but may be + overwritten by a subsequent call to gz_strwinerror + + The gz_strwinerror function does not change the current setting of + GetLastError. */ +char ZLIB_INTERNAL *gz_strwinerror (error) + DWORD error; +{ + static char buf[1024]; + + wchar_t *msgbuf; + DWORD lasterr = GetLastError(); + DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + error, + 0, /* Default language */ + (LPVOID)&msgbuf, + 0, + NULL); + if (chars != 0) { + /* If there is an \r\n appended, zap it. */ + if (chars >= 2 + && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { + chars -= 2; + msgbuf[chars] = 0; + } + + if (chars > sizeof (buf) - 1) { + chars = sizeof (buf) - 1; + msgbuf[chars] = 0; + } + + wcstombs(buf, msgbuf, chars + 1); + LocalFree(msgbuf); + } + else { + sprintf(buf, "unknown win32 error (%ld)", error); + } + + SetLastError(lasterr); + return buf; +} + +#endif /* UNDER_CE */ + +/* Reset gzip file state */ +local void gz_reset(state) + gz_statep state; +{ + if (state->mode == GZ_READ) { /* for reading ... */ + state->have = 0; /* no output data available */ + state->eof = 0; /* not at end of file */ + state->how = LOOK; /* look for gzip header */ + state->direct = 1; /* default for empty file */ + } + state->seek = 0; /* no seek request pending */ + gz_error(state, Z_OK, NULL); /* clear error */ + state->pos = 0; /* no uncompressed data yet */ + state->strm.avail_in = 0; /* no input data yet */ +} + +/* Open a gzip file either by name or file descriptor. */ +local gzFile gz_open(path, fd, mode) + const char *path; + int fd; + const char *mode; +{ + gz_statep state; + + /* allocate gzFile structure to return */ + state = malloc(sizeof(gz_state)); + if (state == NULL) + return NULL; + state->size = 0; /* no buffers allocated yet */ + state->want = GZBUFSIZE; /* requested buffer size */ + state->msg = NULL; /* no error message yet */ + + /* interpret mode */ + state->mode = GZ_NONE; + state->level = Z_DEFAULT_COMPRESSION; + state->strategy = Z_DEFAULT_STRATEGY; + while (*mode) { + if (*mode >= '0' && *mode <= '9') + state->level = *mode - '0'; + else + switch (*mode) { + case 'r': + state->mode = GZ_READ; + break; +#ifndef NO_GZCOMPRESS + case 'w': + state->mode = GZ_WRITE; + break; + case 'a': + state->mode = GZ_APPEND; + break; +#endif + case '+': /* can't read and write at the same time */ + free(state); + return NULL; + case 'b': /* ignore -- will request binary anyway */ + break; + case 'f': + state->strategy = Z_FILTERED; + break; + case 'h': + state->strategy = Z_HUFFMAN_ONLY; + break; + case 'R': + state->strategy = Z_RLE; + break; + case 'F': + state->strategy = Z_FIXED; + default: /* could consider as an error, but just ignore */ + ; + } + mode++; + } + + /* must provide an "r", "w", or "a" */ + if (state->mode == GZ_NONE) { + free(state); + return NULL; + } + + /* save the path name for error messages */ + state->path = malloc(strlen(path) + 1); + if (state->path == NULL) { + free(state); + return NULL; + } + strcpy(state->path, path); + + /* open the file with the appropriate mode (or just use fd) */ + state->fd = fd != -1 ? fd : + open(path, +#ifdef O_LARGEFILE + O_LARGEFILE | +#endif +#ifdef O_BINARY + O_BINARY | +#endif + (state->mode == GZ_READ ? + O_RDONLY : + (O_WRONLY | O_CREAT | ( + state->mode == GZ_WRITE ? + O_TRUNC : + O_APPEND))), + 0666); + if (state->fd == -1) { + free(state->path); + free(state); + return NULL; + } + if (state->mode == GZ_APPEND) + state->mode = GZ_WRITE; /* simplify later checks */ + + /* save the current position for rewinding (only if reading) */ + if (state->mode == GZ_READ) { + state->start = LSEEK(state->fd, 0, SEEK_CUR); + if (state->start == -1) state->start = 0; + } + + /* initialize stream */ + gz_reset(state); + + /* return stream */ + return (gzFile)state; +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzopen(path, mode) + const char *path; + const char *mode; +{ + return gz_open(path, -1, mode); +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzopen64(path, mode) + const char *path; + const char *mode; +{ + return gz_open(path, -1, mode); +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzdopen(fd, mode) + int fd; + const char *mode; +{ + char *path; /* identifier for error messages */ + gzFile gz; + + if (fd == -1 || (path = malloc(7 + 3 * sizeof(int))) == NULL) + return NULL; + sprintf(path, "", fd); /* for debugging */ + gz = gz_open(path, fd, mode); + free(path); + return gz; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzbuffer(file, size) + gzFile file; + unsigned size; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* make sure we haven't already allocated memory */ + if (state->size != 0) + return -1; + + /* check and set requested size */ + if (size == 0) + return -1; + state->want = size; + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzrewind(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || state->err != Z_OK) + return -1; + + /* back up and start over */ + if (LSEEK(state->fd, state->start, SEEK_SET) == -1) + return -1; + gz_reset(state); + return 0; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gzseek64(file, offset, whence) + gzFile file; + z_off64_t offset; + int whence; +{ + unsigned n; + z_off64_t ret; + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* check that there's no error */ + if (state->err != Z_OK) + return -1; + + /* can only seek from start or relative to current position */ + if (whence != SEEK_SET && whence != SEEK_CUR) + return -1; + + /* normalize offset to a SEEK_CUR specification */ + if (whence == SEEK_SET) + offset -= state->pos; + else if (state->seek) + offset += state->skip; + state->seek = 0; + + /* if within raw area while reading, just go there */ + if (state->mode == GZ_READ && state->how == COPY && + state->pos + offset >= state->raw) { + ret = LSEEK(state->fd, offset - state->have, SEEK_CUR); + if (ret == -1) + return -1; + state->have = 0; + state->eof = 0; + state->seek = 0; + gz_error(state, Z_OK, NULL); + state->strm.avail_in = 0; + state->pos += offset; + return state->pos; + } + + /* calculate skip amount, rewinding if needed for back seek when reading */ + if (offset < 0) { + if (state->mode != GZ_READ) /* writing -- can't go backwards */ + return -1; + offset += state->pos; + if (offset < 0) /* before start of file! */ + return -1; + if (gzrewind(file) == -1) /* rewind, then skip to offset */ + return -1; + } + + /* if reading, skip what's in output buffer (one less gzgetc() check) */ + if (state->mode == GZ_READ) { + n = GT_OFF(state->have) || (z_off64_t)state->have > offset ? + (unsigned)offset : state->have; + state->have -= n; + state->next += n; + state->pos += n; + offset -= n; + } + + /* request skip (if not zero) */ + if (offset) { + state->seek = 1; + state->skip = offset; + } + return state->pos + offset; +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gzseek(file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + z_off64_t ret; + + ret = gzseek64(file, (z_off64_t)offset, whence); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gztell64(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* return position */ + return state->pos + (state->seek ? state->skip : 0); +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gztell(file) + gzFile file; +{ + z_off64_t ret; + + ret = gztell64(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gzoffset64(file) + gzFile file; +{ + z_off64_t offset; + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* compute and return effective offset in file */ + offset = LSEEK(state->fd, 0, SEEK_CUR); + if (offset == -1) + return -1; + if (state->mode == GZ_READ) /* reading */ + offset -= state->strm.avail_in; /* don't count buffered input */ + return offset; +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gzoffset(file) + gzFile file; +{ + z_off64_t ret; + + ret = gzoffset64(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzeof(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return 0; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return 0; + + /* return end-of-file state */ + return state->mode == GZ_READ ? + (state->eof && state->strm.avail_in == 0 && state->have == 0) : 0; +} + +/* -- see zlib.h -- */ +const char * ZEXPORT gzerror(file, errnum) + gzFile file; + int *errnum; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return NULL; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return NULL; + + /* return error information */ + if (errnum != NULL) + *errnum = state->err; + return state->msg == NULL ? "" : state->msg; +} + +/* -- see zlib.h -- */ +void ZEXPORT gzclearerr(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return; + + /* clear error and end-of-file */ + if (state->mode == GZ_READ) + state->eof = 0; + gz_error(state, Z_OK, NULL); +} + +/* Create an error message in allocated memory and set state->err and + state->msg accordingly. Free any previous error message already there. Do + not try to free or allocate space if the error is Z_MEM_ERROR (out of + memory). Simply save the error message as a static string. If there is an + allocation failure constructing the error message, then convert the error to + out of memory. */ +void ZLIB_INTERNAL gz_error(state, err, msg) + gz_statep state; + int err; + const char *msg; +{ + /* free previously allocated message and clear */ + if (state->msg != NULL) { + if (state->err != Z_MEM_ERROR) + free(state->msg); + state->msg = NULL; + } + + /* set error code, and if no message, then done */ + state->err = err; + if (msg == NULL) + return; + + /* for an out of memory error, save as static string */ + if (err == Z_MEM_ERROR) { + state->msg = (char *)msg; + return; + } + + /* construct error message with path */ + if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) { + state->err = Z_MEM_ERROR; + state->msg = (char *)"out of memory"; + return; + } + strcpy(state->msg, state->path); + strcat(state->msg, ": "); + strcat(state->msg, msg); + return; +} + +#ifndef INT_MAX +/* portably return maximum value for an int (when limits.h presumed not + available) -- we need to do this to cover cases where 2's complement not + used, since C standard permits 1's complement and sign-bit representations, + otherwise we could just use ((unsigned)-1) >> 1 */ +unsigned ZLIB_INTERNAL gz_intmax() +{ + unsigned p, q; + + p = 1; + do { + q = p; + p <<= 1; + p++; + } while (p > q); + return q >> 1; +} +#endif diff --git a/libs/libwebsockets/win32port/zlib/gzread.c b/libs/libwebsockets/win32port/zlib/gzread.c new file mode 100755 index 0000000000..0f8649b32f --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/gzread.c @@ -0,0 +1,653 @@ +/* gzread.c -- zlib functions for reading gzip files + * Copyright (C) 2004, 2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* Local functions */ +local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); +local int gz_avail OF((gz_statep)); +local int gz_next4 OF((gz_statep, unsigned long *)); +local int gz_head OF((gz_statep)); +local int gz_decomp OF((gz_statep)); +local int gz_make OF((gz_statep)); +local int gz_skip OF((gz_statep, z_off64_t)); + +/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from + state->fd, and update state->eof, state->err, and state->msg as appropriate. + This function needs to loop on read(), since read() is not guaranteed to + read the number of bytes requested, depending on the type of descriptor. */ +local int gz_load(state, buf, len, have) + gz_statep state; + unsigned char *buf; + unsigned len; + unsigned *have; +{ + int ret; + + *have = 0; + do { + ret = read(state->fd, buf + *have, len - *have); + if (ret <= 0) + break; + *have += ret; + } while (*have < len); + if (ret < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + if (ret == 0) + state->eof = 1; + return 0; +} + +/* Load up input buffer and set eof flag if last data loaded -- return -1 on + error, 0 otherwise. Note that the eof flag is set when the end of the input + file is reached, even though there may be unused data in the buffer. Once + that data has been used, no more attempts will be made to read the file. + gz_avail() assumes that strm->avail_in == 0. */ +local int gz_avail(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + + if (state->err != Z_OK) + return -1; + if (state->eof == 0) { + if (gz_load(state, state->in, state->size, + (unsigned *)&(strm->avail_in)) == -1) + return -1; + strm->next_in = state->in; + } + return 0; +} + +/* Get next byte from input, or -1 if end or error. */ +#define NEXT() ((strm->avail_in == 0 && gz_avail(state) == -1) ? -1 : \ + (strm->avail_in == 0 ? -1 : \ + (strm->avail_in--, *(strm->next_in)++))) + +/* Get a four-byte little-endian integer and return 0 on success and the value + in *ret. Otherwise -1 is returned and *ret is not modified. */ +local int gz_next4(state, ret) + gz_statep state; + unsigned long *ret; +{ + int ch; + unsigned long val; + z_streamp strm = &(state->strm); + + val = NEXT(); + val += (unsigned)NEXT() << 8; + val += (unsigned long)NEXT() << 16; + ch = NEXT(); + if (ch == -1) + return -1; + val += (unsigned long)ch << 24; + *ret = val; + return 0; +} + +/* Look for gzip header, set up for inflate or copy. state->have must be zero. + If this is the first time in, allocate required memory. state->how will be + left unchanged if there is no more input data available, will be set to COPY + if there is no gzip header and direct copying will be performed, or it will + be set to GZIP for decompression, and the gzip header will be skipped so + that the next available input data is the raw deflate stream. If direct + copying, then leftover input data from the input buffer will be copied to + the output buffer. In that case, all further file reads will be directly to + either the output buffer or a user buffer. If decompressing, the inflate + state and the check value will be initialized. gz_head() will return 0 on + success or -1 on failure. Failures may include read errors or gzip header + errors. */ +local int gz_head(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + int flags; + unsigned len; + + /* allocate read buffers and inflate memory */ + if (state->size == 0) { + /* allocate buffers */ + state->in = malloc(state->want); + state->out = malloc(state->want << 1); + if (state->in == NULL || state->out == NULL) { + if (state->out != NULL) + free(state->out); + if (state->in != NULL) + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + state->size = state->want; + + /* allocate inflate memory */ + state->strm.zalloc = Z_NULL; + state->strm.zfree = Z_NULL; + state->strm.opaque = Z_NULL; + state->strm.avail_in = 0; + state->strm.next_in = Z_NULL; + if (inflateInit2(&(state->strm), -15) != Z_OK) { /* raw inflate */ + free(state->out); + free(state->in); + state->size = 0; + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + } + + /* get some data in the input buffer */ + if (strm->avail_in == 0) { + if (gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) + return 0; + } + + /* look for the gzip magic header bytes 31 and 139 */ + if (strm->next_in[0] == 31) { + strm->avail_in--; + strm->next_in++; + if (strm->avail_in == 0 && gz_avail(state) == -1) + return -1; + if (strm->avail_in && strm->next_in[0] == 139) { + /* we have a gzip header, woo hoo! */ + strm->avail_in--; + strm->next_in++; + + /* skip rest of header */ + if (NEXT() != 8) { /* compression method */ + gz_error(state, Z_DATA_ERROR, "unknown compression method"); + return -1; + } + flags = NEXT(); + if (flags & 0xe0) { /* reserved flag bits */ + gz_error(state, Z_DATA_ERROR, "unknown header flags set"); + return -1; + } + NEXT(); /* modification time */ + NEXT(); + NEXT(); + NEXT(); + NEXT(); /* extra flags */ + NEXT(); /* operating system */ + if (flags & 4) { /* extra field */ + len = (unsigned)NEXT(); + len += (unsigned)NEXT() << 8; + while (len--) + if (NEXT() < 0) + break; + } + if (flags & 8) /* file name */ + while (NEXT() > 0) + ; + if (flags & 16) /* comment */ + while (NEXT() > 0) + ; + if (flags & 2) { /* header crc */ + NEXT(); + NEXT(); + } + /* an unexpected end of file is not checked for here -- it will be + noticed on the first request for uncompressed data */ + + /* set up for decompression */ + inflateReset(strm); + strm->adler = crc32(0L, Z_NULL, 0); + state->how = GZIP; + state->direct = 0; + return 0; + } + else { + /* not a gzip file -- save first byte (31) and fall to raw i/o */ + state->out[0] = 31; + state->have = 1; + } + } + + /* doing raw i/o, save start of raw data for seeking, copy any leftover + input to output -- this assumes that the output buffer is larger than + the input buffer, which also assures space for gzungetc() */ + state->raw = state->pos; + state->next = state->out; + if (strm->avail_in) { + memcpy(state->next + state->have, strm->next_in, strm->avail_in); + state->have += strm->avail_in; + strm->avail_in = 0; + } + state->how = COPY; + state->direct = 1; + return 0; +} + +/* Decompress from input to the provided next_out and avail_out in the state. + If the end of the compressed data is reached, then verify the gzip trailer + check value and length (modulo 2^32). state->have and state->next are set + to point to the just decompressed data, and the crc is updated. If the + trailer is verified, state->how is reset to LOOK to look for the next gzip + stream or raw data, once state->have is depleted. Returns 0 on success, -1 + on failure. Failures may include invalid compressed data or a failed gzip + trailer verification. */ +local int gz_decomp(state) + gz_statep state; +{ + int ret; + unsigned had; + unsigned long crc, len; + z_streamp strm = &(state->strm); + + /* fill output buffer up to end of deflate stream */ + had = strm->avail_out; + do { + /* get more input for inflate() */ + if (strm->avail_in == 0 && gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) { + gz_error(state, Z_DATA_ERROR, "unexpected end of file"); + return -1; + } + + /* decompress and handle errors */ + ret = inflate(strm, Z_NO_FLUSH); + if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { + gz_error(state, Z_STREAM_ERROR, + "internal error: inflate stream corrupt"); + return -1; + } + if (ret == Z_MEM_ERROR) { + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ + gz_error(state, Z_DATA_ERROR, + strm->msg == NULL ? "compressed data error" : strm->msg); + return -1; + } + } while (strm->avail_out && ret != Z_STREAM_END); + + /* update available output and crc check value */ + state->have = had - strm->avail_out; + state->next = strm->next_out - state->have; + strm->adler = crc32(strm->adler, state->next, state->have); + + /* check gzip trailer if at end of deflate stream */ + if (ret == Z_STREAM_END) { + if (gz_next4(state, &crc) == -1 || gz_next4(state, &len) == -1) { + gz_error(state, Z_DATA_ERROR, "unexpected end of file"); + return -1; + } + if (crc != strm->adler) { + gz_error(state, Z_DATA_ERROR, "incorrect data check"); + return -1; + } + if (len != (strm->total_out & 0xffffffffL)) { + gz_error(state, Z_DATA_ERROR, "incorrect length check"); + return -1; + } + state->how = LOOK; /* ready for next stream, once have is 0 (leave + state->direct unchanged to remember how) */ + } + + /* good decompression */ + return 0; +} + +/* Make data and put in the output buffer. Assumes that state->have == 0. + Data is either copied from the input file or decompressed from the input + file depending on state->how. If state->how is LOOK, then a gzip header is + looked for (and skipped if found) to determine wither to copy or decompress. + Returns -1 on error, otherwise 0. gz_make() will leave state->have as COPY + or GZIP unless the end of the input file has been reached and all data has + been processed. */ +local int gz_make(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + + if (state->how == LOOK) { /* look for gzip header */ + if (gz_head(state) == -1) + return -1; + if (state->have) /* got some data from gz_head() */ + return 0; + } + if (state->how == COPY) { /* straight copy */ + if (gz_load(state, state->out, state->size << 1, &(state->have)) == -1) + return -1; + state->next = state->out; + } + else if (state->how == GZIP) { /* decompress */ + strm->avail_out = state->size << 1; + strm->next_out = state->out; + if (gz_decomp(state) == -1) + return -1; + } + return 0; +} + +/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ +local int gz_skip(state, len) + gz_statep state; + z_off64_t len; +{ + unsigned n; + + /* skip over len bytes or reach end-of-file, whichever comes first */ + while (len) + /* skip over whatever is in output buffer */ + if (state->have) { + n = GT_OFF(state->have) || (z_off64_t)state->have > len ? + (unsigned)len : state->have; + state->have -= n; + state->next += n; + state->pos += n; + len -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && state->strm.avail_in == 0) + break; + + /* need more data to skip -- load up output buffer */ + else { + /* get more output, looking for header if required */ + if (gz_make(state) == -1) + return -1; + } + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzread(file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + unsigned got, n; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || state->err != Z_OK) + return -1; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids the flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_BUF_ERROR, "requested length does not fit in int"); + return -1; + } + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return -1; + } + + /* get len bytes to buf, or less than len if at the end */ + got = 0; + do { + /* first just try copying data from the output buffer */ + if (state->have) { + n = state->have > len ? len : state->have; + memcpy(buf, state->next, n); + state->next += n; + state->have -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && strm->avail_in == 0) + break; + + /* need output data -- for small len or new stream load up our output + buffer */ + else if (state->how == LOOK || len < (state->size << 1)) { + /* get more output, looking for header if required */ + if (gz_make(state) == -1) + return -1; + continue; /* no progress yet -- go back to memcpy() above */ + /* the copy above assures that we will leave with space in the + output buffer, allowing at least one gzungetc() to succeed */ + } + + /* large len -- read directly into user buffer */ + else if (state->how == COPY) { /* read directly */ + if (gz_load(state, buf, len, &n) == -1) + return -1; + } + + /* large len -- decompress directly into user buffer */ + else { /* state->how == GZIP */ + strm->avail_out = len; + strm->next_out = buf; + if (gz_decomp(state) == -1) + return -1; + n = state->have; + state->have = 0; + } + + /* update progress */ + len -= n; + buf = (char *)buf + n; + got += n; + state->pos += n; + } while (len); + + /* return number of bytes read into user buffer (will fit in int) */ + return (int)got; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzgetc(file) + gzFile file; +{ + int ret; + unsigned char buf[1]; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || state->err != Z_OK) + return -1; + + /* try output buffer (no need to check for skip request) */ + if (state->have) { + state->have--; + state->pos++; + return *(state->next)++; + } + + /* nothing there -- try gzread() */ + ret = gzread(file, buf, 1); + return ret < 1 ? -1 : buf[0]; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || state->err != Z_OK) + return -1; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return -1; + } + + /* can't push EOF */ + if (c < 0) + return -1; + + /* if output buffer empty, put byte at end (allows more pushing) */ + if (state->have == 0) { + state->have = 1; + state->next = state->out + (state->size << 1) - 1; + state->next[0] = c; + state->pos--; + return c; + } + + /* if no room, give up (must have already done a gzungetc()) */ + if (state->have == (state->size << 1)) { + gz_error(state, Z_BUF_ERROR, "out of room to push characters"); + return -1; + } + + /* slide output data if needed and insert byte before existing data */ + if (state->next == state->out) { + unsigned char *src = state->out + state->have; + unsigned char *dest = state->out + (state->size << 1); + while (src > state->out) + *--dest = *--src; + state->next = dest; + } + state->have++; + state->next--; + state->next[0] = c; + state->pos--; + return c; +} + +/* -- see zlib.h -- */ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + unsigned left, n; + char *str; + unsigned char *eol; + gz_statep state; + + /* check parameters and get internal structure */ + if (file == NULL || buf == NULL || len < 1) + return NULL; + state = (gz_statep)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || state->err != Z_OK) + return NULL; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return NULL; + } + + /* copy output bytes up to new line or len - 1, whichever comes first -- + append a terminating zero to the string (we don't check for a zero in + the contents, let the user worry about that) */ + str = buf; + left = (unsigned)len - 1; + if (left) do { + /* assure that something is in the output buffer */ + if (state->have == 0) { + if (gz_make(state) == -1) + return NULL; /* error */ + if (state->have == 0) { /* end of file */ + if (buf == str) /* got bupkus */ + return NULL; + break; /* got something -- return it */ + } + } + + /* look for end-of-line in current output buffer */ + n = state->have > left ? left : state->have; + eol = memchr(state->next, '\n', n); + if (eol != NULL) + n = (unsigned)(eol - state->next) + 1; + + /* copy through end-of-line, or remainder if not found */ + memcpy(buf, state->next, n); + state->have -= n; + state->next += n; + state->pos += n; + left -= n; + buf += n; + } while (left && eol == NULL); + + /* found end-of-line or out of space -- terminate string and return it */ + buf[0] = 0; + return str; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzdirect(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're reading */ + if (state->mode != GZ_READ) + return 0; + + /* if the state is not known, but we can find out, then do so (this is + mainly for right after a gzopen() or gzdopen()) */ + if (state->how == LOOK && state->have == 0) + (void)gz_head(state); + + /* return 1 if reading direct, 0 if decompressing a gzip stream */ + return state->direct; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_r(file) + gzFile file; +{ + int ret; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're reading */ + if (state->mode != GZ_READ) + return Z_STREAM_ERROR; + + /* free memory and close file */ + if (state->size) { + inflateEnd(&(state->strm)); + free(state->out); + free(state->in); + } + gz_error(state, Z_OK, NULL); + free(state->path); + ret = close(state->fd); + free(state); + return ret ? Z_ERRNO : Z_OK; +} diff --git a/libs/libwebsockets/win32port/zlib/gzwrite.c b/libs/libwebsockets/win32port/zlib/gzwrite.c new file mode 100755 index 0000000000..e2bcf9d2b8 --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/gzwrite.c @@ -0,0 +1,531 @@ +/* gzwrite.c -- zlib functions for writing gzip files + * Copyright (C) 2004, 2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* Local functions */ +local int gz_init OF((gz_statep)); +local int gz_comp OF((gz_statep, int)); +local int gz_zero OF((gz_statep, z_off64_t)); + +/* Initialize state for writing a gzip file. Mark initialization by setting + state->size to non-zero. Return -1 on failure or 0 on success. */ +local int gz_init(state) + gz_statep state; +{ + int ret; + z_streamp strm = &(state->strm); + + /* allocate input and output buffers */ + state->in = malloc(state->want); + state->out = malloc(state->want); + if (state->in == NULL || state->out == NULL) { + if (state->out != NULL) + free(state->out); + if (state->in != NULL) + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* allocate deflate memory, set up for gzip compression */ + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; + strm->opaque = Z_NULL; + ret = deflateInit2(strm, state->level, Z_DEFLATED, + 15 + 16, 8, state->strategy); + if (ret != Z_OK) { + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* mark state as initialized */ + state->size = state->want; + + /* initialize write buffer */ + strm->avail_out = state->size; + strm->next_out = state->out; + state->next = strm->next_out; + return 0; +} + +/* Compress whatever is at avail_in and next_in and write to the output file. + Return -1 if there is an error writing to the output file, otherwise 0. + flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, + then the deflate() state is reset to start a new gzip stream. */ +local int gz_comp(state, flush) + gz_statep state; + int flush; +{ + int ret, got; + unsigned have; + z_streamp strm = &(state->strm); + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return -1; + + /* run deflate() on provided input until it produces no more output */ + ret = Z_OK; + do { + /* write out current buffer contents if full, or if flushing, but if + doing Z_FINISH then don't write until we get to Z_STREAM_END */ + if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && + (flush != Z_FINISH || ret == Z_STREAM_END))) { + have = (unsigned)(strm->next_out - state->next); + if (have && ((got = write(state->fd, state->next, have)) < 0 || + (unsigned)got != have)) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + if (strm->avail_out == 0) { + strm->avail_out = state->size; + strm->next_out = state->out; + } + state->next = strm->next_out; + } + + /* compress */ + have = strm->avail_out; + ret = deflate(strm, flush); + if (ret == Z_STREAM_ERROR) { + gz_error(state, Z_STREAM_ERROR, + "internal error: deflate stream corrupt"); + return -1; + } + have -= strm->avail_out; + } while (have); + + /* if that completed a deflate stream, allow another to start */ + if (flush == Z_FINISH) + deflateReset(strm); + + /* all done, no errors */ + return 0; +} + +/* Compress len zeros to output. Return -1 on error, 0 on success. */ +local int gz_zero(state, len) + gz_statep state; + z_off64_t len; +{ + int first; + unsigned n; + z_streamp strm = &(state->strm); + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + + /* compress len zeros (len guaranteed > 0) */ + first = 1; + while (len) { + n = GT_OFF(state->size) || (z_off64_t)state->size > len ? + (unsigned)len : state->size; + if (first) { + memset(state->in, 0, n); + first = 0; + } + strm->avail_in = n; + strm->next_in = state->in; + state->pos += n; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + len -= n; + } + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzwrite(file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + unsigned put = len; + unsigned n; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids the flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_BUF_ERROR, "requested length does not fit in int"); + return 0; + } + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* for small len, copy to input buffer, otherwise compress directly */ + if (len < state->size) { + /* copy to input buffer, compress when full */ + do { + if (strm->avail_in == 0) + strm->next_in = state->in; + n = state->size - strm->avail_in; + if (n > len) + n = len; + memcpy(strm->next_in + strm->avail_in, buf, n); + strm->avail_in += n; + state->pos += n; + buf = (char *)buf + n; + len -= n; + if (len && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + } while (len); + } + else { + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* directly compress user buffer to file */ + strm->avail_in = len; + strm->next_in = (voidp)buf; + state->pos += len; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + } + + /* input was all buffered or compressed (put will fit in int) */ + return (int)put; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char buf[1]; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return -1; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* try writing to input buffer for speed (state->size == 0 if buffer not + initialized) */ + if (strm->avail_in < state->size) { + if (strm->avail_in == 0) + strm->next_in = state->in; + strm->next_in[strm->avail_in++] = c; + state->pos++; + return c; + } + + /* no room in buffer or not initialized, use gz_write() */ + buf[0] = c; + if (gzwrite(file, buf, 1) != 1) + return -1; + return c; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzputs(file, str) + gzFile file; + const char *str; +{ + int ret; + unsigned len; + + /* write string */ + len = (unsigned)strlen(str); + ret = gzwrite(file, str, len); + return ret == 0 && len != 0 ? -1 : ret; +} + +#ifdef STDC +#include + +/* -- see zlib.h -- */ +int ZEXPORTVA gzprintf (gzFile file, const char *format, ...) +{ + int size, len; + gz_statep state; + z_streamp strm; + va_list va; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* do the printf() into the input buffer, put length in len */ + size = (int)(state->size); + state->in[size - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(state->in, format, va); + va_end(va); + for (len = 0; len < size; len++) + if (state->in[len] == 0) break; +# else + len = vsprintf(state->in, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(state->in, size, format, va); + va_end(va); + len = strlen(state->in); +# else + len = vsnprintf((char *)(state->in), size, format, va); + va_end(va); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) + return 0; + + /* update buffer and position, defer compression until needed */ + strm->avail_in = (unsigned)len; + strm->next_in = state->in; + state->pos += len; + return len; +} + +#else /* !STDC */ + +/* -- see zlib.h -- */ +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + int size, len; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* do the printf() into the input buffer, put length in len */ + size = (int)(state->size); + state->in[size - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < size; len++) + if (state->in[len] == 0) break; +# else + len = sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(state->in); +# else + len = snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) + return 0; + + /* update buffer and position, defer compression until needed */ + strm->avail_in = (unsigned)len; + strm->next_in = state->in; + state->pos += len; + return len; +} + +#endif + +/* -- see zlib.h -- */ +int ZEXPORT gzflush(file, flush) + gzFile file; + int flush; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* check flush parameter */ + if (flush < 0 || flush > Z_FINISH) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* compress remaining data with requested flush */ + gz_comp(state, flush); + return state->err; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzsetparams(file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* if no change is requested, then do nothing */ + if (level == state->level && strategy == state->strategy) + return Z_OK; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* change compression parameters for subsequent input */ + if (state->size) { + /* flush previous input with previous parameters before changing */ + if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1) + return state->err; + deflateParams(strm, level, strategy); + } + state->level = level; + state->strategy = strategy; + return Z_OK; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_w(file) + gzFile file; +{ + int ret = 0; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're writing */ + if (state->mode != GZ_WRITE) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + ret += gz_zero(state, state->skip); + } + + /* flush, free memory, and close file */ + ret += gz_comp(state, Z_FINISH); + (void)deflateEnd(&(state->strm)); + free(state->out); + free(state->in); + gz_error(state, Z_OK, NULL); + free(state->path); + ret += close(state->fd); + free(state); + return ret ? Z_ERRNO : Z_OK; +} diff --git a/libs/libwebsockets/win32port/zlib/infback.c b/libs/libwebsockets/win32port/zlib/infback.c new file mode 100644 index 0000000000..14770c5635 --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/infback.c @@ -0,0 +1,632 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2009 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->wnext = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + NEEDBITS(here.bits); + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + state->length = (unsigned)here.val; + + /* process literal */ + if (here.op == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/libs/libwebsockets/win32port/zlib/inffast.c b/libs/libwebsockets/win32port/zlib/inffast.c new file mode 100644 index 0000000000..2dfd4127db --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/inffast.c @@ -0,0 +1,340 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2008, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void ZLIB_INTERNAL inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code here; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + wnext = state->wnext; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + here = lcode[hold & lmask]; + dolen: + op = (unsigned)(here.bits); + hold >>= op; + bits -= op; + op = (unsigned)(here.op); + if (op == 0) { /* literal */ + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + PUP(out) = (unsigned char)(here.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(here.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + here = dcode[hold & dmask]; + dodist: + op = (unsigned)(here.bits); + hold >>= op; + bits -= op; + op = (unsigned)(here.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(here.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state->sane) { + strm->msg = + (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (len <= op - whave) { + do { + PUP(out) = 0; + } while (--len); + continue; + } + len -= op - whave; + do { + PUP(out) = 0; + } while (--op > whave); + if (op == 0) { + from = out - dist; + do { + PUP(out) = PUP(from); + } while (--len); + continue; + } +#endif + } + from = window - OFF; + if (wnext == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + here = dcode[here.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + here = lcode[here.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and wnext == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/libs/libwebsockets/win32port/zlib/inffast.h b/libs/libwebsockets/win32port/zlib/inffast.h new file mode 100644 index 0000000000..e1e6db4ac5 --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/libs/libwebsockets/win32port/zlib/inffixed.h b/libs/libwebsockets/win32port/zlib/inffixed.h new file mode 100644 index 0000000000..423d5c5b50 --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/libs/libwebsockets/win32port/zlib/inflate.c b/libs/libwebsockets/win32port/zlib/inflate.c new file mode 100644 index 0000000000..5bec31e2ec --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/inflate.c @@ -0,0 +1,1480 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common wnext == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->wsize = 0; + state->whave = 0; + state->wnext = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + state->sane = 1; + state->back = -1; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateReset2(strm, windowBits) +z_streamp strm; +int windowBits; +{ + int wrap; + struct inflate_state FAR *state; + + /* get the state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + wrap = 0; + windowBits = -windowBits; + } + else { + wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) + windowBits &= 15; +#endif + } + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) + return Z_STREAM_ERROR; + if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { + ZFREE(strm, state->window); + state->window = Z_NULL; + } + + /* update state and reset the rest of it */ + state->wrap = wrap; + state->wbits = (unsigned)windowBits; + return inflateReset(strm); +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + int ret; + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->window = Z_NULL; + ret = inflateReset2(strm, windowBits); + if (ret != Z_OK) { + ZFREE(strm, state); + strm->state = Z_NULL; + } + return ret; +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits < 0) { + state->hold = 0; + state->bits = 0; + return Z_OK; + } + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->wnext = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->wnext = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->wnext; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->wnext, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->wnext = copy; + state->whave = state->wsize; + } + else { + state->wnext += dist; + if (state->wnext == state->wsize) state->wnext = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (state->wbits == 0) + state->wbits = len; + else if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN_; /* decode codes */ + if (flush == Z_TREES) { + DROPBITS(2); + goto inf_leave; + } + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY_; + if (flush == Z_TREES) goto inf_leave; + case COPY_: + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + NEEDBITS(here.bits); + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN_; + if (flush == Z_TREES) goto inf_leave; + case LEN_: + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + if (state->mode == TYPE) + state->back = -1; + break; + } + state->back = 0; + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + state->length = (unsigned)here.val; + if ((int)(here.op) == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + state->mode = LIT; + break; + } + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->back = -1; + state->mode = TYPE; + break; + } + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(here.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->was = state->length; + state->mode = DIST; + case DIST: + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + state->extra = (unsigned)(here.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->whave) { + if (state->sane) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + Trace((stderr, "inflate.c too far\n")); + copy -= state->whave; + if (copy > state->length) copy = state->length; + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = 0; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; +#endif + } + if (copy > state->wnext) { + copy -= state->wnext; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->wnext - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0) + + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy(copy, state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} + +int ZEXPORT inflateUndermine(strm, subvert) +z_streamp strm; +int subvert; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + state->sane = !subvert; +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + return Z_OK; +#else + state->sane = 1; + return Z_DATA_ERROR; +#endif +} + +long ZEXPORT inflateMark(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16; + state = (struct inflate_state FAR *)strm->state; + return ((long)(state->back) << 16) + + (state->mode == COPY ? state->length : + (state->mode == MATCH ? state->was - state->length : 0)); +} diff --git a/libs/libwebsockets/win32port/zlib/inflate.h b/libs/libwebsockets/win32port/zlib/inflate.h new file mode 100644 index 0000000000..a8ef4287df --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/inflate.h @@ -0,0 +1,122 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2009 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY_, /* i/o: same as COPY below, but only first time in */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN_, /* i: same as LEN below, but only first time in */ + LEN, /* i: waiting for length/lit/eob code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to BAD or MEM on error -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) or (raw) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> + HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + (raw) -> TYPEDO + Read deflate blocks: + TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK + STORED -> COPY_ -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN_ + LEN_ -> LEN + Read deflate codes in fixed or dynamic block: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 10K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ + int sane; /* if false, allow invalid distance too far */ + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ +}; diff --git a/libs/libwebsockets/win32port/zlib/inftrees.c b/libs/libwebsockets/win32port/zlib/inftrees.c new file mode 100644 index 0000000000..9dbaec3368 --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/inftrees.c @@ -0,0 +1,330 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.5 Copyright 1995-2010 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code here; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 73, 195}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)1; + here.val = (unsigned short)0; + *(*table)++ = here; /* make a table to force an error */ + *(*table)++ = here; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type == LENS && used >= ENOUGH_LENS) || + (type == DISTS && used >= ENOUGH_DISTS)) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + here.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + here.op = (unsigned char)0; + here.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + here.op = (unsigned char)(extra[work[sym]]); + here.val = base[work[sym]]; + } + else { + here.op = (unsigned char)(32 + 64); /* end of block */ + here.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = here; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if ((type == LENS && used >= ENOUGH_LENS) || + (type == DISTS && used >= ENOUGH_DISTS)) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)(len - drop); + here.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + here.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = here; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/libs/libwebsockets/win32port/zlib/inftrees.h b/libs/libwebsockets/win32port/zlib/inftrees.h new file mode 100644 index 0000000000..a685d8c6ea --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/inftrees.h @@ -0,0 +1,62 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1444, which is the sum of 852 for literal/length codes and 592 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribtution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns returns 852, and "enough 30 6 15" for distance codes returns 592. + The initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in inflate.c and infback.c. If the root table size is + changed, then these maximum sizes would be need to be recalculated and + updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 592 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/libs/libwebsockets/win32port/zlib/trees.c b/libs/libwebsockets/win32port/zlib/trees.c new file mode 100644 index 0000000000..b4a317aced --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/trees.c @@ -0,0 +1,1244 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2010 Jean-loup Gailly + * detect_data_type() function provided freely by Cosmin Truta, 2006 + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local int detect_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (ush)value << s->bi_valid; + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= (ush)value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (ush)val << s->bi_valid;\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (ush)(value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ +#ifdef NO_INIT_GLOBAL_POINTERS + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; +#endif + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, + "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void ZLIB_INTERNAL _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int last; /* one if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void ZLIB_INTERNAL _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int last; /* one if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (s->strm->data_type == Z_UNKNOWN) + s->strm->data_type = detect_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, last); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+last, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+last, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (last) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*last)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int ZLIB_INTERNAL _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "black list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local int detect_data_type(s) + deflate_state *s; +{ + /* black_mask is the bit mask of black-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + unsigned long black_mask = 0xf3ffc07fUL; + int n; + + /* Check for non-textual ("black-listed") bytes. */ + for (n = 0; n <= 31; n++, black_mask >>= 1) + if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) + return Z_BINARY; + + /* Check for textual ("white-listed") bytes. */ + if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 + || s->dyn_ltree[13].Freq != 0) + return Z_TEXT; + for (n = 32; n < LITERALS; n++) + if (s->dyn_ltree[n].Freq != 0) + return Z_TEXT; + + /* There are no "black-listed" or "white-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/libs/libwebsockets/win32port/zlib/trees.h b/libs/libwebsockets/win32port/zlib/trees.h new file mode 100644 index 0000000000..ce8f620444 --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/libs/libwebsockets/win32port/zlib/uncompr.c b/libs/libwebsockets/win32port/zlib/uncompr.c new file mode 100644 index 0000000000..f07773c9de --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/uncompr.c @@ -0,0 +1,59 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003, 2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/libs/libwebsockets/win32port/zlib/zconf.h b/libs/libwebsockets/win32port/zlib/zconf.h new file mode 100644 index 0000000000..88f90f90f4 --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/zconf.h @@ -0,0 +1,428 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# define uncompress z_uncompress +# define zError z_zError +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# define gzFile z_gzFile +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef STDC +# include /* for off_t */ +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +#endif + +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define z_off64_t off64_t +#else +# define z_off64_t z_off_t +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/libs/libwebsockets/win32port/zlib/zlib.h b/libs/libwebsockets/win32port/zlib/zlib.h new file mode 100644 index 0000000000..cba7ab2fb3 --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/zlib.h @@ -0,0 +1,1613 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.5, April 19th, 2010 + + Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.5" +#define ZLIB_VERNUM 0x1250 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 5 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use in the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). Some + output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed code + block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the stream + are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least the + value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect the + compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the + exact value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit() does not process any header information -- that is deferred + until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing will + resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all the uncompressed data. (The size + of the uncompressed data may have been saved by the compressor for this + purpose.) The next operation on this stream must be inflateEnd to deallocate + the decompression state. The use of Z_FINISH is never required, but can be + used to inform inflate that a faster approach may be used for the single + inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK or Z_TREES is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained, so applications that need that information should + instead use raw inflate, see inflateInit2() below, or inflateBack() and + perform their own processing of the gzip header and trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by the + caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any call + of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. The + stream will keep the same compression level and any other attributes that + may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression level is changed, the input available so far is + compressed with the old level (and may be flushed); the new level will take + effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to be + compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if + strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been + found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the + success case, the application may save the current current value of total_in + which indicates where valid compressed data was found. In the error case, + the application may repeatedly call inflateSync, providing more input each + time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + int windowBits)); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above or -1 << 16 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the normal + behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed buffer. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef voidp gzFile; /* opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); + + Opens a gzip (.gz) file for reading or writing. The mode parameter is as + in fopen ("rb" or "wb") but can also include a compression level ("wb9") or + a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only + compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' + for fixed code compression as in "wb9F". (See the description of + deflateInit2 for more information about the strategy parameter.) Also "a" + can be used instead of "w" to request that the gzip stream that will be + written be appended to the file. "+" will result in an error, since reading + and writing to the same gzip file is not supported. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen associates a gzFile with the file descriptor fd. File descriptors + are obtained from calls like open, dup, creat, pipe or fileno (if the file + has been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +/* + Set the internal buffer size used by this library's functions. The + default buffer size is 8192 bytes. This function must be called after + gzopen() or gzdopen(), and before any other calls that read or write the + file. The buffer memory allocation is always deferred to the first read or + write. Two buffers are allocated, either both of the specified size when + writing, or one of the specified size and the other twice that size when + reading. A larger buffer size of, for example, 64K or 128K bytes will + noticeably increase the speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. If + the input file was not in gzip format, gzread copies the given number of + bytes into the buffer. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream, or failing that, reading the rest + of the input file directly without decompression. The entire input file + will be read if gzread is called until it returns less than the requested + len. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. +*/ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes written or 0 in case of + error. +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the arguments to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or 0 in case of error. The number of + uncompressed bytes written is limited to 8191, or one less than the buffer + size given to gzbuffer(). The caller should assure that this limit is not + exceeded. If it is exceeded, then gzprintf() will return an error (0) with + nothing written. In this case, there may also be a buffer overflow with + unpredictable consequences, which is possible only if zlib was compiled with + the insecure functions sprintf() or vsprintf() because the secure snprintf() + or vsnprintf() functions were not available. This can be determined using + zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or a + newline character is read and transferred to buf, or an end-of-file + condition is encountered. If any characters are read or if len == 1, the + string is terminated with a null character. If no characters are read due + to an end-of-file or len < 1, then the buffer is left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte or -1 + in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read as the first character + on the next read. At least one character of push-back is allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter flush + is as in the deflate() function. The return value is the zlib error number + (see function gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatented gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); + + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); + + Returns the starting position for the next gzread or gzwrite on the given + compressed file. This position represents a number of bytes in the + uncompressed data stream, and is zero when starting, even if appending or + reading a gzip stream from the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); + + Returns the current offset in the file being read or written. This offset + includes the count of bytes that precede the gzip stream, for example when + appending or when using gzdopen() for reading. When reading, the offset + does not include as yet unused buffered input. This information can be used + for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns true (1) if the end-of-file indicator has been set while reading, + false (0) otherwise. Note that the end-of-file indicator is set only if the + read tried to go past the end of the input, but came up short. Therefore, + just like feof(), gzeof() may return false even if there is no more data to + read, in the event that the last read request was for the exact number of + bytes remaining in the input file. This will happen if the input file size + is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. This state can change from + false to true while reading the input file if the end of a gzip stream is + reached, but is followed by data that is not another gzip stream. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file and + deallocates the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the given + compressed file. errnum is set to zlib error number. If an error occurred + in the file system and not in the compression library, errnum is set to + Z_ERRNO and the application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is Z_NULL, this function returns the + required initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is Z_NULL, this function returns the required + initial value for the for the crc. Pre- and post-conditioning (one's + complement) is performed within this function so it shouldn't be done by the + application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); +#endif + +#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0 +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# ifdef _LARGEFILE64_SOURCE + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); +#endif + +/* hack for buggy compilers */ +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; +#endif + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); +ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/libs/libwebsockets/win32port/zlib/zutil.c b/libs/libwebsockets/win32port/zlib/zutil.c new file mode 100644 index 0000000000..e33ae8bb5a --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/zutil.c @@ -0,0 +1,318 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005, 2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch ((int)(sizeof(uInt))) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch ((int)(sizeof(uLong))) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch ((int)(sizeof(voidpf))) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch ((int)(sizeof(z_off_t))) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int ZLIB_INTERNAL z_verbose = verbose; + +void ZLIB_INTERNAL z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void ZLIB_INTERNAL zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int ZLIB_INTERNAL zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void ZLIB_INTERNAL zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void ZLIB_INTERNAL zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/libs/libwebsockets/win32port/zlib/zutil.h b/libs/libwebsockets/win32port/zlib/zutil.h new file mode 100644 index 0000000000..a36a406ed9 --- /dev/null +++ b/libs/libwebsockets/win32port/zlib/zutil.h @@ -0,0 +1,274 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ) +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include "zlib.h" + +#ifdef STDC +# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) +# include +# endif +# include +# include +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 +# include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + +#if defined(__BORLANDC__) + #pragma warn -8004 + #pragma warn -8008 + #pragma warn -8066 +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) +# define vsnprintf _vsnprintf +# endif +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int ZLIB_INTERNAL z_verbose; + extern void ZLIB_INTERNAL z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, + unsigned size)); +void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ From e9ce6ae0e9b1f40bf765e42140802c0efad251dc Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Wed, 8 Aug 2012 21:18:06 -0500 Subject: [PATCH 420/822] FS-4504 vs2010 only - plus mod_sofia fix - anybody want to help with 2008 --- Freeswitch.2010.sln | 38 +++ libs/spandsp/src/libspandsp.2010.vcxproj | 17 +- .../src/libspandsp.2010.vcxproj.filters | 3 + libs/spandsp/src/msvc/config.h | 2 + libs/spandsp/src/t42.c | 6 +- libs/win32/Download libjpeg.2010.vcxproj | 81 +++++++ libs/win32/libjpeg/libjpeg.2010.vcxproj | 226 ++++++++++++++++++ .../libjpeg/libjpeg.2010.vcxproj.filters | 186 ++++++++++++++ .../mod_sofia/mod_sofia.2010.vcxproj | 1 + src/mod/endpoints/mod_sofia/rtp.c | 34 ++- 10 files changed, 579 insertions(+), 15 deletions(-) create mode 100644 libs/win32/Download libjpeg.2010.vcxproj create mode 100644 libs/win32/libjpeg/libjpeg.2010.vcxproj create mode 100644 libs/win32/libjpeg/libjpeg.2010.vcxproj.filters diff --git a/Freeswitch.2010.sln b/Freeswitch.2010.sln index cd22423f5b..588637f438 100644 --- a/Freeswitch.2010.sln +++ b/Freeswitch.2010.sln @@ -529,6 +529,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libzrtp", "libs\libzrtp\pro EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_redis", "src\mod\applications\mod_redis\mod_redis.2010.vcxproj", "{886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download libjpeg", "libs\win32\Download libjpeg.2010.vcxproj", "{652AD5F7-8488-489F-AAD0-7FBE064703B6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libjpeg", "libs\win32\libjpeg\libjpeg.2010.vcxproj", "{019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution All|Win32 = All|Win32 @@ -3608,6 +3612,38 @@ Global {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.Release|x64.ActiveCfg = Release|x64 {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.Release|x64 Setup.ActiveCfg = Release|x64 {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.Release|x86 Setup.ActiveCfg = Release|x64 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.All|Win32.ActiveCfg = Release|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.All|Win32.Build.0 = Release|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.All|x64.ActiveCfg = Release|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.All|x64 Setup.ActiveCfg = Release|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.All|x86 Setup.ActiveCfg = Release|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|Win32.ActiveCfg = Debug|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|Win32.Build.0 = Debug|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|x64.ActiveCfg = Debug|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|x64 Setup.ActiveCfg = Debug|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|x86 Setup.ActiveCfg = Debug|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|Win32.ActiveCfg = Release|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|Win32.Build.0 = Release|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|x64.ActiveCfg = Release|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|x64 Setup.ActiveCfg = Release|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|x86 Setup.ActiveCfg = Release|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.All|Win32.ActiveCfg = Release|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.All|Win32.Build.0 = Release|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.All|x64.ActiveCfg = Release|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.All|x64 Setup.ActiveCfg = Release|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.All|x86 Setup.ActiveCfg = Release|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Debug|Win32.ActiveCfg = Debug|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Debug|Win32.Build.0 = Debug|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Debug|x64.ActiveCfg = Debug|x64 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Debug|x64.Build.0 = Debug|x64 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Debug|x64 Setup.ActiveCfg = Release|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Debug|x86 Setup.ActiveCfg = Release|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|Win32.ActiveCfg = Release|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|Win32.Build.0 = Release|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|x64.ActiveCfg = Release|x64 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|x64.Build.0 = Release|x64 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|x64 Setup.ActiveCfg = Release|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|x86 Setup.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -3723,6 +3759,7 @@ Global {23B4D303-79FC-49E0-89E2-2280E7E28940} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B} {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B} {C13CC324-0032-4492-9A30-310A6BD64FF5} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B} + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B} {EC3E5C7F-EE09-47E2-80FE-546363D14A98} = {B8F5B47B-8568-46EB-B320-64C17D2A98BC} {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F} = {0C808854-54D1-4230-BFF5-77B5FD905000} {ACFFF684-4D19-4D48-AF12-88EA1D778BDF} = {0C808854-54D1-4230-BFF5-77B5FD905000} @@ -3761,6 +3798,7 @@ Global {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19} = {C120A020-773F-4EA3-923F-B67AF28B750D} {B808178B-82F0-4CF4-A2B1-921939FA24D0} = {C120A020-773F-4EA3-923F-B67AF28B750D} {D578E676-7EC8-4548-BD8B-845C635F14AD} = {C120A020-773F-4EA3-923F-B67AF28B750D} + {652AD5F7-8488-489F-AAD0-7FBE064703B6} = {C120A020-773F-4EA3-923F-B67AF28B750D} {988CACF7-3FCB-4992-BE69-77872AE67DC8} = {6CD61A1D-797C-470A-BE08-8C31B68BB336} {5BC072DB-3826-48EA-AF34-FE32AA01E83B} = {6CD61A1D-797C-470A-BE08-8C31B68BB336} {FA429E98-8B03-45E6-A096-A4BC5E821DE4} = {6CD61A1D-797C-470A-BE08-8C31B68BB336} diff --git a/libs/spandsp/src/libspandsp.2010.vcxproj b/libs/spandsp/src/libspandsp.2010.vcxproj index 253863f975..0ef3d481b0 100644 --- a/libs/spandsp/src/libspandsp.2010.vcxproj +++ b/libs/spandsp/src/libspandsp.2010.vcxproj @@ -76,7 +76,7 @@ Disabled - .;..\..\src\spandsp;..\..\src;..\..\src\msvc;.\spandsp;.\msvc;..\..\tiff-3.8.2\libtiff;%(AdditionalIncludeDirectories) + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;.\spandsp;.\msvc;..\..\tiff-3.8.2\libtiff;..\..\jpeg-8d;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) true EnableFastChecks @@ -97,7 +97,7 @@ $(IntDir)BuildLog $(ProjectName).htm - .;.\spandsp;.\msvc;..\..\tiff-3.8.2\libtiff;%(AdditionalIncludeDirectories) + .;.\spandsp;.\msvc;..\..\tiff-3.8.2\libtiff;..\..\jpeg-8d;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) MultiThreadedDLL Level4 @@ -118,7 +118,7 @@ Disabled - .;.\spandsp;.\msvc;..\..\tiff-3.8.2\libtiff;%(AdditionalIncludeDirectories) + .;.\spandsp;.\msvc;..\..\tiff-3.8.2\libtiff;..\..\jpeg-8d;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) true EnableFastChecks @@ -139,7 +139,7 @@ $(IntDir)BuildLog $(ProjectName).htm - .;.\spandsp;.\msvc;..\..\tiff-3.8.2\libtiff;%(AdditionalIncludeDirectories) + .;.\spandsp;.\msvc;..\..\tiff-3.8.2\libtiff;..\..\jpeg-8d;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) MultiThreadedDLL Level4 @@ -208,6 +208,7 @@ + @@ -409,6 +410,14 @@ + + {019dbd2a-273d-4ba4-bf86-b5efe2ed76b1} + true + false + false + true + false + {401a40cd-5db4-4e34-ac68-fa99e9fac014} false diff --git a/libs/spandsp/src/libspandsp.2010.vcxproj.filters b/libs/spandsp/src/libspandsp.2010.vcxproj.filters index 0c445ef07c..c7d1210235 100644 --- a/libs/spandsp/src/libspandsp.2010.vcxproj.filters +++ b/libs/spandsp/src/libspandsp.2010.vcxproj.filters @@ -277,6 +277,9 @@ Source Files + + Source Files + diff --git a/libs/spandsp/src/msvc/config.h b/libs/spandsp/src/msvc/config.h index a1eaae16a6..42494d345f 100644 --- a/libs/spandsp/src/msvc/config.h +++ b/libs/spandsp/src/msvc/config.h @@ -74,6 +74,8 @@ #define _MMX_H_ + #define cbrtf(value) pow((float)value, (float).333) + #include // To get alloca #endif diff --git a/libs/spandsp/src/t42.c b/libs/spandsp/src/t42.c index f7f7e1e062..a9eb7afc9c 100644 --- a/libs/spandsp/src/t42.c +++ b/libs/spandsp/src/t42.c @@ -929,7 +929,7 @@ SPAN_DECLARE(int) t42_srgb_to_itulab(logging_state_t *logging, lab_params_t *s, for (pos = 0; pos < srclen; pos += compressor.image_width*compressor.num_components) { - scan_line_in = src + pos; + scan_line_in = (JSAMPROW)src + pos; srgb_to_lab(s, scan_line_out, scan_line_in, compressor.image_width); jpeg_write_scanlines(&compressor, &scan_line_out, 1); } @@ -1033,7 +1033,7 @@ SPAN_DECLARE(int) t42_itulab_to_itulab(logging_state_t *logging, tdata_t *dst, t for (pos = 0; pos < srclen; pos += compressor.image_width*compressor.num_components) { - scan_line_in = src + pos; + scan_line_in = (JSAMPROW)src + pos; jpeg_write_scanlines(&compressor, &scan_line_in, 1); } @@ -1150,7 +1150,7 @@ SPAN_DECLARE(int) t42_itulab_to_srgb(logging_state_t *logging, lab_params_t *s, for (pos = 0; decompressor.output_scanline < decompressor.output_height; pos += decompressor.output_width*decompressor.num_components) { - scan_line_out = dst + pos; + scan_line_out = (JSAMPROW)dst + pos; jpeg_read_scanlines(&decompressor, &scan_line_in, 1); lab_to_srgb(s, scan_line_out, scan_line_in, decompressor.output_width); } diff --git a/libs/win32/Download libjpeg.2010.vcxproj b/libs/win32/Download libjpeg.2010.vcxproj new file mode 100644 index 0000000000..56844e037c --- /dev/null +++ b/libs/win32/Download libjpeg.2010.vcxproj @@ -0,0 +1,81 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + Download libjpeg + {652AD5F7-8488-489F-AAD0-7FBE064703B6} + Download libjpeg + Win32Proj + + + + Utility + MultiByte + + + Utility + MultiByte + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(PlatformName)\jpeg-8d\$(Configuration)\ + $(PlatformName)\jpeg-8d\$(Configuration)\ + + + + $(IntDir)BuildLog $(ProjectName).htm + + + + + + + + + $(IntDir)BuildLog $(ProjectName).htm + + + + + + + + + + + + + Document + Downloading libjpeg. + if not exist "$(ProjectDir)..\jpeg-8d" cscript /nologo "$(ProjectDir)util.vbs" GetUnzip http://www.ijg.org/files/jpegsrc.v8d.tar.gz "$(ProjectDir).." + + $(ProjectDir)..\jpeg-8d;%(Outputs) + Downloading libjpeg. + if not exist "$(ProjectDir)..\jpeg-8d" cscript /nologo "$(ProjectDir)util.vbs" GetUnzip http://www.ijg.org/files/jpegsrc.v8d.tar.gz "$(ProjectDir).." + + $(ProjectDir)..\jpeg-8d;%(Outputs) + + + + + + \ No newline at end of file diff --git a/libs/win32/libjpeg/libjpeg.2010.vcxproj b/libs/win32/libjpeg/libjpeg.2010.vcxproj new file mode 100644 index 0000000000..734f4b8446 --- /dev/null +++ b/libs/win32/libjpeg/libjpeg.2010.vcxproj @@ -0,0 +1,226 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Disabled + Disabled + Disabled + Disabled + false + false + false + false + + + + libjpeg + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1} + Win32Proj + libjpeg + + + + StaticLibrary + false + true + Unicode + + + StaticLibrary + false + true + Unicode + + + StaticLibrary + false + true + Unicode + + + StaticLibrary + false + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + Level3 + NotUsing + Full + true + false + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS + true + true + ..\..\jpeg-8d;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + + + + + Level3 + NotUsing + Full + true + false + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS + true + true + ..\..\jpeg-8d;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + + + + + Level3 + NotUsing + Full + true + false + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS + true + true + ..\..\jpeg-8d;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + + + if not exist "$(ProjectDir)..\..\jpeg-8d\jconfig.h" type "$(ProjectDir)..\..\jpeg-8d\jconfig.vc" > "$(ProjectDir)..\..\jpeg-8d\jconfig.h" + + + + + Level3 + NotUsing + Full + true + false + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS + true + true + ..\..\jpeg-8d;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + + + if not exist "$(ProjectDir)..\..\jpeg-8d\jconfig.h" type "$(ProjectDir)..\..\jpeg-8d\jconfig.vc" > "$(ProjectDir)..\..\jpeg-8d\jconfig.h" + + + + + + \ No newline at end of file diff --git a/libs/win32/libjpeg/libjpeg.2010.vcxproj.filters b/libs/win32/libjpeg/libjpeg.2010.vcxproj.filters new file mode 100644 index 0000000000..6a63450cb4 --- /dev/null +++ b/libs/win32/libjpeg/libjpeg.2010.vcxproj.filters @@ -0,0 +1,186 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.2010.vcxproj b/src/mod/endpoints/mod_sofia/mod_sofia.2010.vcxproj index 5432c3323f..c5b0b0772f 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.2010.vcxproj +++ b/src/mod/endpoints/mod_sofia/mod_sofia.2010.vcxproj @@ -138,6 +138,7 @@ + diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index bf3e36ca19..9e927402e7 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -96,17 +96,35 @@ static switch_status_t channel_send_dtmf(switch_core_session_t *session, const s static switch_status_t channel_receive_event(switch_core_session_t *session, switch_event_t *event); switch_state_handler_table_t crtp_state_handlers = { - .on_init = channel_on_init, - .on_destroy = channel_on_destroy + /*on_init */channel_on_init, + /*on_routing */ NULL, + /*on_execute */ NULL, + /*on_hangup*/ NULL, + /*on_exchange_media*/ NULL, + /*on_soft_execute*/ NULL, + /*on_consume_media*/ NULL, + /*on_hibernate*/ NULL, + /*on_reset*/ NULL, + /*on_park*/ NULL, + /*on_reporting*/ NULL, + /*on_destroy*/ channel_on_destroy + }; switch_io_routines_t crtp_io_routines = { - .outgoing_channel = channel_outgoing_channel, - .read_frame = channel_read_frame, - .write_frame = channel_write_frame, - .receive_message = channel_receive_message, - .receive_event = channel_receive_event, - .send_dtmf = channel_send_dtmf + /*outgoing_channel*/ channel_outgoing_channel, + /*read_frame*/ channel_read_frame, + /*write_frame*/ channel_write_frame, + /*kill_channel*/ NULL, + /*send_dtmf*/ channel_send_dtmf, + /*receive_message*/ channel_receive_message, + /*receive_event*/ channel_receive_event, + /*state_change*/ NULL, + /*read_video_frame*/ NULL, + /*write_video_frame*/ NULL, + /*state_run*/ NULL, + /* resurrect_session*/ NULL + }; From 3389f323636b379ff314a750e1700dabfa312bfe Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Wed, 8 Aug 2012 21:29:06 -0500 Subject: [PATCH 421/822] FS-4504 - tweak --- libs/win32/libjpeg/libjpeg.2010.vcxproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libs/win32/libjpeg/libjpeg.2010.vcxproj b/libs/win32/libjpeg/libjpeg.2010.vcxproj index 734f4b8446..437fb66198 100644 --- a/libs/win32/libjpeg/libjpeg.2010.vcxproj +++ b/libs/win32/libjpeg/libjpeg.2010.vcxproj @@ -156,6 +156,9 @@ true true + + if not exist "$(ProjectDir)..\..\jpeg-8d\jconfig.h" type "$(ProjectDir)..\..\jpeg-8d\jconfig.vc" > "$(ProjectDir)..\..\jpeg-8d\jconfig.h" + @@ -175,6 +178,9 @@ true true + + if not exist "$(ProjectDir)..\..\jpeg-8d\jconfig.h" type "$(ProjectDir)..\..\jpeg-8d\jconfig.vc" > "$(ProjectDir)..\..\jpeg-8d\jconfig.h" + From a21e4ad681d23358d6d6b7567ceccb7f74bcf4cc Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Thu, 9 Aug 2012 08:31:12 -0500 Subject: [PATCH 422/822] FS-4504 vs2010 update x64 download settings for libjpeg --- Freeswitch.2010.sln | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Freeswitch.2010.sln b/Freeswitch.2010.sln index 588637f438..505e448276 100644 --- a/Freeswitch.2010.sln +++ b/Freeswitch.2010.sln @@ -3620,11 +3620,13 @@ Global {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|Win32.ActiveCfg = Debug|Win32 {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|Win32.Build.0 = Debug|Win32 {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|x64.ActiveCfg = Debug|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|x64.Build.0 = Debug|Win32 {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|x64 Setup.ActiveCfg = Debug|Win32 {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|x86 Setup.ActiveCfg = Debug|Win32 {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|Win32.ActiveCfg = Release|Win32 {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|Win32.Build.0 = Release|Win32 {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|x64.ActiveCfg = Release|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|x64.Build.0 = Release|Win32 {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|x64 Setup.ActiveCfg = Release|Win32 {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|x86 Setup.ActiveCfg = Release|Win32 {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.All|Win32.ActiveCfg = Release|Win32 From a4115a099be77ae001a1d13d0ba0a1cc1e0f624c Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Thu, 9 Aug 2012 08:34:26 -0500 Subject: [PATCH 423/822] FS-4504 vs2010 add libjpeg download dependency --- Freeswitch.2010.sln | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Freeswitch.2010.sln b/Freeswitch.2010.sln index 505e448276..26c0348421 100644 --- a/Freeswitch.2010.sln +++ b/Freeswitch.2010.sln @@ -532,6 +532,9 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download libjpeg", "libs\win32\Download libjpeg.2010.vcxproj", "{652AD5F7-8488-489F-AAD0-7FBE064703B6}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libjpeg", "libs\win32\libjpeg\libjpeg.2010.vcxproj", "{019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}" + ProjectSection(ProjectDependencies) = postProject + {652AD5F7-8488-489F-AAD0-7FBE064703B6} = {652AD5F7-8488-489F-AAD0-7FBE064703B6} + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From d1b45ae65b49e602c4fb649d0220cfb79ca7e3b4 Mon Sep 17 00:00:00 2001 From: Steve Underwood Date: Thu, 9 Aug 2012 21:58:22 +0800 Subject: [PATCH 424/822] A couple of typos in spandsp Improvements to image flattening in spandsp's image translate code --- libs/spandsp/src/image_translate.c | 16 +++++++--------- libs/spandsp/src/spandsp/ima_adpcm.h | 2 +- libs/spandsp/src/spandsp/private/ima_adpcm.h | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/libs/spandsp/src/image_translate.c b/libs/spandsp/src/image_translate.c index 54037990fc..4ee2c211bf 100644 --- a/libs/spandsp/src/image_translate.c +++ b/libs/spandsp/src/image_translate.c @@ -163,10 +163,9 @@ static int image_gray16_to_colour16_row(uint16_t colour16[], uint16_t gray16[], for (i = pixels - 1; i >= 0; i--) { - /* TODO: need to balance the colours */ - colour16[3*i] = gray16[i]; - colour16[3*i + 1] = gray16[i]; - colour16[3*i + 2] = gray16[i]; + colour16[3*i] = saturateu16((gray16[i]*36532) >> 15); + colour16[3*i + 1] = saturateu16((gray16[i]*37216) >> 16); + colour16[3*i + 2] = saturateu16((gray16[i]*47900) >> 14); } return pixels; } @@ -178,10 +177,9 @@ static int image_gray16_to_colour8_row(uint8_t colour8[], uint16_t gray16[], int for (i = pixels - 1; i >= 0; i--) { - /* TODO: need to balance the colours */ - colour8[3*i] = gray16[i] >> 8; - colour8[3*i + 1] = gray16[i] >> 8; - colour8[3*i + 2] = gray16[i] >> 8; + colour8[3*i] = saturateu8((gray16[i]*36532) >> 23); + colour8[3*i + 1] = saturateu8((gray16[i]*37216) >> 24); + colour8[3*i + 2] = saturateu8((gray16[i]*47900) >> 22); } return pixels; } @@ -530,7 +528,7 @@ SPAN_DECLARE(int) image_translate_row(image_translate_state_t *s, uint8_t buf[], else { i = s->output_width*s->output_bytes_per_pixel; - memcpy(buf, s->pixel_row[1], i); + memcpy(buf, s->pixel_row[0], i); } return i; } diff --git a/libs/spandsp/src/spandsp/ima_adpcm.h b/libs/spandsp/src/spandsp/ima_adpcm.h index 292bdd5d83..2942efa859 100644 --- a/libs/spandsp/src/spandsp/ima_adpcm.h +++ b/libs/spandsp/src/spandsp/ima_adpcm.h @@ -1,7 +1,7 @@ /* * SpanDSP - a series of DSP components for telephony * - * ima_adpcm.c - Conversion routines between linear 16 bit PCM data and + * ima_adpcm.h - Conversion routines between linear 16 bit PCM data and * IMA/DVI/Intel ADPCM format. * * Written by Steve Underwood diff --git a/libs/spandsp/src/spandsp/private/ima_adpcm.h b/libs/spandsp/src/spandsp/private/ima_adpcm.h index 21ead941af..2fc7d2c114 100644 --- a/libs/spandsp/src/spandsp/private/ima_adpcm.h +++ b/libs/spandsp/src/spandsp/private/ima_adpcm.h @@ -1,7 +1,7 @@ /* * SpanDSP - a series of DSP components for telephony * - * private/ima_adpcm.c - Conversion routines between linear 16 bit PCM data + * private/ima_adpcm.h - Conversion routines between linear 16 bit PCM data * and IMA/DVI/Intel ADPCM format. * * Written by Steve Underwood From d3c89bae347f64cc37b483138010db767d97d4b4 Mon Sep 17 00:00:00 2001 From: Steve Underwood Date: Thu, 9 Aug 2012 22:19:49 +0800 Subject: [PATCH 425/822] Fixed a misplaced #endif that only causes trouble when you hit the right combination --- libs/spandsp/tests/v27ter_tests.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libs/spandsp/tests/v27ter_tests.c b/libs/spandsp/tests/v27ter_tests.c index db5a13d29f..93bda4c815 100644 --- a/libs/spandsp/tests/v27ter_tests.c +++ b/libs/spandsp/tests/v27ter_tests.c @@ -231,7 +231,11 @@ static void qam_report(void *user_data, const complexf_t *constel, const complex { printf("Equalizer B:\n"); for (i = 0; i < len; i++) +#if defined(SPANDSP_USE_FIXED_POINT) printf("%3d (%15.5f, %15.5f)\n", i, coeffs[i].re/V27TER_CONSTELLATION_SCALING_FACTOR, coeffs[i].im/V27TER_CONSTELLATION_SCALING_FACTOR); +#else + printf("%3d (%15.5f, %15.5f) -> %15.5f\n", i, coeffs[i].re, coeffs[i].im, powerf(&coeffs[i])); +#endif #if defined(ENABLE_GUI) if (use_gui) { @@ -241,10 +245,10 @@ static void qam_report(void *user_data, const complexf_t *constel, const complex qam_monitor_update_equalizer(qam_monitor, coeffs, len); #endif } +#endif } update_interval = 100; } -#endif } else { @@ -601,7 +605,7 @@ int main(int argc, char *argv[]) exit(2); } } - return 0; + return 0; } /*- End of function --------------------------------------------------------*/ /*- End of file ------------------------------------------------------------*/ From c8c85fc27fda11260cd8e950bf5ed3ab5a0d1fbb Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Thu, 9 Aug 2012 11:15:07 -0400 Subject: [PATCH 426/822] add t38_options and media_type to rtp term --- .../mod_media_gateway/media_gateway.c | 3 ++ .../mod_media_gateway/mod_media_gateway.h | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 9df5e2a2e0..63646c4943 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -125,6 +125,9 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, kRFC2833PT, "%d", term->u.rtp.rfc2833_pt); switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, kRATE, "%d", term->u.rtp.rate); switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, kCODEC, term->u.rtp.codec); + + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, kMEDIATYPE, mg_media_type2str(term->u.rtp.media_type)); + } else if (term->type == MG_TERM_TDM) { switch_snprintf(dialstring, sizeof dialstring, "tdm/%s", term->name); diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index 46f850ff16..4285526af3 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -79,6 +79,7 @@ typedef struct mg_context_s mg_context_t; #define kRFC2833PT "rfc2833_pt" #define kMODE "mode" #define kRATE "rate" +#define kMEDIATYPE "media_type" /* TDM parameters understood by the controllable channel */ #define kSPAN_ID "span" @@ -96,6 +97,32 @@ enum { } mg_termination_flags; + +typedef enum { + MGM_AUDIO = 0, + MGM_IMAGE, + MGM_INVALID +} mg_media_type_t; + +static inline const char *mg_media_type2str(mg_media_type_t type) { + switch (type) { + case MGM_AUDIO: + return "audio"; + case MGM_IMAGE: + return "image"; + case MGM_INVALID: + return NULL; + } +} + +static inline mg_media_type_t mg_media_type_parse(const char *str) { + if (!strcasecmp(str, "audio")) { + return MGM_AUDIO; + } else if (!strcasecmp(str, "image")) { + return MGM_IMAGE; + } +} + struct mg_context_s { uint32_t context_id; mg_termination_t *terminations[MG_CONTEXT_MAX_TERMS]; @@ -133,6 +160,8 @@ struct mg_termination_s { int rate; /*!< Sampling rate */ const char *codec; /*!< Codec to use, using the freeswitch nomenclature. This could be "PCMU" for G711.U, "PCMA" for G711.A, or "G729" for g729 */ int term_id; + switch_t38_options_t t38_options; + mg_media_type_t media_type; } rtp; struct { From 83e0d9c3bd34711cf9368606d705c440647c7b5e Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Thu, 9 Aug 2012 11:18:13 -0400 Subject: [PATCH 427/822] should be a ptr --- src/mod/endpoints/mod_media_gateway/mod_media_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index 4285526af3..d0041401d4 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -160,7 +160,7 @@ struct mg_termination_s { int rate; /*!< Sampling rate */ const char *codec; /*!< Codec to use, using the freeswitch nomenclature. This could be "PCMU" for G711.U, "PCMA" for G711.A, or "G729" for g729 */ int term_id; - switch_t38_options_t t38_options; + switch_t38_options_t *t38_options; mg_media_type_t media_type; } rtp; From f254f2a5fe2a39f1cbe42d033a219ffdd24d85d3 Mon Sep 17 00:00:00 2001 From: Christopher Rienzo Date: Thu, 9 Aug 2012 15:57:51 +0000 Subject: [PATCH 428/822] Add default configuration example to mod_speex/conf/autoload_configs --- .../conf/autoload_configs/speex.conf.xml | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/mod/codecs/mod_speex/conf/autoload_configs/speex.conf.xml diff --git a/src/mod/codecs/mod_speex/conf/autoload_configs/speex.conf.xml b/src/mod/codecs/mod_speex/conf/autoload_configs/speex.conf.xml new file mode 100644 index 0000000000..220229037a --- /dev/null +++ b/src/mod/codecs/mod_speex/conf/autoload_configs/speex.conf.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From f044f4625034319693f6dd81645483c4a4a9be7c Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Thu, 9 Aug 2012 11:56:29 -0500 Subject: [PATCH 429/822] add apr stub to get the real OS socket --- src/include/switch_apr.h | 1 + src/include/switch_types.h | 8 ++++++++ src/switch_apr.c | 5 +++++ 3 files changed, 14 insertions(+) diff --git a/src/include/switch_apr.h b/src/include/switch_apr.h index e7a41d03d9..bd19353991 100644 --- a/src/include/switch_apr.h +++ b/src/include/switch_apr.h @@ -1443,6 +1443,7 @@ SWITCH_DECLARE(switch_status_t) switch_socket_create_pollset(switch_pollfd_t ** */ SWITCH_DECLARE(switch_status_t) switch_socket_create_pollfd(switch_pollfd_t **pollfd, switch_socket_t *sock, int16_t flags, void *client_data, switch_memory_pool_t *pool); SWITCH_DECLARE(switch_status_t) switch_match_glob(const char *pattern, switch_array_header_t ** result, switch_memory_pool_t *p); +SWITCH_DECLARE(switch_status_t) switch_os_sock_get(switch_os_socket_t *thesock, switch_socket_t *sock); SWITCH_DECLARE(switch_status_t) switch_socket_addr_get(switch_sockaddr_t ** sa, switch_bool_t remote, switch_socket_t *sock); /** diff --git a/src/include/switch_types.h b/src/include/switch_types.h index b4ec368021..696078a06e 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1784,6 +1784,14 @@ typedef enum { SSH_FLAG_STICKY = (1 << 0) } switch_state_handler_flag_t; +#ifdef WIN32 +typedef SOCKET apr_os_sock_t; +#else +typedef int apr_os_sock_t; +#endif + +typedef apr_os_sock_t switch_os_socket_t; + typedef struct apr_pool_t switch_memory_pool_t; typedef uint16_t switch_port_t; typedef uint8_t switch_payload_t; diff --git a/src/switch_apr.c b/src/switch_apr.c index 5936c7223e..c854c97617 100644 --- a/src/switch_apr.c +++ b/src/switch_apr.c @@ -665,6 +665,11 @@ SWITCH_DECLARE(switch_status_t) switch_thread_create(switch_thread_t ** new_thre /* socket stubs */ +SWITCH_DECLARE(switch_status_t) switch_os_sock_get(switch_os_socket_t *thesock, switch_socket_t *sock) +{ + return apr_os_sock_get(thesock, sock); +} + SWITCH_DECLARE(switch_status_t) switch_socket_addr_get(switch_sockaddr_t ** sa, switch_bool_t remote, switch_socket_t *sock) { return apr_socket_addr_get(sa, (apr_interface_e) remote, sock); From 17755cbd571ae7ffe9b89aa58dad1f87a2394454 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Thu, 9 Aug 2012 14:22:30 -0400 Subject: [PATCH 430/822] adding t38 option code --- .../media_gateway_cmd_handler.c | 5 +- .../mod_media_gateway/media_gateway_stack.h | 1 + .../mod_media_gateway/media_gateway_utils.c | 464 +++++++++++++----- .../mod_media_gateway/mod_media_gateway.h | 2 + 4 files changed, 335 insertions(+), 137 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 1eacf4fb23..cff0c7ffa9 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -727,6 +727,7 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i } + mg_print_t38_attributes(term); /* TODO - locally assigned SDP must be the part of termination...which we can use to fill responses*/ @@ -793,6 +794,7 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i mg_fill_mgco_termid(out_termId, (char*)term->name, strlen((char*)term->name), &rsp.u.mgCmdRsp[0]->memCp); } + if(is_rtp){ /* Whatever Media descriptor we have received, we can copy that and then * whatever we want we can modify the fields */ /* Kapil - TODO - will see if there is any problem of coping the @@ -822,7 +824,6 @@ switch_status_t handle_mg_add_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *i } /* only for RTP */ - if(is_rtp){ if(SWITCH_STATUS_FALSE == mg_build_sdp(&desc->u.media, inc_med_desc, mg_profile, term, &rsp.u.mgCmdRsp[0]->memCp)) { if(term->mg_error_code && (*term->mg_error_code == MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT)){ mg_util_set_err_string(&errTxt, " Unsupported Codec "); @@ -1209,6 +1210,8 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand term->u.rtp.term_id); } + mg_print_t38_attributes(term); + /* SDP updated to termination */ megaco_activate_termination(term); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index 1c7e8c614c..d06e796c54 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -218,6 +218,7 @@ switch_status_t mg_send_ins_service_change(megaco_profile_t* mg_profile, const c switch_status_t mg_send_notify(megaco_profile_t* mg_profile, const char* term_name, MgMgcoObsEvt* oevt); switch_status_t mg_send_dtmf_notify(megaco_profile_t* mg_profile, const char* term_name, char* digits, int num_of_collected_digits); switch_status_t mg_send_ito_notify(megaco_profile_t* mg_profile); +void mg_print_t38_attributes(mg_termination_t* term); switch_status_t mg_util_build_obs_evt_desc (MgMgcoObsEvt *obs_event, MgMgcoRequestId *request_id, MgMgcoObsEvtDesc **ptr_obs_desc); void mg_print_time(); switch_status_t mg_activate_ito_timer(megaco_profile_t* profile); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index 11d68f026c..7fd2d2a1ca 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -430,6 +430,56 @@ void mg_util_set_cmd_name_string (MgStr *errTxt, MgMgcoCommand *cmd) } } +/*****************************************************************************************************************************/ +void mgco_fill_t38_sdp_attr(CmSdpAttrSet *s, mg_termination_t* term, CmMemListCp *memCp) +{ + int i=0x00; + + if(!term->u.rtp.t38_options) return; + if (!s->numComp.pres) return ; + + for (i = 0; i < s->numComp.val; i++) { + CmSdpAttr *a = s->attr[i]; + if(NOTPRSNT == a->type.pres) continue; + + switch(a->type.val) + { + case CM_SDP_ATTR_T38_FAX: + { + CmSdpAttrT38Fax* f = &a->u.fax; + if(NOTPRSNT == f->type.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "CM_SDP_ATTR_T38_FAX: TYPE not present \n"); + break; + } + +/* NOTE - Ideally i should not change ,whatever is coming we can return..due to +trillium issue forcefully coping the data...will remove once get trillium fix*/ +if(f->type.val == CM_SDP_ATTR_T38_FAX_UNKNOWN) { +if((i==0) && term->u.rtp.t38_options->T38FaxRateManagement){ +MG_SET_TKNSTROSXL((f->u.unknown.name),strlen("FaxRateManagement"),"FaxRateManagement", memCp); +MG_SET_TKNSTROSXL((f->u.unknown.val), + strlen(term->u.rtp.t38_options->T38FaxRateManagement), + term->u.rtp.t38_options->T38FaxRateManagement, memCp); +} +if((i==1) && term->u.rtp.t38_options->T38FaxUdpEC){ +MG_SET_TKNSTROSXL((f->u.unknown.name),strlen("FaxUdpEC"),"FaxUdpEC", memCp); +MG_SET_TKNSTROSXL((f->u.unknown.val), + strlen(term->u.rtp.t38_options->T38FaxUdpEC), + term->u.rtp.t38_options->T38FaxUdpEC, memCp); +} +if((i==2)){ +char buf[10] = {0}; +sprintf(buf,"%d",term->u.rtp.t38_options->T38MaxBitRate); +MG_SET_TKNSTROSXL((f->u.unknown.name),strlen("MaxBitRate"),"MaxBitRate", memCp); +MG_SET_TKNSTROSXL((f->u.unknown.val), + strlen(buf), buf, memCp); +} +} +} +} +} +} /*****************************************************************************************************************************/ void mgco_handle_sdp_attr_set(CmSdpAttrSet *s, mg_termination_t* term) { @@ -754,9 +804,47 @@ void mgco_handle_sdp_attr_set(CmSdpAttrSet *s, mg_termination_t* term) break; } case CM_SDP_ATTR_T38_FAX: - { - break; - } + { + CmSdpAttrT38Fax* f = &a->u.fax; + if(NOTPRSNT == f->type.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "CM_SDP_ATTR_T38_FAX: TYPE not present \n"); + break; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t CM_SDP_ATTR_T38_FAX: type=%d\n", f->type.val); + + if(f->type.val == CM_SDP_ATTR_T38_FAX_UNKNOWN) { + if(f->u.unknown.name.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "T38: Attribute : name[len=%d, value=%s] \n", + f->u.unknown.name.len,(char*)f->u.unknown.name.val); + } + if(f->u.unknown.val.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "T38: Attribute : value[len=%d, value=%s] \n", + f->u.unknown.val.len,(char*)f->u.unknown.val.val); + } + } + + /* filling default values */ + if(NULL == term->u.rtp.t38_options){ + term->u.rtp.t38_options = + switch_core_alloc(term->pool, sizeof *term->u.rtp.t38_options); + } + term->u.rtp.t38_options->T38FaxVersion = 0x01; + term->u.rtp.t38_options->T38MaxBitRate = 14400; + term->u.rtp.t38_options->T38FaxRateManagement = + switch_core_strdup(term->pool,"transferredTCF") ; + //term->u.rtp.t38_options->T38FaxMaxBuffer = ; + //term->u.rtp.t38_options->T38FaxMaxDatagram = ; + term->u.rtp.t38_options->T38FaxUdpEC = + switch_core_strdup(term->pool,"t38UDPRedundancy") ; + //term->u.rtp.t38_options->T38VendorInfo = + + break; + } default: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Not supported Type[%d]\n",a->type.val); break; @@ -765,8 +853,6 @@ void mgco_handle_sdp_attr_set(CmSdpAttrSet *s, mg_termination_t* term) }else{ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "a-line not present \n"); } - - } void mgco_handle_sdp_c_line(CmSdpConn *s, mg_termination_t* term, mgco_sdp_types_e sdp_type) @@ -852,7 +938,8 @@ void mgco_handle_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sd CmSdpMedProtoFmts *a = s->pflst[i]; /*Prot*/ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " Proto Type = %d \n", (NOTPRSNT != a->prot.type.pres)?a->prot.type.val:-1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + " Proto Type = %d \n", (NOTPRSNT != a->prot.type.pres)?a->prot.type.val:-1); switch(a->prot.type.val) { case CM_SDP_MEDIA_PROTO_UNKNOWN: @@ -867,6 +954,12 @@ void mgco_handle_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sd (NOTPRSNT != a->prot.u.subtype.type.pres)?a->prot.u.subtype.type.val: -1); break; } + case CM_SDP_MEDIA_PROTO_UDPTL: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + " Proto Type T38 -UDPTL , subtype = %d \n", + (NOTPRSNT != a->prot.u.subtype.type.pres)?a->prot.u.subtype.type.val: -1); + } } /*repeated from "prot" field */ @@ -881,7 +974,8 @@ void mgco_handle_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sd int i = 0x00; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " CM_SDP_MEDIA_PROTO_RTP: \n"); if(NOTPRSNT != r->num.pres){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " Number of Formats[%d] \n", r->num.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + " Number of Formats[%d] \n", r->num.val); for(i=0;inum.val;i++){ mgco_print_CmSdpU8OrNil(r->fmts[i]); @@ -961,10 +1055,31 @@ void mgco_handle_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sd break; } - case CM_SDP_UDPTL_FMT_T38: + case CM_SDP_MEDIA_PROTO_UDPTL: { - /*CmSdpMedFmtUdptlList* t = &a->u.t38;*/ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " CM_SDP_UDPTL_FMT_T38: \n"); + CmSdpMedFmtUdptlList* t = &a->u.t38; + int i = 0; + + if(NOTPRSNT == t->num.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + " CM_SDP_MEDIA_PROTO_UDPTL: no format defines..\n"); + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + " CM_SDP_MEDIA_PROTO_UDPTL: formats[%d]\n", t->num.val); + + for(i=0; i< t->num.val;i++) + { + CmSdpT38Fmt* f = t->fmts[i]; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + " f->knownFmt.pres=%d, f->knownFmt.val=%d\n", + f->knownFmt.pres,f->knownFmt.val); + if(f->unknownFmt.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "f->unknownFmt.val[%s]\n",f->unknownFmt.val); + } + } + break; } default: @@ -985,7 +1100,8 @@ void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sd if (sdp->numComp.pres == NOTPRSNT) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, - " No %s SDP present \n", (MG_SDP_LOCAL== sdp_type)?"MG_SDP_LOCAL":"MG_SDP_REMOTE"); + " No %s SDP present \n", + (MG_SDP_LOCAL== sdp_type)?"MG_SDP_LOCAL":"MG_SDP_REMOTE"); return; } @@ -1000,38 +1116,52 @@ void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sd /************************************************************************************************************************/ /* Version */ if(NOTPRSNT != s->ver.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " SDP Version = %d \n", s->ver.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + " SDP Version = %d \n", s->ver.val); } /************************************************************************************************************************/ /* Orig */ if(NOTPRSNT != s->orig.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "********** SDP orig line ****** \n \t Type = %d \n", s->orig.type.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "********** SDP orig line ****** \n \t Type = %d \n", + s->orig.type.val); if(NOTPRSNT != s->orig.orig.pres.pres) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t User Name = %s \n", - (NOTPRSNT != s->orig.orig.usrName.pres)?(char*)s->orig.orig.usrName.val:"Not Present"); + (NOTPRSNT != s->orig.orig.usrName.pres)? + (char*)s->orig.orig.usrName.val:"Not Present"); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Session Id = %s \n", - (NOTPRSNT != s->orig.orig.sessId.pres)?(char*)s->orig.orig.sessId.val:"Not Present"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t Session Id = %s \n", + (NOTPRSNT != s->orig.orig.sessId.pres)? + (char*)s->orig.orig.sessId.val:"Not Present"); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Session Version = %s \n", - (NOTPRSNT != s->orig.orig.sessVer.pres)?(char*)s->orig.orig.sessVer.val:"Not Present"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t Session Version = %s \n", + (NOTPRSNT != s->orig.orig.sessVer.pres)? + (char*)s->orig.orig.sessVer.val:"Not Present"); /* sdpAddr */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Net Type = %d \n", - (NOTPRSNT != s->orig.orig.sdpAddr.netType.type.pres)?s->orig.orig.sdpAddr.netType.type.val:-1); + (NOTPRSNT != s->orig.orig.sdpAddr.netType.type.pres)? + s->orig.orig.sdpAddr.netType.type.val:-1); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Address Type = %d \n", - (NOTPRSNT != s->orig.orig.sdpAddr.addrType.pres)?s->orig.orig.sdpAddr.addrType.val:-1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t Address Type = %d \n", + (NOTPRSNT != s->orig.orig.sdpAddr.addrType.pres) + ?s->orig.orig.sdpAddr.addrType.val:-1); /* print IPV4 address */ - if (s->orig.orig.sdpAddr.addrType.pres && s->orig.orig.sdpAddr.addrType.val == CM_SDP_ADDR_TYPE_IPV4 && + if (s->orig.orig.sdpAddr.addrType.pres && + s->orig.orig.sdpAddr.addrType.val == CM_SDP_ADDR_TYPE_IPV4 && s->orig.orig.sdpAddr.netType.type.val == CM_SDP_NET_TYPE_IN && - s->orig.orig.sdpAddr.u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) { + s->orig.orig.sdpAddr.u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) + { if (s->orig.orig.sdpAddr.u.ip4.addrType.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Address: %d.%d.%d.%d\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "Address: %d.%d.%d.%d\n", s->orig.orig.sdpAddr.u.ip4.u.ip.b[0].val, s->orig.orig.sdpAddr.u.ip4.u.ip.b[1].val, s->orig.orig.sdpAddr.u.ip4.u.ip.b[2].val, @@ -1039,18 +1169,20 @@ void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sd } }else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t O-line not present \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t O-line not present \n"); } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "********** ****** \n"); } } else{ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t O-line not present \n"); } - /************************************************************************************************************************/ +/************************************************************************************************************************/ /* Session Name (s = line) */ if(NOTPRSNT != s->sessName.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Session Name = %s \n", s->sessName.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t Session Name = %s \n", s->sessName.val); } else{ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t s-line not present \n"); } @@ -1059,18 +1191,22 @@ void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sd /* Session Info(i= line) */ if(NOTPRSNT != s->info.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Session Info = %s \n", s->info.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t Session Info = %s \n", s->info.val); } else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t i-line not present \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t i-line not present \n"); } /************************************************************************************************************************/ /* Session Uri */ if(NOTPRSNT != s->uri.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Session Uri = %s \n", s->uri.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t Session Uri = %s \n", s->uri.val); } else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t uri not present \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t uri not present \n"); } /************************************************************************************************************************/ @@ -1098,26 +1234,34 @@ void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sd if(NOTPRSNT != s->sdpTime.pres.pres) { if(NOTPRSNT != s->sdpTime.sdpOpTimeSet.numComp.pres) { int i = 0x00; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SDP op time present with total component[%d]\n", s->sdpTime.sdpOpTimeSet.numComp.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "SDP op time present with total component[%d]\n", + s->sdpTime.sdpOpTimeSet.numComp.val); for (i = 0;isdpTime.sdpOpTimeSet.numComp.val;i++){ CmSdpOpTime* t = s->sdpTime.sdpOpTimeSet.sdpOpTime[i]; if(NOTPRSNT == t->pres.pres) continue; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Start Time = %s \n", - (NOTPRSNT != t->startTime.pres)?(char*)t->startTime.val:"Not Present"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t Start Time = %s \n", + (NOTPRSNT != t->startTime.pres)? + (char*)t->startTime.val:"Not Present"); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Stop Time = %s \n", - (NOTPRSNT != t->stopTime.pres)?(char*)t->stopTime.val:"Not Present"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t Stop Time = %s \n", + (NOTPRSNT != t->stopTime.pres)? + (char*)t->stopTime.val:"Not Present"); /*repeat time repFieldSet */ if(NOTPRSNT != t->repFieldSet.numComp.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SDP repeat time present with total component[%d]\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "SDP repeat time present with total component[%d]\n", t->repFieldSet.numComp.val); /*TODO - print repeat fields */ }else{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SDP repeat time not present \n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "SDP repeat time not present \n"); } } /* sdpOpTimeSet.numComp for loop -- end */ }else{/*sdpOpTimeSet.numComp.pres if -- end */ @@ -1139,7 +1283,8 @@ void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sd (NOTPRSNT != s->keyType.keyType.pres)?s->keyType.keyType.val:-1); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Key Data = %s \n", - (NOTPRSNT != s->keyType.key_data.pres)?(char*)s->keyType.key_data.val:"Not Present"); + (NOTPRSNT != s->keyType.key_data.pres)? + (char*)s->keyType.key_data.val:"Not Present"); }else{ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "k-line not present \n"); } @@ -1153,7 +1298,9 @@ void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sd /* Media Descriptor Set */ if (s->mediaDescSet.numComp.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "****** Media Descriptor Set present with numComp[%d]\n", s->mediaDescSet.numComp.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "****** Media Descriptor Set present with numComp[%d]\n", + s->mediaDescSet.numComp.val); for (mediaId = 0; mediaId < s->mediaDescSet.numComp.val; mediaId++) { CmSdpMediaDesc *desc = s->mediaDescSet.mediaDesc[mediaId]; @@ -1162,11 +1309,17 @@ void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sd /* Media Field */ { CmSdpMediaField* f = &desc->field; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Media Type = %d \n",(NOTPRSNT != f->mediaType.pres)?f->mediaType.val:-1); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Media = %s \n",(NOTPRSNT != f->media.pres)?(char*)f->media.val:"Not Present"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t Media Type = %d \n", + (NOTPRSNT != f->mediaType.pres)?f->mediaType.val:-1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t Media = %s \n",(NOTPRSNT != f->media.pres)? + (char*)f->media.val:"Not Present"); + /* Channel ID */ if(NOTPRSNT != f->id.type.pres){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t VcId Type = %d \n", f->id.type.val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t VcId Type = %d \n", f->id.type.val); switch(f->id.type.val){ case CM_SDP_VCID_PORT: { @@ -1208,9 +1361,10 @@ void mgco_handle_incoming_sdp(CmSdpInfoSet *sdp, mg_termination_t* term, mgco_sd } /*info */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t Info = %s \n",(NOTPRSNT != desc->info.pres)?(char*)desc->info.val:"Not Present"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "\t Info = %s \n",(NOTPRSNT != desc->info.pres)?(char*)desc->info.val:"Not Present"); - /*connection set */ + /*connection set */ { int cnt=0x00; if(NOTPRSNT != desc->connSet.numComp.pres){ @@ -1976,122 +2130,160 @@ switch_status_t mg_build_sdp(MgMgcoMediaDesc* out, MgMgcoMediaDesc* inc, megaco_ } /**********************************************************************************************************************************/ /* orig (o- line) fill with our info */ - MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.pres), 1); - MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.type), CM_SDP_SPEC); - MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.orig.pres), 1); +MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.pres), 1); +MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.type), CM_SDP_SPEC); +MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->orig.orig.pres), 1); - MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.usrName, 1, "-", memCp); - MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.sessId, 1, "0", memCp); - MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.sessVer, 1, "0", memCp); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.netType.type), - CM_SDP_NET_TYPE_IN); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.addrType), +MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.usrName, 1, "-", memCp); +MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.sessId, 1, "0", memCp); +MG_SET_TKNSTROSXL(psdp->info[psdp->numComp.val-1]->orig.orig.sessVer, 1, "0", memCp); +MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.netType.type), +CM_SDP_NET_TYPE_IN); +MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.addrType), CM_SDP_ADDR_TYPE_IPV4); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.addrType), +MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.addrType), CM_SDP_IPV4_IP_UNI); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.addrType), +MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.addrType), CM_SDP_IPV4_IP_UNI); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[0]), +MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[0]), atoi(ipAddress[0])); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[1]), +MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[1]), atoi(ipAddress[1])); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[2]), +MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[2]), atoi(ipAddress[2])); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[3]), +MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->orig.orig.sdpAddr.u.ip4.u.ip.b[3]), atoi(ipAddress[3])); /**********************************************************************************************************************************/ /* session-name , let it be like this if present, else skip it */ /**********************************************************************************************************************************/ /* "c=" line - ipaddress */ - MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.netType.type),CM_SDP_NET_TYPE_IN); - MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.addrType), CM_SDP_ADDR_TYPE_IPV4); - MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.u.ip4.addrType), CM_SDP_IPV4_IP_UNI); +MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.netType.type),CM_SDP_NET_TYPE_IN); +MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.addrType), CM_SDP_ADDR_TYPE_IPV4); +MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->conn.u.ip4.addrType), CM_SDP_IPV4_IP_UNI); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[0]), atoi(ipAddress[0])); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[1]), atoi(ipAddress[1])); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[2]), atoi(ipAddress[2])); - MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[3]), atoi(ipAddress[3])); +MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[0]), atoi(ipAddress[0])); +MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[1]), atoi(ipAddress[1])); +MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[2]), atoi(ipAddress[2])); +MG_SET_VAL_PRES( (psdp->info[psdp->numComp.val-1]->conn.u.ip4.u.uniIp.b[3]), atoi(ipAddress[3])); /**********************************************************************************************************************************/ - /* t= line */ - MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->sdpTime.pres),1); +/* t= line */ +MG_INIT_TOKEN_VALUE(&(psdp->info[psdp->numComp.val-1]->sdpTime.pres),1); /**********************************************************************************************************************************/ - /* fill media descriptors */ - { - CmSdpMediaDescSet* med = &psdp->info[psdp->numComp.val-1]->mediaDescSet; - CmSdpMediaDesc* media; +/* fill media descriptors */ +{ +CmSdpMediaDescSet* med = &psdp->info[psdp->numComp.val-1]->mediaDescSet; +CmSdpMediaDesc* media; - if((NOTPRSNT == med->numComp.pres) || (0 == med->numComp.val)){ - mg_add_lcl_media(med, mg_profile, term, memCp); - }else{ - for(j =0;j < med->numComp.val; j++){ - media = med->mediaDesc[j]; - /* check for choose port and fill the port */ - if(NOTPRSNT != media->field.id.type.pres){ - if(CM_SDP_VCID_CHOOSE == media->field.id.type.val){ - MG_INIT_TOKEN_VALUE(&(media->field.id.type),CM_SDP_VCID_PORT); - MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.type),CM_SDP_PORT_INT); - MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.pres),1); - MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.type), CM_SDP_SPEC); - MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.val), term->u.rtp.local_port); +if((NOTPRSNT == med->numComp.pres) || (0 == med->numComp.val)){ + mg_add_lcl_media(med, mg_profile, term, memCp); +}else{ + for(j =0;j < med->numComp.val; j++){ + media = med->mediaDesc[j]; + /* check for choose port and fill the port */ + if(NOTPRSNT != media->field.id.type.pres){ + if(CM_SDP_VCID_CHOOSE == media->field.id.type.val){ + MG_INIT_TOKEN_VALUE(&(media->field.id.type),CM_SDP_VCID_PORT); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.type),CM_SDP_PORT_INT); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.pres),1); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.type), CM_SDP_SPEC); + MG_INIT_TOKEN_VALUE(&(media->field.id.u.port.u.portInt.port.val), term->u.rtp.local_port); - } - } + } + } - /* check for codec */ - if((NOTPRSNT == media->field.par.numProtFmts.pres) || - (0 == media->field.par.numProtFmts.val)){ - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"No codec specified in incoming local descriptor \n"); - mg_add_supported_media_codec(media, mg_profile, term, memCp ); - }else{ - /* check for media format/codec */ - for(k =0;k < media->field.par.numProtFmts.val; k++){ - format = media->field.par.pflst[k]; - if ((NOTPRSNT != format->protType.pres) && - (CM_SDP_MEDIA_PROTO_RTP == format->protType.val)) - { - if((NOTPRSNT != format->u.rtp.num.pres) - &&(0 != format->u.rtp.num.val)) - { - /* If the codec type is CHOOSE then we need to fill our list */ - for(i = 0; i < format->u.rtp.num.val; i++) - { - fmt = format->u.rtp.fmts[i]; + /* check for codec */ +if((NOTPRSNT == media->field.par.numProtFmts.pres) || + (0 == media->field.par.numProtFmts.val)){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, + "No codec specified in incoming local descriptor \n"); + mg_add_supported_media_codec(media, mg_profile, term, memCp ); +}else{ +/* check for media format/codec */ + for(k =0;k < media->field.par.numProtFmts.val; k++){ +format = media->field.par.pflst[k]; +if ((NOTPRSNT != format->protType.pres) && + (CM_SDP_MEDIA_PROTO_RTP == format->protType.val)) +{ + if((NOTPRSNT != format->u.rtp.num.pres) + &&(0 != format->u.rtp.num.val)) + { + /* If the codec type is CHOOSE then we need to fill our list */ + for(i = 0; i < format->u.rtp.num.val; i++) { + fmt = format->u.rtp.fmts[i]; + if((NOTPRSNT == fmt->type.pres) || (NOTPRSNT == fmt->val.pres)) continue; + if(CM_SDP_CHOOSE == fmt->type.val){ + choose_codec = 0x1; + } + } + if(choose_codec){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + "CHOOSE codec is requested fill out supported codecs \n"); - if((NOTPRSNT == fmt->type.pres) || (NOTPRSNT == fmt->val.pres)) continue; - - if(CM_SDP_CHOOSE == fmt->type.val){ - choose_codec = 0x1; - } - } - if(choose_codec){ - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "CHOOSE codec is requested fill out supported codecs \n"); - - /* delete existing rtp format list..TODO find better way */ - for(i = 0; i < format->u.rtp.num.val; i++) - { - mgUtlShrinkList((Void ***)&format->u.rtp.fmts, sizeof(CmSdpU8OrNil), &format->u.rtp.num, memCp); - } - /* If the codec type is CHOOSE then we need to fill our list */ - mg_add_supported_media_codec(media, mg_profile, term, memCp); - } - else if (!choose_codec && (SWITCH_STATUS_FALSE == mg_rem_unsupported_codecs(mg_profile, term , &format->u.rtp, &media->attrSet, memCp))) - { - return SWITCH_STATUS_FALSE; - } - } - } - } - } - } - } + /* delete existing rtp format list..TODO find better way */ + for(i = 0; i < format->u.rtp.num.val; i++) + { + mgUtlShrinkList((Void ***)&format->u.rtp.fmts, sizeof(CmSdpU8OrNil), &format->u.rtp.num, memCp); + } + /* If the codec type is CHOOSE then we need to fill our list */ + mg_add_supported_media_codec(media, mg_profile, term, memCp); + } else if (!choose_codec && + (SWITCH_STATUS_FALSE == + mg_rem_unsupported_codecs(mg_profile, term , &format->u.rtp, &media->attrSet, memCp))) + { + return SWITCH_STATUS_FALSE; + } + } +}else if ((NOTPRSNT != format->protType.pres) && + (CM_SDP_MEDIA_PROTO_UDPTL == format->protType.val)){ +/* ideally whatever is received we can send back * +* due to issue in trillium , we need to manually copy the fields now */ + mgco_fill_t38_sdp_attr(&media->attrSet, term, memCp); +} +} +} +} +} +} /**********************************************************************************************************************************/ - } +} - } } return SWITCH_STATUS_SUCCESS; } /*****************************************************************************************************************************/ +void mg_print_t38_attributes(mg_termination_t* term) +{ + switch_assert(term); + + if((MG_TERM_RTP == term->type) && (term->u.rtp.t38_options)){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + "switch_t38_options_t for termination[%s]\n", term->name); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"T38FaxVersion[%d]\n", + term->u.rtp.t38_options->T38FaxVersion); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"T38MaxBitRate[%d]\n", + term->u.rtp.t38_options->T38MaxBitRate); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"T38FaxFillBitRemoval[%d]\n", + term->u.rtp.t38_options->T38FaxFillBitRemoval); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"T38FaxTranscodingMMR[%d]\n", + term->u.rtp.t38_options->T38FaxTranscodingMMR); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"T38FaxTranscodingJBIG[%d]\n", + term->u.rtp.t38_options->T38FaxTranscodingJBIG); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"T38FaxRateManagement[%s]\n", + (NULL != term->u.rtp.t38_options->T38FaxRateManagement)? + term->u.rtp.t38_options->T38FaxRateManagement:"NULL"); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"T38FaxMaxBuffer[%d]\n", + term->u.rtp.t38_options->T38FaxMaxBuffer); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"T38FaxMaxDatagram[%d]\n", + term->u.rtp.t38_options->T38FaxMaxDatagram); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"T38FaxUdpEC[%s]\n", + (NULL != term->u.rtp.t38_options->T38FaxUdpEC)? + term->u.rtp.t38_options->T38FaxUdpEC:"NULL"); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO,"T38VendorInfo[%s]\n", + (NULL != term->u.rtp.t38_options->T38VendorInfo)? + term->u.rtp.t38_options->T38VendorInfo:"NULL"); + } + +} diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index d0041401d4..da705cc86e 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -113,6 +113,7 @@ static inline const char *mg_media_type2str(mg_media_type_t type) { case MGM_INVALID: return NULL; } + return NULL; } static inline mg_media_type_t mg_media_type_parse(const char *str) { @@ -121,6 +122,7 @@ static inline mg_media_type_t mg_media_type_parse(const char *str) { } else if (!strcasecmp(str, "image")) { return MGM_IMAGE; } + return MGM_INVALID; } struct mg_context_s { From 6e8736bb0609c6633adc1ac6abf7f6caf2a8be58 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Thu, 9 Aug 2012 13:42:21 -0500 Subject: [PATCH 431/822] FS-4504 vs2008 pro still need express --- Freeswitch.2008.sln | 32 ++ libs/spandsp/src/libspandsp.2008.vcproj | 28 +- libs/win32/Download libjpeg.2008.vcproj | 97 +++++ libs/win32/libjpeg/libjpeg.2008.vcproj | 531 ++++++++++++++++++++++++ 4 files changed, 676 insertions(+), 12 deletions(-) create mode 100644 libs/win32/Download libjpeg.2008.vcproj create mode 100644 libs/win32/libjpeg/libjpeg.2008.vcproj diff --git a/Freeswitch.2008.sln b/Freeswitch.2008.sln index 781fdcb766..62b24591a7 100644 --- a/Freeswitch.2008.sln +++ b/Freeswitch.2008.sln @@ -718,6 +718,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtiff", "libs\spandsp\src EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspandsp", "libs\spandsp\src\libspandsp.2008.vcproj", "{1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}" ProjectSection(ProjectDependencies) = postProject + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A} = {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A} {329A6FA0-0FCC-4435-A950-E670AEFA9838} = {329A6FA0-0FCC-4435-A950-E670AEFA9838} {DEE932AB-5911-4700-9EEB-8C7090A0A330} = {DEE932AB-5911-4700-9EEB-8C7090A0A330} {401A40CD-5DB4-4E34-AC68-FA99E9FAC014} = {401A40CD-5DB4-4E34-AC68-FA99E9FAC014} @@ -960,6 +961,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_gsmopen", "src\mod\endp EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gsmlib", "src\mod\endpoints\mod_gsmopen\gsmlib\gsmlib-1.10-patched-13ubuntu\win32\gsmlib.vcproj", "{26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libjpeg", "libs\win32\libjpeg\libjpeg.2008.vcproj", "{FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}" + ProjectSection(ProjectDependencies) = postProject + {21A7DA70-555E-49FA-942B-D84A38B61243} = {21A7DA70-555E-49FA-942B-D84A38B61243} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download libjpeg", "libs\win32\Download libjpeg.2008.vcproj", "{21A7DA70-555E-49FA-942B-D84A38B61243}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution All|Win32 = All|Win32 @@ -2719,6 +2727,28 @@ Global {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Debug|x64.ActiveCfg = Debug|x64 {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Release|Win32.ActiveCfg = Release|Win32 {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Release|x64.ActiveCfg = Release|x64 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.All|Win32.ActiveCfg = Debug|x64 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.All|x64.ActiveCfg = Debug|x64 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.All|x64.Build.0 = Debug|x64 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Debug|Win32.Build.0 = Debug|Win32 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Debug|x64.ActiveCfg = Debug|x64 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Debug|x64.Build.0 = Debug|x64 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Release|Win32.ActiveCfg = Release|Win32 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Release|Win32.Build.0 = Release|Win32 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Release|x64.ActiveCfg = Release|x64 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Release|x64.Build.0 = Release|x64 + {21A7DA70-555E-49FA-942B-D84A38B61243}.All|Win32.ActiveCfg = Release|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.All|Win32.Build.0 = Release|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.All|x64.ActiveCfg = Release|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.Debug|Win32.ActiveCfg = Debug|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.Debug|Win32.Build.0 = Debug|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.Debug|x64.ActiveCfg = Debug|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.Debug|x64.Build.0 = Debug|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.Release|Win32.ActiveCfg = Release|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.Release|Win32.Build.0 = Release|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.Release|x64.ActiveCfg = Release|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.Release|x64.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2845,6 +2875,7 @@ Global {B376D494-D7DD-4B2A-99E2-52916D5A8CD8} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B} {23B4D303-79FC-49E0-89E2-2280E7E28940} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B} {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B} + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B} {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A} = {C120A020-773F-4EA3-923F-B67AF28B750D} {4F92B672-DADB-4047-8D6A-4BB3796733FD} = {C120A020-773F-4EA3-923F-B67AF28B750D} {2DEE4895-1134-439C-B688-52203E57D878} = {C120A020-773F-4EA3-923F-B67AF28B750D} @@ -2863,6 +2894,7 @@ Global {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19} = {C120A020-773F-4EA3-923F-B67AF28B750D} {B808178B-82F0-4CF4-A2B1-921939FA24D0} = {C120A020-773F-4EA3-923F-B67AF28B750D} {D578E676-7EC8-4548-BD8B-845C635F14AD} = {C120A020-773F-4EA3-923F-B67AF28B750D} + {21A7DA70-555E-49FA-942B-D84A38B61243} = {C120A020-773F-4EA3-923F-B67AF28B750D} {988CACF7-3FCB-4992-BE69-77872AE67DC8} = {6CD61A1D-797C-470A-BE08-8C31B68BB336} {5BC072DB-3826-48EA-AF34-FE32AA01E83B} = {6CD61A1D-797C-470A-BE08-8C31B68BB336} {FA429E98-8B03-45E6-A096-A4BC5E821DE4} = {6CD61A1D-797C-470A-BE08-8C31B68BB336} diff --git a/libs/spandsp/src/libspandsp.2008.vcproj b/libs/spandsp/src/libspandsp.2008.vcproj index cf68451ede..4ed0560d5e 100644 --- a/libs/spandsp/src/libspandsp.2008.vcproj +++ b/libs/spandsp/src/libspandsp.2008.vcproj @@ -45,7 +45,7 @@ + + @@ -699,11 +703,11 @@ Name="Header Files" > - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/win32/libjpeg/libjpeg.2008.vcproj b/libs/win32/libjpeg/libjpeg.2008.vcproj new file mode 100644 index 0000000000..881078ca9b --- /dev/null +++ b/libs/win32/libjpeg/libjpeg.2008.vcproj @@ -0,0 +1,531 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 8aee9d87b79c24ae3d4d3340dec7229314c2333f Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Thu, 9 Aug 2012 14:52:23 -0400 Subject: [PATCH 432/822] t38 fax code --- src/mod/endpoints/mod_media_gateway/media_gateway_cli.c | 2 ++ src/mod/endpoints/mod_media_gateway/media_gateway_utils.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c index a93bd0467c..31fac31d5c 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c @@ -735,6 +735,8 @@ switch_status_t handle_term_status_cli_cmd(switch_stream_handle_t *stream, megac if(MG_TERM_RTP == term->type){ stream->write_function(stream, "RTP Termination ID [%d] \n",term->u.rtp.term_id); + stream->write_function(stream, "RTP MEDIA Type [%s] \n", + ( MGM_IMAGE == term->u.rtp.media_type)?"MGM_IMAGE":"MGM_AUDIO"); stream->write_function(stream, "RTP Termination Local Address[%s] \n", (NULL != term->u.rtp.local_addr)?term->u.rtp.local_addr:"NULL"); stream->write_function(stream, "RTP Termination Local Port[%d] \n",term->u.rtp.local_port); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index 7fd2d2a1ca..985d383d9e 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -972,6 +972,7 @@ void mgco_handle_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sd { CmSdpMedFmtRtpList* r = &a->u.rtp; int i = 0x00; + term->u.rtp.media_type = MGM_AUDIO; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " CM_SDP_MEDIA_PROTO_RTP: \n"); if(NOTPRSNT != r->num.pres){ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, @@ -1065,6 +1066,8 @@ void mgco_handle_sdp_media_param(CmSdpMedPar *s, mg_termination_t* term, mgco_sd " CM_SDP_MEDIA_PROTO_UDPTL: no format defines..\n"); } + term->u.rtp.media_type = MGM_IMAGE; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " CM_SDP_MEDIA_PROTO_UDPTL: formats[%d]\n", t->num.val); From 8aa901c422fb2b7815edcae216fe5666981f51c9 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Thu, 9 Aug 2012 17:10:27 -0400 Subject: [PATCH 433/822] add spandsp cng-tone detect --- .../mod_media_gateway/media_gateway.c | 12 +-- .../mod_media_gateway/mod_media_gateway.c | 88 ++++--------------- .../mod_media_gateway/mod_media_gateway.h | 2 + 3 files changed, 27 insertions(+), 75 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 63646c4943..ff96998538 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -84,7 +84,7 @@ megaco_profile_t* megaco_get_profile_by_suId(SuId suId) static switch_status_t mg_on_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction) { switch_channel_t *channel = switch_core_session_get_channel(session); - mg_termination_t *term = switch_channel_get_private(channel, "_mg_term_"); + mg_termination_t *term = switch_channel_get_private(channel, PVT_MG_TERM); //char digit[2] = { dtmf->digit }; if (!term) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find termination structure for session [%s]\n", @@ -158,7 +158,7 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) } if (zstr(term->uuid)) { - switch_channel_t *channel; + switch_channel_t *channel; if (switch_ivr_originate(NULL, &session, &cause, dialstring, 0, NULL, NULL, NULL, NULL, var_event, 0, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to instanciate termination [%s]: %s\n", term->name, switch_channel_cause2str(cause)); status = SWITCH_STATUS_FALSE; @@ -167,9 +167,11 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) term->uuid = switch_core_strdup(term->pool, switch_core_session_get_uuid(session)); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Termination [%s] successfully instanciated as [%s] [%s]\n", term->name, dialstring, switch_core_session_get_uuid(session)); - channel = switch_core_session_get_channel(session); - switch_channel_set_private(channel, "_mg_term_", term); - switch_core_event_hook_add_recv_dtmf(session, mg_on_dtmf); + channel = switch_core_session_get_channel(session); + switch_channel_set_private(channel, PVT_MG_TERM, term); + switch_core_event_hook_add_recv_dtmf(session, mg_on_dtmf); + + switch_core_session_execute_application_async(session, "spandsp_start_fax_detect", "mg_notify cng 120 cng"); } switch_set_flag(term, MGT_ACTIVE); diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 771732d680..66b91072b4 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -26,6 +26,22 @@ SWITCH_STANDARD_API(megaco_function) return mg_process_cli_cmd(cmd, stream); } +SWITCH_STANDARD_APP(mg_notify_function) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + mg_termination_t *term = switch_channel_get_private(channel, PVT_MG_TERM); + + if (!term) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "mg_notify called on a non-supported channel.\n"); + return; + } + + if (!strcmp(data, "cng")) { + mg_send_t38_cng_notify(term->profile, term->name); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Sent CNG notify\n"); + } +} + static switch_status_t console_complete_hashtable(switch_hash_t *hash, const char *line, const char *cursor, switch_console_callback_match_t **matches) { switch_hash_index_t *hi; @@ -92,6 +108,7 @@ static void mg_event_handler(switch_event_t *event) SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load) { switch_api_interface_t *api_interface; + switch_application_interface_t *app_interface; memset(&megaco_globals, 0, sizeof(megaco_globals)); megaco_globals.pool = pool; @@ -105,6 +122,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load) switch_thread_rwlock_create(&megaco_globals.peer_profile_rwlock, pool); SWITCH_ADD_API(api_interface, "mg", "media_gateway", megaco_function, MEGACO_FUNCTION_SYNTAX); + SWITCH_ADD_APP(app_interface, "mg_notify", "", "sends a notify to the mgc", mg_notify_function, "", 0); switch_console_set_complete("add mg profile ::mg::list_profiles start"); switch_console_set_complete("add mg profile ::mg::list_profiles stop"); @@ -246,77 +264,7 @@ void handle_sng_log(uint8_t level, char *fmt, ...) va_end(ptr); } /*****************************************************************************************************************************/ - -#if 0 -static switch_status_t mgco_parse_local_sdp(mg_termination_t *term, CmSdpInfoSet *sdp) -{ - int i; - CmSdpInfoSet *local_sdp; - /* Parse the local SDP while copying the important bits over to our local structure, - * while taking care of editing choose request and replacing them by real values */ - if (!term->u.rtp.local_sdp) { - local_sdp = term->u.rtp.local_sdp = switch_core_alloc(term->context->pool, sizeof *term->u.rtp.local_sdp); - } - - - if (sdp->numComp.pres == NOTPRSNT) { - return SWITCH_STATUS_FALSE; - } - - for (i = 0; i < sdp->numComp.val; i++) { - CmSdpInfo *s = sdp->info[i]; - int mediaId; - - local_sdp->info[i] = switch_core_alloc(term->context->pool, sizeof *(local_sdp->info[i])); - *(local_sdp->info[i]) = *(sdp->info[i]); - - if (s->conn.addrType.pres && s->conn.addrType.val == CM_SDP_ADDR_TYPE_IPV4 && - s->conn.netType.type.val == CM_SDP_NET_TYPE_IN && - s->conn.u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) { - - if (s->conn.u.ip4.addrType.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Local address: %d.%d.%d.%d\n", - s->conn.u.ip4.u.uniIp.b[0].val, - s->conn.u.ip4.u.uniIp.b[1].val, - s->conn.u.ip4.u.uniIp.b[2].val, - s->conn.u.ip4.u.uniIp.b[3].val); - - /* TODO: Double-check bind address for this profile */ - - } - if (s->attrSet.numComp.pres) { - for (mediaId = 0; mediaId < s->attrSet.numComp.val; mediaId++) { - CmSdpAttr *a = s->attrSet.attr[mediaId]; - local_sdp->info[i]->attrSet.attr[mediaId] = switch_core_alloc(term->context->pool, sizeof(CmSdpAttr)); - *(local_sdp->info[i]->attrSet.attr[mediaId]) = *a; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Media %p\n", (void*)a); - } - } - - if (s->mediaDescSet.numComp.pres) { - for (mediaId = 0; mediaId < s->mediaDescSet.numComp.val; mediaId++) { - CmSdpMediaDesc *desc = s->mediaDescSet.mediaDesc[mediaId]; - local_sdp->info[i]->mediaDescSet.mediaDesc[mediaId] = switch_core_alloc(term->context->pool, sizeof(CmSdpMediaDesc)); - *(local_sdp->info[i]->mediaDescSet.mediaDesc[mediaId]) = *desc; - - if (desc->field.mediaType.val == CM_SDP_MEDIA_AUDIO && - desc->field.id.type.val == CM_SDP_VCID_PORT && - desc->field.id.u.port.type.val == CM_SDP_PORT_INT && - desc->field.id.u.port.u.portInt.port.type.val == CM_SDP_SPEC) { - int port = desc->field.id.u.port.u.portInt.port.val.val; - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Port: %d\n", port); - - } - } - } - } - } - - return SWITCH_STATUS_SUCCESS; -} -#endif /* KAPIL- NOTE : We are using Command mode operation of MEGACO stack, so we will always get command indication instead of transaction */ /* Below API is not useful ... just leaving as it is...*/ diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index d0041401d4..44f4b98319 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -22,6 +22,8 @@ #define MEGACO_LOGGING_CLI_SYNTAX "logging [enable|disable]" #define MEGACO_FUNCTION_SYNTAX "profile [name] [start | stop] [status] [xmlstatus] [peerxmlstatus]" +#define PVT_MG_TERM "_mg_term_" + struct megaco_globals { switch_memory_pool_t *pool; switch_hash_t *profile_hash; From 75abcd20995713c1b325b2169b40198981d9812d Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 9 Aug 2012 16:27:15 -0500 Subject: [PATCH 434/822] fix build --- src/include/switch_types.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 696078a06e..381ab22012 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1785,13 +1785,11 @@ typedef enum { } switch_state_handler_flag_t; #ifdef WIN32 -typedef SOCKET apr_os_sock_t; +typedef SOCKET switch_os_socket_t; #else -typedef int apr_os_sock_t; +typedef int switch_os_socket_t; #endif -typedef apr_os_sock_t switch_os_socket_t; - typedef struct apr_pool_t switch_memory_pool_t; typedef uint16_t switch_port_t; typedef uint8_t switch_payload_t; From 24e363d6f59afb5de6883bd95afd531212f9a651 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Thu, 9 Aug 2012 18:00:15 -0400 Subject: [PATCH 435/822] quickfix --- src/mod/endpoints/mod_media_gateway/media_gateway.c | 4 +++- src/mod/endpoints/mod_sofia/rtp.c | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index ff96998538..8409cdc0e1 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -171,7 +171,9 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) switch_channel_set_private(channel, PVT_MG_TERM, term); switch_core_event_hook_add_recv_dtmf(session, mg_on_dtmf); - switch_core_session_execute_application_async(session, "spandsp_start_fax_detect", "mg_notify cng 120 cng"); + if (term->type == MG_TERM_TDM) { + switch_core_session_execute_application_async(session, "spandsp_start_fax_detect", "mg_notify cng 120 cng"); + } } switch_set_flag(term, MGT_ACTIVE); diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 2afbb3fe02..3a41065fe3 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -476,7 +476,7 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi rate, ptime, 1, - /*SWITCH_CODEC_FLAG_ENCODE |*/ SWITCH_CODEC_FLAG_DECODE, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); goto fail; @@ -487,7 +487,7 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi rate, ptime, 1, - SWITCH_CODEC_FLAG_ENCODE /*| SWITCH_CODEC_FLAG_DECODE*/, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); goto fail; From 72f1d392fb71f5890e40a27c269cb23f55ff60cc Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Thu, 9 Aug 2012 21:39:28 -0600 Subject: [PATCH 436/822] FS-4504 --resolve --- Freeswitch.2008.express.sln | 26 ++++++++++++++++++++++++++ Freeswitch.2010.express.sln | 28 ++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/Freeswitch.2008.express.sln b/Freeswitch.2008.express.sln index cd0033bba2..c077efb7ff 100644 --- a/Freeswitch.2008.express.sln +++ b/Freeswitch.2008.express.sln @@ -542,6 +542,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_lcr", "src\mod\applicat EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspandsp", "libs\spandsp\src\libspandsp.2008.vcproj", "{1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}" ProjectSection(ProjectDependencies) = postProject + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A} = {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A} {329A6FA0-0FCC-4435-A950-E670AEFA9838} = {329A6FA0-0FCC-4435-A950-E670AEFA9838} {DEE932AB-5911-4700-9EEB-8C7090A0A330} = {DEE932AB-5911-4700-9EEB-8C7090A0A330} {401A40CD-5DB4-4E34-AC68-FA99E9FAC014} = {401A40CD-5DB4-4E34-AC68-FA99E9FAC014} @@ -667,6 +668,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_directory", "src\mod\ap EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ldns", "libs\win32\ldns\ldns-lib\ldns-lib.2008.vcproj", "{23B4D303-79FC-49E0-89E2-2280E7E28940}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download libjpeg", "libs\win32\Download libjpeg.2008.vcproj", "{21A7DA70-555E-49FA-942B-D84A38B61243}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libjpeg", "libs\win32\libjpeg\libjpeg.2008.vcproj", "{FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}" + ProjectSection(ProjectDependencies) = postProject + {21A7DA70-555E-49FA-942B-D84A38B61243} = {21A7DA70-555E-49FA-942B-D84A38B61243} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution All|Win32 = All|Win32 @@ -2138,6 +2146,24 @@ Global {23B4D303-79FC-49E0-89E2-2280E7E28940}.Release|Win32.ActiveCfg = Release|Win32 {23B4D303-79FC-49E0-89E2-2280E7E28940}.Release|Win32.Build.0 = Release|Win32 {23B4D303-79FC-49E0-89E2-2280E7E28940}.Release|x64.ActiveCfg = Release|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.All|Win32.ActiveCfg = Release|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.All|Win32.Build.0 = Release|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.All|x64.ActiveCfg = Release|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.Debug|Win32.ActiveCfg = Debug|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.Debug|Win32.Build.0 = Debug|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.Debug|x64.ActiveCfg = Debug|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.Release|Win32.ActiveCfg = Release|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.Release|Win32.Build.0 = Release|Win32 + {21A7DA70-555E-49FA-942B-D84A38B61243}.Release|x64.ActiveCfg = Release|Win32 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.All|Win32.ActiveCfg = Debug|Win32 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.All|Win32.Build.0 = Debug|Win32 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.All|x64.ActiveCfg = Debug|Win32 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Debug|Win32.Build.0 = Debug|Win32 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Debug|x64.ActiveCfg = Debug|Win32 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Release|Win32.ActiveCfg = Release|Win32 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Release|Win32.Build.0 = Release|Win32 + {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Freeswitch.2010.express.sln b/Freeswitch.2010.express.sln index baea4a0c35..6833f61bc3 100644 --- a/Freeswitch.2010.express.sln +++ b/Freeswitch.2010.express.sln @@ -219,6 +219,9 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_lcr", "src\mod\applications\mod_lcr\mod_lcr.2010.vcxproj", "{1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspandsp", "libs\spandsp\src\libspandsp.2010.vcxproj", "{1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}" + ProjectSection(ProjectDependencies) = postProject + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1} = {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspeex", "libs\speex\win32\VS2008\libspeex\libspeex.vcxproj", "{E972C52F-9E85-4D65-B19C-031E511E9DB4}" EndProject @@ -322,6 +325,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpcre Generate pcre_chart EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libzrtp", "libs\libzrtp\projects\win\libzrtp.2010.vcxproj", "{C13CC324-0032-4492-9A30-310A6BD64FF5}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download libjpeg", "libs\win32\Download libjpeg.2010.vcxproj", "{652AD5F7-8488-489F-AAD0-7FBE064703B6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libjpeg", "libs\win32\libjpeg\libjpeg.2010.vcxproj", "{019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}" + ProjectSection(ProjectDependencies) = postProject + {652AD5F7-8488-489F-AAD0-7FBE064703B6} = {652AD5F7-8488-489F-AAD0-7FBE064703B6} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution All|Win32 = All|Win32 @@ -2002,6 +2012,24 @@ Global {C13CC324-0032-4492-9A30-310A6BD64FF5}.Release|Win32.Build.0 = Release|Win32 {C13CC324-0032-4492-9A30-310A6BD64FF5}.Release|x64.ActiveCfg = Release|x64 {C13CC324-0032-4492-9A30-310A6BD64FF5}.Release|x64.Build.0 = Release|x64 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.All|Win32.ActiveCfg = Release|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.All|Win32.Build.0 = Release|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.All|x64.ActiveCfg = Release|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|Win32.ActiveCfg = Debug|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|Win32.Build.0 = Debug|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|x64.ActiveCfg = Debug|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|Win32.ActiveCfg = Release|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|Win32.Build.0 = Release|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|x64.ActiveCfg = Release|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.All|Win32.ActiveCfg = Release|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.All|Win32.Build.0 = Release|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.All|x64.ActiveCfg = Release|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Debug|Win32.ActiveCfg = Debug|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Debug|Win32.Build.0 = Debug|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Debug|x64.ActiveCfg = Debug|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|Win32.ActiveCfg = Release|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|Win32.Build.0 = Release|Win32 + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From ad1784f87697779cb5bbcda0c0e5f81323faead6 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Fri, 10 Aug 2012 04:41:14 -0400 Subject: [PATCH 437/822] adding cli command to show status of all termination in single command --- .../mod_media_gateway/media_gateway_cli.c | 85 ++++++++++++++----- 1 file changed, 66 insertions(+), 19 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c index 31fac31d5c..d2234f859c 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c @@ -16,6 +16,7 @@ switch_status_t megaco_profile_status(switch_stream_handle_t *stream, megaco_pro switch_status_t megaco_profile_xmlstatus(switch_stream_handle_t *stream, megaco_profile_t* mg_cfg); switch_status_t megaco_profile_peer_xmlstatus(switch_stream_handle_t *stream, megaco_profile_t* mg_cfg); switch_status_t handle_term_status_cli_cmd(switch_stream_handle_t *stream, megaco_profile_t* mg_profile, char* term_id); +switch_status_t handle_all_term_status_cli_cmd(switch_stream_handle_t *stream, megaco_profile_t* mg_profile); void get_peer_xml_buffer(char* prntBuf, MgPeerSta* cfm); void megaco_cli_print_usage(switch_stream_handle_t *stream); switch_status_t handle_show_activecalls_cli_cmd(switch_stream_handle_t *stream, megaco_profile_t* mg_profile); @@ -188,21 +189,6 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre stream->write_function(stream, "-ERR No such profile\n"); } -/**********************************************************************************/ - }else if (!strcmp(argv[2], "termstatus")) { -/**********************************************************************************/ - /* mg termstatus */ - - if (zstr(argv[3])) { - goto usage; - } - - if(profile){ - megaco_profile_release(profile); - handle_term_status_cli_cmd(stream, profile, argv[3]); - } else { - stream->write_function(stream, "-ERR No such profile\n"); - } /**********************************************************************************/ }else if (!strcmp(argv[2], "show")) { /**********************************************************************************/ @@ -214,12 +200,25 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre if(profile){ megaco_profile_release(profile); if(!strcasecmp(argv[3], "activecalls")){ + /* mg show activecalls */ handle_show_activecalls_cli_cmd(stream, profile); - } - } else { + /*******************************************************************/ + }else if(!strcasecmp(argv[3], "alltermstatus")){ + /*******************************************************************/ + /* mg show alltermstatus */ + handle_all_term_status_cli_cmd(stream, profile); + }else if(!strcasecmp(argv[3], "termstatus")){ + /*******************************************************************/ + /* mg show termstatus */ + if (zstr(argv[4])) { + goto usage; + } + handle_term_status_cli_cmd(stream, profile, argv[4]); + } else { + /*******************************************************************/ stream->write_function(stream, "-ERR No such profile\n"); + } } - /**********************************************************************************/ }else { /**********************************************************************************/ @@ -271,7 +270,6 @@ void megaco_cli_print_usage(switch_stream_handle_t *stream) stream->write_function(stream, "Usage: Profile Specific\n"); stream->write_function(stream, "mg profile start \n"); stream->write_function(stream, "mg profile stop \n"); - stream->write_function(stream, "mg profile termstatus \n"); stream->write_function(stream, "mg profile status \n"); stream->write_function(stream, "mg profile xmlstatus \n"); stream->write_function(stream, "mg profile peerxmlstatus \n"); @@ -280,6 +278,8 @@ void megaco_cli_print_usage(switch_stream_handle_t *stream) stream->write_function(stream, "mg profile send ito notify \n"); stream->write_function(stream, "mg profile send cng \n"); stream->write_function(stream, "mg profile show activecalls \n"); + stream->write_function(stream, "mg profile show termstatus \n"); + stream->write_function(stream, "mg profile show alltermstatus \n"); stream->write_function(stream, "Usage: Logging \n"); stream->write_function(stream, "mg logging enable \n"); @@ -698,7 +698,54 @@ void get_peer_xml_buffer(char* prntBuf, MgPeerSta* cfm) } /******************************************************************************/ +switch_status_t handle_all_term_status_cli_cmd(switch_stream_handle_t *stream, megaco_profile_t* mg_profile) +{ + void *val = NULL; + switch_hash_index_t *hi = NULL; + mg_termination_t *term = NULL; + const void *var; + if(!mg_profile){ + stream->write_function(stream, "-ERR NULL profile\n"); + return SWITCH_STATUS_FALSE; + } + + stream->write_function(stream, " Termination Name"); + stream->write_function(stream, "\t Termination State"); + stream->write_function(stream, "\t Termination Type"); + stream->write_function(stream, "\t Span-Id "); + stream->write_function(stream, "\t Channel-Id "); + + for (hi = switch_hash_first(NULL, mg_profile->terminations); hi; hi = switch_hash_next(hi)) { + switch_hash_this(hi, &var, NULL, &val); + term = (mg_termination_t *) val; + if(!term) continue; + + stream->write_function(stream, "\n"); + + stream->write_function(stream, " %s",(NULL != term->name)?term->name:"NULL"); + if(MG_TERM_RTP == term->type){ + stream->write_function(stream, "\t\t\t IN-SERVICE"); + }else{ + stream->write_function(stream, "\t\t\t %s", + (switch_test_flag(term, MG_IN_SERVICE))?"IN-SERVICE":"OUT-OF-SERVICE"); + } + stream->write_function(stream, "\t\t %s",(MG_TERM_RTP == term->type)?"MG_TERM_RTP":"MG_TERM_TDM"); + + if(MG_TERM_TDM == term->type){ + stream->write_function(stream, "\t\t %s", + (NULL != term->u.tdm.span_name)?term->u.tdm.span_name:"NULL"); + stream->write_function(stream, "\t\t %d",term->u.tdm.channel); + }else{ + stream->write_function(stream, "\t\t -"); + stream->write_function(stream, "\t\t -"); + } + stream->write_function(stream, "\n"); + } + + return SWITCH_STATUS_SUCCESS; +} +/******************************************************************************/ switch_status_t handle_term_status_cli_cmd(switch_stream_handle_t *stream, megaco_profile_t* mg_profile, char* term_id) { mg_termination_t* term = NULL; From f6e5cae7c5ad549efa5c305b6254f061173e1684 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Fri, 10 Aug 2012 05:37:39 -0400 Subject: [PATCH 438/822] fixing modify resp issue --- .../media_gateway_cmd_handler.c | 277 ++++++++++-------- .../mod_media_gateway/media_gateway_xml.c | 13 +- 2 files changed, 170 insertions(+), 120 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index cff0c7ffa9..4e93abbf11 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -1065,7 +1065,7 @@ error: */ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd) { - mg_context_t* mg_ctxt = NULL; + mg_context_t* mg_ctxt = NULL; MgMgcoContextId *ctxtId; MgStr errTxt; MgMgcoInd *mgErr; @@ -1073,7 +1073,11 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand MgMgcoTermIdLst* termLst; mg_termination_t* term = NULL; switch_status_t ret; + MgMgcoAudRetParm *desc; + MgMgcoMediaDesc* inc_med_desc = NULL; + MgMgcoLocalDesc *local = NULL; int err_code; + int mediaId; /*MgMgcoAmmReq *cmd = &inc_cmd->u.mgCmdInd[0]->cmd.u.mod;*/ U32 txn_id = inc_cmd->transId.val; @@ -1114,109 +1118,109 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand /* context id presence check is already being done, we are here it means context-id requested in megaco message is present */ /********************************************************************/ - /* MGT_TERMID_ROOT = If ROOT term then there will not be any conext */ + /* MGT_TERMID_ROOT = If ROOT term then there will not be any conext */ - if(MGT_TERMID_ROOT == termId->type.val){ - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, - "Modify request is for ROOT termination \n"); + if(MGT_TERMID_ROOT == termId->type.val){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + "Modify request is for ROOT termination \n"); - /* check if we have ito packg request */ - mg_is_ito_pkg_req(mg_profile, inc_cmd); + /* check if we have ito packg request */ + mg_is_ito_pkg_req(mg_profile, inc_cmd); - /* TODO */ + /* TODO */ - /********************************************************************/ - } else if(MGT_TERMID_OTHER == termId->type.val){ - /********************************************************************/ + /********************************************************************/ + } else if(MGT_TERMID_OTHER == termId->type.val){ + /********************************************************************/ #ifdef BIT_64 - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, - "Modify request is for termination[%s] and context: type[%d], value[%d] \n", - termId->name.lcl.val, ctxtId->type.val, ctxtId->val.val); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + "Modify request is for termination[%s] and context: type[%d], value[%d] \n", + termId->name.lcl.val, ctxtId->type.val, ctxtId->val.val); #else - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, - "Modify request is for termination[%s] and context: type[%d], value[%ld] \n", - termId->name.lcl.val, ctxtId->type.val, ctxtId->val.val); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + "Modify request is for termination[%s] and context: type[%d], value[%ld] \n", + termId->name.lcl.val, ctxtId->type.val, ctxtId->val.val); #endif - term = megaco_find_termination(mg_profile, (char*)termId->name.lcl.val); + term = megaco_find_termination(mg_profile, (char*)termId->name.lcl.val); - if(NULL == term){ - mg_util_set_term_string(&errTxt,termId); - err_code = MGT_MGCO_RSP_CODE_UNKNOWN_TERM_ID; - goto error; - } + if(NULL == term){ + mg_util_set_term_string(&errTxt,termId); + err_code = MGT_MGCO_RSP_CODE_UNKNOWN_TERM_ID; + goto error; + } - /* termination specified...context should also be specified */ + /* termination specified...context should also be specified */ - /* check if we have terminations in the context */ + /* check if we have terminations in the context */ - if (NOTPRSNT != ctxtId->type.pres) { - if(MGT_CXTID_OTHER == ctxtId->type.val) { - /*find context based on received context-id */ - mg_ctxt = megaco_get_context(mg_profile, ctxtId->val.val); - if(NULL == mg_ctxt){ - mg_util_set_ctxt_string(&errTxt, ctxtId); - err_code = MGT_MGCO_RSP_CODE_UNKNOWN_CTXT; - goto error; - } + if (NOTPRSNT != ctxtId->type.pres) { + if(MGT_CXTID_OTHER == ctxtId->type.val) { + /*find context based on received context-id */ + mg_ctxt = megaco_get_context(mg_profile, ctxtId->val.val); + if(NULL == mg_ctxt){ + mg_util_set_ctxt_string(&errTxt, ctxtId); + err_code = MGT_MGCO_RSP_CODE_UNKNOWN_CTXT; + goto error; + } - if(SWITCH_STATUS_FALSE == megaco_context_is_term_present(mg_ctxt, term)){ - /* ERROR - termination didnt bind with requested context */ - mg_util_set_term_string(&errTxt,termId); - err_code = MGT_MGCO_RSP_CODE_NO_TERM_CTXT; - goto error; - } + if(SWITCH_STATUS_FALSE == megaco_context_is_term_present(mg_ctxt, term)){ + /* ERROR - termination didnt bind with requested context */ + mg_util_set_term_string(&errTxt,termId); + err_code = MGT_MGCO_RSP_CODE_NO_TERM_CTXT; + goto error; + } - }else if(MGT_CXTID_NULL == ctxtId->type.val) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, - "Modify request is for NULL Context \n"); - /*TODO - NULL context...nothing to do now...jump to response to send +ve response */ - goto response; - }else if(MGT_CXTID_ALL == ctxtId->type.val) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, - "Modify request is for ALL Context \n"); - /*TODO - ALL context...nothing to do now...jump to response to send +ve response */ - goto response; - } - } + }else if(MGT_CXTID_NULL == ctxtId->type.val) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + "Modify request is for NULL Context \n"); + /*TODO - NULL context...nothing to do now...jump to response to send +ve response */ + goto response; + }else if(MGT_CXTID_ALL == ctxtId->type.val) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + "Modify request is for ALL Context \n"); + /*TODO - ALL context...nothing to do now...jump to response to send +ve response */ + goto response; + } + } - /* Not sure if MODIFY can come with Context ALL with specified term */ + /* Not sure if MODIFY can come with Context ALL with specified term */ - /********************************************************************/ + /********************************************************************/ - ret = mg_prc_descriptors(mg_profile, inc_cmd, term, &inc_cmd->u.mgCmdInd[0]->memCp); + ret = mg_prc_descriptors(mg_profile, inc_cmd, term, &inc_cmd->u.mgCmdInd[0]->memCp); - /* IF there is any error , return */ - if(term->mg_error_code && (*term->mg_error_code == MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT)){ - mg_util_set_err_string(&errTxt, " Unsupported Codec "); - err_code = MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT; - /* TODO delete RTP termination */ - goto error; + /* IF there is any error , return */ + if(term->mg_error_code && (*term->mg_error_code == MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT)){ + mg_util_set_err_string(&errTxt, " Unsupported Codec "); + err_code = MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT; + /* TODO delete RTP termination */ + goto error; + } + + if(MG_TERM_RTP == term->type){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"MODIFY REQUEST - Updated RTP attributes:" + " local_addr[%s] local_port[%d] remote_addr[%s], remote_port[%d], ptime[%d] pt[%d], " + " rfc2833_pt[%d] rate[%d], codec[%s], term_id[%d]\n", + ((NULL != term->u.rtp.local_addr)?term->u.rtp.local_addr:NULL), + term->u.rtp.local_port, + ((NULL != term->u.rtp.remote_addr)?term->u.rtp.remote_addr:NULL), + term->u.rtp.remote_port, + term->u.rtp.ptime, + term->u.rtp.pt, + term->u.rtp.rfc2833_pt, + term->u.rtp.rate, + ((NULL != term->u.rtp.codec)?term->u.rtp.codec:NULL), + term->u.rtp.term_id); + } + + mg_print_t38_attributes(term); + + + /* SDP updated to termination */ + megaco_activate_termination(term); } - if(MG_TERM_RTP == term->type){ - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"MODIFY REQUEST - Updated RTP attributes:" - " local_addr[%s] local_port[%d] remote_addr[%s], remote_port[%d], ptime[%d] pt[%d], " - " rfc2833_pt[%d] rate[%d], codec[%s], term_id[%d]\n", - ((NULL != term->u.rtp.local_addr)?term->u.rtp.local_addr:NULL), - term->u.rtp.local_port, - ((NULL != term->u.rtp.remote_addr)?term->u.rtp.remote_addr:NULL), - term->u.rtp.remote_port, - term->u.rtp.ptime, - term->u.rtp.pt, - term->u.rtp.rfc2833_pt, - term->u.rtp.rate, - ((NULL != term->u.rtp.codec)?term->u.rtp.codec:NULL), - term->u.rtp.term_id); - } - - mg_print_t38_attributes(term); - - - /* SDP updated to termination */ - megaco_activate_termination(term); - } - /* TODO - copy inc descriptor...not sure if we need to do this.. */ /********************************************************************/ @@ -1230,54 +1234,97 @@ switch_status_t handle_mg_modify_cmd(megaco_profile_t* mg_profile, MgMgcoCommand /* Kapil - to fill the response structure and call the response API to send Modify response */ response: - { /* send response */ + { /* send response */ - MgMgcoCommand rsp; - int ret = 0x00; + MgMgcoCommand rsp; + int ret = 0x00; - memset(&rsp,0, sizeof(rsp)); + memset(&rsp,0, sizeof(rsp)); - /*copy transaction-id*/ - memcpy(&rsp.transId, &inc_cmd->transId,sizeof(MgMgcoTransId)); + /*copy transaction-id*/ + memcpy(&rsp.transId, &inc_cmd->transId,sizeof(MgMgcoTransId)); - /*copy context-id*/ /*TODO - in case of $ context should be generated by app, we should not simply copy incoming structure */ - memcpy(&rsp.contextId, &inc_cmd->contextId,sizeof(MgMgcoContextId)); + /*copy context-id*/ /*TODO - in case of $ context should be generated by app, we should not simply copy incoming structure */ + memcpy(&rsp.contextId, &inc_cmd->contextId,sizeof(MgMgcoContextId)); - /*copy peer identifier */ - memcpy(&rsp.peerId, &inc_cmd->peerId,sizeof(TknU32)); + /*copy peer identifier */ + memcpy(&rsp.peerId, &inc_cmd->peerId,sizeof(TknU32)); - /*fill response structue */ - if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&rsp.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ - return ret; - } + /*fill response structue */ + if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&rsp.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ + return ret; + } - rsp.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; - rsp.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; - rsp.u.mgCmdRsp[0]->type.val = MGT_MODIFY; - rsp.u.mgCmdRsp[0]->u.mod.pres.pres = PRSNT_NODEF; - rsp.u.mgCmdRsp[0]->u.mod.termIdLst.num.pres = PRSNT_NODEF; - rsp.u.mgCmdRsp[0]->u.mod.termIdLst.num.val = 1; + rsp.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; + rsp.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; + rsp.u.mgCmdRsp[0]->type.val = MGT_MODIFY; + rsp.u.mgCmdRsp[0]->u.mod.pres.pres = PRSNT_NODEF; + rsp.u.mgCmdRsp[0]->u.mod.termIdLst.num.pres = PRSNT_NODEF; + rsp.u.mgCmdRsp[0]->u.mod.termIdLst.num.val = 1; - mgUtlAllocMgMgcoTermIdLst(&rsp.u.mgCmdRsp[0]->u.mod.termIdLst, &inc_cmd->u.mgCmdReq[0]->cmd.u.mod.termIdLst); + mgUtlAllocMgMgcoTermIdLst(&rsp.u.mgCmdRsp[0]->u.mod.termIdLst, &inc_cmd->u.mgCmdReq[0]->cmd.u.mod.termIdLst); #ifdef GCP_VER_2_1 - termId = rsp.u.mgCmdRsp[0]->u.mod.termIdLst.terms[0]; + termId = rsp.u.mgCmdRsp[0]->u.mod.termIdLst.terms[0]; #else - termId = &(rsp.u.mgCmdRsp[0]->u.mod.termId); + termId = &(rsp.u.mgCmdRsp[0]->u.mod.termId); #endif - /*mg_fill_mgco_termid(termId, (char*)"term1",&req->u.mgCmdRsp[0]->memCp);*/ + /*mg_fill_mgco_termid(termId, (char*)"term1",&req->u.mgCmdRsp[0]->memCp);*/ - /* We will always send one command at a time..*/ - rsp.cmdStatus.pres = PRSNT_NODEF; - rsp.cmdStatus.val = CH_CMD_STATUS_END_OF_CMD; + if((MG_TERM_RTP == term->type) && + ((NOTPRSNT != inc_cmd->u.mgCmdInd[0]->cmd.u.mod.dl.num.pres) && + (0 != inc_cmd->u.mgCmdInd[0]->cmd.u.mod.dl.num.val))) { + /* Whatever Media descriptor we have received, we can copy that and then + * whatever we want we can modify the fields */ + /* Kapil - TODO - will see if there is any problem of coping the + * descriptor */ - rsp.cmdType.pres = PRSNT_NODEF; - rsp.cmdType.val = CH_CMD_TYPE_RSP; + inc_med_desc = &inc_cmd->u.mgCmdInd[0]->cmd.u.mod.dl.descs[0]->u.media; + + if (mgUtlGrowList((void ***)&rsp.u.mgCmdRsp[0]->u.mod.audit.parms, sizeof(MgMgcoAudRetParm), + &rsp.u.mgCmdRsp[0]->u.mod.audit.num, &rsp.u.mgCmdRsp[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + /* copy media descriptor */ + desc = rsp.u.mgCmdRsp[0]->u.mod.audit.parms[rsp.u.mgCmdRsp[0]->u.mod.audit.num.val-1]; + desc->type.pres = PRSNT_NODEF; + desc->type.val = MGT_MEDIADESC; + mgUtlCpyMgMgcoMediaDesc(&desc->u.media, inc_med_desc, &rsp.u.mgCmdRsp[0]->memCp); + /* see if we have received local descriptor */ + if((NOTPRSNT != desc->u.media.num.pres) && + (0 != desc->u.media.num.val)) + { + for(mediaId=0; mediaIdu.media.num.val; mediaId++) { + if(MGT_MEDIAPAR_LOCAL == desc->u.media.parms[mediaId]->type.val) { + local = &desc->u.media.parms[mediaId]->u.local; + } + } + } + + /* only for RTP */ + if(SWITCH_STATUS_FALSE == mg_build_sdp(&desc->u.media, inc_med_desc, mg_profile, term, &rsp.u.mgCmdRsp[0]->memCp)) { + if(term->mg_error_code && (*term->mg_error_code == MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT)){ + mg_util_set_err_string(&errTxt, " Unsupported Codec "); + err_code = MGT_MGCP_RSP_CODE_INCONSISTENT_LCL_OPT; + goto error; + } + } + } + + /* We will always send one command at a time..*/ + rsp.cmdStatus.pres = PRSNT_NODEF; + rsp.cmdStatus.val = CH_CMD_STATUS_END_OF_CMD; + + rsp.cmdType.pres = PRSNT_NODEF; + rsp.cmdType.val = CH_CMD_TYPE_RSP; - ret = sng_mgco_send_cmd(mg_profile->idx, &rsp); + ret = sng_mgco_send_cmd(mg_profile->idx, &rsp); - } + } return SWITCH_STATUS_SUCCESS; diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index 08044bc9f7..65b9e8b393 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -71,7 +71,7 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) for (mg_term = switch_xml_child(mg_phys_terms, "map"); mg_term; mg_term = mg_term->next) { // const char *prefix = switch_xml_attr(mg_term, "termination-id-prefix"); - //const char *sztermination_id_base = switch_xml_attr(mg_term, "termination-id-base"); + const char *sztermination_id_base = switch_xml_attr(mg_term, "termination-id-base"); const char *tech = switch_xml_attr(mg_term, "tech"); const char *channel_prefix = switch_xml_attr(mg_term, "channel-prefix"); const char *channel_map = switch_xml_attr(mg_term, "channel-map"); @@ -84,6 +84,7 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) int chanmap_count = 0; int i = 0; int startchan, endchan, j; + int mg_term_idx = (sztermination_id_base)?atoi(sztermination_id_base):1; /* we can have following combinations * * i) only one channel i.e. channel-map="1" @@ -103,14 +104,15 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) startchan = atoi(chanmap[0]); endchan = atoi(chanmap[1]); for (j = startchan; j <= endchan; j++) { - mg_create_tdm_term(profile, tech, channel_prefix, prefix, j, j); + mg_create_tdm_term(profile, tech, channel_prefix, prefix, mg_term_idx, j); + mg_term_idx++; } } }else{ /* case (i) */ p = channel_map_dup; startchan = endchan = atoi(p); - mg_create_tdm_term(profile, tech, channel_prefix, prefix, startchan, startchan); + mg_create_tdm_term(profile, tech, channel_prefix, prefix, mg_term_idx, startchan); } }else { @@ -124,9 +126,10 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload) for (j = startchan; j <= endchan; j++) { if (0 == i) - mg_create_tdm_term(profile, tech, channel_prefix, prefix, j, j); + mg_create_tdm_term(profile, tech, channel_prefix, prefix, mg_term_idx, j); else - mg_create_tdm_term(profile, tech, channel_prefix, prefix, j, j-1); + mg_create_tdm_term(profile, tech, channel_prefix, prefix, mg_term_idx, j-1); + mg_term_idx++; } } } From 2df26cf79d1cc3b627e1f6a38c109471a5c6e97c Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Fri, 10 Aug 2012 06:46:01 -0400 Subject: [PATCH 439/822] hardcoding t38 sdp fields... --- .../mod_media_gateway/media_gateway_cli.c | 2 +- .../mod_media_gateway/media_gateway_utils.c | 51 ++++++++++++++++--- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c index d2234f859c..7d50ecfa19 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c @@ -279,7 +279,7 @@ void megaco_cli_print_usage(switch_stream_handle_t *stream) stream->write_function(stream, "mg profile send cng \n"); stream->write_function(stream, "mg profile show activecalls \n"); stream->write_function(stream, "mg profile show termstatus \n"); - stream->write_function(stream, "mg profile show alltermstatus \n"); + stream->write_function(stream, "mg profile show alltermstatus \n"); stream->write_function(stream, "Usage: Logging \n"); stream->write_function(stream, "mg logging enable \n"); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index 985d383d9e..c18057d3da 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -452,24 +452,26 @@ void mgco_fill_t38_sdp_attr(CmSdpAttrSet *s, mg_termination_t* term, CmMemListCp "CM_SDP_ATTR_T38_FAX: TYPE not present \n"); break; } +printf("f->u.unknown.name.val[%s, len=%d]\n", f->u.unknown.name.val, f->u.unknown.name.len); /* NOTE - Ideally i should not change ,whatever is coming we can return..due to trillium issue forcefully coping the data...will remove once get trillium fix*/ if(f->type.val == CM_SDP_ATTR_T38_FAX_UNKNOWN) { -if((i==0) && term->u.rtp.t38_options->T38FaxRateManagement){ +if(!strncasecmp((char*)f->u.unknown.name.val,"transferredTCF",14) && term->u.rtp.t38_options->T38FaxRateManagement){ +printf("KAPIL - adding FaxRateManagement \n"); MG_SET_TKNSTROSXL((f->u.unknown.name),strlen("FaxRateManagement"),"FaxRateManagement", memCp); MG_SET_TKNSTROSXL((f->u.unknown.val), strlen(term->u.rtp.t38_options->T38FaxRateManagement), term->u.rtp.t38_options->T38FaxRateManagement, memCp); -} -if((i==1) && term->u.rtp.t38_options->T38FaxUdpEC){ +}else if((!strncasecmp((char*)f->u.unknown.name.val,"t38UDPRedundancy",16)) && term->u.rtp.t38_options->T38FaxUdpEC){ +printf("KAPIL - adding FaxUdpEC \n"); MG_SET_TKNSTROSXL((f->u.unknown.name),strlen("FaxUdpEC"),"FaxUdpEC", memCp); MG_SET_TKNSTROSXL((f->u.unknown.val), strlen(term->u.rtp.t38_options->T38FaxUdpEC), term->u.rtp.t38_options->T38FaxUdpEC, memCp); -} -if((i==2)){ +}else if(!strncasecmp((char*)f->u.unknown.name.val,"14400",5)){ char buf[10] = {0}; +printf("KAPIL - adding MaxBitRate \n"); sprintf(buf,"%d",term->u.rtp.t38_options->T38MaxBitRate); MG_SET_TKNSTROSXL((f->u.unknown.name),strlen("MaxBitRate"),"MaxBitRate", memCp); MG_SET_TKNSTROSXL((f->u.unknown.val), @@ -2065,16 +2067,19 @@ switch_status_t mg_rem_unsupported_codecs (megaco_profile_t* mg_profile, mg_term /*****************************************************************************************************************************/ + switch_status_t mg_build_sdp(MgMgcoMediaDesc* out, MgMgcoMediaDesc* inc, megaco_profile_t* mg_profile, mg_termination_t* term, CmMemListCp *memCp) { CmSdpU8OrNil *fmt = NULL; CmSdpInfoSet *psdp = NULL; + CmSdpInfoSet *pRsdp = NULL; char* ipAddress[4]; int i = 0x00; int j = 0x00; int choose_codec = 0x00; int k = 0x00; MgMgcoLocalDesc *local = NULL; + MgMgcoLocalDesc *remote = NULL; int fresh_sdp = 0x00; char* dup = NULL; CmSdpMedProtoFmts *format=NULL; @@ -2107,17 +2112,51 @@ switch_status_t mg_build_sdp(MgMgcoMediaDesc* out, MgMgcoMediaDesc* inc, megaco_ for(i=0; inum.val; i++) { if(MGT_MEDIAPAR_LOCAL == out->parms[i]->type.val) { local = &out->parms[i]->u.local; - break; } else if(MGT_MEDIAPAR_STRPAR == out->parms[i]->type.val){ MgMgcoStreamDesc *stream = &out->parms[i]->u.stream; if((NOTPRSNT != stream->sl.pres.pres) && (NOTPRSNT != stream->sl.local.pres.pres)){ local = &stream->sl.local; } + }else if(MGT_MEDIAPAR_REMOTE == out->parms[i]->type.val) { + remote = &out->parms[i]->u.remote; } } } } +if(remote && (NOTPRSNT != remote->sdp.numComp.pres) && (0 != remote->sdp.numComp.val)){ +pRsdp = &(remote->sdp); +for(i=0; i< pRsdp->numComp.val; i++) { +/* fill media descriptors */ +{ +CmSdpMediaDescSet* med = &pRsdp->info[pRsdp->numComp.val-1]->mediaDescSet; +CmSdpMediaDesc* media; + +if((NOTPRSNT != med->numComp.pres) || (0 != med->numComp.val)){ + for(j =0;j < med->numComp.val; j++){ + media = med->mediaDesc[j]; + + /* check for codec */ +if((NOTPRSNT != media->field.par.numProtFmts.pres) || + (0 != media->field.par.numProtFmts.val)){ + for(k =0;k < media->field.par.numProtFmts.val; k++){ +format = media->field.par.pflst[k]; +if ((NOTPRSNT != format->protType.pres) && + (CM_SDP_MEDIA_PROTO_UDPTL == format->protType.val)){ +/* ideally whatever is received we can send back * +* due to issue in trillium , we need to manually copy the fields now */ + mgco_fill_t38_sdp_attr(&media->attrSet, term, memCp); +} +} +} +} +} +} +/**********************************************************************************************************************************/ +} +} + + if(!local || (NOTPRSNT == local->sdp.numComp.pres) || (0 == local->sdp.numComp.val)){ /* local sdp is not part of media descriptor, then add local sdp*/ mg_add_local_descriptor(out, mg_profile, term, memCp); From 116a09e85476cd35ad37209954e8b7c6a0749a44 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Fri, 10 Aug 2012 07:08:47 -0400 Subject: [PATCH 440/822] add some t38 vars --- .../mod_media_gateway/media_gateway.c | 3 +- .../mod_media_gateway/mod_media_gateway.c | 1 + src/mod/endpoints/mod_sofia/rtp.c | 35 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 8409cdc0e1..bd9401b419 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -127,7 +127,8 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, kCODEC, term->u.rtp.codec); switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, kMEDIATYPE, mg_media_type2str(term->u.rtp.media_type)); - + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "fax_enable_t38", "true"); + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "rtp_execute_on_image", "t38_gateway peer nocng"); } else if (term->type == MG_TERM_TDM) { switch_snprintf(dialstring, sizeof dialstring, "tdm/%s", term->name); diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index 66b91072b4..2afd7a778c 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -39,6 +39,7 @@ SWITCH_STANDARD_APP(mg_notify_function) if (!strcmp(data, "cng")) { mg_send_t38_cng_notify(term->profile, term->name); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Sent CNG notify\n"); + switch_channel_set_variable(channel, "mg_cng_detected", "true"); } } diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 3a41065fe3..279e5a5ac1 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -523,6 +523,21 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi switch_channel_set_variable(channel, kRFC2833PT, szpt); switch_rtp_set_telephony_event(tech_pvt->rtp_session, pt); } + + if (compare_var(event, channel, kMODE)) { + const char *newmode = switch_channel_get_variable(channel, kMODE); + const char *mode = switch_channel_get_variable(channel, kMODE); + + if (!strcmp(newmode, "image")) { + switch_channel_set_variable(tech_pvt->channel, "has_t38", "true"); + switch_channel_set_app_flag_key("T38", tech_pvt->channel, CF_APP_T38); + switch_channel_execute_on(tech_pvt->channel, "rtp_execute_on_image"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got IMAGE description\n"); + } + + switch_channel_set_variable(channel, kMODE, newmode); + } + } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Received unknown command [%s] in event.\n", !command ? "null" : command); } @@ -554,6 +569,26 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s assert(tech_pvt != NULL); switch (msg->message_id) { + case SWITCH_MESSAGE_INDICATE_UDPTL_MODE: + { + switch_t38_options_t *t38_options = switch_channel_get_private(tech_pvt->channel, "t38_options"); + if (!t38_options) { + goto end; + } + + switch_rtp_udptl_mode(tech_pvt->rtp_session); + break; + } + case SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION\n"); + break; + } + case SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA\n"); + break; + } case SWITCH_MESSAGE_INDICATE_DEBUG_AUDIO: { if (switch_rtp_ready(tech_pvt->rtp_session) && !zstr(msg->string_array_arg[0]) && !zstr(msg->string_array_arg[1])) { From 540c2a91dafad0d100b9ab2909a30fd27d780556 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Fri, 10 Aug 2012 07:22:07 -0400 Subject: [PATCH 441/822] t38 --- src/mod/endpoints/mod_media_gateway/media_gateway.c | 9 +++++++++ src/mod/endpoints/mod_sofia/rtp.c | 9 ++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index bd9401b419..3590762cb5 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -147,6 +147,10 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) switch_core_session_receive_event(session, &var_event); + if (term->u.rtp.t38_options) { + switch_channel_set_private(channel, "t38_options", term->u.rtp.t38_options); + } + switch_core_session_rwunlock(session); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sent refresh to channel [%s], for termination [%s]\n", term->uuid, term->name); @@ -170,6 +174,11 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Termination [%s] successfully instanciated as [%s] [%s]\n", term->name, dialstring, switch_core_session_get_uuid(session)); channel = switch_core_session_get_channel(session); switch_channel_set_private(channel, PVT_MG_TERM, term); + + if (term->u.rtp.t38_options) { + switch_channel_set_private(channel, "t38_options", term->u.rtp.t38_options); + } + switch_core_event_hook_add_recv_dtmf(session, mg_on_dtmf); if (term->type == MG_TERM_TDM) { diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 279e5a5ac1..9f0bc0147f 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -40,7 +40,7 @@ #define kPTIME "ptime" #define kPT "pt" #define kRFC2833PT "rfc2833_pt" -#define kMODE "mode" +#define kMEDIATYPE "media_type" #define kRATE "rate" static struct { @@ -524,9 +524,8 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi switch_rtp_set_telephony_event(tech_pvt->rtp_session, pt); } - if (compare_var(event, channel, kMODE)) { - const char *newmode = switch_channel_get_variable(channel, kMODE); - const char *mode = switch_channel_get_variable(channel, kMODE); + if (compare_var(event, channel, kMEDIATYPE)) { + const char *newmode = switch_channel_get_variable(channel, kMEDIATYPE); if (!strcmp(newmode, "image")) { switch_channel_set_variable(tech_pvt->channel, "has_t38", "true"); @@ -535,7 +534,7 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got IMAGE description\n"); } - switch_channel_set_variable(channel, kMODE, newmode); + switch_channel_set_variable(channel, kMEDIATYPE, newmode); } } else { From 659c06d356b248b7e232e43f97226c7b1761d868 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Fri, 10 Aug 2012 07:47:10 -0500 Subject: [PATCH 442/822] FS-4219 -- resolve windows version string. thanks Peter --- libs/win32/util.vbs | 68 +++++++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/libs/win32/util.vbs b/libs/win32/util.vbs index 4f13e21ad0..a6f3cf835d 100644 --- a/libs/win32/util.vbs +++ b/libs/win32/util.vbs @@ -314,6 +314,31 @@ Function GetTimeUTC() End Function +Function GetWeekDay(DateTime) + + DayOfWeek = DatePart("w", DateTime) + + Select Case DayOfWeek + Case 1 GetWeekDay = "Sun" + Case 2 GetWeekDay = "Mon" + Case 3 GetWeekDay = "Tue" + Case 4 GetWeekDay = "Wed" + Case 5 GetWeekDay = "Thu" + Case 6 GetWeekDay = "Fri" + Case 7 GetWeekDay = "Sat" + End Select + +End Function + +Function GetMonthName(DateTime) + + Val = MonthName(Month(DateTime), True) + Val = UCase(Left(Val, 1)) & Mid(Val, 2, 4) + + GetMonthName = Val + +End Function + Sub CreateVersion(tmpFolder, VersionDir, includebase, includedest) Dim oExec @@ -321,6 +346,7 @@ Sub CreateVersion(tmpFolder, VersionDir, includebase, includedest) strVerMinor = FindVersionStringInConfigure(VersionDir & "configure.in", "SWITCH_VERSION_MINOR") strVerMicro = FindVersionStringInConfigure(VersionDir & "configure.in", "SWITCH_VERSION_MICRO") strVerRev = FindVersionStringInConfigure(VersionDir & "configure.in", "SWITCH_VERSION_REVISION") + strVerHuman = FindVersionStringInConfigure(VersionDir & "configure.in", "SWITCH_VERSION_REVISION_HUMAN") 'Set version to the one reported by configure.in If strVerRev <> "" Then @@ -329,6 +355,7 @@ Sub CreateVersion(tmpFolder, VersionDir, includebase, includedest) Dim sLastFile Const ForReading = 1 + Const ShowUnclean = False 'Don't show unclean state for now 'Try To read revision from git If FSO.FolderExists(VersionDir & ".git") Then @@ -337,30 +364,38 @@ Sub CreateVersion(tmpFolder, VersionDir, includebase, includedest) If IsNumeric(strFromProc) Then lastChangedDateTime = DateAdd("s", strFromProc, "01/01/1970 00:00:00") strLastCommit = YEAR(lastChangedDateTime) & Pd(Month(lastChangedDateTime), 2) & Pd(DAY(lastChangedDateTime), 2) & "T" & Pd(Hour(lastChangedDateTime), 2) & Pd(Minute(lastChangedDateTime), 2) & Pd(Second(lastChangedDateTime), 2) & "Z" + strLastCommitHuman = GetWeekDay(lastChangedDateTime) & ", " & Pd(DAY(lastChangedDateTime), 2) & " " & GetMonthName(lastChangedDateTime) & " " & YEAR(lastChangedDateTime) & " " & Pd(Hour(lastChangedDateTime), 2) & ":" & Pd(Minute(lastChangedDateTime), 2) & ":" & Pd(Second(lastChangedDateTime), 2) & " Z" Else - strLastCommit = "UNKNOWN" + strLastCommit = "" + strLastCommitHuman = "" End If 'Get revision hash strRevision = ExecAndGetResult(tmpFolder, VersionDir, "git rev-list -n1 --abbrev=10 --abbrev-commit HEAD") - If strRevision = "" Then - strRevision = "UNKNOWN" - End If + If strLastCommit <> "" And strLastCommitHuman <> "" And strRevision <> "" Then + 'Bild version string + strGitVer = "git~" & strLastCommit & "~" & strRevision + strVerHuman = "; git at commit " & strRevision & " on " & strLastCommitHuman - 'Bild version string - strGitVer="git~" & strLastCommit & "~" & strRevision - - 'Check for local changes, if found, append to git revision string - If ExecAndGetExitCode(tmpFolder, VersionDir, "git diff-index --quiet HEAD") <> 0 Then - lastChangedDateTime = GetTimeUTC() - strGitVer = strGitVer & "+unclean~" & YEAR(lastChangedDateTime) & Pd(Month(lastChangedDateTime), 2) & Pd(DAY(lastChangedDateTime), 2) & "T" & Pd(Hour(lastChangedDateTime), 2) & Pd(Minute(lastChangedDateTime), 2) & Pd(Second(lastChangedDateTime), 2) & "Z" + 'Check for local changes, if found, append to git revision string + If ShowUnclean Then + If ExecAndGetExitCode(tmpFolder, VersionDir, "git diff-index --quiet HEAD") <> 0 Then + lastChangedDateTime = GetTimeUTC() + strGitVer = strGitVer & "+unclean~" & YEAR(lastChangedDateTime) & Pd(Month(lastChangedDateTime), 2) & Pd(DAY(lastChangedDateTime), 2) & "T" & Pd(Hour(lastChangedDateTime), 2) & Pd(Minute(lastChangedDateTime), 2) & Pd(Second(lastChangedDateTime), 2) & "Z" + End If + End If + Else + strGitVer = "" + strVerHuman = "" End If If strVerRev = "" Then VERSION=strGitVer Else - VERSION=VERSION & "+" & strGitVer + If strGitVer <> "" Then + VERSION=VERSION & "+" & strGitVer + End If End If sLastVersion = "" @@ -371,13 +406,9 @@ Sub CreateVersion(tmpFolder, VersionDir, includebase, includedest) sLastFile.Close End If - If VERSION = "" Then - VERSION = "-UNKNOWN" - End If - - If VERSION <> sLastVersion Then + If VERSION & " " & strVerHuman <> sLastVersion Then Set MyFile = fso.CreateTextFile(tmpFolder & "lastversion", True) - MyFile.WriteLine(VERSION) + MyFile.WriteLine(VERSION & " " & strVerHuman) MyFile.Close FSO.CopyFile includebase, includedest, true @@ -385,6 +416,7 @@ Sub CreateVersion(tmpFolder, VersionDir, includebase, includedest) FindReplaceInFile includedest, "@SWITCH_VERSION_MAJOR@", strVerMajor FindReplaceInFile includedest, "@SWITCH_VERSION_MINOR@", strVerMinor FindReplaceInFile includedest, "@SWITCH_VERSION_MICRO@", strVerMicro + FindReplaceInFile includedest, "@SWITCH_VERSION_REVISION_HUMAN@", strVerHuman End If End Sub From 15a0b911bb1976193f8c7706676ba59d69c1c08e Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Fri, 10 Aug 2012 11:11:21 -0400 Subject: [PATCH 443/822] removing t38 hardcoded code --- .../mod_media_gateway/media_gateway_utils.c | 205 +++++++++--------- 1 file changed, 99 insertions(+), 106 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index c18057d3da..143af18d36 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -430,58 +430,6 @@ void mg_util_set_cmd_name_string (MgStr *errTxt, MgMgcoCommand *cmd) } } -/*****************************************************************************************************************************/ -void mgco_fill_t38_sdp_attr(CmSdpAttrSet *s, mg_termination_t* term, CmMemListCp *memCp) -{ - int i=0x00; - - if(!term->u.rtp.t38_options) return; - if (!s->numComp.pres) return ; - - for (i = 0; i < s->numComp.val; i++) { - CmSdpAttr *a = s->attr[i]; - if(NOTPRSNT == a->type.pres) continue; - - switch(a->type.val) - { - case CM_SDP_ATTR_T38_FAX: - { - CmSdpAttrT38Fax* f = &a->u.fax; - if(NOTPRSNT == f->type.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, - "CM_SDP_ATTR_T38_FAX: TYPE not present \n"); - break; - } -printf("f->u.unknown.name.val[%s, len=%d]\n", f->u.unknown.name.val, f->u.unknown.name.len); - -/* NOTE - Ideally i should not change ,whatever is coming we can return..due to -trillium issue forcefully coping the data...will remove once get trillium fix*/ -if(f->type.val == CM_SDP_ATTR_T38_FAX_UNKNOWN) { -if(!strncasecmp((char*)f->u.unknown.name.val,"transferredTCF",14) && term->u.rtp.t38_options->T38FaxRateManagement){ -printf("KAPIL - adding FaxRateManagement \n"); -MG_SET_TKNSTROSXL((f->u.unknown.name),strlen("FaxRateManagement"),"FaxRateManagement", memCp); -MG_SET_TKNSTROSXL((f->u.unknown.val), - strlen(term->u.rtp.t38_options->T38FaxRateManagement), - term->u.rtp.t38_options->T38FaxRateManagement, memCp); -}else if((!strncasecmp((char*)f->u.unknown.name.val,"t38UDPRedundancy",16)) && term->u.rtp.t38_options->T38FaxUdpEC){ -printf("KAPIL - adding FaxUdpEC \n"); -MG_SET_TKNSTROSXL((f->u.unknown.name),strlen("FaxUdpEC"),"FaxUdpEC", memCp); -MG_SET_TKNSTROSXL((f->u.unknown.val), - strlen(term->u.rtp.t38_options->T38FaxUdpEC), - term->u.rtp.t38_options->T38FaxUdpEC, memCp); -}else if(!strncasecmp((char*)f->u.unknown.name.val,"14400",5)){ -char buf[10] = {0}; -printf("KAPIL - adding MaxBitRate \n"); -sprintf(buf,"%d",term->u.rtp.t38_options->T38MaxBitRate); -MG_SET_TKNSTROSXL((f->u.unknown.name),strlen("MaxBitRate"),"MaxBitRate", memCp); -MG_SET_TKNSTROSXL((f->u.unknown.val), - strlen(buf), buf, memCp); -} -} -} -} -} -} /*****************************************************************************************************************************/ void mgco_handle_sdp_attr_set(CmSdpAttrSet *s, mg_termination_t* term) { @@ -817,24 +765,106 @@ void mgco_handle_sdp_attr_set(CmSdpAttrSet *s, mg_termination_t* term) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\t CM_SDP_ATTR_T38_FAX: type=%d\n", f->type.val); - if(f->type.val == CM_SDP_ATTR_T38_FAX_UNKNOWN) { - if(f->u.unknown.name.pres){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, - "T38: Attribute : name[len=%d, value=%s] \n", - f->u.unknown.name.len,(char*)f->u.unknown.name.val); - } - if(f->u.unknown.val.pres){ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, - "T38: Attribute : value[len=%d, value=%s] \n", - f->u.unknown.val.len,(char*)f->u.unknown.val.val); - } + if(NULL == term->u.rtp.t38_options){ + term->u.rtp.t38_options = + switch_core_alloc(term->pool, sizeof *term->u.rtp.t38_options); + } + switch(f->type.val) + { + case CM_SDP_ATTR_T38_FAX_VER: + { + term->u.rtp.t38_options->T38FaxVersion = f->u.num.val; + break; + } + case CM_SDP_ATTR_T38_MAX_BIT_RATE: + { + term->u.rtp.t38_options->T38MaxBitRate = f->u.num.val; + break; + } + case CM_SDP_ATTR_T38_FAX_FILL_BIT_RMVL: + { + term->u.rtp.t38_options->T38FaxFillBitRemoval = f->u.num.val; + break; + } + case CM_SDP_ATTR_T38_FAX_TRNS_MMR: + { + term->u.rtp.t38_options->T38FaxTranscodingMMR = f->u.num.val; + break; + } + case CM_SDP_ATTR_T38_FAX_TRNS_JBIG: + { + term->u.rtp.t38_options->T38FaxTranscodingJBIG = f->u.num.val; + break; + } + case CM_SDP_ATTR_T38_FAX_RATE_MNGMNT: + { + switch(f->u.val.val) + { + case CM_SDP_ATTR_T38_FAX_RATE_MNG_LOC_TCF: + { + term->u.rtp.t38_options->T38FaxRateManagement = + switch_core_strdup(term->pool,"localTCF") ; + break; + } + case CM_SDP_ATTR_T38_FAX_RATE_MNG_TRANSF_TCF: + { + term->u.rtp.t38_options->T38FaxRateManagement = + switch_core_strdup(term->pool,"transferredTCF") ; + break; + } + } + break; + } + case CM_SDP_ATTR_T38_FAX_MAX_BFR: + { + term->u.rtp.t38_options->T38FaxMaxBuffer = f->u.num.val; + break; + } + case CM_SDP_ATTR_T38_FAX_MAX_DATAGRAM: + { + term->u.rtp.t38_options->T38FaxMaxDatagram = f->u.num.val; + break; + } + case CM_SDP_ATTR_T38_FAX_UDP_EC: + { + switch(f->u.val.val) + { + case CM_SDP_ATTR_T38_FAX_UDP_EC_UDP_FEC: + { + term->u.rtp.t38_options->T38FaxUdpEC = + switch_core_strdup(term->pool,"t38UDPNoEC"); + break; + } + case CM_SDP_ATTR_T38_FAX_UDP_EC_UDP_RED: + { + term->u.rtp.t38_options->T38FaxUdpEC = + switch_core_strdup(term->pool,"t38UDPRedundancy") ; + break; + } + } + break; + } + case CM_SDP_ATTR_T38_FAX_UNKNOWN: + { + if(f->u.unknown.name.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "T38: Attribute : name[len=%d, value=%s] \n", + f->u.unknown.name.len,(char*)f->u.unknown.name.val); + } + if(f->u.unknown.val.pres){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "T38: Attribute : value[len=%d, value=%s] \n", + f->u.unknown.val.len,(char*)f->u.unknown.val.val); + } + break; + } + + default: + break; } - /* filling default values */ - if(NULL == term->u.rtp.t38_options){ - term->u.rtp.t38_options = - switch_core_alloc(term->pool, sizeof *term->u.rtp.t38_options); - } + +#if 0 term->u.rtp.t38_options->T38FaxVersion = 0x01; term->u.rtp.t38_options->T38MaxBitRate = 14400; term->u.rtp.t38_options->T38FaxRateManagement = @@ -844,6 +874,7 @@ void mgco_handle_sdp_attr_set(CmSdpAttrSet *s, mg_termination_t* term) term->u.rtp.t38_options->T38FaxUdpEC = switch_core_strdup(term->pool,"t38UDPRedundancy") ; //term->u.rtp.t38_options->T38VendorInfo = +#endif break; } @@ -2072,7 +2103,6 @@ switch_status_t mg_build_sdp(MgMgcoMediaDesc* out, MgMgcoMediaDesc* inc, megaco_ { CmSdpU8OrNil *fmt = NULL; CmSdpInfoSet *psdp = NULL; - CmSdpInfoSet *pRsdp = NULL; char* ipAddress[4]; int i = 0x00; int j = 0x00; @@ -2124,38 +2154,6 @@ switch_status_t mg_build_sdp(MgMgcoMediaDesc* out, MgMgcoMediaDesc* inc, megaco_ } } -if(remote && (NOTPRSNT != remote->sdp.numComp.pres) && (0 != remote->sdp.numComp.val)){ -pRsdp = &(remote->sdp); -for(i=0; i< pRsdp->numComp.val; i++) { -/* fill media descriptors */ -{ -CmSdpMediaDescSet* med = &pRsdp->info[pRsdp->numComp.val-1]->mediaDescSet; -CmSdpMediaDesc* media; - -if((NOTPRSNT != med->numComp.pres) || (0 != med->numComp.val)){ - for(j =0;j < med->numComp.val; j++){ - media = med->mediaDesc[j]; - - /* check for codec */ -if((NOTPRSNT != media->field.par.numProtFmts.pres) || - (0 != media->field.par.numProtFmts.val)){ - for(k =0;k < media->field.par.numProtFmts.val; k++){ -format = media->field.par.pflst[k]; -if ((NOTPRSNT != format->protType.pres) && - (CM_SDP_MEDIA_PROTO_UDPTL == format->protType.val)){ -/* ideally whatever is received we can send back * -* due to issue in trillium , we need to manually copy the fields now */ - mgco_fill_t38_sdp_attr(&media->attrSet, term, memCp); -} -} -} -} -} -} -/**********************************************************************************************************************************/ -} -} - if(!local || (NOTPRSNT == local->sdp.numComp.pres) || (0 == local->sdp.numComp.val)){ /* local sdp is not part of media descriptor, then add local sdp*/ @@ -2277,11 +2275,6 @@ if ((NOTPRSNT != format->protType.pres) && return SWITCH_STATUS_FALSE; } } -}else if ((NOTPRSNT != format->protType.pres) && - (CM_SDP_MEDIA_PROTO_UDPTL == format->protType.val)){ -/* ideally whatever is received we can send back * -* due to issue in trillium , we need to manually copy the fields now */ - mgco_fill_t38_sdp_attr(&media->attrSet, term, memCp); } } } From 036063d2a9ed56eb123acc77c2a7d1d9c733263d Mon Sep 17 00:00:00 2001 From: Stefan Knoblich Date: Wed, 8 Aug 2012 17:30:03 +0200 Subject: [PATCH 444/822] mod_freetdm: Fix typo. Signed-off-by: Stefan Knoblich --- libs/freetdm/mod_freetdm/mod_freetdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 64d34f232c..2f66edd019 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -864,7 +864,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc ftdm_channel_wait(tech_pvt->ftdmchan, &wflags, ftdm_channel_get_io_interval(tech_pvt->ftdmchan) * 10); if (!(wflags & FTDM_WRITE)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Dropping frame! (write note ready) in channel %s device %d:%d!\n", name, span_id, chan_id); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Dropping frame! (write not ready) in channel %s device %d:%d!\n", name, span_id, chan_id); return SWITCH_STATUS_SUCCESS; } From 2ad2b6d31bf201b0779a5c217039860e2e009395 Mon Sep 17 00:00:00 2001 From: Stefan Knoblich Date: Fri, 10 Aug 2012 17:05:46 +0200 Subject: [PATCH 445/822] ftmod_isdn: Avoid stack smashing buffer overflow in isdn_tones_run(). The len variable can, in certain situations (large burst of incoming non-SLIN audio), exceed the size of the on-stack frame buffer, which causes ftdm_buffer_read_loop() to overwrite the dt_buffer pointer. Use ftdm_min() to make sure len (after conversion to SLIN units) isn't larger than the frame buffer size. Also adds are couple more code comments. Signed-off-by: Stefan Knoblich --- .../freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c index 11139f7fb4..99ff253835 100644 --- a/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c +++ b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c @@ -1936,6 +1936,11 @@ static void *ftdm_isdn_tones_run(ftdm_thread_t *me, void *obj) continue; } + /* + * Teletone operates on SLIN data (2 bytes per sample). + * Convert the length of non-SLIN codecs, so we read + * the right amount of samples from the buffer. + */ if (chan->effective_codec != FTDM_CODEC_SLIN) { len *= 2; } @@ -1943,6 +1948,12 @@ static void *ftdm_isdn_tones_run(ftdm_thread_t *me, void *obj) /* seek to current offset */ ftdm_buffer_seek(dt_buffer, data->offset); + /* + * ftdm_channel_read() can read up to sizeof(frame) bytes + * (in certain situations). Avoid overflowing the stack (and smashing dt_buffer) + * if the codec is not slin and we had to double the length. + */ + len = ftdm_min(len, sizeof(frame)); rlen = ftdm_buffer_read_loop(dt_buffer, frame, len); if (chan->effective_codec != FTDM_CODEC_SLIN) { @@ -1954,6 +1965,12 @@ static void *ftdm_isdn_tones_run(ftdm_thread_t *me, void *obj) codec_func = fio_slin2alaw; } + /* + * Convert SLIN to native format (a-law/u-law), + * input size is 2 bytes per sample, output size + * (after conversion) is one byte per sample + * (= max. half the input size). + */ if (codec_func) { status = codec_func(frame, sizeof(frame), &rlen); } else { @@ -1968,11 +1985,12 @@ static void *ftdm_isdn_tones_run(ftdm_thread_t *me, void *obj) * of data actually written to channel. */ if (chan->effective_codec != FTDM_CODEC_SLIN) { - data->offset += rlen << 1; /* teletone buffer is slin (= len * 2) */ + data->offset += rlen << 1; /* Teletone buffer is in SLIN (= rlen * 2) */ } else { data->offset += rlen; } + /* Limit offset to [0..Rate(Samples/s)-1] in SLIN (2 bytes per sample) units. */ data->offset %= (ts.rate << 1); } } From bb0187ba9462db626c02dae4925036f20b6e5cfb Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Fri, 10 Aug 2012 12:23:03 -0400 Subject: [PATCH 446/822] fixing issue --- src/mod/endpoints/mod_media_gateway/media_gateway.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 3590762cb5..3b12dadfeb 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -143,6 +143,7 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) /* A UUID is present, check if the channel still exists */ switch_core_session_t *session; if ((session = switch_core_session_locate(term->uuid))) { + switch_channel_t *channel = switch_core_session_get_channel(session); switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "command", "media_modify"); switch_core_session_receive_event(session, &var_event); @@ -373,6 +374,7 @@ void megaco_termination_destroy(mg_termination_t *term) free(term->active_events); term->active_events = NULL; } + term->context = NULL; switch_clear_flag(term, MGT_ALLOCATED); switch_clear_flag(term, MGT_ACTIVE); @@ -412,6 +414,7 @@ switch_status_t megaco_context_add_termination(mg_context_t *ctx, mg_termination return SWITCH_STATUS_FALSE; } + term->context = ctx; if (ctx->terminations[0]) { ctx->terminations[1] = term; } else if (ctx->terminations[1]) { From 53543aa72d164d2fb524a84d53d9ba305fed9ddd Mon Sep 17 00:00:00 2001 From: kapil Date: Fri, 10 Aug 2012 12:24:33 -0400 Subject: [PATCH 447/822] matt code changes --- src/mod/endpoints/mod_media_gateway/media_gateway.c | 3 ++- .../mod_media_gateway/media_gateway_cmd_handler.c | 10 ++++++++-- src/mod/endpoints/mod_sofia/rtp.c | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 3590762cb5..78c0d40099 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -374,6 +374,7 @@ void megaco_termination_destroy(mg_termination_t *term) term->active_events = NULL; } + switch_clear_flag(term, MGT_ALLOCATED); switch_clear_flag(term, MGT_ACTIVE); @@ -427,7 +428,7 @@ switch_status_t megaco_context_add_termination(mg_context_t *ctx, mg_termination if (zstr(ctx->terminations[1]->uuid)) { megaco_activate_termination(ctx->terminations[1]); } - + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Bridging: %s (%s) <> %s (%s)\n", ctx->terminations[0]->name, ctx->terminations[0]->uuid, ctx->terminations[1]->name, ctx->terminations[1]->uuid); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index 4e93abbf11..5aa1abb4a2 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -2879,8 +2879,14 @@ switch_status_t mg_send_notify(megaco_profile_t* mg_profile, const char* term_n request.transId.val = get_txn_id(); request.contextId.type.pres = PRSNT_NODEF; - request.contextId.type.val = MGT_CXTID_NULL; - + if(term->context){ + printf("Temrination is in context, adding context-id[%d]\n",term->context->context_id); + request.contextId.type.val = MGT_CXTID_OTHER; + request.contextId.val.pres = PRSNT_NODEF; + request.contextId.val.val = term->context->context_id; + } else{ + request.contextId.type.val = MGT_CXTID_NULL; + } request.cmdStatus.pres = PRSNT_NODEF; request.cmdStatus.val = CH_CMD_STATUS_END_OF_TXN; diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 9f0bc0147f..4eb43b146c 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -220,7 +220,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi rate, ptime, 1, - /*SWITCH_CODEC_FLAG_ENCODE |*/ SWITCH_CODEC_FLAG_DECODE, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); goto fail; @@ -231,7 +231,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi rate, ptime, 1, - SWITCH_CODEC_FLAG_ENCODE /*| SWITCH_CODEC_FLAG_DECODE*/, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); goto fail; From 7cbdc67b0cd0155f937305b078c62adbc1956ea1 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Fri, 10 Aug 2012 13:40:27 -0400 Subject: [PATCH 448/822] wait for it... --- src/mod/endpoints/mod_media_gateway/media_gateway.c | 12 ++++++------ src/mod/endpoints/mod_sofia/rtp.c | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 134b609a27..3652946bce 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -127,8 +127,8 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, kCODEC, term->u.rtp.codec); switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, kMEDIATYPE, mg_media_type2str(term->u.rtp.media_type)); - switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "fax_enable_t38", "true"); - switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "rtp_execute_on_image", "t38_gateway peer nocng"); + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "fax_enable_t38", "true"); + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "rtp_execute_on_image", "t38_gateway peer nocng"); } else if (term->type == MG_TERM_TDM) { switch_snprintf(dialstring, sizeof dialstring, "tdm/%s", term->name); @@ -143,14 +143,14 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) /* A UUID is present, check if the channel still exists */ switch_core_session_t *session; if ((session = switch_core_session_locate(term->uuid))) { - switch_channel_t *channel = switch_core_session_get_channel(session); + switch_channel_t *channel = switch_core_session_get_channel(session); switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "command", "media_modify"); - switch_core_session_receive_event(session, &var_event); - - if (term->u.rtp.t38_options) { + if (term->u.rtp.t38_options) { switch_channel_set_private(channel, "t38_options", term->u.rtp.t38_options); } + + switch_core_session_receive_event(session, &var_event); switch_core_session_rwunlock(session); diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 4eb43b146c..d6284cc20a 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -509,7 +509,7 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi } if (compare_var(event, channel, kRFC2833PT)) { - const char *szpt = switch_channel_get_variable(channel, kRFC2833PT); + const char *szpt = switch_event_get_header(event, kRFC2833PT); int pt = !zstr(szpt) ? atoi(szpt) : 0; tech_pvt->rfc2833_pt = pt; @@ -525,7 +525,7 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi } if (compare_var(event, channel, kMEDIATYPE)) { - const char *newmode = switch_channel_get_variable(channel, kMEDIATYPE); + const char *newmode = switch_event_get_header(event, kMEDIATYPE); if (!strcmp(newmode, "image")) { switch_channel_set_variable(tech_pvt->channel, "has_t38", "true"); From 618392299b831f09b683f2e98c0d93b5b6ef342e Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 10 Aug 2012 20:12:20 -0500 Subject: [PATCH 449/822] add javascript chatplan app --- .../mod_spidermonkey/mod_spidermonkey.c | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c b/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c index 83e723e061..7ba7975e98 100644 --- a/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c +++ b/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c @@ -3628,7 +3628,7 @@ static int env_init(JSContext * cx, JSObject * javascript_object) return 1; } -static void js_parse_and_execute(switch_core_session_t *session, const char *input_code, struct request_obj *ro) +static void js_parse_and_execute(switch_core_session_t *session, const char *input_code, struct request_obj *ro, switch_event_t *message) { JSObject *javascript_global_object = NULL; char buf[1024], *arg, *argv[512]; @@ -3657,6 +3657,12 @@ static void js_parse_and_execute(switch_core_session_t *session, const char *inp if (!(session && new_js_session(cx, javascript_global_object, session, &jss, "session", flags))) { switch_snprintf(buf, sizeof(buf), "~var session = false;"); eval_some_js(buf, cx, javascript_global_object, &rval); + + if (message) { + new_js_event(message, "message", cx, javascript_global_object); + } + + } if (ro) { new_request(cx, javascript_global_object, ro); @@ -3704,7 +3710,16 @@ static void js_parse_and_execute(switch_core_session_t *session, const char *inp SWITCH_STANDARD_APP(js_dp_function) { - js_parse_and_execute(session, data, NULL); + js_parse_and_execute(session, data, NULL, NULL); +} + +SWITCH_STANDARD_CHAT_APP(js_chat_function) +{ + + js_parse_and_execute(NULL, data, NULL, message); + + return SWITCH_STATUS_SUCCESS; + } struct js_task { @@ -3717,7 +3732,7 @@ static void *SWITCH_THREAD_FUNC js_thread_run(switch_thread_t *thread, void *obj struct js_task *task = (struct js_task *) obj; switch_memory_pool_t *pool; - js_parse_and_execute(NULL, task->code, NULL); + js_parse_and_execute(NULL, task->code, NULL, NULL); if ((pool = task->pool)) { switch_core_destroy_memory_pool(&pool); @@ -3775,7 +3790,7 @@ SWITCH_STANDARD_API(jsapi_function) ro.session = session; ro.stream = stream; - js_parse_and_execute(session, (char *) cmd, &ro); + js_parse_and_execute(session, (char *) cmd, &ro, NULL); return SWITCH_STATUS_SUCCESS; } @@ -3795,6 +3810,8 @@ SWITCH_STANDARD_API(launch_async) SWITCH_MODULE_LOAD_FUNCTION(mod_spidermonkey_load) { switch_application_interface_t *app_interface; + switch_chat_application_interface_t *chat_app_interface; + //switch_status_t status; //if ((status = init_js()) != SWITCH_STATUS_SUCCESS) { @@ -3812,6 +3829,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_spidermonkey_load) SWITCH_ADD_APP(app_interface, "javascript", "Launch JS ivr", "Run a javascript ivr on a channel", js_dp_function, " +

The Perl API for reading and writing tpl is nearly identical to the C API. This +document will briefly explain the Perl API and provide examples. The chief +motivation for having a Perl API is to communicate with C programs that use tpl.

+
+ + + +
+
Tip
+
+
Start with the C API
This document assumes familiarity with the C API. The concepts of using tpl +are not explained here. For an introduction to tpl and its C API, see the +User Guide.
+
+

Tpl.pm

+

The Tpl.pm file (in the lang/perl) directory contains the Perl module. You +can copy it to another directory if you wish. Your Perl program may need to +include a use lib statement to find the module.

+
+
+
#!/usr/bin/perl
+use lib "/some/directory";
+use Tpl;
+
+

tpl_map

+

This function resembles the C version, except that it’s invoked via the Tpl +module, and it takes references to Perl variables after the format string.

+
+
+
my $i;
+my $tpl = Tpl->tpl_map("A(i)",\$i);
+
+

The return value is a tpl object; all other API calls are object methods. +Incidentally, there is no tpl_free() method corresponding to the C API.

+

Fixed-length arrays

+

Format strings such as i# denote a fixed-length array. In the Perl API, +fixed-length arrays require two arguments: a list reference, and the fixed +length. For example:

+
+
+
my @x;
+my $tpl = Tpl->tpl_map("i#", \@x, 10);
+
+

When fixed-length arrays are packed or unpacked, the specified number of +elements will be copied from (or placed into) the designated list.

+

Structures

+

Format strings containing S(…) are handled in the Perl API as if only the +interior, parenthesized part was present. (It does not work like the C API). So +simply ignore the S(…) and consider only its interior format characters when +constructing the argument list:

+
+
+
my ($str, $int);
+my $tpl = Tpl->tpl_map("S(si)", \$str, \$int);
+
+

It really only makes sense to use S(…) in a format string in the Perl API if +you are communicating with a C program that uses structures.

+

tpl_pack

+

This is nearly identical to the C version. The only argument is the index +number to pack.

+
+
+
$tpl->tpl_pack(1);
+
+

tpl_dump

+

This method is a little different than the C version. Given no arguments, it +returns the tpl image; given one argument it writes a file with that name.

+
+
+
$tpl->tpl_dump("demo.tpl");   # writes demo.tpl
+
+

Or,

+
+
+
my $img = $tpl->tpl_dump();
+
+

The tpl image is a binary buffer. You can do whatever you want with it, such as +write it to a socket or pipe (probably to C program listening on the other end), +or save it somewhere and later re-load it using tpl_load().

+

tpl_load

+

This method loads a tpl image from a file or from a Perl variable. It takes +one argument. If it’s not a reference, it’s assumed to be a filename to load.

+
+
+
$tpl->tpl_load("demo.tpl");
+
+

Otherwise, if the argument is a Perl reference, it’s construed as a variable +containing the tpl image:

+
+
+
$tpl->tpl_load(\$img);
+
+

The method will die if the image is invalid or the file doesn’t exist. You +can wrap it with eval to catch such errors:

+
+
+
eval { $tpl->tpl_load(\$img); };
+print "failed to load\n" if $@;
+
+

tpl_unpack

+

This is nearly identical to the C version. The only argument is the index +number to unpack.

+
+
+
$tpl->tpl_unpack(1);
+
+ +

Examples

+
+

Integer array

+
+
Packing A(i) to file
+
+
#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Tpl;
+
+my $i;
+my $tpl = Tpl->tpl_map("A(i)",\$i);
+for($i=0; $i<10; $i++) {
+    $tpl->tpl_pack(1);
+}
+$tpl->tpl_dump("demo.tpl");
+
+
+
Unpacking A(i) from file
+
+
#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Tpl;
+
+my $j;
+my $tpl2 = Tpl->tpl_map("A(i)",\$j);
+$tpl2->tpl_load("demo.tpl");
+while($tpl2->tpl_unpack(1) > 0) {
+    print "$j\n";
+}
+
+

Message-passing

+

While the bulk of this example is socket handling, it demonstrates how you can +use tpl as a message-passing format. In the real-world, you might have a C +server and a Perl client, for example. In this example, we’ll code both a client +and a server in Perl.

+
+
+

Server

+

The server waits for a connection from a client. When it gets one, it accepts +the connection and immediately forks a child process to handle it. Then it goes +back to waiting for another new connection.

+

The server child process handles the client by loading and unpacking the tpl +image sent by the client (containing an array of integers). It calculates their +sum and constructs a new tpl image containing the sum, which it sends back to +the client.

+
+
Server
+
+
#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use IO::Socket::INET;
+use Tpl;
+
+$SIG{CHLD} = "IGNORE"; # don't create zombies
+
+our $port = 2000;
+
+sub handle_client {
+    my $client = shift;
+
+    undef $/;
+    my $request = <$client>; # get request (slurp)
+
+    # read input array, and calculate total
+    my ($i,$total);
+    my $tpl = Tpl->tpl_map("A(i)", \$i);
+    eval { $tpl->tpl_load(\$request); };
+    die "received invalid tpl" if $@;
+    $total += $i while $tpl->tpl_unpack(1) > 0;
+
+    # formulate response and send
+    my $tpl2 = Tpl->tpl_map("i", \$total);
+    $tpl2->tpl_pack(0);
+    my $response = $tpl2->tpl_dump();
+    print $client $response;
+    close $client;
+}
+
+my $server = IO::Socket::INET->new(LocalPort => $port,
+                   Type => SOCK_STREAM,
+                   Reuse => 1,
+                   Listen => 10 )
+        or die "Can't listen on port $port: $!\n";
+
+while (1) {
+    my $client = $server->accept();
+    next unless $client;
+    # new connection
+    my $pid = fork;
+    die "can't fork: $!\n" unless defined $pid;
+    if ($pid > 0) {
+        # parent
+        close $client;
+    } elsif ($pid == 0) {
+        # child
+        handle_client($client);
+        exit(0);
+    }
+}
+close ($server);
+
+

Client

+

The client is a simpler program. It constructs the tpl image containing the +integer array (taken from its command-line arguments), connects to the server +and sends the tpl image to it, and then awaits the response tpl. The response +containing the sum is loaded, unpacked and printed.

+
+
Client
+
+
#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use IO::Socket::INET;
+use Tpl;
+
+our $port = 2000;
+
+# construct tpl
+my $i;
+my $tpl = Tpl->tpl_map("A(i)",\$i);
+$tpl->tpl_pack(1) while ($i=shift @ARGV);
+my $request = $tpl->tpl_dump();
+
+# send to server, get response
+my $socket = IO::Socket::INET->new("localhost:$port") or die "can't connect";
+print $socket $request;
+shutdown($socket,1);        # done writing (half-close)
+undef $/;
+my $response = <$socket>;       # get reply (slurp)
+
+# decode response (or print error)
+my $total;
+my $tpl2 = Tpl->tpl_map("i", \$total);
+eval { $tpl2->tpl_load(\$response); };
+die "invalid response\n" if $@;
+$tpl2->tpl_unpack(0);
+print "total is $total\n";
+
+

Running thise example

+

If the client and server programs are in client.pl and server.pl, then +you can run the example by starting the server in one window:

+
+
+
./server.pl
+
+

Then run the client in another window. E.g.,

+
+
+
./client.pl 1 2 3 4 5
+
+

The client runs and then exits, printing:

+
+
+
total is 15
+
+

You can re-run the client with different arguments. When done, type Ctrl-C in +the server window to terminate it.

+
+ + + diff --git a/libs/libtpl-1.5/doc/html/styles.css b/libs/libtpl-1.5/doc/html/styles.css new file mode 100755 index 0000000000..c23156eee9 --- /dev/null +++ b/libs/libtpl-1.5/doc/html/styles.css @@ -0,0 +1,160 @@ +#banner { + /* font-size: x-large; */ + /* background: #ff00ff; */ + /* height: 100px; */ +} + +#topnav { + /* background-image: url(img/grad_topnav.png); */ + /* background-repeat: repeat-y; */ + /* background-color: #af00af; */ + /* height: 25px; */ + margin: 10px 0px 10px 20px; + padding: 3px; + font-size: 9pt; + font-family: sans-serif; + /* border-style: solid; */ + /* border-width: 1px; */ +} + + +#topnav {font-weight: bold} +#topnav a {font-weight: normal} + +h1,p { margin: 0; } /* non-0 margin on firefox */ + +#mid { + background-image: url(img/grad_azure.png); + background-repeat: repeat-y; + /* background-color: #ffddaa; */ + padding-top: 20px; + margin-bottom: 10px; +} + +#mid img { + padding-left: 10px; + vertical-align: middle; +} + +a img { + border: 0 +} + +#nav { + background-color: #fff8f1; + margin-left: 10px; + margin-top: 20px; + float: left; + padding: 10px; + border-style: solid; + border-width: 2px; + font-family: sans-serif; +} + + +#nav h2 { + font-weight: bold; + font-size: 10pt; +} + +#nav h3 { + /* font-weight: bold; */ + padding-left: 5px; + /* font-style: oblique; */ + font-family: sans-serif; + font-size: 7pt; +} + +#nav div { + font-size: 9pt; + padding-left: 15px; +} + +#main { + background: #ffffff; + margin-top: 20px; + margin-left: 170px; + padding-left: 20px; + height: 100%; + /* font-family: sans-serif; */ +} + +#main h1 { + font-family: sans-serif; +} + + +.listing { + margin: 20px; + font-family: sans-serif; + font-weight: bold; +} + +.code { + padding: 10px; + background: #f3f3f3; + font-size: 8pt; + font-weight: normal; + width: 80%; + border-style: solid; + border-width: 1px; +} + +.code pre { + padding-left: 20px; + padding-right: 80px; +} + +#formatstrings { + margin: 20px; +} + +#footer { + /* background: #00ffff; */ + margin-top: 5px; + font-size: small; + font-family: sans-serif; +} + +em { + font-weight: bold; +} + +hr { + height: 0.04em; + background: black; + margin: 0 10% 0 0; +} + +#footer img { + margin-right: 5px; + float: right; +} + +.lead { + font-family: sans-serif; + font-size: larger; + font-weight: bold; + /* font-style: oblique; */ + margin: 30px 30px 30px 0px; + color: #1122dd; +} + +ol { + font-family: monospace; + background: #dddddd; + padding-top: 10px; + padding-bottom: 10px; + width: 80%; + border-width: 1px; + border-style: solid; + /* font-size: smaller; */ +} + +#main #portrait { + float: right; + font-size: smaller; + font-family: sans-serif; + text-align: center; + margin: 10px; +} diff --git a/libs/libtpl-1.5/doc/html/tdh-quirks.css b/libs/libtpl-1.5/doc/html/tdh-quirks.css new file mode 100755 index 0000000000..7478972ce1 --- /dev/null +++ b/libs/libtpl-1.5/doc/html/tdh-quirks.css @@ -0,0 +1,31 @@ +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-content { + padding-left: 2.0em; +} + +div.exampleblock-content { + border-left: 2px solid silver; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } diff --git a/libs/libtpl-1.5/doc/html/tdh.css b/libs/libtpl-1.5/doc/html/tdh.css new file mode 100755 index 0000000000..b9679f31ff --- /dev/null +++ b/libs/libtpl-1.5/doc/html/tdh.css @@ -0,0 +1,301 @@ +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; +} + +strong { + font-weight: bold; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revision { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble, +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-right: 10%; + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.5em; + margin-bottom: 2.5em; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock { + margin-right: 0%; +} +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock > div.content { + padding-left: 2.0em; +} + +div.attribution { + text-align: right; +} +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 2px solid silver; +} + +div.exampleblock > div.content { + border-left: 2px solid silver; + padding: 0.5em; +} + +div.verseblock div.content { + white-space: pre; +} + +div.imageblock div.content { padding-left: 0; } +div.imageblock img { border: 1px solid silver; } +span.image img { border-style: none; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: italic; +} +dd > *:first-child { + margin-top: 0; +} + +ul, ol { + list-style-position: outside; +} +div.olist2 ol { + list-style-type: lower-alpha; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} + +div.hlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hlist td { + padding-bottom: 5px; +} +td.hlist1 { + vertical-align: top; + font-style: italic; + padding-right: 0.8em; +} +td.hlist2 { + vertical-align: top; +} + +@media print { + div#footer-badges { display: none; } +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +#toc { + float: right; + font-family: sans-serif; + border: 1px solid #000; + margin: 0px 0px 20px 20px; + padding: 0px; + background: #f0f0f0; + font-size: 80%; +} + +#toc #hdr { + color:#ffffff; + background:#98b1c4; + text-align:center; + margin-bottom:5px; +} + +a img { + border: 0 +} + +#toc a:visited, #toc a:link { color:#000; text-decoration: none } +#toc a:hover { color:#00f; text-decoration: underline; } + +#toc .level2 { margin-left: 1em; margin-top: 2px; margin-bottom: 2px; text-decoration: underline; } +#toc .level3 { margin-left: 2em; font-size: 0.8em } + +.toplink { + float: right; + font-size: 50%; + cursor: pointer; +} + +#topnav {font-weight: bold} +#topnav a {font-weight: normal} diff --git a/libs/libtpl-1.5/doc/html/toc.css b/libs/libtpl-1.5/doc/html/toc.css new file mode 100755 index 0000000000..ae3363ee51 --- /dev/null +++ b/libs/libtpl-1.5/doc/html/toc.css @@ -0,0 +1,35 @@ +#toc { + float: right; + font-family: sans-serif; + border: 1px solid #000; + margin: 0px 0px 20px 20px; + padding: 0px; + background: #f0f0f0; + font-size: 80%; +} + +#toc #hdr { + color:#ffffff; + background:#98b1c4; + text-align:center; + margin-bottom:5px; +} + +a img { + border: 0 +} + +#toc a:visited, #toc a:link { color:#000; text-decoration: none } +#toc a:hover { color:#00f; text-decoration: underline; } + +#toc .level2 { margin-left: 1em; margin-top: 2px; margin-bottom: 2px; text-decoration: underline; } +#toc .level3 { margin-left: 2em; font-size: 0.8em } + +.toplink { + float: right; + font-size: 50%; + cursor: pointer; +} + +#topnav {font-weight: bold} +#topnav a {font-weight: normal} diff --git a/libs/libtpl-1.5/doc/html/userguide.html b/libs/libtpl-1.5/doc/html/userguide.html new file mode 100755 index 0000000000..368a605f20 --- /dev/null +++ b/libs/libtpl-1.5/doc/html/userguide.html @@ -0,0 +1,1539 @@ + + + + + +tpl User Guide + + + + + +
+
+SourceForge.net +
+ sf.net summary page > + tpl home > + tpl User Guide + [View PDF] +
+
+
+

Overview

+
+
+ +

Serialization in C

+

Tpl is a library for serializing C data. The data is stored in its natural +binary form. The API is small and tries to stay "out of the way". +Tpl can serialize many C data types, including structures.

+

Uses for tpl

+

Tpl makes a convenient file format. For example, suppose a program needs to +store a list of user names and ids. This can be expressed using the format +string A(si). If the program needs two such lists (say, one for regular +users and one for administrators) this could be expressed as A(si)A(si). It +is easy to read and write this kind of structured data using tpl.

+

Tpl can also be used as an IPC message format. It handles byte order issues +and deframing individual messages off of a stream automatically.

+

Expressing type

+

The "data type" of a tpl is explicitly stated as a format string. There is +never any ambiguity about the type of data stored in a tpl. Some examples:

+
    +
  • +

    +A(is) is a variable-length array of integer-string pairs +

    +
  • +
  • +

    +A(is)A(is) are two such arrays, completely independent of one another +

    +
  • +
  • +

    +S(ci) is a structure containing a char and integer +

    +
  • +
  • +

    +S(ci)# is a fixed-length array of the latter structure +

    +
  • +
  • +

    +A(A(i)) is a nested array, that is, an array of integer arrays +

    +
  • +
+

The tpl image

+

A tpl image is the serialized form of a tpl, stored in a memory buffer or file, +or written to a file descriptor.

+

What’s in a tpl image?

+

There is no need to understand the internal structure of the tpl image. But for the +curious, the image is a strictly defined binary buffer having two sections, +a header and the data. The header encodes the length of the image, its +format string, endian order and other flags. The data section contains the +packed data.

+

No framing needed

+

A property of the tpl image is that consecutive images can be written to a stream +without requiring any delimiter between them. The reader making use of +tpl_gather (or tpl_load in TPL_FD mode) will obtain exactly one tpl image at +a time. Therefore tpl images can be used as an IPC message format without any +higher-level framing protocol.

+

Data portability

+

A tpl image generated on one kind of CPU will generally be portable to other +CPU types when tpl is used properly. This may be a surprise considering that +tpl is a binary format. But tpl has been carefully designed to make this work. +Each format character has an associated explicitly-sized type. For +integer and floating point types, whose "endian" or byte-order convention varies +from one CPU to another, tpl automatically and transparently corrects the +endian order (if needed) during the unpacking process. Floating point numbers +present their own special difficulties. No guarantees +are made with regard to floating point portability. That said, because many +modern CPU’s use IEEE 754 floating point representation, data is likely to be +portable among them.

+

XML and Perl

+

Note: The tplxml utility and the Perl module are currently unsupported in tpl 1.5.

+

XML

+

While a tpl image is a binary entity, you can view any tpl image in XML format +using the included tplxml utility, located in the lang/perl directory.

+
+
+
tplxml file.tpl > file.xml
+tplxml file.xml > file.tpl
+
+

The utility is bidirectional, as shown. The file extension is not important; +tplxml inspects its input to see if it’s tpl or XML. You can also pipe data +into it instead of giving it a filename. The tplxml utility is slow. Its +purpose is two-fold: debugging (manual inspection of the data in a tpl), and +interoperability with XML-based programs. The resulting XML is often ten times +the size of the original binary tpl image.

+

Perl

+

There is a Perl module in lang/perl/Tpl.pm. The Perl API +is convenient for writing Perl scripts that interoperate with C programs, and +need to pass structured data back and forth. It is written in pure Perl.

+

Platforms

+

The tpl software was developed for POSIX systems and has been tested on 32- and 64-bit +platforms including:

+
    +
  • +

    +Linux +

    +
  • +
  • +

    +Solaris +

    +
  • +
  • +

    +Mac OS X +

    +
  • +
  • +

    +OpenBSD +

    +
  • +
  • +

    +Windows using Visual Studio 2008 or 2010, or Cygwin or MinGW +

    +
  • +
+

BSD licensed

+

This software is made available under the +revised BSD license. +It is free and open source.

+

Download

+

Please follow the link to download on the +tpl website.

+

Getting help

+

If you need help, you are welcome to email the author at +thanson@users.sourceforge.net.

+

Resources

+
+
+News +
+
+

+ The author has a news feed for software updates +(RSS) +. +

+
+
+
+

Build and install

+
+

Tpl has no dependencies on libraries other than the system C library. You +can simply copy the tpl source into your project, so you have no dependencies. +Alternatively, you can build tpl as a library and link it to your program.

+

As source

+

The simplest way to use tpl is to copy the source files tpl.h and tpl.c +(from the src/ directory) right into your project, and build them with the +rest of your source files. No special compiler flags are required.

+

As a library

+

Alternatively, to build tpl as a library, from the top-level directory, run:

+
+
+
./configure
+make
+make install
+
+

This installs a static library libtpl.a and a shared library (e.g., +libtpl.so), if your system supports them, in standard places. The installation +directory can be customized using ./configure --prefix=/some/directory. Run +configure --help for further options.

+

Test suite

+

You can compile and run the built-in test suite by running:

+
+
+
cd tests/
+make
+
+

On Windows

+

DLL

+

On the tpl home page, a Visual Studio 2008 solution package is available for +download. This zip file contains pre-built 32- and 64-bit versions of tpl as a +DLL. If you like, you can build the DLL yourself using VS2008 or VS2010 (the +free Express Edition is sufficient) by opening the solution file and choosing +Build Solution.

+

Non-DLL usage

+

Alternatively, tpl can be used directly (instead of as a DLL) by compiling +the tpl sources right into your program. To do this, add tpl.c, tpl.h, +win/mman.h and win/mmap.c to your program’s source and header files and +add the preprocessor definition TPL_NOLIB.

+

MinGW/Cygwin

+

Prior to tpl release 1.5, using tpl on Windows required building it with MinGW +or Cygwin. This is no longer necessary. If you want to build it that way anyway, +use the non-Windows (i.e. tar.bz2) tpl download and follow the "configure; make; +make install" approach.

+
+

API concepts

+
+

To use tpl, you need to know the order in which to call the API functions, and +the background concepts of format string, arrays and index numbers.

+

Order of functions

+

Creating a tpl is always the first step, and freeing it is the last step. In +between, you either pack and dump the tpl (if you’re serializing data) or you +load a tpl image and unpack it (if you’re deserializing data).

+
+ + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Order of usage
Step If you’re serializing… If you’re deserializing…

1.

tpl_map()

tpl_map()

2.

tpl_pack()

tpl_load()

3.

tpl_dump()

tpl_unpack()

4.

tpl_free()

tpl_free()

+
+

Format string

+

When a tpl is created using tpl_map(), its data type is expressed as a format +string. Each character in the format string has an associated argument of a +specific type. For example, this is how a format string and its arguments are +passed in to tpl_map:

+
+
+
tpl_node *tn;
+char c;
+int i[10];
+tn = tpl_map("ci#", &c, i, 10);  /* ci# is our format string */
+
+
+ + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Supported format characters
Type Description Required argument type

j

16-bit signed int

int16_t* or equivalent

v

16-bit unsigned int

uint16_t* or equivalent

i

32-bit signed int

int32_t* or equivalent

u

32-bit unsigned int

uint32_t* or equivalent

I

64-bit signed int

int64_t* or equivalent

U

64-bit unsigned int

uint64_t* or equivalent

c

character (byte)

char*

s

string

char**

f

64-bit double precision float

double* (varies by platform)

#

array length; modifies preceding iujvIUcsf or S(…)

int

B

binary buffer (arbitrary-length)

tpl_bin*

S

structure (…)

struct *

$

nested structure (…)

none

A

array (…)

none

+
+

Explicit sizes

+

The sizes of data types such as long and double vary by platform. This must +be kept in mind because most tpl format characters require a pointer argument to +a specific-sized type, listed above. You can use explicit-sized types such as +int32_t (defined in inttypes.h) in your program if you find this helpful.

+
The trouble with double
+

Unfortunately there are no standard explicit-sized floating-point types-- no +float64_t, for example. If you plan to serialize double on your platform +using tpl’s f format character, first be sure that your double is 64 bits. +Second, if you plan to deserialize it on a different kind of CPU, be sure that +both CPU’s use the same floating-point representation such as IEEE 754.

+

Arrays

+

Arrays come in two kinds: fixed-length and variable-length arrays. +Intuitively, they can be thought of like conventional C arrays and linked lists. +In general, use fixed-length arrays if possible, and variable-length arrays +if necessary. The variable-length arrays support more complex data types, and +give or receive the elements to your program one by one.

+

Fixed-length vs. Variable-length arrays

+
+
+Notation +
+
+

+ Fixed-length arrays are denoted like i# (a simple type followed by one or + more # signs), but variable-length arrays are denoted like A(i). +

+
+
+Element handling +
+
+

+ All the elements of a fixed-length array are packed or unpacked at once. But + the elements of a variable-length array are packed or unpacked one by one. +

+
+
+Array length +
+
+

+ The number of elements in a fixed-length array is specified before use-- + before any data is packed. But variable-length arrays do not have a fixed + element count. They can have any number of elements packed into them. When + unpacking a variable-length array, they are unpacked one by one until they + are exhausted. +

+
+
+Element types +
+
+

+ Elements of fixed-length arrays can be the integer, byte, double, string + types or structures. (This excludes format characters BA). Fixed-length + arrays can also be multi-dimensional like i##. Variable-length arrays can + have simple or complex elements-- for example, an array of ints A(i), an + array of int/double pairs A(if), or even nested arrays like A(A(if)). +

+
+
+

Before explaining all the concepts, it’s illustrative to see how both kinds of +arrays are used. Let’s pack the integers 0 through 9 both ways.

+
+
Packing 0-9 as a fixed-length array
+
+
#include "tpl.h"
+int main() {
+    tpl_node *tn;
+    int x[] = {0,1,2,3,4,5,6,7,8,9};
+
+    tn = tpl_map("i#", x, 10);
+    tpl_pack(tn,0);                         /* pack all 10 elements at once */
+    tpl_dump(tn, TPL_FILE, "/tmp/fixed.tpl");
+    tpl_free(tn);
+}
+
+

Note that the length of the fixed-length array (10) was passed as an argument to +tpl_map(). The corresponding unpacking example is listed +further below. Now let’s see how we would pack 0-9 as a variable-length array:

+
+
Packing 0-9 as a variable-length array
+
+
#include "tpl.h"
+int main() {
+    tpl_node *tn;
+    int x;
+
+    tn = tpl_map("A(i)", &x);
+    for(x = 0; x < 10; x++) tpl_pack(tn,1);  /* pack one element at a time */
+    tpl_dump(tn, TPL_FILE, "/tmp/variable.tpl");
+    tpl_free(tn);
+}
+
+

Notice how we called tpl_pack in a loop, once for each element 0-9. Again, +there is a corresponding unpacking example shown later in the +guide. You might also notice that this time, we passed 1 as the final argument +to tpl_pack. This is an index number designating which variable-length array +we’re packing. In this case, there is only one.

+

Index numbers

+

Index numbers identify a particular variable-length array in the format string. +Each A(…) in a format string has its own index number. The index numbers +are assigned left-to-right starting from 1. Examples:

+
+
+
A(i)        /* index number 1 */
+A(i)A(i)    /* index numbers 1 and 2 */
+A(A(i))     /* index numbers 1 and 2 (order is independent of nesting) */
+
+
Special index number 0
+

The special index number 0 designates all the format characters that are not +inside an A(…). Examples of what index 0 does (and does not) designate:

+
+
+
S(ius)      /* index 0 designates the whole thing */
+iA(c)u      /* index 0 designates the i and the u */
+c#A(i)S(ci) /* index 0 designates the c# and the S(ci) */
+
+

An index number is passed to tpl_pack and tpl_unpack to specify which +variable-length array (or non-array, in the case of index number 0) to act upon.

+

Integers

+

The array examples above demonstrated how integers could be +packed. We’ll show some further examples here of unpacking integers and dealing +with multi-dimensional arrays. The same program could be used to demonstrate +working with byte, 16-bit shorts, 32-bit or 64-bit signed and unsigned integers +with only a change to the data type and the format character.

+
+
Unpacking 0-9 from a fixed-length array
+
+
#include "tpl.h"
+int main() {
+    tpl_node *tn;
+    int x[10];
+
+    tn = tpl_map("i#", x, 10);
+    tpl_load(tn, TPL_FILE, "/tmp/fixed.tpl");
+    tpl_unpack(tn,0);  /* unpack all 10 elements at once */
+    tpl_free(tn);
+    /* now do something with x[0]...x[9].. (not shown */
+}
+
+

For completeness, let’s also see how to unpack a variable-length integer array.

+
+
Unpacking 0-9 from a variable-length array
+
+
#include "tpl.h"
+int main() {
+    tpl_node *tn;
+    int x;
+
+    tn = tpl_map("A(i)", &x);
+    tpl_load(tn, TPL_FILE, "/tmp/variable.tpl");
+    while (tpl_unpack(tn,1) > 0) printf("%d\n",x); /* unpack one by one */
+    tpl_free(tn);
+}
+
+

Multi-dimensional arrays

+

A multi-dimensional matrix of integers can be packed and unpacked the same way +as any fixed-length array.

+
+
+
int xy[XDIM][YDIM];
+...
+tn = tpl_map("i##", xy, XDIM, YDIM);
+tpl_pack(tn, 0);
+
+

This single call to tpl_pack packs the entire matrix.

+

Strings

+

Tpl can serialize C strings. A different format is used for char* vs. char[ ] +as described below. Let’s look at char* first:

+
+
Packing a string
+
+
    #include "tpl.h"
+
+    int main() {
+        tpl_node *tn;
+        char *s = "hello, world!";
+        tn = tpl_map("s", &s);
+        tpl_pack(tn,0);  /* copies "hello, world!" into the tpl */
+        tpl_dump(tn,TPL_FILE,"string.tpl");
+        tpl_free(tn);
+    }
+
+

The char* must point to a null-terminated string or be a NULL pointer.

+

When deserializing (unpacking) a C string, space for it will be allocated +automatically, but you are responsible for freeing it (unless it is NULL):

+
+
Unpacking a string
+
+
    #include "tpl.h"
+
+    int main() {
+        tpl_node *tn;
+        char *s;
+        tn = tpl_map("s", &s);
+        tpl_load(tn,TPL_FILE,"string.tpl");
+        tpl_unpack(tn,0);   /* allocates space, points s to "hello, world!" */
+        printf("unpacked %s\n", s);
+        free(s);            /* our responsibility to free s */
+        tpl_free(tn);
+    }
+
+

char* vs char[ ]

+

The s format character is only for use with char* types. In the example +above, s is a char*. If it had been a char s[14], we would use the format +characters c# to pack or unpack it, as a fixed-length character array. (This +unpacks the characters "in-place", instead of into a dynamically allocated +buffer). Also, a fixed-length buffer described by c# need not be +null-terminated.

+

Arrays of strings

+

You can use fixed- or variable-length arrays of strings in tpl. An example of +packing a fixed-length two-dimensional array of strings is shown here.

+
+
+
char *labels[2][3] = { {"one", "two", "three"},
+                       {"eins", "zwei", "drei" } };
+tpl_node *tn;
+tn = tpl_map("s##", labels, 2, 3);
+tpl_pack(tn,0);
+tpl_dump(tn,TPL_FILE,filename);
+tpl_free(tn);
+
+

Later, when unpacking these strings, the programmer must remember to free them +one by one, after they are no longer needed.

+
+
+
char *olabels[2][3];
+int i,j;
+
+
+
+
tn = tpl_map("s##", olabels, 2, 3);
+tpl_load(tn,TPL_FILE,filename);
+tpl_unpack(tn,0);
+tpl_free(tn);
+
+
+
+
for(i=0;i<2;i++) {
+  for(j=0;j<3;j++) {
+    printf("%s\n", olabels[i][j]);
+    free(olabels[i][j]);
+  }
+}
+
+

Binary buffers

+

Packing an arbitrary-length binary buffer (tpl format character B) makes use +of the tpl_bin structure. You must declare this structure and populate it +with the address and length of the binary buffer to be packed.

+
+
Packing a binary buffer
+
+
    #include "tpl.h"
+    #include <sys/time.h>
+
+    int main() {
+        tpl_node *tn;
+        tpl_bin tb;
+
+        /* we'll use a timeval as our guinea pig */
+        struct timeval tv;
+        gettimeofday(&tv,NULL);
+
+        tn = tpl_map( "B", &tb );
+        tb.sz = sizeof(struct timeval);  /* size of buffer to pack */
+        tb.addr = &tv;                   /* address of buffer to pack */
+        tpl_pack( tn, 0 );
+        tpl_dump(tn, TPL_FILE, "bin.tpl");
+        tpl_free(tn);
+    }
+
+

When you unpack a binary buffer, tpl will automatically allocate it, and will +populate your tpl_bin structure with its address and length. You are +responsible for eventually freeing the buffer.

+
+
Unpacking a binary buffer
+
+
    #include "tpl.h"
+
+    int main() {
+        tpl_node *tn;
+        tpl_bin tb;
+
+        tn = tpl_map( "B", &tb );
+        tpl_load( tn, TPL_FILE, "bin.tpl" );
+        tpl_unpack( tn, 0 );
+        tpl_free(tn);
+
+        printf("binary buffer of length %d at address %p\n", tb.sz, tb.addr);
+        free(tb.addr);  /* our responsibility to free it */
+    }
+
+

Structures

+

You can use tpl to pack and unpack structures, and arrays of structures.

+
+
+
struct ci {
+    char c;
+    int i;
+};
+struct ci s = {'a', 1};
+
+
+
+
tn = tpl_map("S(ci)", &s);  /* pass structure address */
+tpl_pack(tn, 0);
+tpl_dump(tn, TPL_FILE, "struct.tpl");
+tpl_free(tn);
+
+

As shown, omit the individual arguments for the format characters inside the +parenthesis. The exception is for fixed-length arrays; when S(…) contains a +# character, its length argument is required: tpl_map("S(f#i)", &s, 10);

+

When using the S(…) format, the only characters allowed inside the +parentheses are iujvcsfIU#$().

+

Structure arrays

+

Arrays of structures are the same as simple arrays. Fixed- or variable- length +arrays are supported.

+
+
+
struct ci sa[100], one;
+
+
+
+
tn = tpl_map("S(ci)#", sa, 100);  /* fixed-length array of 100 structures */
+tn = tpl_map("A(S(ci))", &one);   /* variable-length array (one at a time)*/
+
+

The differences between fixed- and variable-length arrays are explained in the +Arrays section.

+

Nested structures

+

When dealing with nested structures, the outermost structure uses the S format +character, and the inner nested structures use the $ format. Only the +outermost structure’s address is given to tpl_map.

+
+
+
struct inner_t {
+  char a;
+}
+
+
+
+
struct outer_t {
+  char b;
+  struct inner_t i;
+}
+
+
+
+
tpl_node *tn;
+struct outer_t outer = {'b', {'a'}};
+
+
+
+
tn = tpl_map("S(c$(c))", &outer);
+
+

Structures can nest to any level. Currently tpl does not support fixed-length +array suffixes on inner structures. However the outermost structure can have a +length suffix even if it contains some nested structures.

+

Linked lists

+

While tpl has no specific data type for a linked list, the technique for +packing them is illustrated here. First describe your list element as a +format string and then surround it with A(…) to describe it as +variable-length array. Then, using a temporary variable, iterate over each +list element, copying it to the temporary variable and packing it.

+
+
+
struct element {
+  char c;
+  int i;
+  struct element *next;
+}
+
+
+
+
struct element *list, *i, tmp;
+tpl_node *tn;
+
+
+
+
/* add some elements to list.. (not shown)*/
+
+
+
+
tn = tpl_map("A(ci)", &tmp);
+for(i = list; i != NULL; i=i->next) {
+  tmp = *i;
+  tpl_pack(tn, 1);
+}
+tpl_dump(tn,TPL_FILE,"list.tpl");
+tpl_free(tn);
+
+

Unpacking is similar. The for loop is just replaced with:

+
+
+
while( tpl_unpack(tn,1) > 0) {
+  struct element *newelt = malloc(sizeof(struct element));
+  *newelt = tmp;
+  add_to_list(list, newelt);
+}
+
+

As you can see, tpl does not reinstate the whole list at once-- just one +element at a time. You need to link the elements manually. A future release of +tpl may support pointer swizzling to make this easier.

+
+

API

+
+

tpl_map

+

The only way to create a tpl is to call tpl_map(). The first argument is the +format string. This is followed by a list of arguments as required by +the particular characters in the format string. E.g,

+
+
+
tpl_node *tn;
+int i;
+tn = tpl_map( "A(i)", &i );
+
+

The function creates a mapping between the items in the format string and the C +program variables whose addresses are given. Later, the C variables will be read +or written as the tpl is packed or unpacked.

+

This function returns a tpl_node* on success, or NULL on failure.

+

tpl_pack

+

The function tpl_pack() packs data into a tpl. The arguments to +tpl_pack() are a tpl_node* and an index number.

+
+
+
tn = tpl_map("A(i)A(c)", &i, &c);
+for(i=0; i<10; i++) tpl_pack(tn, 1);    /* pack 0-9 into index 1 */
+for(c='a; c<='z'; c++) tpl_pack(tn, 2); /* pack a-z into index 2 */
+
+
+
+

Index number 0

+

It is necessary to pack index number 0 only if the format string contains +characters that are not inside an A(…), such as the i in the format string +iA(c).

+

Variable-length arrays

+
Adding elements to an array
+

To add elements to a variable-length array, call tpl_pack() repeatedly. Each +call adds another element to the array.

+
Zero-length arrays are ok
+

It’s perfectly acceptable to pack nothing into a variable-length array, +resulting in a zero-length array.

+
Packing nested arrays
+

In a format string containing a nested, variable-length array, such as +A(A(s)), the inner, child array should be packed prior to the parent array.

+

When you pack a parent array, a "snapshot" of the current child array is placed +into the parent’s new element. Packing a parent array also empties the child +array. This way, you can pack new data into the child, then pack the parent +again. This creates distinct parent elements which each contain distinct child +arrays.

+
+ + + +
+
Tip
+
When dealing with nested arrays like A(A(i)), pack them from the "inside +out" (child first), but unpack them from the "outside in" (parent first).
+
+

The example below creates a tpl having the format string A(A(c)).

+
+
Packing nested arrays
+
+
#include "tpl.h"
+
+int main() {
+    char c;
+    tpl_node *tn;
+
+    tn = tpl_map("A(A(c))", &c);
+
+    for(c='a'; c<'c'; c++) tpl_pack(tn,2);  /* pack child (twice) */
+    tpl_pack(tn, 1);                        /* pack parent */
+
+    for(c='1'; c<'4'; c++) tpl_pack(tn,2);  /* pack child (three times) */
+    tpl_pack(tn, 1);                        /* pack parent */
+
+    tpl_dump(tn, TPL_FILE, "test40.tpl");
+    tpl_free(tn);
+}
+
+

This creates a nested array in which the parent has two elements: the first +element is the two-element nested array a, b; and the second element is +the three-element nested array 1, 2, 3. +The nested unpacking example shows how this tpl is unpacked.

+

tpl_dump

+

After packing a tpl, tpl_dump() is used to write the tpl image to a file, +memory buffer or file descriptor. The corresponding modes are shown below. A +final mode is for querying the output size without actually performing the dump.

+
+ +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Write to… Usage

file

tpl_dump(tn, TPL_FILE, "file.tpl" );

file descriptor

tpl_dump(tn, TPL_FD, 2);

memory

tpl_dump(tn, TPL_MEM, &addr, &len );

caller’s memory

tpl_dump(tn, TPL_MEM|TPL_PREALLOCD, buf, sizeof(buf));

just get size

tpl_dump(tn, TPL_GETSIZE, &sz);

+
+

The first argument is the tpl_node* and the second is one of these constants:

+
+
+TPL_FILE +
+
+

+ Writes the tpl to a file whose name is given in the following argument. + The file is created with permissions 664 (rw-rw-r--) unless further + restricted by the process umask. +

+
+
+TPL_FD +
+
+

+ Writes the tpl to the file descriptor given in the following argument. + The descriptor can be either blocking or non-blocking, but will busy-loop + if non-blocking and the contents cannot be written immediately. +

+
+
+TPL_MEM +
+
+

+ Writes the tpl to a memory buffer. The following two arguments must be a + void** and a size_t*. The function will allocate a buffer and store + its address and length into these locations. The caller is responsible to + free() the buffer when done using it. +

+
+
+TPL_MEM|TPL_PREALLOCD +
+
+

+ Writes the tpl to a memory buffer that the caller has already allocated or + declared. The following two arguments must be a void* and a size_t + specifying the buffer address and size respectively. (If the buffer is of + insufficient size to receive the tpl dump, the function will return -1). + This mode can be useful in conjunction with tpl_load in TPL_EXCESS_OK + mode, as shown here. +

+
+
+TPL_GETSIZE +
+
+

+ This special mode does not actually dump the tpl. Instead it places the size + that the dump would require into the uint32_t pointed to by the + following argument. +

+
+
+

The return value is 0 on success, or -1 on error.

+

The tpl_dump() function does not free the tpl. Use tpl_free() to release +the tpl’s resources when done.

+
+ + + +
+
Tip
+
+
Back-to-back tpl images require no delimiter
If you want to store a series of tpl images, or transmit sequential tpl images +over a socket (perhaps as messages to another program), you can simply dump them +sequentially without needing to add any delimiter for the individual tpl images. +Tpl images are internally delimited, so tpl_load will read just one at a time +even if multiple images are contiguous.
+
+

tpl_load

+

This API function reads a previously-dumped tpl image from a file, memory +buffer or file descriptor, and prepares it for subsequent unpacking. The format +string specified in the preceding call to tpl_map() will be cross-checked +for equality with the format string stored in the tpl image.

+
+
+
tn = tpl_map( "A(i)", &i );
+tpl_load( tn, TPL_FILE, "demo.tpl" );
+
+

The first argument to tpl_load() is the tpl_node*. The second argument is +one of the constants:

+
+
+TPL_FILE +
+
+

+ Loads the tpl from the file named in the following argument. It is also + possible to bitwise-OR this flag with TPL_EXCESS_OK as explained below. +

+
+
+TPL_MEM +
+
+

+ Loads the tpl from a memory buffer. The following two arguments must be a + void* and a size_t, specifying the buffer address and size, + respectively. The caller must not free the memory buffer until after + freeing the tpl with tpl_free(). (If the caller wishes to hand over + responsibility for freeing the memory buffer, so that it’s automatically + freed along with the tpl when tpl_free() is called, the constant + TPL_UFREE may be bitwise-OR’d with TPL_MEM to achieve this). + Furthermore, TPL_MEM may be bitwise-OR’d with TPL_EXCESS_OK, explained + below. +

+
+
+TPL_FD +
+
+

+ Loads the tpl from the file descriptor given in the following argument. + The descriptor is read until one complete tpl image is loaded; no bytes + past the end of the tpl image will be read. The descriptor can be either + blocking or non-blocking, but will busy-loop if non-blocking and the + contents cannot be read immediately. +

+
+
+

During loading, the tpl image will be extensively checked for internal validity.

+

This function returns 0 on success or -1 on error.

+

TPL_EXCESS_OK

+

When reading a tpl image from a file or memory (but not from a file descriptor) +the size of the file or memory buffer must exactly equal that of the tpl image +stored therein. In other words, no excess trailing data beyond the tpl image is +permitted. The bit flag TPL_EXCESS_OK can be OR’d with TPL_MEM or TPL_FILE +to relax this requirement.

+

A situation where this flag can be useful is in conjunction with tpl_dump in +the TPL_MEM|TPL_PREALLOCD mode. In this example, the program does not concern +itself with the actual tpl size as long as LEN is sufficiently large.

+
+
+
char buf[LEN];  /* will store and read tpl images here */
+...
+tpl_dump(tn, TPL_MEM|TPL_PREALLOCD, buf, LEN);
+...
+tpl_load(tn, TPL_MEM|TPL_EXCESS_OK, buf, LEN);
+
+

tpl_unpack

+

The tpl_unpack() function unpacks data from the tpl. When data is unpacked, +it is copied to the C program variables originally specified in tpl_map(). +The first argument to tpl_unpack is the tpl_node* for the tpl and the +second argument is an index number.

+
+
+
tn = tpl_map( "A(i)A(c)", &i, &c );
+tpl_load( tn, TPL_FILE, "nested.tpl" );
+while (tpl_unpack( tn, 1) > 0) printf("i is %d\n", i); /* unpack index 1 */
+while (tpl_unpack( tn, 2) > 0) printf("c is %c\n", c); /* unpack index 2 */
+
+

Index number 0

+

It is necessary to unpack index number 0 only if the format string contains +characters that are not inside an A(…), such as the i in the format string +iA(c).

+

Variable-length arrays

+
Unpacking elements from an array
+

For variable-length arrays, each call to tpl_unpack() unpacks another element. +The return value can be used to tell when you’re done: if it’s positive, an +element was unpacked; if it’s 0, nothing was unpacked because there are no more +elements. A negative retun value indicates an error (e.g. invalid index number). +In this document, we usually unpack variable-length arrays using a while loop:

+
+
+
while( tpl_unpack( tn, 1 ) > 0 ) {
+    /* got another element */
+}
+
+
Array length
+

When unpacking a variable-length array, it may be convenient to know ahead of +time how many elements will need to be unpacked. You can use tpl_Alen() to +get this number.

+
Unpacking nested arrays
+

In a format string containing a nested variable-length array such as A(A(s)), +unpack the outer, parent array before unpacking the child array.

+

When you unpack a parent array, it prepares the child array for unpacking. +After unpacking the elements of the child array, the program can repeat the +process by unpacking another parent element, then the child elements, and so on. +The example below unpacks a tpl having the format string A(A(c)).

+
+
Unpacking nested arrays
+
+
#include "tpl.h"
+#include <stdio.h>
+
+int main() {
+    char c;
+    tpl_node *tn;
+
+    tn = tpl_map("A(A(c))", &c);
+
+    tpl_load(tn, TPL_FILE, "test40.tpl");
+    while (tpl_unpack(tn,1) > 0) {
+        while (tpl_unpack(tn,2) > 0) printf("%c ",c);
+        printf("\n");
+    }
+    tpl_free(tn);
+}
+
+

The file test40.tpl is from the nested packing example. When +run, this program prints:

+
+
+
a b
+1 2 3
+
+

tpl_free

+

The final step for any tpl is to release it using tpl_free(). Its only +argument is the the tpl_node* to free.

+
+
+
tpl_free( tn );
+
+

This function does not return a value (it is void).

+

tpl_Alen

+

This function takes a tpl_node* and an index number and returns an int +specifying the number of elements in the variable-length array.

+
+
+
num_elements = tpl_Alen(tn, index);
+
+

This is mainly useful for programs that unpack data and need to know ahead of +time the number of elements that will need to be unpacked. (It returns the +current number of elements; it will decrease as elements are unpacked).

+

tpl_peek

+

This function peeks into a file or a memory buffer containing a tpl image and +and returns a copy of its format string. It can also peek at the lengths of +any fixed-length arrays in the format string, or it can also peek into the data +stored in the tpl.

+

Format peek

+

The format string can be obtained +like this:

+
+
+
fmt = tpl_peek(TPL_FILE, "file.tpl");
+fmt = tpl_peek(TPL_MEM, addr, sz);
+
+

On success, a copy of the format string is returned. The caller must eventually +free it. On error, such as a non-existent file, or an invalid tpl image, it +returns NULL.

+

Array length peek

+

The lengths of all fixed-length arrays in the format string can be queried using +the TPL_FXLENS mode. It provides the number of such fixed-length arrays and +their lengths. If the former is non-zero, the caller must free the latter array +when finished. The format string itself must also be freed.

+
+
+
uint32_t num_fxlens, *fxlens, j;
+fmt = tpl_peek(TPL_FILE|TPL_FXLENS, filename, &num_fxlens, &fxlens);
+if (fmt) {
+  printf("format %s, num_fxlens %u\n", fmt, num_fxlens);
+  for(j=0; j<num_fxlens; j++) printf("fxlens[%u] %u\n", j, fxlens[j]);
+  if (num_fxlens > 0) free(fxlens);
+  free(fmt);
+}
+
+

The TPL_FXLENS mode is mutually exclusive with TPL_DATAPEEK.

+

Data peek

+

To peek into the data, additional arguments are used. This is a quick +alternative to mapping, loading and unpacking the tpl, but peeking is limited +to the data in index 0. In other words, no peeking into A(…) types. +Suppose the tpl image in file.tpl has the format string siA(i). Then the +index 0 format characters are si. This is how to peek at their content:

+
+
+
char *s;
+int i;
+fmt = tpl_peek(TPL_FILE | TPL_DATAPEEK, "file.tpl", "si", &s, &i);
+
+

Now s, i, and fmt have been populated with data. The caller must +eventually free fmt and s because they are allocated strings. +Of course, it works with TPL_MEM as well as TPL_FILE. Notice that +TPL_DATAPEEK was OR’d with the mode. You can also specify any leading +portion of the index 0 format if you don’t want to peek at the whole thing:

+
+
+
fmt = tpl_peek(TPL_FILE | TPL_DATAPEEK, "file.tpl", "s", &s);
+
+

The TPL_DATAPEEK mode is mutually exclusive with TPL_FXLENS.

+
Structure peek
+

Lastly you can peek into S(…) structures in index 0, but omit the +surrounding S(…) in the format, and specify an argument to receive +each structure member individually. You can specify any leading portion +of the structure format. For example if struct.tpl has the format string +S(si), you can peek at its data in these ways:

+
+
+
fmt = tpl_peek(TPL_FILE | TPL_DATAPEEK, "struct.tpl", "s", &s);
+fmt = tpl_peek(TPL_FILE | TPL_DATAPEEK, "struct.tpl", "si", &s, &i);
+
+

tpl_jot

+

This is a quick shortcut for generating a tpl. It can be used instead of the +usual "map, pack, dump, and free" lifecycle. With tpl_jot all those steps are +handled for you. It only works for simple formats-- namely, those without +A(…) in their format string. Here is how it is used:

+
+
+
char *hello = "hello", *world = "world";
+tpl_jot( TPL_FILE, "file.tpl", "ss", &hello, &world);
+
+

It supports the three standard modes, TPL_FILE, TPL_FD and TPL_MEM. +It returns -1 on failure (such as a bad format string or error writing the +file) or 0 on success.

+

tpl_hook

+

Most users will just leave these hooks at their default values. You can change +these hook values if you want to modify tpl’s internal memory management and +error reporting behavior.

+

A global structure called tpl_hook encapsulates the hooks. A program can +reconfigure any hook by specifying an alternative function whose prototype +matches the default. For example:

+
+
+
#include "tpl.h"
+extern tpl_hook_t tpl_hook;
+
+
+
+
int main() {
+    tpl_hook.oops = printf;
+    ...
+}
+
+
+ + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Configurable hooks
Hook Description Default

tpl_hook.oops

log error messages

tpl_oops

tpl_hook.malloc

allocate memory

malloc

tpl_hook.realloc

reallocate memory

realloc

tpl_hook.free

free memory

free

tpl_hook.fatal

log fatal message and exit

tpl_fatal

tpl_hook.gather_max

tpl_gather max image size

0 (unlimited)

+
+

The oops hook

+

The oops has the same prototype as printf. The built-in default oops +handling function writes the error message to stderr.

+

The fatal hook

+

The fatal hook is invoked when a tpl function cannot continue because of an out- +of-memory condition or some other usage violation or inconsistency. It has this +prototype:

+
+
+
void fatal_fcn(char *fmt, ...);
+
+

The fatal hook must not return. It must either exit, or if the program needs +to handle the failure and keep executing, setjmp and longjmp can be used. +The default behavior is to exit(-1).

+
+
Using longjmp in a fatal error handler
+
+
#include <setjmp.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include "tpl.h"
+
+jmp_buf env;
+extern tpl_hook_t tpl_hook;
+
+void catch_fatal(char *fmt, ...) {
+  va_list ap;
+
+  va_start(ap, fmt);
+  vfprintf(stderr, fmt, ap);
+  va_end(ap);
+  longjmp(env,-1);                /* return to setjmp point */
+}
+
+int main() {
+  int err;
+  tpl_node *tn;
+  tpl_hook.fatal = catch_fatal;    /* install fatal handler */
+
+  err = setjmp(env); /* on error, control will return here  */
+  if (err) {
+    printf("caught error!\n");
+    return -1;
+  }
+
+  tn = tpl_map("@");              /* generate a fatal error */
+  printf("program ending, without error\n");
+  return 0;
+}
+
+

This example is included in tests/test123.c. When run, this program prints:

+
+
+
unsupported option @
+failed to parse @
+caught error!
+
+

tpl_gather

+
+
+

The prototype for this function is:

+
+
+
int tpl_gather( int mode, ...);
+
+

The mode argument is one of three constants listed below, which must be +followed by the mode-specific required arguments:

+
+
+
TPL_GATHER_BLOCKING,    int fd, void **img, size_t *sz
+TPL_GATHER_NONBLOCKING, int fd, tpl_gather_t **gs, tpl_gather_cb *cb, void *data
+TPL_GATHER_MEM,         void *addr, size_t sz, tpl_gather_t **gs, tpl_gather_cb *cb, void *data
+
+
+ + + +
+
Note
+
+
tpl_hook.gather_max
All modes honor tpl_hook.gather_max, specifying the maximum byte size for a +tpl image to be gathered (the default is unlimited, signified by 0). If a source +attempts to send a tpl image larger than this maximum, whatever partial image +has been read will be discarded, and no further reading will take place; in this +case tpl_gather will return a negative (error) value to inform the caller that +it should stop gathering from this source, and close the originating file +descriptor if there is one. (The whole idea is to prevent untrusted sources from +sending extremely large tpl images which would consume too much memory.)
+
+

TPL_GATHER_BLOCKING

+

In this mode, tpl_gather blocks while reading file descriptor fd until one +complete tpl image is read. No bytes past the end of the tpl image will be read. +The address of the buffer containing the image is returned in img and its size +is placed in sz. The caller is responsible for eventually freeing the buffer. +The function returns 1 on success, 0 on end-of-file, or a negative number on +error.

+

TPL_GATHER_NONBLOCKING

+

This mode is for non-blocking, event-driven programs that implement their +own file descriptor readability testing using select() or the like. In this +mode, tpl images are gathered in chunks as data becomes readable. Whenever a +full tpl image has been gathered, it invokes a caller-specified callback to do +something with the image. The arguments are the file descriptor fd which the +caller has determined to be readable and which must be in non-blocking mode, a +pointer to a file-descriptor-specific handle which the caller has declared +(explained below); a callback to invoke when a tpl image has been read; and an +opaque pointer that will passed to the callback.

+

For each file descriptor on which tpl_gather will be used, the caller must +declare a tpl_gather_t* and initialize it to NULL. Thereafter it will be +used internally by tpl_gather whenever data is readable on the descriptor.

+

The callback will only be invoked whenever tpl_gather() has accumulated one +complete tpl image. It must have this prototype:

+
+
+
int (tpl_gather_cb)(void *img, size_t sz, void *data);
+
+

The callback can do anything with the tpl image but it must not free it. It can +be copied if it needs to survive past the callback’s return. The callback should +return 0 under normal circumstances, or a negative number to abort; that is, +returning a negative number causes tpl_gather itself to discard any remaining +full or partial tpl images that have been read, and to return a negative number +(-4 in particular) to signal its caller to close the file descriptor.

+

The return value of tpl_gather() is negative if an error occured or 0 if a +normal EOF was encountered-- both cases require that the caller close the file +descriptor (and stop monitoring it for readability, obviously). If the return +value is positive, the function succeeded in gathering whatever data was +currently readable, which may have been a partial tpl image, or one or more +complete images.

+
Typical Usage
+

The program will have established a file descriptor in non-blocking mode and +be monitoring it for readability, using select(). Whenever it’s readable, the +program calls tpl_gather(). In skeletal terms:

+
+
+
tpl_gather_t *gt=NULL;
+int rc;
+
+
+
+
void fd_is_readable(int fd) {
+  rc = tpl_gather( TPL_GATHER_NONBLOCKING, fd, &gt, callback, NULL );
+  if (rc <= 0) {
+      close(fd);               /* got eof or fatal */
+      stop_watching_fd(fd);
+  }
+}
+
+
+
+
int callback( void *img, size_t sz, void *data ) {
+  printf("got a tpl image\n"); /* do something with img. do not free it. */
+  return 0;                    /* normal (no error) */
+}
+
+

TPL_GATHER_MEM

+

This mode is identical to TPL_GATHER_NONBLOCKING except that it gathers from a +memory buffer instead of from a file descriptor. In other words, if some other +layer of code-- say, a decryption function (that is decrypting fixed-size +blocks) produces tpl fragments one-by-one, this mode can be used to reconstitute +the tpl images and invoke the callback for each one. Its parameters are the same +as for the TPL_GATHER_NONBLOCKING mode except that instead of a file +descriptor, it takes a buffer address and size. The return values are also the +same as for TPL_GATHER_NONBLOCKING noting of course there is no file +descriptor to close on a non-positive return value.

+
+ + + diff --git a/libs/libtpl-1.5/doc/pdf/userguide.pdf b/libs/libtpl-1.5/doc/pdf/userguide.pdf new file mode 100755 index 0000000000000000000000000000000000000000..b870fdcb9b14674826113f18c30608f4481e3137 GIT binary patch literal 157721 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
({Bh$@j#T|L< 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

Hkt41jU0xG@>r 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

Zy^cP2*Ka83cpn?Gqh5<6_f0oq$2@Ft> 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

NE4zhTZ9$ygW4^7DeCq7y| zXwRk3s-7GqZ;s>w-=~^WJEmBbOAUE-&~!twtz7viRAP7M8dP0wxUDy5_uQY*DZnpW zc~b7qVfqoNcaQ3`ca&^Xew+Pq1Cz4~+B{ygk%lcjH$tu-yiEBJi%5846v@xlzsCRE zZ7k&XLHIy1F3a`n@)G|IUaBewo;Jl*4mDqG_R!hETIDWH7rYjdL7=ZVN(|4kR66%A zQQM5w=!$*-gvZ(U9N5$rL9mF>WkK)e`<<^Oe4sx*bd+F4Q7gT>{CU6p>AHI?;-0Ax zNyFez5d1eI;{O2z|AqNrnN&=i>|7jyND+vLeknBmISBsC1{e72e|h3K5o;53{5Qb* zn~Ba}pZ)7*^M46~Ie{1$Xgk9S^uXi*s$N)t?U5Y7USL)rCT3@0`6m*_SKC(qP#^xa zUH`0Y6~OYl66KX*cHqQc)&2a@1o~R>FBu;YDgO?D0YJmnzpK(-DP{$l(Xep8B4hd8 z|LaTmukXu0p*emdGya|D z_%}7tKhp&OPtN~Y_5V+100nygkjyyMv58x5{)^0L{uDyc53etlaMA!>(5)Na=W{Ry zCGNltv7~!i>DAcYuv-xI>1T&%LNc{X!R*+lRS=2z25bI|FwqJ4FjRKqfK8%z-|=@N z8OS%Kc8nc5+Pb57xvusCHT#!D<_PzY(y*#Jx83vNM;Es)T@zH3qeA+@Sp4QGJUid>>&RlFR*qjcq~}T@6B9$wOk|cxBc{Q$c$)}NPp9d6 zdo4DOa>!5zVw<(f|7^ayplWXpxbgD~P%hfpLc=!_V{KT_wFi@=Z(47{@@u(Mr5el5 z#~H20KL?-sh+3n$-wkK;gPBZIDU5NBR5g5~{j_T3m}%Y{ZkpDwb=`XG_QUo!o*~WK z^)S_IC7quq&*~j)(8djWG7OvWEP~!f0`!%S&-$(Fn8_sKp3jd*A>4jVRpY|Sr^jCW zN)NIv3~nYSlkM)`hBY5Wa0y_Mo|SF704+V;aMU3P`Mww`01{HI9&Ts#OauDj*P?)B#p_ZjwTcIe`K z7uxmix1pcGoZLF^Hrbt18Vd$FphQ7lWUnwgIRno}m+)tAGxNDi724>kQ76*Ox$dmM zOveqdeem3iucsv5L#Zqas}WkQLO(RyQ#xkVMm1^a_SEAX#4SG?Xw2^2X%dy&7eO~M za;QD7_VOys)#YNmYm}Jn#v=o$D9)b^ZC3}CbW17En^d{XbNI!!1`Y9YlS!F=(YsKI zQn&qphifn7R4w>zYUKSVCV47;^sqsxASk_*sW&%?6B@W?CJ=^}m7bU;{Z?ZEQcgyQ z+Bw1%Z(zwGulN!ot?w7GKW^wbvCh=3Sn13;3DZh%2O{j{@@kRA?Ln7W&NYgESE!Ri zs+@$jw7`nDzJF+B>{H!CrAzSgE%uvZ%%pU#7(g&R2uBKgUd>wo6`Y8fISdlLSF*gC z8H%y?0hv0!bZ67ABpfd$8rZPHGtY#xUOzNiwl#;#m)9;8YPD$z7CRt>Mvk#>|H$$>I-JX?l-g2ohC4kh9Kb1 z(Ll$Fa*4`S2W;z1I^&~DLvjWE2re_AB~Gp`0a1N^E97@x3}#ciEzLR-i!Zm9wI^kO zmeuK^TgDzX#XB3|6s%pb?$KD5Ukax%K^DhCKtc$}MsP8pOd2D$v99d zC;<3VmIV?Iu}k>1A0{!rApXQt8P0W-imMH2c~D}s4T2cU8cbM;B#~+9aPP)3wXh(u z65732lF6)y8J)9$`=o-%GdDBM7I#1=`IgO0nMiC^-59d9s)O(p0FD{d=?x6 zJij0Zp(!G$&K7Q(@UmTAfDSV}n;Ftey~79^KgnMp=k4>GhU8N|d$nHLa6 z$wG7sVtXFi>(6A$G~x%J5-0E4G~Z?vo8hG-wg*U!dzIU9JboA|Lbu`P7{P|Yjg!Tp z&w@xVD-r)Sk8KB>&=u%RhhQ$=8XQJY=Lq#B zkk9RmSkc|^F;AMl|8fMT*bm<1`6XB=F>$Bfkc6^#J}(S5lKfbSY}3DwR!hE7N~)SV z!!}{yj$sKSla^z%KXX=|>rJCjw5ip(tm|$0&?mKQvh>@T(#Ujl&fDBa{v43F}4Xrs#GFX-I_&V8R)v#~-NdW6>ujjwAMK zv+t_-^YFSI6yKj>x9xL&^KFJ8P9`pO;-4f8m30l0c5J0+Q+yz8G(NA9XIe~Z4;YqM zq|Hbwp0#GZK-VRvJ~Vn4`gU+q;Kq9HL@^OR2YT-((Gxa!HeWiF=CC`Tzgih8fjK?C zrc|P=N%)1p{5f>q&@PC;d~`jjFkYlHsILZ}7`VR34CD7gE^uMSL&7!R(1RhI^s*}P z;ui3Pan&vorj3!{B23nvIjkKv0^~i9t_JP$I-T`PB=cV2hYB>^Xj%N>P7r$EkW)0)S9kq%Sk3G#j^EX(RLlA}jEnt5}@V6k1e_HDa>% zp@E-B)){uad)>ddAvw>?`XnT%Wq7qGey#UWNcsc^k-q9!vrlm~Yn_u-;0~UUaeEmj z=zVu~inNY+(324^b8Ja$G1`gU#-yZZ6Z9qesNm+Sw#ADr4^e?_ zYfy@;XEL>9U{lm?!j!qVfs`;6f5R{Gl?PWUql~F2oqG8Db=+Z?xtzg=or#3KMKN5^ zZIWWL7_Zu;82yu;Qt|%n=Kw{+3FVUTf)`P^NYq4X0m*&)rSU&O;q-zy&s-v z3rokpszmdXD2uDbHh(B7?kSS?aoDaIFtvYkszdmJ_z2Dd3@!#DH9p&k9Kfw;0;ep)}w8{RB@hZTB0K=n&N_q3M`JY7F)g34Fn z#J3QM`b+r_mem=C$@w}HYEywpq9pBd5-qVU-#wUZJB742Jksu4_> z44uVVe09N-cC+LA6JuxI^^SxHhIa%7KJ#AI{w+dptFJ)(N-{6oL8F%fLYj3RZUUsWiGU}{ild(H=E8)11jnxfJE>Th@cb9Gl9;zukjc zEc9Y|<{xzCRUr!!hJJq*smC@c5bwjttU@5FnM)Vq;I(kx%DDmU2L9vhrjnn72L z3azH{UExyN%01qT<-@h5aa{!NAtm{u;!x^xrYS2I)isH{h@Z5zKeXX#kf{-!JR?~O zXzuuU%TSC4OQp(RG8e&>Ad2=PAtHW?U`2l4u<8!JgwBi7^_%nPy&b z0l5w%(i2e)LtA4%&)XbMXaN_h5>cVbJ{a$%s9mloHOx^PQ3W@e#sLEbJP-725~>=)3~3PtO8SX3r)^d+nMeb~^}{a~naW6W~mlup(= zK%Y4$&(>V@Lym0f(z+Cn_5MRu*n`AShg6p?v(WG zY>CEy6sOp_ObYa@T=_oNHQLVR#(xdR0E9!(<4q=F zZhBf-C*Vh8c6*Ua^t`IGwltGe!t@9{5`LSZairHC!ePpjRRdE7&kN>#lU&hZIuVjmG z0*%K0b1`tYe?5iY*Ub5Q%+PC(iVc|d1MG)=rTF*m%vaXT22A^TrSFdO_n4tq2L^`y zZ~^}8qviZPX6V&oVAv1WD=|ZyzsC%{S_};P;eN%z4R~t*^JcRF!+yA5@uBAYJ!a_D zk%1f~_bU-?oWNkL|M-~M0Ia}Vray%Hvd7=zOrOic1~bR z>7R@x=kGB?uP&LD4Y=8VY!~2<4)Iq81^@|O79hX)$6f=!D*tiGzpTn%IbHzve{isW z@#oCI3H>?nKRBDf)GnX^?ayM4zy7WM>u>fyAuRuAoAZBbYy3xiCFkG50{)w?1a1Z3 zpYoL*?|^*eAj*qxmk2X**nAepm~Q8sJSY}7w8C@Z9PCst2O?ht&vcPgdVzN*+w=Ly z#q>gTN#$Y)n>-{PMl&;0GqddUclT&-1pQDYNM)|cFGNu!UyM5il9KT5F8k6a(N!ta zdD#5YKl(hnJlJFUYoR8n>q-ysTrPJpY#oG zcp(pHK&eD9q%b6cxa*Yan<~FC(nO_NYx=`BpumSHNOe%%7wp-ri?i-R^RyQf?3L>B`69(G~B z;Q|=Loy>cTZApCit(9TaQ9me|UCJM630i)O3;Vn;O|KJqUljqo{`@Ldr(vYcMz!IG zh-c6HP8-~KSe_}~0}q>z%hYca%XZK_89pRq1W%LZaC*!E#>!Xq2Td*S>dGhy8?YmS zs1?Mqp(MBG^YZT0(CnYM9G|8Wb3?!qRF3fR!;# zo22cT8`$b;5cJC`uX5oVNpQI{%`GB06$vdM7+#V`FS#o2wXbcI)V|&3`|M(NtHx=y zz07Re1|^oC6k2kdMYWG}&P})c;O~cLlo;l6+m4;PQ>5MSXbX4pH1!!x#;A`-G0Opu55EQk9;n12t(o61x4iO)5->+8=pV(V^SZaH_(&!)o=xT1MG2Ka4Se4 z?X7X^up0OvsNeLI&vly!9~h16)cfIoNW0X<7VdrXoTQR3%A1PI@aD{@c%>7I!q8m? z8M9;(-3SInXa$moClVQP99u*aH46ENSOgzU0>(jZmJkm82f9Cw(>y_dSlnV4G_xV6 zq5*9h`X;;))O)-7u8&s(a^6SG&oU~KBX-m5zfiXKqcw`)D#P&KI;t-twJRg zY5_g)H$UAS?vKXp=chg&bU*a8>g^o7XesL<$gf7>J;HyKX+txI(mBneQe^)@;849@ zhs|2}RYI;cP0~$5<|BEekt%foWe5fW!s0`&R&L>~_afR9$oL0ViymucT)&Y_ToDP` zu(=H|L#WON!ntq3h{It@-6p!Gx@Pb27%be|M$1-HOF!x2K!}{0mOWo)v^&sm3I!yk z={RbBAk9661I>(7Y74=Z<^bK1z&T7xi~&A;Yx;;o_+01NqsSx(SCcU&dt!#-0Kx9e zL(r4{u=ONkW}{~waDk380H>V3TI0n1^@Y%jktd!hC&0Ug9DoiXLyRN;G=^Lk>6Jp7 zrO+hyAbB$z|3XI>&z{SF)pW|M5B-g-?5ee`*{)*xM4OZPsL$>4P3E~`o4D&yrk&7| zf{TWz=0?lacQr1`V%V*bWwYthNO6ncjOZDegl#GO{Zd>WeL-dktXd~H@Xn5ea%v|qgHLK~+?C5)Y7h1wV?ZD- zd5&t@5-L-cPlDgZsF(}SiJQ>|gjc1IdTF3vrztU;j3Vf0Fbo%3X!Sx(!%xu(R+*P_ zxJk~g6(8&@Fd$6=T`o2W2Ma7`<4%dlh^!(#*UR)Z>tV>K26N zp0MR!XP8JO1Rqt)vyr#8Ru={&^ApTo)dOK3sw+q?(EhN2-;H;XaJ!*@M$O*Q2o2#` zzIcC}tg{*8?RMYSmM~#zF~Ci(+~=i3KB*7nt-$uw!8!G~I;J3)Y+vJGaOK=>#Q7^Ss~B2YkD?i<&#mOKYM%$)`~! z8_!oOlG?V58%4@P-PKJKssv#Dk3DPm^_kv!^yiw-!_v?KvxTL%6}(;~Hpeji3#}|z z5296_BthuyI}_G}Cq$r+R`j{8oht*O?YyAZ9zCUuZW{UD#<4FSRltpN zZkqB$c|)I4cl^Rvc@G3Ghz3=cQt~HClOMV`=#4s5KZqC*@lRDANKyNIchy(O9ajAG zb3*XzOm-T^6%m}-TKgaL5a(ZEQ2%-(eU%>iuNTL^(LXP!*muFj4P<4M3>-~toq<}HU*P87hKE3oTd4;e@my;jTyG<9JE0?9u|{tcPFRt)&Xe7wdX{4Pp)wHW9c^vhuX_mThW zl>KYk|8HpNf9w0g`IlqNzsCL-T4DoYx__wd7}q-f)vEHd(=Vh3QVW>qPFez;l1o(C z(bgV-zW9kcaU(ayLYtc(pTE}4=jr_8W_+#j$Xdsi7XD4p9kyd=U;6r&sWA9Ig3juxdcu3GULOdgOeSwAXRH zy0ncSg~g!C8d3Tr*R}R^SJ$-^_@uvnM=v#d1iB=ECR|HvCxXa;v*_z^)i_3xZ^Pajn@+@UZ$ za@Fq!_3~LiR*4@xhwjg_mCT$7Ropl?Na-G35{6iQhO^9XxNlU1Yo4V3vEYez)&KaI z;k3@m3Aa2oURu*XDh1DHQ#@5Noln9$C!aQtF+R&nciAJufIPMkTW_oXI zj|8)@kisOQS{F5{c|e4?Cf=)qsy?pGo2Q(xfR&KWIZg zZKUYl& za%8w+BmM^$*hvI$vKiiwaI;dtU+No~N>>7Smj^?8=DTKBSL}P5yQxL)pyVV9uG>Uo z59op=^$!bYpBpCYIA^VqKtR%k^*%tGecA--XOmnZ(54hE2p58G!$@yBYv};hw&2`T zo%3QVO`fu39^YL3IoPbHAUlH@nU|aVP1szuizJ(caO}^+c}?xC?SKo})Ml2T!K<*d z&`mgZHmzo$tH(ICI|d=RWF7+b1N(;M@@9%06^jhSrpE~!Vql5O!C$i??%-V5`up0< ztbl(oBq4!CG;Iy&chEp-7{|}7_$74k!wUd&B~H7g5!~+8l|Zu%p{7;q&)S8Bluv#V z^<*uC8?!F!<4BD8!67S~OIKwmDk5O0;mW}UeaG!MW1=X`FeF)_7ya{Zf-i>c8<||T z4gDd9MPnRJdV2PpQR$&)TRI?O4XD$9vRU&b=mkp129TOTH%kN&=HNRk&!UyLvWp^` z2?Wpu;n6j!WIMo}nS6Hqu48fMJ30+qB~TL^W7%}9Xv1|+TE$y|XtuqYwro$E#8afLUr%8xvslIEl=JH`d>OG%;IBc(u za6L&+&Kr7*;8miVs)Fg8^J!dVnG0Hv(j|sT$juH-A}0t>VYRUFTXZPIJO@!mR=iu{ z!PCy;r>Q|R`E}*TgVZ-8vD`{ICapG$At2ad@pNzw>>#n`jF3W-BB1e)bugcE9ot5u zsVgrtY`3xwmFD5Zk#Z4WFqiKn1-|R98YU;AY{|^1T#-l$4b3s}%MX1(F?wbp-}?%p zXO%fT#i-C`fVqi0Z_BO;Csy8Bo%tMkmx|e8%R(q_nUyO`-_cD-yBr!`qi-rzF{3v- z=~f>P%WVNJrNv!i`4EVvdK70gw1src{9_5yIxs_#Q_Ygjikkaq@1sqzTI)Q;CkGRj zrQmf|S)2M2qO6LwV{jS(bRaSv`VgyWM1jZ)cf3SG6Vs7bA6G`Qz`{83&Jjg1^mzgz zCZjeOh#E3))x26N;c}-G?^}{Hg%|Wis{v*VN`=oxs^^*Y&W5>?;zjmlbUy@~jp3Na&%G;Is`y0EP`*<4Y4_zBE1F-sg$KK=KQ8!d?8BT1gkQgLc@3G{eoJJKO$nzL1L0nn( zH7?BUPB#lXUk3h%Gw0R13A=61wOM8Xv~$6yCSVsXjAyA79)wz*gA^h_6)jccW${mMAoVC)1XY z0W3r`#ISe1p-H($IP~d}U0|Xb(_!~m!Q<6wMps0Yys$@qA|>G6$^QWkuOp?uUK;<7 zl>SOZ1%C8@jg)>DS9AU~kAH}iem7)%t@wX3Y2*AovFg=gAk+f@*ZBLpJK%4YcE2FU zE7Rrx_U-?|hQAkc{+?R(YB5j;|I1kU_u^m9r~l_U{SPCv0WZ~GF*)V@J+$hzf!WxB zm#x6Nt`sFBYw(<4zYdVQVKBSF9 zN&Am)AvS|Z@5P5L_X$~ztuEQf3TS7y2-~moi`P;sCu`2Rawgh#W6Nnb%3ha|mPHPb znp~Wkut6p$%wC$S$ zn`&CdH>wF=K;-79{-8%K?9>wYJNB6+oebzBiCa(*7S#e$M$1j9cc-B6OmJ0HO2QP65N z3Dzj^E4R?s1v?+B+!GT28`}6gGh7GYy?KXkn|V_& zJpG398#Z&-ED;|{1-7l6sPeD(c~L5sc{^Xkr!{!5R@1^tSu_egrsqB_>SfqyG~Jyx zT4yx&9XB2x?FD`pR9i-E)|nM4C-4=^@XSK z7#42$PL)BS@i>yAJ9`=KR^Emh6zjq$ zEFoel9z_QG*utExLZFPo(EgxmlhPA}wBpBVqu-n`Kq@Ibsdjs{$+bNVNTQ#(8_vM^ zUf-pXYKBwmWu5u>&KI?LfJMbd_D5I_?G@}qi|7@nFtot3n#9GJky!+h3C4mKPF0N>a_TJZMF-=IF)+Zvla|P(OYJx#k3_;lCp2Rtksdv}BOms4 z^^FH_dmjbV;8L+N%-;GjAPq@c6PQnwz)JUi`oeKZG&%J%bm0beknl%pj;{EWs(aZXbLvY5T=1HTkh@<&%uGUa7|u@QU)wvd4H{r zjg{c5Jj+s^_FiW75Xe&FgfQ>&6CTEzvZuTN)8FK7CX5zo$42n=-7}F+W_td34jMl| ztLU^K_K-RAJgW0l92D74{&`3#j%57i!tm>ca;HW$J*JVl;5sWgIdL57U<)?MOMcuy z%V^wy2tNaR%yA7qk_egon?>J2X?X?&ghQ5$nD6+Z;@RH|OG&RWR#;>|mdn{EeW19& zU`Pm+xWcBX_sbAF`(TowQ@EtN%fQ^x+0FJtj+vR{4bF!wL_OpWFiLTof!#YIVPI&W z3(%C%EchQV54j;IVdsrXz*U>dmfti^jBu5FF3dyWmk4MM?y*WQ^5HA6=TE(I7=dDv z854j_G&hoXs}ndvhW5@eO16rTk((baQZ_X>Qq~q)KTa0?^U!xs9b94PEmTPJ?ZhbT zXxXtJC)=nI$2I-UZ?n%t^8&xtBO#L)428>mz$~>Cg^b}fm8O&{NaZjfo#vA;en0Aj zd9^Heh5=QSXBHUnMtZn==l?71JHVnynm|RxQv?H|m_sY?Iqo>2NiYGcqJZ2uZtFXx@zRHxOtWN`P@2}rzP$$Mk)#U0v zg(4*N=ekY`7o!I3pr?s_V=pr(XK?X*r|d)6u!}E9!=I6(NrxKd@c~aRWr=EBY z-?pLgCa)aZPtUe_JJyYLv3s-Dd&-Cv+1ptcuOIKE_Dbc5ooQ7vZ;Y*|CrvvH;Dt)>AfhewQ> zI6@WJe~;J96CdkX!+F+8qpXs?hPU!;`f-`o<)_9j}`DJ<%!*zmTc&~ti$?|jkV>+w%?EsOgdyr^<3TA~1Ez*0@AbcP-RpjI zetl0#ZN-A}#k;rNvOW-aD7)J2o?Z{f>Hm0d-(qu7Ooq%jXvQ0Xx!|NGou=I`TKKp;D+i!lb0<{@L9Oq|5@cv2d-|YKYdH>bDD

`OecYNFpL!mUOkFl}iC>9RN9~d1>0K|_G%uDu`cXAi>g+eD z;oX+Oy9{f#Uy-LOeY>xV|7u9Bl00A0^x(!91r4XbOnlMMs!sQ0$0rS~x(6Rv+{<}V z^MMVk_U+YhMogNOYxT>A>>K1BuGHgPma|=;tZZILNR2bEE1wHEy?y4HyjH{K4EX!D z>-qdCCtWKqEPu4@n7xOR-))#95BuTlTJ7?ovU%4$-|TDAdVzeh^MeUpuiB?S$q%{} zRq5NCzwXYcV(VFU;msZ!d$gVSWXqbbo}a4?@9!k}@n}K0?;Z9H2~Mn)l2I_RMpL(< zm9v`LU)y)_=X{W`%Q?1S5N&qEaq19@=Yb_4W_-`b2R-%zjv#A zM$BBCnLPdUr#j1br&qT(-df&yL~fk{`w#id8WK6U%)E_$DSxdk?)%a?d{9bYH)gv* zQ!>|KJM&@K-ec-#t&J7e47Hmb*!-z->-@7zTD~iYn0R;2?ggnuT{X84ubf(E`;jx& z`??wn+>Hg!V_z>@+Qa5iyWl=vZas!9Jds#6d~KEWNxeVsv9+-cU+Q*q%#`@^6<@sy z*$8TV{?|S3{)=7P{FuG6Gt9XG)}xx-mks-IY>EP=TtvTW2R|;@cKg_rrl5TXCfxAZ zQT1)P@$t2`%^n}`TPfT26I0+mrG5Lv!{_^#ZSu)GeP27@#~yv#j&f~mEIGfvuj9bF zb@M|MN0xLuZQXr+u;$2+$hxp5)wp=zWzRQ?U%9g8m;e6uW=-YfZPvj7NXEVg^jg$; z<)-!nwoGc1Y@chN(K&C|;DY@F2X7DBTdR96$n4On*K`4~NrC%MHgC4$+U5L&W%h>? z9xj%&sXfn75O**7nKX8Uq_~s)-{;jZXR%GQ239iE&DojK017Gi#>bx6$Km4pD*!#_p)~9yVH&@pQ7{(Xx-F!WP8vxtq8rVU+XXHy1OaS{#kLP`OvbjL%G@PZ+A_v5S+E!vH1y1VenrIX*? z-pP}iY)R`_=JzS_wr_$CPJbTQvT$;h_QBmF zBOC46cqx1Kswblsb^qX(to8iTE4_EX%@%`(x)!Bv@?0{k=HQdf`~F(e>gM9miMp!` zwy(P0YtIJ1S^L&bviaipXhj#_C*2gsH$|V{d@*`U=7erZ+Vh*|4%}O#?UA89mq#Dp z(9`+$_pMWF?_ASW`Z3|C-4w&TwrH43nY7kQK%?Qxw?hh}W{40Iv(bpF} z1M)j`Uq5pEuDR=M=Tz53O}=YLU1+@Jys*iDYlT-+r%lPKa_P5;ni*y5?_K`uTKVlK zTaTPHCAHhJUK;yR~rM#_PX_{`%rQ zEnL0EEl(w%ar*wsknB$@2RE2@Z?$)e?8+SmxmQi8{WgDk&)El?cDvo(lv#h?o2_Z@ z9(?_L^IBBM&bW!48~toopUGri|K2^ViqC*uIUizoW*vO+eZ$Y;&za+uR`tufq8^*O zPx;%7>}6AX7p>0d8Sdxc?yvrKq4~^1PA6@xlayh>X#>7&?6A4R+J;X|<2+3cV=n)g zmOrU+<#U(Yo&2(B{h=%6pV?^Kzi*0&JJD)GL(@a2`9n8GdUi1NK781&q;K7E>Iun@ ze{5}6_R+xVq3aE@4_jLK*xq`%JmZn`46Ezg2mYPfe(Inz zqk>Cb>hHa|{p{`Av6^=I~n~bS3#$AoP0*YrRHrrZ1mo==WT1Z**hUVt)^AoHXV*K2PbD-eU?4&&s~{U9<>T~Xw>1yhy0WUk@wfd z#6%^^n@*3jZTw>CreihEeeYgwk34Dpr!R#mUT0@-lvLZ(YTeLA+luQXxNnXea&3&W za>tYG27gB#@4nZk$E?_iTjHt(Ed4SjKjn6xhf&i%oO(X^=iZFyFV8;hUAVp7L}jq! z%e7VR403N<{IJrqSxYj?Xa06H@<*@8#P8BsT>_o&RO!0-@TEC+v%=F)ob3LmvFNSR zG3Wfth!s~Ws`lI%b)ms;O$=8P9hBW?JhZV5Eje;>!RVz?)1IZh2~?_UpC3?ssaI}m zX8g65gR%}x?X`?t&} zmt9q_J&_*oQmb0_q|~pbwHj1szTv{Ki#C_idw*MIQ?_->%i(kC)l({bBHawp zzr!|MA0XJ)3OxPQ7s=9gh{f7b6~zWuKqn z-`k>6pxp2OpLi^O&yGtBK;cE)kN+5tCGRv5tNf4gSn?G)(aQhumYa%v2u`fByG-Gx zhWkya7$KRdFIrhHgM$qsr-jJp*hDMCfgdT{enPiQ26IKY?G6Wi#GYeQk&mK@wXB2# zKQfUUQB>q10ny5k_97R#5k-X`ANm&|QNoEII9EZ_3``UTutjKwSEEEv7@$0wf3FND zeiUMdoT$Vqv6kV)j{KHck|Gd$s{AOmf>n6xXxFkGMUmPR#^&1 z%EU61sFW_T%8*!vo>HW{&A$WYAC!Rtt{HL{IfkMlpJNka7^JYlwN4^JLO#bPTG?F% z_af8BP*hYhnF!77Hiw8ZAm3vXZ5b{&61kR1MLx$SS{IHBsl`q?kz^O0~*tnuA{|5nsJFMI!Vkf&`0RFXQxd%Lu2u~8yE&m4rldIu@L^xSQ zRi<|TM21=J4rj_>=Zdb(-xvA^(U!yA)l#tqgFId;HdJy2oGBAg1%l_D{;6R(ypIS| zfbKPMKvcA0nbJ)z^3tFRzp?c%T3e3JwTf&zsvz(6--j7xcZ$sm@;xlEZp%F2;XKHj zrD^^T0w#lDmchwLva*c4-%YG#DF~QSBsElp??V34vLgH@+9sky{Q|DJvInf`zeERk8-#=5Hb}f5G$NfpO!vl`_^?h=tYt)Cw ztB;RMSaNVoH>aUiqZ}po@7BxE`cjS6eXj-6z}@Esm%A|$BU0idbrP%d_LynugW>%d(yYwx1Dc)#(kMrXX$q9 zRLAe<>>Ac)>@GiFK0;>`*z4Q$qEVAwz7=iW+2HoWmrd9F=s#9gf7|d)+07em8=bal zdW&s8FQyG?^`P(Wq;gNK!?On0xG=xSw%d~xt)9rr2Mkf3x~|Nem-XZ8e7hOxKhDg9 zYdLGpi|Uhk?{FV@Jm|Sq!uP?6hdUJ+I>iiM*tJHzilO5&XB|^iDr4Wc+RM7#M|5)T z)+s$Y&HlNjU9xW_)6B^QU2onlYBS(Sz@`reUe2)1@T?d+?34GPcVh=!f8#!LRnCs2 zRX5sw8N1~}xvKL*Iu7jA>d@fP{w^tn%gg>TVAS~e`-~r6Io_{oOnIAoKYQEWg5-l4 zt`Q;5jP3BIFY0_uUTgiwllNb~G`c^@^y`M|*WX{?{Al#+!@)6)?mc?y?I7PXtJyJT zc<}?%kecn{KW+2ua8@5wGJKLl{(zFVV}D!RcKM!+cF#}EYgFs^R+1RdUM&@j8k+V4-Cv9td>o8`5TV(kM#vWyU zj(>Rdk6Udk&$Mb(Cu!ub{3-+PeD&CMeCx@QkwJ@;AJw+2ybBTvhJ3RsH>p!j@RPGy z-UX9BB%aGDJpbKg<37hTsrqqqZU+9=+HKe8Uj2$s{I;n5qdf`hJfoMqo&EdpTT$ii zkE`45XIZJC-;;{(CZ(O6qaRkysaNP9Z<>DDI``Jp6IFIRsNwG~tE=9*?zuzVeSwP; z)%9L`<$v6;c4xQ6j;?WG%8{1m4>F&`(sJpTi@q%U>J#5r@u zg228LQ{t?Rzb|mFJ;JNWgC6IP|LD`Rqf>kJRF^?RY7J}>ezrs7@!eB8UK=!g(wxFG z70;R`#3knK{n>3q<;xD~sWGXSw$~ZyGku?H(ws7XIlj)-Z20@cf*SG;J6)~%obi8Z z-8Vh`_2Ai8W^In}NXuDR({|ZItEx+nHa*s_@tqm_SI_hO&@`>J?T76)CR9RXM2x-wBXJ)>y^PpS$8r=w)l9u?VXdix4IO)a&lPk@LXKMQpc_ zbYR3(7pumJc@D0fE5E8UBX7uv@741bOq<$jSvjwD8oydAZiT%`4jI>UQ))<`YN;-J zj?C_DZ@aEcZ2NA%avm(|?QFO1i~a8D&s)xu%xS-7{iBv0D$Ta`N}ASirom^tjaBO; z_sT=lipz(_HGCIxpr~>?)#a^mZm%Qljwblq<=RFKJb16qwnn}BB`kOn|1@CT+2WFq z$-jFrr}teidnm2o??p}(-Z&|zUum8*qftcX`8#ha)1BSd#$`2(?A5EzkIaEY zc!W!nd5)*6FEO2;pF3^Jf&AMIcRXLeUp=D!o6v0g)PN!9rmSpfuA~>nV0>{ zz%yxIPHd>5-VvFzb3pf#ww;>EKFPKEJV{nji@IeW^{CEAKW1-sli}t51xV zo1)_AkJ>wP9!yJL7;?zlsUT|MA0eZ6ZMi$OS*3~o2hv_ejaOz zZqdG^X325Ot1ipBxpv}7x5|^A+4pHXXMfGwSFg3WP_dh$K=SNn=%y}>x?cWT$#%nu zvDUH4T`zi6+;n%fQ;2e@v0{ssUXW(+Y|*r$I^{h3ZlCcoWI*TnyT2~;P+kdLHMvo4 zSYsw*ivG?#Wd+&K5x=6J)h#!DXh`j?(&W&?18l4MEsft)x9RJV2O2jU=cIX7bDYg% z-~KLt*(ML$)^+m=yG}7tOP{W(y|B3JV}}m~ri_FSy9fF5>K)3rcu=o+LSnB?bMGu3C0kwiB&5-YjIW0m4d|L!=5i}1 zyBBk7&QK3@N_N@#D(3F2lyHx+uJYBDs$E{a@^kI}vVntEcGlSaC8y zTXm^2Z21x2>5#xukf!iyb5%BIWSd~u)9)`#z4^f@TiNJGQp_HP$I_MxW;O&i0I%akG-`w00qHnm${6DW#xd zpR1M1Z27#n#69==@~xv>VusE&b5F&)!KNwDqnHzp&Chc+JcjMQ`VKANu&@ zHCf+^_4A&tJ?r*{1_~h+8TrRHp=Bgc!O`hB=3AgK7{iM!6lGArx73D>KatKy=*-8!XOt$WQsY~E1Wb?^5>ybee9gAVW*hrMCZIM=jt!=k6bmT+^)TW*_Rrh`f;1{_YdnJcd9zd`2J{2iFIha z^Pv|Xj(?qEyUf1L-HekPQXlGaYdmnwoU*!?dq2sG!G3= zt#@{%MNWI#eER%uy-pij{T_TLh0jDZ7%jYpY)!-=O^u_gw545;#A+ z%DY#0tGB(9xc=3N`rjLmT>E5v-rXDhAIPkZ_xtOT^HP&y)96-31^e$N>y~+q_ zwBdoFkN?jXxlKlUzGx{;zFGLKY?x+tFRMdK8kMd1+ONWa-bkcy?U$f6TcpLHMigW{P*&6)q~fnKRwHN zJ9gpVy9ai+T6wgA)T&M88%vDo8v|@wUEIFre7E>nj!R}LPS1Yg9M$6PpQkrI8qw`h zOl!uW`1_zH{g}F2zaG9bXy)1Q2Gb^f7}2>+(AkT(=jK_jOf`PUTyiD3LD`=w>p818 zH;{cbU7I_xr0Kkb=DshgznlH;oXxtYkE`|RVrYD`XVi~KSEZ-(vRQ|Ve=qULnZ0UU z%G5u@D|NFDTbJ>3O}U!wZBlL&Eyz0^GqG0FLqGStUb|^yVt&Qn5*D>B+Ht11qpnP$ zw8j>b>ZH}I$`joRNBpr}x#*^gS3u-QuRAuHJLwf%+K$p685uq1)}_y9Cf|*`qBfzk?`8bE?pbnrYShN$Q|Yl^zoe}1{zz}1D_OmI``itt<1gyV z=Vdi2UbuLJ&y%OE8xP7on!dWX!CEz-MwqnhpZ2q3QZ6)Kdc5h?R=x|m-qXL_*w|0b zY_5}3Ca(Xn_cMCP?XnWT?^^Q0E_VNpR?>;8@m2O+I6uYR=eD}CUv{T5Asc+{do++a zoiqNr+_hgz4};&k zuKyWX_r&Dqvllek>X_KLl6TnI8)eUCW!?X1yjFZ&AN{&QhR@ZYVx4bE)xhMhwfbzC z!mJp)!$(`?(4cz(b=_-iw%=CxI?rkR-d$}^?N~HycSPv7%oN%2ABs?(<4 zD9wSXquZ8Q+0fsZGNXOso<2G8dlfAd7k9YL|5jY{w}vI-?#jES&wR7Es`J_D;j62! zyB9J&;eEM-%@i{;`*p0pq|Cb!sY{>LN$u0FXTjr-$}J}=4hVmHv*OBQRi5TA^f;~D zcy;ojx()9i&CHy%p`=IE$OA>K1A;nuZfJak)4WBm zmv;R1x$xPmES+Y`+x}ChNygVYI>B)8#qZ@(yS8Y5_|DzH&6nr(ZxMfgw#3=GtrJsk z>%NlnxxN)`Y+fv_y4fqh;b*tOyDI9Qj<^(gH=}3!2Jg<-h~MfJ{p{cbmm9saO?eYr zc;9%q$8AmCnJK%jl;kB1^>aGpw{T*=owH*uKAq+5akj7Hf{6pa=sxa_9^jZAxb0`t zq1Ib^IsU$^=GT#p&iy*O!>--3Q})d|-1JF!`{6>Fxbp)ZwfXZ=k=2H!cEck>W{hmM z!#%y`slmrj96GjR#{S2JynC$Lh6y{vfeQhcz!>j_QBn)X%4bLK96p?b z#ZAV|o+~SC*y!$|yRY9x{(SWE&&OXn&U9YrI6p&T>Y@u?InnNo%dF*ZGAd@&sJ-g& zN&o7H8azpA-lc|b%#CWl+swYVDa6Mq$JcAv`Ia()^YO z3biAh=5~K^aNUxU)gFT%#HJ4mE*=*A_}Xkw<%uhL_pk3(J;=IqD7fLG+Swjk?u;s$ z-L>|MM>jj^^mSeQ9qm7POFkR+EXmCbh=1q%>Cag%16375X4L;?cigmg-`HkdoGZ4r zyFX8|JSFYHZhP(IgLNWxTIS%em!tQ%*}h9%`Dbv0i_+zFRy#+%{k{E~zE+v;V55fQ zI@BoA*la(rv3HAE{W><-e)hzY3D-KOyWH87S=eRwp~@q?j_Im2-m&DQV$gKoW^XTC z>bxv2EoMTOin1QNj=41JQsr{Ow}O-FUV8YI>v?$6q1KbzGtT3eF(Io08rRvdJgR8H zk?@;?6QU|wojm{PFPoX826p)=55GD6RNv+m{7;7%-ZgwZV_MhpW!0m9?6@1F?ce5H zYJ-}6tv)&IHEh}J&>_rrNt@95F}(-r2MmhY%T&Di;*U;td4K4v;#JA#Twb3{t(Na{ z!C$-1?#|c#4Pw+Sz2@hoZFB6F(Z5Hf?vJJ>>zkL%ewqE-hdr6;`IF|H*z?*}v+0x# z(|NB?#@Nlnc1@|^vP7}+j%{cjCrOA>wF+x=B_tEq#cU0~4iaS^>E zTn`?zZ@W4^t$S45%MG{QW+p$-KZ$)K8T-Vy^Qlv>7JdFvriEL%Zf)~SdmkLU)^%I_ zmM?3ZiweAN^fkO6^RsFA?U2P;Igt~#4e7)D(RK09j*U*8oV&C}F%!3>>`)O~gukQn z54H$ei3nQ+#rXeo@_>qc;>D&z2PfzNM7nKMf(J0MMS%M8-)s@IWkD?Jbmf0c9-!j< z>;pDV{C7+t_Ah#vOAfd9{cFn#xNrj<-Jxs|@--EeNXrV?o=}Tz$p{iA{);X0&!?0A z-)#}Wb1bZo_(X>oLUqyMHcS^?SeO>BH$krf4FUErZqbI=P;Ho#lnFJ&YC=Nb<`X7N z$AsybFry|UR%eK2BI2UMHO9Coy(TV}@i*x;rU*vQ{$mI?L~BPfM!@YPl~|BTnP8)K zw3dm|MaP-oRUb=NAjXKjvCPp7;VnPg2Q5q&4egi)(y!r;jzU?gCNLiFVm0d&kSG&GJ}}GFamIEuol<}GzG(-Y*)=tj=m6`E<|SxiHl<5qC!kGw0$3!wC8F&SpiDnE;3^R%`GA1ULiDO1HW0GW87a6fzbIKgwimbMkD(pGRe?g$`d z$q0_q>$R~AC`U9Av{CpUOcoPs)P!oIG{%vPiD-wdY5>ZWJjx;HHYijF^ASjZ_n&za z$X#j{=upF$Xaaq51Rfn`D*TQQEU7{{v^S6X8nTL@Dem@tk53tp%b1XI{05v|HLOkiAa?6?@M6N7+K z8-`mbom6-g1*54ms2;q6Gv1)lf&Mm~4f;@?b>uF{n)_do`)c*0wXrZ2+w=<7>p=DM zT0lu}7DMKLZGr2)7=HfE!v8D&zPc!_sf}N(Mz0Iub)J2aolBVbUy++T&&Mmc>gs>R z%XXR=QMurj=KmG7WkgBzf~%|lztQt~BDjwGf5pu5B)|a5gpXVBHX)0E# z|1XUya7HO0#Tj()FV2#Jf7vG@oRsE^9h5k!P|&D5z9vv8vHy)yB^wBKa>tie2ROO2 zH)}Y#vl-n^?)Z8Mfa44#VWar6!T+UE?&U%54s-6VI_@?FE;Y&=#^tk@b@l!)jeRrWbiG!inry=01kwX7+4M+%Mp%7Zr^-VqOQ4xtK7st)TMoHp&{=hFnOE-YNb(S1 z2*Dwohs-h@XHr{wC*%6Vjvr3&hEg+6ROZpaqA%lqiHW`-Gu+&5Rx#mW#wqLn*eY!C zVCJzrp-IB!BuSP*hl3OX<-n0-Mu!AYAd-U93g*5-0yZ~(?4no7VnT+np$e3k$ImQL zW`1#mu>3L;!pV?emI>`$c3R-WAAlNU2p?au@QdgJK2}rO2Q#@m5fB`^F%zgL)y?n% zv4CF$a_)X#mOwMPeB>e%8Xr$G_ner}+$C77d|@M8Fc?C!oMi-ePzxA=Z)LJD0^K*o zjx}CK@HJJXjKIgUgvb%4gy7%{rr5r6cXn|KnM2N!F49+#xyhP9c+l`wyS%<~oMcJI zmk&d!SyZ^Lv!Y_|x~QlKZY?&CCTsn%tqMm|#pp_FkHvLtcLG;0fi1{FLV!;xf}(D+Ro9wW`I@`%6?VqjSd7!!ft0kR+< zi7=DMa){%Xd0cSUpejoQ_e)IW37$DJ6MVuS9U)Vm-1d5nfGK+a7 zBg`u)wmeW{cv@g%N-z;b%qtmwP|Ms`V$cQX&^zgP&ar(pTSu0`V9SZYzz?foQrCn!7lQZl@%pSHP*=p&! zDT|pjhkhBqgpCrZNXFarQ$$Z zTU%)v(V4AQU1sYkgAxt@e*oatL5LGW_IALuOeGr%?9JxFKMQksr z#rA>&Lu@h7;QyAsiONNlF?{LRmB03#?@* z)tQj2{BTP#8jQC5mn#G;Z~EGj8sQ4!bM=nbd8@4|}&wk&Zi!nUHqJR-Ifm+b82L|Rgu#z(e2H`bU196wm8;H*a6aqfqR zl#3Wt7JG^?r#L?0=4dKV&x9Pem{No#MMyV0nK9bZ6^JE+qmU)T>|u)VU&QjV7+!?k z#RZ5E2Pu$YmDZ-TEFyZ-VHY_at6ETS_77<|(ahNdw z%=U`~lZb6(F^vezh)*fEqF}6?Eyv0$X9i(;eEVd6}`fzAjOssJ6Fd?xOj=aU}A*>!gmpSu*#VW9P zxUOR^a|WG=RuD0Fc-9Wr7;A8GzmQfi+dby6E;;Q)!c9CANNCIou=1y!nK}!b#4MiD zh=b7FF(bu{p-ePXDCBmj$!b<6W(%`a2V*>(Za3Q$=B{D}6On7FglAHy@T$+X*HZ%t z3r<5^x)?&*1ja&&k*kxOCDh3!NE3?kC4(T3EebN1OhK`RAWd|T#%R=xbA|m}OceSo zMh8FH$-w>$3Nb)(WlXHe6}C4qClDOf3({+&!($^{om8y#M8Jb$wAztS$j$<;&=h0{ z3o^x`Bptx0WLH{LXbRE<>2;9JXM_&H?el0=V&NvpQwh-`AlJ)aT{L_a6dZ?gKQS82 zT=+cL6be`%Im@ICg&M4CLU2eD3k8ZpgLKg*Na@fcbU1PWg&`3dW6)?5{ulbhuB`wM z)x>HzD)0+xs6#B!V2srS>-4%<)LHzB9xlUp*>wti3aM^-g9dkmYfC#e2KuLq4KnHC zwTP$qodi@FN+53zCGiEtLh=s6izN_>!gOP`Ko@2=>gZ@la?%9rwHyc!2SQfL&M*Vy zPQ`MaHzz2#1chs3V^ISUT73+B&aMH_fDUpc#|E((ra=-U5FA5=B|$PMV+~APD^?3h zT4(^+i2yLzz#fVE3MqF0cV`tQhC{}iMjsR#qYnz##71b1LBV=M$Vk*1U?VC6Sz)a< z@z0~QQM@l%(@^}&XhXCZZjL0#`3oNt6f!P+j4m3Oz#1Wd33lFNq3a-=aUrpBFczr) z*g!{xh9JlvMpfZEZ77y5b5;Z@j1CIb>w_RAGaL;Zn}Y$h01l0S9H7BrZ4LxALS`zO z2Vrs1IK>f_;#-1{92iDxjiYtiF#s!_y^x!TB-VU!kV{aEUK5Lk7*%8!J*Wsh#xn&0 z@wI6Pn+ei-A%iI%^5md1y6B(~C}q_!Dvg13I2aY-D5LRY6B*!((y3Z1ETs%$)c`c- zUMgUgGV|fj)$>Y8n8-)df z6I1w!wVYXCSThQ`gc7=i+5!d-SP9H^=LWV^i*Q`hj)lx}z1B_cCI#|XSJ27D0tIED zWIb&@R1Q#1=Ucv20F)!&0#yQ(n-&(RJ3u+LXo0GrtE|`0Z%vJ)&&+u4TLtQ`J2#;$ zQ0T9Un^G1i^jBqR4bBn35{1};&pd!gu*w%n1!4j=FgPG9EC_7YEv(uF0PA}>xghz4 z3BtZ;1IX}11M=8VjgyPs1Svm|6(1e$)&?=zd^A-E2ZgM{r%nKYpaRrjZ>} zKEeuUXxJ!|5RL|io2dK-(D1N6hwyteK&)FQgu@UiIkxffph3ciSBQRk0G#!1FdlaO z0Y+eXGv}Tmig^XV3k9e91tmbUg7vfsTtKvfTUP`%fNFSvh@Fvw0w7z#Bg4`<&fOG|?boh-+5bY{9nkB>qB}fq1I2=`kYVm}sw9ilri@jN2 z5KST3=az1w2)Ls%Co&3#01yIyR6H@_w*?$h;dD@Tq^tfNH?f7CKz-oJ z4G$aY0vmZFv7sKYaYC{L21&(+F3A!YC6zg;lb{ubNyVu+e&4W&syKy4l%Qc^U2tJT zPzenaXLk~{5Q8`imncFU;w)mK2(gG;H;E#|BTl&zMTkk9nMxEPE^+n?QH0pUSxZC_ z;*&Y~QNTes$p$5ydm*eOLww??k<#IXN{CP9Oji;gLdZHrBzI+qPi)|cDnfkX+!vx7 zh)>*NK@=fAvA!9F5b=rA@!aHfu+05OF# z{{;nzDV!lCC_qf%>~%o_VhU$w3kncZ%(?M=A(vyOa88q;24V{5Me_=|Q|uA{{>tC=@!lM;R5+i?jmE0~?bRFkXS>fpf+LZ6MOk$?<&B;VNBJ zK+grZ`vVow!Uzu|LV?I!gaSmmh|X8yQ5Tt{aL+2LVU8y7`V03@qXN2HN=&-Q3{_&% zMHV+Do(dvM8{9yQ+Mul_B_>^DS#!svi)eo+K%|SPLMTD(648WEf&@ZD5yI8AP$06B zz?I&pfS$bYW+W=0B?XRLqc+S=7>~j5P$Via`zL||Bq<{62Rv$t3g{tm$LtbWJ5-om zB4#NRAa=1kg8~7D62va^(Gk9&LJ8suzV${pO`rs^h24cCu>oJ)c@77sgP{&E#$80A zLkV!kT|{p~39!apL~%n2@CMx;jzfbyZo&=5&@~YQ9Ikdp1@wri@KA~v;3_!XedP%2sL7{yU21JYXVg6x=U?x=Ra%2U2hDoKJ$!4u|TZAn+9nQ-$*%%n@2P7URyDux2P1jB)3* zY79gI(P%5UDZm2ID09{n3qhmHg+EvbVjZ_Avk)|z-15Rg&?s`@8Ww`M#Hkb(0_;(7 zdXa^|XsI|$hlKz`RP0GXCl?k1oKSJL0){|$6r2^r0)Pk=7wupnKm>cQ38-xhfgUTk zQN{r1u!0jI41oSBxP=h|pt}lA!D9f@Y=XWajmC*P{sL(-F1msNuzv)Xv$K<)1t5rk zWStIyxX?QL(P)5h>tqaf*1jbgKB;B+%t!D64D_=Xv0!RT;lL=VrN5uJGS1lNfq^;bc@wNmd0=3XjI%0vU|^JtGX!~HV3&-u6U_G;V1>k@nrye^k2$FE=_U492mzYIK3-`V-06+i(dip%}ko00&3Mfy9IE>IkTD;z=3rf zF9dMl9cRi4;7Gp2+C^d})-KW!bi3GX-WD)!lXGaY<6$DHAG5h7n$2$XVKi7o_cx#>?9VrPw;?Q|ia<!YmUX zMwnU{GhY?)F=J0a#@9!}Qlu5Qfr2Cn*gu4RD!8?sg+S{H&c|gTP)o(BOSEOHfoul= zamoULLgS)hkQHWjj}Ryf?(soinH_8diZsL`RAxy*5H2Qk)Yh(n1OV|1|*kne&12GY!TF}R>S4ioxq?jLOXnm3qXePg*l z432^5qI9uD;*JaNQ{klqs5e~34|^X4n*~JNE`Y>>`>YFWvYX%%0!)Y?eF%AN+*j-! z1m0-d-2fM>^+tDLKqaguY#8ot0)XHEDI~+=bR!k3W!Ud~7~m=_rk_b$`Zd!pz^`39 zeCdpfE2LXFG5sO6L2HC;I_}!GcI^NT4a8`py>K=JOc(4;0?xiZ1Kqm9^;E%{=xD9c z$)#@u+$#nDiwOqt)J6wYApe|Z72^ij~7r@~DAQW5U!vLQQMGE*Z_#1~$NEp&P z0+<}4Wdt3751&L5d?$e$xruh694GMzzLP^<2r)*0PlCb^g6|{}HFEPw7z%6%U~&kj z5#NE}dWejr2Z~7v>cVV8YmWdXcgI(c@L_;YjXZ5W4F2{&VO${$j;0WOk;vWg6+`^* z5I(vu;LDJG0p&!G2gJjOb^#xH?~v?^lpYT_wnX<2$ApOfL8mEv*g)Zb2P#4)G9J{J zL;rAuo~Vmg4iZMvCXsvK7zY14z=sp*_%NidP>h9u;jBCXOzwe=3qB0+;p?FIFu;ei z{74vDK?N|mhZ-4-d>G)vcSZ1FfDdQqkT6<5dw7sz3HYR>js<);^OwMfgO~!C0u&L^ zXTT?+b(0ilkO=BZz+oljMF9;HFgR5R{|R{j{ez{GhM_%3K^yP}Br^8-FoX{UmiaJ* z52d;hFb@=&7Qhq|1=^0_!vLR}k}Ca&UE3ofvgB}T|h7t(GYy6 zfF+9N9}aQ~zJuiw8J#2y#RLT~1-!aPz@UFP$xZN`1blfKp9}@p1>ZsX6*43FFu(_o zZ3!o202~G_2Ab9eAw~g!%$tc zl|;aB?y~>}sbDC=&4(d;lpdFWs-t95hI6L*btOvJ?IqfUqp%*79*5U2$aNa}jJ+cQ zpNbqegb#Twg72U%a@zx?si8Fp38%NEj#h4ERLmz8qFA3ZH`1B@)Qd z5|L+ooSxtx&d(%ZI7>wUgX}F4d6u9Mh2T30yz@=>5APBRz5}VJL9T;<&x7)h)DZ2V)+5Mmr0Io4ndl2FwWMz)QA1)cv91EW`23E5 z4ya46`^eowsYrtFU^yav1HdOofhECr$W2mBYjw)4Fr&=3uY|J9}u*mh6zl32l()be!+K8m*fkyfzy-)-+|YIwxakj zDZFe<*_{vpA?Fd`!^tiDx)Kj?VMXwfG6Z$;c^pAqfKl_q19Hg--b4TJekoCxUK_#1 zCVffhpPbgGaK3y`hqWjBw(<}3;PG*IuBCk06u(U4Oy3td4Oz?V~KPkp*sN|cs{~*QFIN( zn~63kA5jW=4Q=G}zXLDXgS1%zA5IhHe}`aXTo3T!8>0B%0X|wz!NsQMARPQ4=PKw# za?L|tJn3^nUvU0Czg+|)>5ziOMe9GMNNfp~b6Q@&Fd=vaVI+Edl{k@)=nH5{VO{8- z2Q4q4B8agBdTGA`>Qb=`fRTL$dhsDyeqR8eoE$d@uhDZAV5AQVid{|nmmnIHtU*c@ zK?k$}#^p z>_))cQ5HJ^qy2LTQjl{CLZJ9wDq&qYSfeC9*is_aJgAGaUx~W-fC&NfpymQxlScV( zU?rmMZed+eyAb^QFJT$C?DPCX-WpF%TA| zV|d^kl==`B-9+yPKuDE}hsi+vsJ;L?Qs>CPzohsA*CLQIE>qxhi$XeJdzBhj3l`Sj>55|tp_kQ=?g)a6(aqlT+w@m@Eru$sPFJWdLeDF#X|KD z)D^`)cMnRxfLKxS7ZiIS&ZRny?of`q}EHAMPz&f?KYC}Fo4lHHW2Zk z<}}DDrJofL@*rsg^NNxK$Wx>_tNAq6oLFqb(fYST}7l-1h2fiR$AkU!f$=Cx3 zAI>%}E|jQ8 z+8|&?P`(<#sC5A(lG0&tewmUX2uo2u7@VFZ_ZJ|nNAJbJ1v?`B^B{BcAgl*F*@RvL z7!}_DE0&54L#UaIT?0Odu2cAE-xORSdfecuF>Wp6^Z|qz>2ZVeXXM%ltfI#awgX7o zAc{%ZVc zyc0%)vPA(##lGMIC@QxMJU_}l1sF9Kz#O9H0>G%b0G0qX7eI!nxd0{&<)?rLM#~Fq zn33`fW)sZ=5nls^3CTGFM<;0>0JEqzV6Kwu7EB|W2QXJjT?e5^ng=5LOyJJYa|^=v zVaCPp?lOi4KT`Xf@mV;4+0D&?F;6<3LIe4zK4UU zREz>(REz?4c4%I~_5wM+;D%Cb8SHdWHW$Ds{Rdk>l>SpedKjtO0Y>RRcqx+7e*h!* za6yaHHWwVlrN29R+92z%3G3F!ia-2^dsI=>FKttdYp(nhHH3!y$rZ$J(ZWe>pxO;r8? z+yX_}43O_b*+bA5%9es%V#;QK!!nf42F_EyB&_BX9gxRE={3m3p>!CWw4wA6^o7!4 zFk|RG!*&lT2jJpRd{M(jB01)2u>Z*U0l7Go&kp%CR4f;ASSZ^EGKDBV6mnCjF^70W z>HM|CBk1^~8Xl=7Wfx%7yi~)5IHc@?OGnL1fKl^O4Mrw8F9Al)OEp|0L(WS$0YlA8 zfKhwGYS??H_zZCxiZ(cxK#dU?Y!q#vcFB3E1|x*jIcgw{q76c{#9Rfd6JH%H(D#r| zNR2t{bWrx68bp`s3oIZs9klHYDVmfn2JVsh5fTp&D^kWiAj^iL4U`GV1IXg0>>PGw zWB=bGfAskjaM>wc0=Z07%mea=sCfxH`BeYF5}?K$qSTbU0A-ZE0+*ed3y@+>$(0Ap z1(NrWKSb#vSOG{q1e~JIG{9*RP>RG_0afFjpTkKd?zRK zC;$dYcT`{SJ$6L9)V>hZrS_;0j9dc%hA%r1%HvtTc>@-$NVt7C0e3&{u?R zM>$30x&<(N%_~utvJX%;2sz&XhVP6P)P-GQQfI@CgF9)*LR|dQXU<@NK<9`Ga%;N}knfa^DZ?!iq`Cvj?>&45>4g93^giA&f+=0aDPXPRZ;U7tSd4P57ut*Yzcgj20-Z{P_g8?3L;7E3n3V} z?gLE0*F&*JjZUvM+O%tD!vw> +v1.0, October 2006 + +include::sflogo.txt[] +include::topnav.txt[] + +Examples +-------- +include::toc.txt[] + +This document is a set of representative examples demonstrating how to use +tpl. If you're looking for a more explanatory document, please read the +link:userguide.html[User Guide]. + +An integer array +~~~~~~~~~~~~~~~~ + +.Storing an array of integers to file +------------------------------------------------------------------------------- +#include "tpl.h" + +int main() { + tpl_node *tn; + int i; + + tn = tpl_map( "A(i)", &i ); + for( i=0; i<10; i++ ) { + tpl_pack( tn, 1 ); + } + tpl_dump( tn, TPL_FILE, "demo.tpl" ); + tpl_free( tn ); +} +------------------------------------------------------------------------------- + +A program that unpacks this tpl data file is shown below. + +.Re-reading an array of integers from file +------------------------------------------------------------------------------- +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + int i; + + tn = tpl_map( "A(i)", &i ); + tpl_load( tn, TPL_FILE, "demo.tpl" ); + while (tpl_unpack( tn, 1 ) > 0) { + printf("%d ", i); + } + tpl_free( tn ); +} +------------------------------------------------------------------------------- + +When run, this program prints: + + 0 1 2 3 4 5 6 7 8 9 + + +A nested array +~~~~~~~~~~~~~~ + +.Packing nested arrays +-------------------------------------------------------------------------------- +#include "tpl.h" + +int main() { + char c; + tpl_node *tn; + + tn = tpl_map("A(A(c))", &c); + + for(c='a'; c<'c'; c++) tpl_pack(tn,2); + tpl_pack(tn, 1); + + for(c='1'; c<'4'; c++) tpl_pack(tn,2); + tpl_pack(tn, 1); + + tpl_dump(tn, TPL_FILE, "test40.tpl"); + tpl_free(tn); +} +-------------------------------------------------------------------------------- + +This creates a nested array in which the parent has two elements: the first +element is the two-element nested array 'a', 'b'; and the second element is +the three-element nested array '1', '2', '3'. + +.Unpacking nested arrays +-------------------------------------------------------------------------------- +#include "tpl.h" +#include + +int main() { + char c; + tpl_node *tn; + + tn = tpl_map("A(A(c))", &c); + + tpl_load(tn, TPL_FILE, "test40.tpl"); + while (tpl_unpack(tn,1) > 0) { + while (tpl_unpack(tn,2) > 0) printf("%c ",c); + printf("\n"); + } + tpl_free(tn); +} +-------------------------------------------------------------------------------- + + +When run, this program prints: + + a b + 1 2 3 + +A string array +~~~~~~~~~~~~~~ + +.Packing a string array +------------------------------------------------------------------------------- + #include "tpl.h" + + int main() { + tpl_node *tn; + char *s; + + tn = tpl_map( "A(s)", &s ); + + s = "bob"; + tpl_pack(tn, 1); + + s = "betty"; + tpl_pack(tn, 1); + + tpl_dump(tn, TPL_FILE, "strings.tpl"); + tpl_free(tn); + } +------------------------------------------------------------------------------- + +.Unpacking a string array +------------------------------------------------------------------------------- + #include + #include "tpl.h" + + int main() { + tpl_node *tn; + char *s; + + tn = tpl_map( "A(s)", &s ); + tpl_load( tn, TPL_FILE, "strings.tpl" ); + + while (tpl_unpack( tn, 1 ) > 0) { + printf("%s\n", s); + free(s); /* important! */ + } + + tpl_free(tn); + } +------------------------------------------------------------------------------- + +When run, this program prints: + + bob + betty + +Integer/string pairs +~~~~~~~~~~~~~~~~~~~~ + +.Packing integer/string pairs +------------------------------------------------------------------------------- +#include "tpl.h" + +int main(int argc, char *argv[]) { + tpl_node *tn; + int id; + char *name, *names[] = { "joe", "bob", "mary" }; + + tn = tpl_map("A(is)", &id, &name); + + for(id=0,name=names[id]; id < 3; name=names[++id]) + tpl_pack(tn,1); + + tpl_dump(tn, TPL_FILE, "/tmp/test35.tpl"); + tpl_free(tn); +} +------------------------------------------------------------------------------- + +.Unpacking integer/string pairs +------------------------------------------------------------------------------- +#include +#include "tpl.h" + +int main(int argc, char *argv[]) { + tpl_node *tn; + int id; + char *name; + + tn = tpl_map("A(is)", &id, &name); + tpl_load(tn, TPL_FILE, "/tmp/test35.tpl"); + + while ( tpl_unpack(tn,1) > 0 ) + printf("id %d, user %s\n", id, name); + + tpl_free(tn); +} +------------------------------------------------------------------------------- + +When run, this program prints: + + id 0, user joe + id 1, user bob + id 2, user mary + +A binary buffer +~~~~~~~~~~~~~~~ + +.Packing a binary buffer +------------------------------------------------------------------------------- + #include "tpl.h" + #include + + int main() { + tpl_node *tn; + tpl_bin tb; + struct timeval tv; /* we'll pack this structure as raw binary */ + gettimeofday(&tv,NULL); /* populate the structure with some data */ + + tn = tpl_map( "B", &tb ); + tb.sz = sizeof(struct timeval); + tb.addr = &tv; + tpl_pack( tn, 0 ); + + tpl_dump(tn, TPL_FILE, "bin.tpl"); + tpl_free(tn); + } +------------------------------------------------------------------------------- + + +.Unpacking a binary buffer +------------------------------------------------------------------------------- + #include "tpl.h" + + int main() { + tpl_node *tn; + tpl_bin tb; + + tn = tpl_map( "B", &tb ); + tpl_load( tn, TPL_FILE, "bin.tpl" ); + + tpl_unpack( tn, 0 ); + printf("binary buffer of length %d at address %p\n", tb.sz, tb.addr); + free(tb.addr); /* important! */ + + tpl_free(tn); + } +------------------------------------------------------------------------------- + + +Simple pipe IPC +~~~~~~~~~~~~~~~ + +This is a simple example of inter-process communication (IPC) over a pipe. + +.IPC over a pipe +------------------------------------------------------------------------------- +int main() { + tpl_node *tn; + unsigned i, sum=0; + int fd[2], pid; + + pipe(fd); + if ( (pid = fork()) == 0) { /* child */ + + tn = tpl_map("A(u)",&i); + tpl_load(tn, TPL_FD, fd[0]); + while (tpl_unpack(tn,1) > 0) sum += i; + tpl_free(tn); + printf("sum is %d\n", sum); + + } else if (pid > 0) { /* parent */ + + tn = tpl_map("A(u)",&i); + for(i=0;i<10000;i++) tpl_pack(tn,1); + tpl_dump(tn,TPL_FD, fd[1] ); + tpl_free(tn); + + waitpid(pid,NULL,0); + } +} +------------------------------------------------------------------------------- + +The child unpacks the integers in the message, and sums them, printing: + + 49995000 + +The example above (with `#include` headers omitted here) is included in the +file `tests/test28.c`. diff --git a/libs/libtpl-1.5/doc/txt/future.txt b/libs/libtpl-1.5/doc/txt/future.txt new file mode 100755 index 0000000000..dc2240ffb7 --- /dev/null +++ b/libs/libtpl-1.5/doc/txt/future.txt @@ -0,0 +1,52 @@ +For future reference these are some API design ideas- not working code! + +-------------------------------------------------------------------------------- +Java API ideas +-------------------------------------------------------------------------------- +http://www.ioplex.com/~miallen/encdec/ (binary pack/unpack utilities) + +The Java API would take an object, and a list of field names, then use the +Java Reflection API to read or write those fields during packing and +unpacking. + +I.e. if you are going to unpack a tpl with format string A(if), you +might create a Java class that has two instance variables (an int and +a double). Then you create an object of that class, and pass it to +tpl_map (or perhaps a constructor for the Tpl class), like + +class Unpacker { + int count; + double weight; +} +... +Unpacker up = new Unpacker(); +Tpl tn = new Tpl("A(if)", up, "count", "weight"); +tn.tpl_unpack(1); // stores unpacked values into count,weight using Reflection + +-------------------------------------------------------------------------------- +Ruby API ideas +-------------------------------------------------------------------------------- +#!/usr/local/ruby/bin/ruby -w + +class Tpl < Hash + def initialize(fmt, *args) + @fmt = fmt + @args = args + end + + def pack + @args.each {|key| puts "#{key} #{self[key]}"} + end +end + + +p = Tpl.new("A(i)", :id); +10.times do |i| + p[:id] = i + p.pack +end +p.dump("/tmp/file.tpl") # p.dump(arg) checks arg.respond_to?(:write) + +p = Tpl.new("A(i)", :id); +p.load("/tmp/file.tpl") +p.unpack(1) {|h| puts h[:id]} diff --git a/libs/libtpl-1.5/doc/txt/perl.txt b/libs/libtpl-1.5/doc/txt/perl.txt new file mode 100755 index 0000000000..5c66843c85 --- /dev/null +++ b/libs/libtpl-1.5/doc/txt/perl.txt @@ -0,0 +1,302 @@ +tpl Perl API +============ +Troy D. Hanson +v1.1, April 2007 + +include::sflogo.txt[] +include::topnav.txt[] + +Perl API +-------- +include::toc.txt[] + +The Perl API for reading and writing tpl is nearly identical to the C API. This +document will briefly explain the Perl API and provide examples. The chief +motivation for having a Perl API is to communicate with C programs that use tpl. + +[TIP] +.Start with the C API +This document assumes familiarity with the C API. The concepts of using tpl +are not explained here. For an introduction to tpl and its C API, see the +link:userguide.html[User Guide]. + +Tpl.pm +~~~~~~ +The `Tpl.pm` file (in the `lang/perl`) directory contains the Perl module. You +can copy it to another directory if you wish. Your Perl program may need to +include a `use lib` statement to find the module. + + #!/usr/bin/perl + use lib "/some/directory"; + use Tpl; + +tpl_map +~~~~~~~ +This function resembles the C version, except that it's invoked via the `Tpl` +module, and it takes references to Perl variables after the format string. + + my $i; + my $tpl = Tpl->tpl_map("A(i)",\$i); + +The return value is a tpl object; all other API calls are object methods. +Incidentally, there is no `tpl_free()` method corresponding to the C API. + +Fixed-length arrays +^^^^^^^^^^^^^^^^^^^ +Format strings such as `i#` denote a fixed-length array. In the Perl API, +fixed-length arrays require two arguments: a list reference, and the fixed +length. For example: + + my @x; + my $tpl = Tpl->tpl_map("i#", \@x, 10); + +When fixed-length arrays are packed or unpacked, the specified number of +elements will be copied from (or placed into) the designated list. + +Structures +^^^^^^^^^^ +Format strings containing `S(...)` are handled in the Perl API as if only the +interior, parenthesized part was present. (It does not work like the C API). So +simply ignore the `S(...)` and consider only its interior format characters when +constructing the argument list: + + my ($str, $int); + my $tpl = Tpl->tpl_map("S(si)", \$str, \$int); + +It really only makes sense to use `S(...)` in a format string in the Perl API if +you are communicating with a C program that uses structures. + +tpl_pack +~~~~~~~~ +This is nearly identical to the C version. The only argument is the index +number to pack. + + $tpl->tpl_pack(1); + +tpl_dump +~~~~~~~~ +This method is a little different than the C version. Given no arguments, it +returns the tpl image; given one argument it writes a file with that name. + + $tpl->tpl_dump("demo.tpl"); # writes demo.tpl + +Or, + + my $img = $tpl->tpl_dump(); + +The tpl image is a binary buffer. You can do whatever you want with it, such as +write it to a socket or pipe (probably to C program listening on the other end), +or save it somewhere and later re-load it using `tpl_load()`. + +tpl_load +~~~~~~~~ +This method loads a tpl image from a file or from a Perl variable. It takes +one argument. If it's not a reference, it's assumed to be a filename to load. + + $tpl->tpl_load("demo.tpl"); + +Otherwise, if the argument is a Perl reference, it's construed as a variable +containing the tpl image: + + $tpl->tpl_load(\$img); + +The method will `die` if the image is invalid or the file doesn't exist. You +can wrap it with `eval` to catch such errors: + + eval { $tpl->tpl_load(\$img); }; + print "failed to load\n" if $@; + +tpl_unpack +~~~~~~~~~~ +This is nearly identical to the C version. The only argument is the index +number to unpack. + + $tpl->tpl_unpack(1); + +Examples +-------- + +Integer array +~~~~~~~~~~~~~ + +.Packing A(i) to file +-------------------------------------------------------------------------------- +#!/usr/bin/perl + +use strict; +use warnings; + +use Tpl; + +my $i; +my $tpl = Tpl->tpl_map("A(i)",\$i); +for($i=0; $i<10; $i++) { + $tpl->tpl_pack(1); +} +$tpl->tpl_dump("demo.tpl"); +-------------------------------------------------------------------------------- + +.Unpacking A(i) from file +-------------------------------------------------------------------------------- +#!/usr/bin/perl + +use strict; +use warnings; + +use Tpl; + +my $j; +my $tpl2 = Tpl->tpl_map("A(i)",\$j); +$tpl2->tpl_load("demo.tpl"); +while($tpl2->tpl_unpack(1) > 0) { + print "$j\n"; +} +-------------------------------------------------------------------------------- + +Message-passing +~~~~~~~~~~~~~~~ +While the bulk of this example is socket handling, it demonstrates how you can +use tpl as a message-passing format. In the real-world, you might have a C +server and a Perl client, for example. In this example, we'll code both a client +and a server in Perl. + +.A server that sums integers +******************************************************************************** +Programming literature is rife with contrived examples so we will follow in that +tradition. Our server will do no more than sum a list of integers. But in doing +so it will demonstrate message passing adequately. Both its input (the integer +array) and its output (an integer) are tpl images, passed over a TCP/IP socket. +******************************************************************************** + +Server +^^^^^^ +The server waits for a connection from a client. When it gets one, it accepts +the connection and immediately forks a child process to handle it. Then it goes +back to waiting for another new connection. + +The server child process handles the client by loading and unpacking the tpl +image sent by the client (containing an array of integers). It calculates their +sum and constructs a new tpl image containing the sum, which it sends back to +the client. + +.Server +-------------------------------------------------------------------------------- +#!/usr/bin/perl + +use strict; +use warnings; + +use IO::Socket::INET; +use Tpl; + +$SIG{CHLD} = "IGNORE"; # don't create zombies + +our $port = 2000; + +sub handle_client { + my $client = shift; + + undef $/; + my $request = <$client>; # get request (slurp) + + # read input array, and calculate total + my ($i,$total); + my $tpl = Tpl->tpl_map("A(i)", \$i); + eval { $tpl->tpl_load(\$request); }; + die "received invalid tpl" if $@; + $total += $i while $tpl->tpl_unpack(1) > 0; + + # formulate response and send + my $tpl2 = Tpl->tpl_map("i", \$total); + $tpl2->tpl_pack(0); + my $response = $tpl2->tpl_dump(); + print $client $response; + close $client; +} + +my $server = IO::Socket::INET->new(LocalPort => $port, + Type => SOCK_STREAM, + Reuse => 1, + Listen => 10 ) + or die "Can't listen on port $port: $!\n"; + +while (1) { + my $client = $server->accept(); + next unless $client; + # new connection + my $pid = fork; + die "can't fork: $!\n" unless defined $pid; + if ($pid > 0) { + # parent + close $client; + } elsif ($pid == 0) { + # child + handle_client($client); + exit(0); + } +} +close ($server); +-------------------------------------------------------------------------------- + +Client +^^^^^^ + +The client is a simpler program. It constructs the tpl image containing the +integer array (taken from its command-line arguments), connects to the server +and sends the tpl image to it, and then awaits the response tpl. The response +containing the sum is loaded, unpacked and printed. + +.Client +-------------------------------------------------------------------------------- +#!/usr/bin/perl + +use strict; +use warnings; + +use IO::Socket::INET; +use Tpl; + +our $port = 2000; + +# construct tpl +my $i; +my $tpl = Tpl->tpl_map("A(i)",\$i); +$tpl->tpl_pack(1) while ($i=shift @ARGV); +my $request = $tpl->tpl_dump(); + +# send to server, get response +my $socket = IO::Socket::INET->new("localhost:$port") or die "can't connect"; +print $socket $request; +shutdown($socket,1); # done writing (half-close) +undef $/; +my $response = <$socket>; # get reply (slurp) + +# decode response (or print error) +my $total; +my $tpl2 = Tpl->tpl_map("i", \$total); +eval { $tpl2->tpl_load(\$response); }; +die "invalid response\n" if $@; +$tpl2->tpl_unpack(0); +print "total is $total\n"; +-------------------------------------------------------------------------------- + +Running thise example +^^^^^^^^^^^^^^^^^^^^^ +If the client and server programs are in `client.pl` and `server.pl`, then +you can run the example by starting the server in one window: + + ./server.pl + +Then run the client in another window. E.g., + + ./client.pl 1 2 3 4 5 + +The client runs and then exits, printing: + + total is 15 + +You can re-run the client with different arguments. When done, type `Ctrl-C` in +the server window to terminate it. + +// vim: set tw=80 wm=2 syntax=asciidoc: + diff --git a/libs/libtpl-1.5/doc/txt/sflogo.txt b/libs/libtpl-1.5/doc/txt/sflogo.txt new file mode 100755 index 0000000000..68b153b0c7 --- /dev/null +++ b/libs/libtpl-1.5/doc/txt/sflogo.txt @@ -0,0 +1,5 @@ +ifdef::backend-xhtml11[] ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +SourceForge.net ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +endif::backend-xhtml11[] diff --git a/libs/libtpl-1.5/doc/txt/toc.txt b/libs/libtpl-1.5/doc/txt/toc.txt new file mode 100755 index 0000000000..458eed18e2 --- /dev/null +++ b/libs/libtpl-1.5/doc/txt/toc.txt @@ -0,0 +1,85 @@ +ifdef::backend-xhtml11[] ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +

+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +endif::backend-xhtml11[] diff --git a/libs/libtpl-1.5/doc/txt/topnav.txt b/libs/libtpl-1.5/doc/txt/topnav.txt new file mode 100755 index 0000000000..257e665cf7 --- /dev/null +++ b/libs/libtpl-1.5/doc/txt/topnav.txt @@ -0,0 +1,10 @@ +ifdef::backend-xhtml11[] ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +
+ sf.net summary page > + tpl home > + {doctitle} + [View PDF] +
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +endif::backend-xhtml11[] diff --git a/libs/libtpl-1.5/doc/txt/userguide.txt b/libs/libtpl-1.5/doc/txt/userguide.txt new file mode 100755 index 0000000000..705fe3b59c --- /dev/null +++ b/libs/libtpl-1.5/doc/txt/userguide.txt @@ -0,0 +1,1264 @@ +tpl User Guide +============== +Troy D. Hanson +v1.5, February 2010 + +include::sflogo.txt[] +include::topnav.txt[] + +Overview +-------- +include::toc.txt[] + +Serialization in C +~~~~~~~~~~~~~~~~~~ +Tpl is a library for serializing C data. The data is stored in its natural +binary form. The API is small and tries to stay "out of the way". +Tpl can serialize many C data types, including structures. + +Uses for tpl +~~~~~~~~~~~~ +Tpl makes a convenient file format. For example, suppose a program needs to +store a list of user names and ids. This can be expressed using the format +string `A(si)`. If the program needs two such lists (say, one for regular +users and one for administrators) this could be expressed as `A(si)A(si)`. It +is easy to read and write this kind of structured data using tpl. + +Tpl can also be used as an IPC message format. It handles byte order issues +and deframing individual messages off of a stream automatically. + +Expressing type +~~~~~~~~~~~~~~~ +The "data type" of a tpl is explicitly stated as a format string. There is +never any ambiguity about the type of data stored in a tpl. Some examples: + +* `A(is)` is a variable-length array of integer-string pairs +* `A(is)A(is)` are two such arrays, completely independent of one another +* `S(ci)` is a structure containing a char and integer +* `S(ci)#` is a fixed-length array of the latter structure +* `A(A(i))` is a nested array, that is, an array of integer arrays + +The tpl image +~~~~~~~~~~~~~ +A tpl image is the serialized form of a tpl, stored in a memory buffer or file, +or written to a file descriptor. + +What's in a tpl image? +^^^^^^^^^^^^^^^^^^^^^^ +There is no need to understand the internal structure of the tpl image. But for the +curious, the image is a strictly defined binary buffer having two sections, +a header and the data. The header encodes the length of the image, its +format string, endian order and other flags. The data section contains the +packed data. + +No framing needed +^^^^^^^^^^^^^^^^^ +A property of the tpl image is that consecutive images can be written to a stream +without requiring any delimiter between them. The reader making use of +`tpl_gather` (or `tpl_load` in `TPL_FD` mode) will obtain exactly one tpl image at +a time. Therefore tpl images can be used as an IPC message format without any +higher-level framing protocol. + +Data portability +^^^^^^^^^^^^^^^^ +A tpl image generated on one kind of CPU will generally be portable to other +CPU types when tpl is used properly. This may be a surprise considering that +tpl is a binary format. But tpl has been carefully designed to make this work. +Each <> has an associated explicitly-sized type. For +integer and floating point types, whose "endian" or byte-order convention varies +from one CPU to another, tpl automatically and transparently corrects the +endian order (if needed) during the unpacking process. Floating point numbers +present their own <>. 'No guarantees +are made with regard to floating point portability.' That said, because many +modern CPU's use IEEE 754 floating point representation, data is likely to be +portable among them. + +XML and Perl +~~~~~~~~~~~~ +'Note: The `tplxml` utility and the Perl module are currently unsupported in tpl 1.5.' + +XML +^^^ +While a tpl image is a binary entity, you can view any tpl image in XML format +using the included `tplxml` utility, located in the `lang/perl` directory. + + tplxml file.tpl > file.xml + tplxml file.xml > file.tpl + +The utility is bidirectional, as shown. The file extension is not important; +`tplxml` inspects its input to see if it's tpl or XML. You can also pipe data +into it instead of giving it a filename. The `tplxml` utility is slow. Its +purpose is two-fold: debugging (manual inspection of the data in a tpl), and +interoperability with XML-based programs. The resulting XML is often ten times +the size of the original binary tpl image. + +Perl +^^^^ +There is a Perl module in `lang/perl/Tpl.pm`. The link:perl.html[Perl API] +is convenient for writing Perl scripts that interoperate with C programs, and +need to pass structured data back and forth. It is written in pure Perl. + +Platforms +~~~~~~~~~ +The tpl software was developed for POSIX systems and has been tested on 32- and 64-bit +platforms including: + + * Linux + * Solaris + * Mac OS X + * OpenBSD + * Windows using Visual Studio 2008 or 2010, or Cygwin or MinGW + +BSD licensed +~~~~~~~~~~~~ +This software is made available under the +link:license.html[revised BSD license]. +It is free and open source. + +Download +~~~~~~~~ +Please follow the link to download on the +http://tpl.sourceforge.net[tpl website]. + +Getting help +~~~~~~~~~~~~ +If you need help, you are welcome to email the author at +mailto:thanson@users.sourceforge.net[]. + +Resources +~~~~~~~~~ +News:: + The author has a news feed for http://troydhanson.wordpress.com/feed/[software updates] image:img/rss.png[(RSS)]. + +Build and install +----------------- + +Tpl has no dependencies on libraries other than the system C library. You +can simply copy the tpl source into your project, so you have no dependencies. +Alternatively, you can build tpl as a library and link it to your program. + +As source +~~~~~~~~~ +The simplest way to use tpl is to copy the source files `tpl.h` and `tpl.c` +(from the `src/` directory) right into your project, and build them with the +rest of your source files. No special compiler flags are required. + +As a library +~~~~~~~~~~~~ +Alternatively, to build tpl as a library, from the top-level directory, run: + + ./configure + make + make install + +This installs a static library `libtpl.a` and a shared library (e.g., +`libtpl.so`), if your system supports them, in standard places. The installation +directory can be customized using `./configure --prefix=/some/directory`. Run +`configure --help` for further options. + +Test suite +^^^^^^^^^^ +You can compile and run the built-in test suite by running: + + cd tests/ + make + +On Windows +~~~~~~~~~~ + +DLL +^^^ +On the tpl home page, a Visual Studio 2008 solution package is available for +download. This zip file contains pre-built 32- and 64-bit versions of tpl as a +DLL. If you like, you can build the DLL yourself using VS2008 or VS2010 (the +free Express Edition is sufficient) by opening the solution file and choosing +Build Solution. + +Non-DLL usage +^^^^^^^^^^^^^ +Alternatively, tpl can be used directly (instead of as a DLL) by compiling +the tpl sources right into your program. To do this, add `tpl.c`, `tpl.h`, +`win/mman.h` and `win/mmap.c` to your program's source and header files and +add the preprocessor definition `TPL_NOLIB`. + +MinGW/Cygwin +^^^^^^^^^^^^ +Prior to tpl release 1.5, using tpl on Windows required building it with MinGW +or Cygwin. This is no longer necessary. If you want to build it that way anyway, +use the non-Windows (i.e. tar.bz2) tpl download and follow the "configure; make; +make install" approach. + +API concepts +------------ +To use tpl, you need to know the order in which to call the API functions, and +the background concepts of format string, arrays and index numbers. + +Order of functions +~~~~~~~~~~~~~~~~~~ +Creating a tpl is always the first step, and freeing it is the last step. In +between, you either pack and dump the tpl (if you're serializing data) or you +load a tpl image and unpack it (if you're deserializing data). + +.Order of usage +[width="50%",cols="^1,^5m,^5m",grid="none",options="header"] +|=============================================================================== +|Step | If you're serializing...| If you're deserializing... +| 1. | tpl_map() | tpl_map() +| 2. | tpl_pack() | tpl_load() +| 3. | tpl_dump() | tpl_unpack() +| 4. | tpl_free() | tpl_free() +|=============================================================================== + +[[format]] +Format string +~~~~~~~~~~~~~ +When a tpl is created using `tpl_map()`, its data type is expressed as a format +string. Each character in the format string has an associated argument of a +specific type. For example, this is how a format string and its arguments are +passed in to `tpl_map`: + + tpl_node *tn; + char c; + int i[10]; + tn = tpl_map("ci#", &c, i, 10); /* ci# is our format string */ + +[[types]] +.Supported format characters +[width="90%",grid="none",options="header",cols="5^m,20,20"] +|================================================================================ +|Type | Description | Required argument type +| j | 16-bit signed int | int16_t* or equivalent +| v | 16-bit unsigned int | uint16_t* or equivalent +| i | 32-bit signed int | int32_t* or equivalent +| u | 32-bit unsigned int | uint32_t* or equivalent +| I | 64-bit signed int | int64_t* or equivalent +| U | 64-bit unsigned int | uint64_t* or equivalent +| c | character (byte) | char* +| s | string | char** +| f | 64-bit double precision float | double* (varies by platform) +| # | array length; modifies preceding `iujvIUcsf` or `S(...)`| int +| B | binary buffer (arbitrary-length) | tpl_bin* +| S | structure (...) | struct * +| $ | nested structure (...) | none +| A | array (...) | none +|================================================================================ + +Explicit sizes +^^^^^^^^^^^^^^ +The sizes of data types such as `long` and `double` vary by platform. This must +be kept in mind because most tpl format characters require a pointer argument to +a specific-sized type, listed above. You can use explicit-sized types such as +`int32_t` (defined in `inttypes.h`) in your program if you find this helpful. + +[[trouble_with_double]] +The trouble with double ++++++++++++++++++++++++ +Unfortunately there are no standard explicit-sized floating-point types-- no +`float64_t`, for example. If you plan to serialize `double` on your platform +using tpl's `f` format character, first be sure that your `double` is 64 bits. +Second, if you plan to deserialize it on a different kind of CPU, be sure that +both CPU's use the same floating-point representation such as IEEE 754. + +[[arrays]] +Arrays +~~~~~~ +Arrays come in two kinds: *fixed-length* and *variable-length* arrays. +Intuitively, they can be thought of like conventional C arrays and linked lists. +In general, use fixed-length arrays if possible, and variable-length arrays +if necessary. The variable-length arrays support more complex data types, and +give or receive the elements to your program one by one. + +Fixed-length vs. Variable-length arrays +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Notation:: + Fixed-length arrays are denoted like `i#` (a simple type followed by one or + more `#` signs), but variable-length arrays are denoted like `A(i)`. +Element handling:: + All the elements of a fixed-length array are packed or unpacked at once. But + the elements of a variable-length array are packed or unpacked one by one. +Array length:: + The number of elements in a fixed-length array is specified before use-- + before any data is packed. But variable-length arrays do not have a fixed + element count. They can have any number of elements packed into them. When + unpacking a variable-length array, they are unpacked one by one until they + are exhausted. +Element types:: + Elements of fixed-length arrays can be the integer, byte, double, string + types or structures. (This excludes format characters `BA`). Fixed-length + arrays can also be multi-dimensional like `i##`. Variable-length arrays can + have simple or complex elements-- for example, an array of ints `A(i)`, an + array of int/double pairs `A(if)`, or even nested arrays like `A(A(if))`. + +Before explaining all the concepts, it's illustrative to see how both kinds of +arrays are used. Let's pack the integers 0 through 9 both ways. + +//|================================================================================ +//|Fixed-length array packing | Variable-length array packing +//|#include "tpl.h" | #include "tpl.h" +//|int main() { | int main() { +//| tpl_node *tn; | tpl_node *tn; +//| int x[] = {0,1,2,3,4,5,6,7,8,9}; | int x; +//| | +//| tn = tpl_map("i#", x, 10); | tn = tpl_map("A(i)", &x); +//| /* pack all 10 elements at once */ | /* pack one element at a time */ +//| tpl_pack(tn,0); | for(x = 0; x < 10; x++) tpl_pack(tn,1); +//| tpl_dump(tn, TPL_FILE, "/tmp/fixed.tpl");| tpl_dump(tn, TPL_FILE, "/tmp/variable.tpl"); +//| tpl_free(tn); | tpl_free(tn); +//|} | } +//|================================================================================ + +[[fixed_pack]] +.Packing 0-9 as a fixed-length array +------------------------------------------------------------------------------- +#include "tpl.h" +int main() { + tpl_node *tn; + int x[] = {0,1,2,3,4,5,6,7,8,9}; + + tn = tpl_map("i#", x, 10); + tpl_pack(tn,0); /* pack all 10 elements at once */ + tpl_dump(tn, TPL_FILE, "/tmp/fixed.tpl"); + tpl_free(tn); +} +------------------------------------------------------------------------------- + +Note that the length of the fixed-length array (10) was passed as an argument to +`tpl_map()`. The corresponding unpacking <> is listed +further below. Now let's see how we would pack 0-9 as a variable-length array: + +.Packing 0-9 as a variable-length array +------------------------------------------------------------------------------- +#include "tpl.h" +int main() { + tpl_node *tn; + int x; + + tn = tpl_map("A(i)", &x); + for(x = 0; x < 10; x++) tpl_pack(tn,1); /* pack one element at a time */ + tpl_dump(tn, TPL_FILE, "/tmp/variable.tpl"); + tpl_free(tn); +} +------------------------------------------------------------------------------- + +Notice how we called `tpl_pack` in a loop, once for each element 0-9. Again, +there is a corresponding unpacking <> shown later in the +guide. You might also notice that this time, we passed 1 as the final argument +to tpl_pack. This is an index number designating which variable-length array +we're packing. In this case, there is only one. + +[[index]] +Index numbers +^^^^^^^^^^^^^ +Index numbers identify a particular variable-length array in the format string. +Each `A(...)` in a format string has its own index number. The index numbers +are assigned left-to-right starting from 1. Examples: + + A(i) /* index number 1 */ + A(i)A(i) /* index numbers 1 and 2 */ + A(A(i)) /* index numbers 1 and 2 (order is independent of nesting) */ + +Special index number 0 +++++++++++++++++++++++ +The special index number 0 designates all the format characters that are not +inside an `A(...)`. Examples of what index 0 does (and does not) designate: + + S(ius) /* index 0 designates the whole thing */ + iA(c)u /* index 0 designates the i and the u */ + c#A(i)S(ci) /* index 0 designates the c# and the S(ci) */ + +An index number is passed to `tpl_pack` and `tpl_unpack` to specify which +variable-length array (or non-array, in the case of index number 0) to act upon. + +Integers +~~~~~~~~ +The array examples <> demonstrated how integers could be +packed. We'll show some further examples here of unpacking integers and dealing +with multi-dimensional arrays. The same program could be used to demonstrate +working with byte, 16-bit shorts, 32-bit or 64-bit signed and unsigned integers +with only a change to the data type and the format character. + +[[fixed_unpack]] +.Unpacking 0-9 from a fixed-length array +-------------------------------------------------------------------------------- +#include "tpl.h" +int main() { + tpl_node *tn; + int x[10]; + + tn = tpl_map("i#", x, 10); + tpl_load(tn, TPL_FILE, "/tmp/fixed.tpl"); + tpl_unpack(tn,0); /* unpack all 10 elements at once */ + tpl_free(tn); + /* now do something with x[0]...x[9].. (not shown */ +} +-------------------------------------------------------------------------------- + +For completeness, let's also see how to unpack a variable-length integer array. + +[[var_unpack]] +.Unpacking 0-9 from a variable-length array +------------------------------------------------------------------------------- +#include "tpl.h" +int main() { + tpl_node *tn; + int x; + + tn = tpl_map("A(i)", &x); + tpl_load(tn, TPL_FILE, "/tmp/variable.tpl"); + while (tpl_unpack(tn,1) > 0) printf("%d\n",x); /* unpack one by one */ + tpl_free(tn); +} +------------------------------------------------------------------------------- + +[[multidim_int]] +Multi-dimensional arrays +^^^^^^^^^^^^^^^^^^^^^^^^ +A multi-dimensional matrix of integers can be packed and unpacked the same way +as any fixed-length array. + + int xy[XDIM][YDIM]; + ... + tn = tpl_map("i##", xy, XDIM, YDIM); + tpl_pack(tn, 0); + +This single call to `tpl_pack` packs the entire matrix. + +Strings +~~~~~~~ +Tpl can serialize C strings. A different format is used for `char*` vs. `char[ ]` +as described below. Let's look at `char*` first: + +.Packing a string +------------------------------------------------------------------------------- + #include "tpl.h" + + int main() { + tpl_node *tn; + char *s = "hello, world!"; + tn = tpl_map("s", &s); + tpl_pack(tn,0); /* copies "hello, world!" into the tpl */ + tpl_dump(tn,TPL_FILE,"string.tpl"); + tpl_free(tn); + } +------------------------------------------------------------------------------- + +The `char*` must point to a null-terminated string or be a `NULL` pointer. + +When deserializing (unpacking) a C string, space for it will be allocated +automatically, but you are responsible for freeing it (unless it is `NULL`): + +.Unpacking a string +------------------------------------------------------------------------------- + #include "tpl.h" + + int main() { + tpl_node *tn; + char *s; + tn = tpl_map("s", &s); + tpl_load(tn,TPL_FILE,"string.tpl"); + tpl_unpack(tn,0); /* allocates space, points s to "hello, world!" */ + printf("unpacked %s\n", s); + free(s); /* our responsibility to free s */ + tpl_free(tn); + } +------------------------------------------------------------------------------- + +char* vs char[ ] +^^^^^^^^^^^^^^^^ +The `s` format character is only for use with `char*` types. In the example +above, `s` is a `char*`. If it had been a `char s[14]`, we would use the format +characters `c#` to pack or unpack it, as a fixed-length character array. (This +unpacks the characters "in-place", instead of into a dynamically allocated +buffer). Also, a fixed-length buffer described by `c#` need not be +null-terminated. + +Arrays of strings +^^^^^^^^^^^^^^^^^ +You can use fixed- or variable-length arrays of strings in tpl. An example of +packing a fixed-length two-dimensional array of strings is shown here. + + char *labels[2][3] = { {"one", "two", "three"}, + {"eins", "zwei", "drei" } }; + tpl_node *tn; + tn = tpl_map("s##", labels, 2, 3); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,filename); + tpl_free(tn); + +Later, when unpacking these strings, the programmer must remember to free them +one by one, after they are no longer needed. + + char *olabels[2][3]; + int i,j; + + tn = tpl_map("s##", olabels, 2, 3); + tpl_load(tn,TPL_FILE,filename); + tpl_unpack(tn,0); + tpl_free(tn); + + for(i=0;i<2;i++) { + for(j=0;j<3;j++) { + printf("%s\n", olabels[i][j]); + free(olabels[i][j]); + } + } + +Binary buffers +~~~~~~~~~~~~~~ +Packing an arbitrary-length binary buffer (tpl format character `B`) makes use +of the `tpl_bin` structure. You must declare this structure and populate it +with the address and length of the binary buffer to be packed. + +.Packing a binary buffer +------------------------------------------------------------------------------- + #include "tpl.h" + #include + + int main() { + tpl_node *tn; + tpl_bin tb; + + /* we'll use a timeval as our guinea pig */ + struct timeval tv; + gettimeofday(&tv,NULL); + + tn = tpl_map( "B", &tb ); + tb.sz = sizeof(struct timeval); /* size of buffer to pack */ + tb.addr = &tv; /* address of buffer to pack */ + tpl_pack( tn, 0 ); + tpl_dump(tn, TPL_FILE, "bin.tpl"); + tpl_free(tn); + } +------------------------------------------------------------------------------- + +When you unpack a binary buffer, tpl will automatically allocate it, and will +populate your `tpl_bin` structure with its address and length. You are +responsible for eventually freeing the buffer. + +.Unpacking a binary buffer +------------------------------------------------------------------------------- + #include "tpl.h" + + int main() { + tpl_node *tn; + tpl_bin tb; + + tn = tpl_map( "B", &tb ); + tpl_load( tn, TPL_FILE, "bin.tpl" ); + tpl_unpack( tn, 0 ); + tpl_free(tn); + + printf("binary buffer of length %d at address %p\n", tb.sz, tb.addr); + free(tb.addr); /* our responsibility to free it */ + } +------------------------------------------------------------------------------- + +Structures +~~~~~~~~~~ +You can use tpl to pack and unpack structures, and arrays of structures. + + struct ci { + char c; + int i; + }; + struct ci s = {'a', 1}; + + tn = tpl_map("S(ci)", &s); /* pass structure address */ + tpl_pack(tn, 0); + tpl_dump(tn, TPL_FILE, "struct.tpl"); + tpl_free(tn); + +As shown, omit the individual arguments for the format characters inside the +parenthesis. The exception is for fixed-length arrays; when `S(...)` contains a +`#` character, its length argument is required: `tpl_map("S(f#i)", &s, 10);` + +When using the `S(...)` format, the only characters allowed inside the +parentheses are `iujvcsfIU#$()`. + +Structure arrays +^^^^^^^^^^^^^^^^ +Arrays of structures are the same as simple arrays. Fixed- or variable- length +arrays are supported. + + struct ci sa[100], one; + + tn = tpl_map("S(ci)#", sa, 100); /* fixed-length array of 100 structures */ + tn = tpl_map("A(S(ci))", &one); /* variable-length array (one at a time)*/ + +The differences between fixed- and variable-length arrays are explained in the +<> section. + +Nested structures +^^^^^^^^^^^^^^^^^ +When dealing with nested structures, the outermost structure uses the `S` format +character, and the inner nested structures use the `$` format. Only the +'outermost' structure's address is given to `tpl_map`. + + struct inner_t { + char a; + } + + struct outer_t { + char b; + struct inner_t i; + } + + tpl_node *tn; + struct outer_t outer = {'b', {'a'}}; + + tn = tpl_map("S(c$(c))", &outer); + +Structures can nest to any level. Currently tpl does not support fixed-length +array suffixes on inner structures. However the outermost structure can have a +length suffix even if it contains some nested structures. + +Linked lists +~~~~~~~~~~~~ +While tpl has no specific data type for a linked list, the technique for +packing them is illustrated here. First describe your list element as a +format string and then surround it with `A(...)` to describe it as +variable-length array. Then, using a temporary variable, iterate over each +list element, copying it to the temporary variable and packing it. + + struct element { + char c; + int i; + struct element *next; + } + + struct element *list, *i, tmp; + tpl_node *tn; + + /* add some elements to list.. (not shown)*/ + + tn = tpl_map("A(ci)", &tmp); + for(i = list; i != NULL; i=i->next) { + tmp = *i; + tpl_pack(tn, 1); + } + tpl_dump(tn,TPL_FILE,"list.tpl"); + tpl_free(tn); + +Unpacking is similar. The `for` loop is just replaced with: + + while( tpl_unpack(tn,1) > 0) { + struct element *newelt = malloc(sizeof(struct element)); + *newelt = tmp; + add_to_list(list, newelt); + } + +As you can see, tpl does not reinstate the whole list at once-- just one +element at a time. You need to link the elements manually. A future release of +tpl may support 'pointer swizzling' to make this easier. + +API +--- + +[[tpl_map]] +tpl_map +~~~~~~~ +The only way to create a tpl is to call `tpl_map()`. The first argument is the +<>. This is followed by a list of arguments as required by +the particular characters in the format string. E.g, + + tpl_node *tn; + int i; + tn = tpl_map( "A(i)", &i ); + +The function creates a mapping between the items in the format string and the C +program variables whose addresses are given. Later, the C variables will be read +or written as the tpl is packed or unpacked. + +This function returns a `tpl_node*` on success, or `NULL` on failure. + +[[tpl_pack]] +tpl_pack +~~~~~~~~ +The function `tpl_pack()` packs data into a tpl. The arguments to +`tpl_pack()` are a `tpl_node*` and an <>. + + tn = tpl_map("A(i)A(c)", &i, &c); + for(i=0; i<10; i++) tpl_pack(tn, 1); /* pack 0-9 into index 1 */ + for(c='a; c<='z'; c++) tpl_pack(tn, 2); /* pack a-z into index 2 */ + +.Data is copied when packed +******************************************************************************** +Every call to `tpl_pack()` immediately 'copies' the data being packed. Thus +the program is free to immediately overwrite or re-use the packed variables. +******************************************************************************** + +Index number 0 +^^^^^^^^^^^^^^ +It is necessary to pack index number 0 only if the format string contains +characters that are not inside an `A(...)`, such as the `i` in the format string +`iA(c)`. + +Variable-length arrays +^^^^^^^^^^^^^^^^^^^^^^ + +Adding elements to an array ++++++++++++++++++++++++++++ +To add elements to a variable-length array, call `tpl_pack()` repeatedly. Each +call adds another element to the array. + +Zero-length arrays are ok ++++++++++++++++++++++++++ +It's perfectly acceptable to pack nothing into a variable-length array, +resulting in a zero-length array. + +[[nested_pack]] +Packing nested arrays ++++++++++++++++++++++ +In a format string containing a nested, variable-length array, such as +`A(A(s))`, the inner, child array should be packed prior to the parent array. + +When you pack a parent array, a "snapshot" of the current child array is placed +into the parent's new element. Packing a parent array also empties the child +array. This way, you can pack new data into the child, then pack the parent +again. This creates distinct parent elements which each contain distinct child +arrays. + +[TIP] +When dealing with nested arrays like `A(A(i))`, 'pack' them from the "inside +out" (child first), but 'unpack' them from the "outside in" (parent first). + +The example below creates a tpl having the format string `A(A(c))`. + +.Packing nested arrays +-------------------------------------------------------------------------------- +#include "tpl.h" + +int main() { + char c; + tpl_node *tn; + + tn = tpl_map("A(A(c))", &c); + + for(c='a'; c<'c'; c++) tpl_pack(tn,2); /* pack child (twice) */ + tpl_pack(tn, 1); /* pack parent */ + + for(c='1'; c<'4'; c++) tpl_pack(tn,2); /* pack child (three times) */ + tpl_pack(tn, 1); /* pack parent */ + + tpl_dump(tn, TPL_FILE, "test40.tpl"); + tpl_free(tn); +} +-------------------------------------------------------------------------------- + +This creates a nested array in which the parent has two elements: the first +element is the two-element nested array 'a', 'b'; and the second element is +the three-element nested array '1', '2', '3'. +The <> shows how this tpl is unpacked. + +[[tpl_dump]] +tpl_dump +~~~~~~~~ +After packing a tpl, `tpl_dump()` is used to write the tpl image to a file, +memory buffer or file descriptor. The corresponding modes are shown below. A +final mode is for querying the output size without actually performing the dump. + +[width="80%",options="header",cols="30^d,70m",grid="none"] +|================================================================================ +|Write to... |Usage +|file |tpl_dump(tn, TPL_FILE, "file.tpl" ); +|file descriptor |tpl_dump(tn, TPL_FD, 2); +|memory |tpl_dump(tn, TPL_MEM, &addr, &len ); +|caller's memory |tpl_dump(tn, TPL_MEM\|TPL_PREALLOCD, buf, sizeof(buf)); +|just get size |tpl_dump(tn, TPL_GETSIZE, &sz); +|================================================================================ + +The first argument is the `tpl_node*` and the second is one of these constants: + +`TPL_FILE`:: + Writes the tpl to a file whose name is given in the following argument. + The file is created with permissions 664 (`rw-rw-r--`) unless further + restricted by the process `umask`. +`TPL_FD`:: + Writes the tpl to the file descriptor given in the following argument. + The descriptor can be either blocking or non-blocking, but will busy-loop + if non-blocking and the contents cannot be written immediately. +`TPL_MEM`:: + Writes the tpl to a memory buffer. The following two arguments must be a + `void\*\*` and a `size_t*`. The function will allocate a buffer and store + its address and length into these locations. The caller is responsible to + `free()` the buffer when done using it. +`TPL_MEM|TPL_PREALLOCD`:: + Writes the tpl to a memory buffer that the caller has already allocated or + declared. The following two arguments must be a `void*` and a `size_t` + specifying the buffer address and size respectively. (If the buffer is of + insufficient size to receive the tpl dump, the function will return -1). + This mode can be useful in conjunction with `tpl_load` in `TPL_EXCESS_OK` + mode, as shown <> +`TPL_GETSIZE`:: + This special mode does not actually dump the tpl. Instead it places the size + that the dump 'would' require into the `uint32_t` pointed to by the + following argument. + +The return value is 0 on success, or -1 on error. + +The `tpl_dump()` function does not free the tpl. Use `tpl_free()` to release +the tpl's resources when done. + +[TIP] +.Back-to-back tpl images require no delimiter +If you want to store a series of tpl images, or transmit sequential tpl images +over a socket (perhaps as messages to another program), you can simply dump them +sequentially without needing to add any delimiter for the individual tpl images. +Tpl images are internally delimited, so `tpl_load` will read just one at a time +even if multiple images are contiguous. + +[[tpl_load]] +tpl_load +~~~~~~~~ +This API function reads a previously-dumped tpl image from a file, memory +buffer or file descriptor, and prepares it for subsequent unpacking. The format +string specified in the preceding call to `tpl_map()` will be cross-checked +for equality with the format string stored in the tpl image. + + tn = tpl_map( "A(i)", &i ); + tpl_load( tn, TPL_FILE, "demo.tpl" ); + +The first argument to `tpl_load()` is the `tpl_node*`. The second argument is +one of the constants: + +`TPL_FILE`:: + Loads the tpl from the file named in the following argument. It is also + possible to bitwise-OR this flag with `TPL_EXCESS_OK` as explained below. +`TPL_MEM`:: + Loads the tpl from a memory buffer. The following two arguments must be a + `void*` and a `size_t`, specifying the buffer address and size, + respectively. The caller must not free the memory buffer until after + freeing the tpl with `tpl_free()`. (If the caller wishes to hand over + responsibility for freeing the memory buffer, so that it's automatically + freed along with the tpl when `tpl_free()` is called, the constant + `TPL_UFREE` may be bitwise-OR'd with `TPL_MEM` to achieve this). + Furthermore, `TPL_MEM` may be bitwise-OR'd with `TPL_EXCESS_OK`, explained + below. +`TPL_FD`:: + Loads the tpl from the file descriptor given in the following argument. + The descriptor is read until one complete tpl image is loaded; no bytes + past the end of the tpl image will be read. The descriptor can be either + blocking or non-blocking, but will busy-loop if non-blocking and the + contents cannot be read immediately. + +During loading, the tpl image will be extensively checked for internal validity. + +This function returns 0 on success or -1 on error. + +[[excess_ok]] +`TPL_EXCESS_OK` +^^^^^^^^^^^^^^^ +When reading a tpl image from a file or memory (but not from a file descriptor) +the size of the file or memory buffer must exactly equal that of the tpl image +stored therein. In other words, no excess trailing data beyond the tpl image is +permitted. The bit flag `TPL_EXCESS_OK` can be OR'd with `TPL_MEM` or `TPL_FILE` +to relax this requirement. + +A situation where this flag can be useful is in conjunction with `tpl_dump` in +the `TPL_MEM|TPL_PREALLOCD` mode. In this example, the program does not concern +itself with the actual tpl size as long as `LEN` is sufficiently large. + + char buf[LEN]; /* will store and read tpl images here */ + ... + tpl_dump(tn, TPL_MEM|TPL_PREALLOCD, buf, LEN); + ... + tpl_load(tn, TPL_MEM|TPL_EXCESS_OK, buf, LEN); + + + + +[[tpl_unpack]] +tpl_unpack +~~~~~~~~~~ +The `tpl_unpack()` function unpacks data from the tpl. When data is unpacked, +it is copied to the C program variables originally specified in `tpl_map()`. +The first argument to `tpl_unpack` is the `tpl_node*` for the tpl and the +second argument is an <>. + + tn = tpl_map( "A(i)A(c)", &i, &c ); + tpl_load( tn, TPL_FILE, "nested.tpl" ); + while (tpl_unpack( tn, 1) > 0) printf("i is %d\n", i); /* unpack index 1 */ + while (tpl_unpack( tn, 2) > 0) printf("c is %c\n", c); /* unpack index 2 */ + +Index number 0 +^^^^^^^^^^^^^^ +It is necessary to unpack index number 0 only if the format string contains +characters that are not inside an `A(...)`, such as the `i` in the format string +`iA(c)`. + +Variable-length arrays +^^^^^^^^^^^^^^^^^^^^^^ + +Unpacking elements from an array +++++++++++++++++++++++++++++++++ +For variable-length arrays, each call to `tpl_unpack()` unpacks another element. +The return value can be used to tell when you're done: if it's positive, an +element was unpacked; if it's 0, nothing was unpacked because there are no more +elements. A negative retun value indicates an error (e.g. invalid index number). +In this document, we usually unpack variable-length arrays using a `while` loop: + + while( tpl_unpack( tn, 1 ) > 0 ) { + /* got another element */ + } + +Array length +++++++++++++ +When unpacking a variable-length array, it may be convenient to know ahead of +time how many elements will need to be unpacked. You can use `tpl_Alen()` to +get this number. + +[[nested_unpack]] +Unpacking nested arrays ++++++++++++++++++++++++ +In a format string containing a nested variable-length array such as `A(A(s))`, +unpack the outer, parent array before unpacking the child array. + +When you unpack a parent array, it prepares the child array for unpacking. +After unpacking the elements of the child array, the program can repeat the +process by unpacking another parent element, then the child elements, and so on. +The example below unpacks a tpl having the format string `A(A(c))`. + +.Unpacking nested arrays +-------------------------------------------------------------------------------- +#include "tpl.h" +#include + +int main() { + char c; + tpl_node *tn; + + tn = tpl_map("A(A(c))", &c); + + tpl_load(tn, TPL_FILE, "test40.tpl"); + while (tpl_unpack(tn,1) > 0) { + while (tpl_unpack(tn,2) > 0) printf("%c ",c); + printf("\n"); + } + tpl_free(tn); +} +-------------------------------------------------------------------------------- + +The file `test40.tpl` is from the <>. When +run, this program prints: + + a b + 1 2 3 + +[[tpl_free]] +tpl_free +~~~~~~~~ +The final step for any tpl is to release it using `tpl_free()`. Its only +argument is the the `tpl_node*` to free. + + tpl_free( tn ); + +This function does not return a value (it is `void`). + +[[tpl_alen]] +tpl_Alen +~~~~~~~~ +This function takes a `tpl_node*` and an index number and returns an `int` +specifying the number of elements in the variable-length array. + + num_elements = tpl_Alen(tn, index); + +This is mainly useful for programs that unpack data and need to know ahead of +time the number of elements that will need to be unpacked. (It returns the +current number of elements; it will decrease as elements are unpacked). + +[[tpl_peek]] +tpl_peek +~~~~~~~~ +This function peeks into a file or a memory buffer containing a tpl image and +and returns a copy of its format string. It can also peek at the lengths of +any fixed-length arrays in the format string, or it can also peek into the data +stored in the tpl. + +Format peek +^^^^^^^^^^^ +The format string can be obtained +like this: + + fmt = tpl_peek(TPL_FILE, "file.tpl"); + fmt = tpl_peek(TPL_MEM, addr, sz); + +On success, a copy of the format string is returned. The caller must eventually +free it. On error, such as a non-existent file, or an invalid tpl image, it +returns `NULL`. + +Array length peek +^^^^^^^^^^^^^^^^^ +The lengths of all fixed-length arrays in the format string can be queried using +the `TPL_FXLENS` mode. It provides the number of such fixed-length arrays and +their lengths. If the former is non-zero, the caller must free the latter array +when finished. The format string itself must also be freed. + + uint32_t num_fxlens, *fxlens, j; + fmt = tpl_peek(TPL_FILE|TPL_FXLENS, filename, &num_fxlens, &fxlens); + if (fmt) { + printf("format %s, num_fxlens %u\n", fmt, num_fxlens); + for(j=0; j 0) free(fxlens); + free(fmt); + } + +The `TPL_FXLENS` mode is mutually exclusive with `TPL_DATAPEEK`. + + +Data peek +^^^^^^^^^ +To peek into the data, additional arguments are used. This is a quick +alternative to mapping, loading and unpacking the tpl, but peeking is limited +to the data in index 0. In other words, no peeking into `A(...)` types. +Suppose the tpl image in `file.tpl` has the format string `siA(i)`. Then the +index 0 format characters are `si`. This is how to peek at their content: + + char *s; + int i; + fmt = tpl_peek(TPL_FILE | TPL_DATAPEEK, "file.tpl", "si", &s, &i); + +Now `s`, `i`, and `fmt` have been populated with data. The caller must +eventually free `fmt` and `s` because they are allocated strings. +Of course, it works with `TPL_MEM` as well as `TPL_FILE`. Notice that +`TPL_DATAPEEK` was OR'd with the mode. You can also specify 'any leading +portion' of the index 0 format if you don't want to peek at the whole thing: + + fmt = tpl_peek(TPL_FILE | TPL_DATAPEEK, "file.tpl", "s", &s); + +The `TPL_DATAPEEK` mode is mutually exclusive with `TPL_FXLENS`. + +Structure peek +++++++++++++++ +Lastly you can peek into `S(...)` structures in index 0, but omit the +surrounding `S(...)` in the format, and specify an argument to receive +each structure member individually. You can specify any leading portion +of the structure format. For example if `struct.tpl` has the format string +`S(si)`, you can peek at its data in these ways: + + fmt = tpl_peek(TPL_FILE | TPL_DATAPEEK, "struct.tpl", "s", &s); + fmt = tpl_peek(TPL_FILE | TPL_DATAPEEK, "struct.tpl", "si", &s, &i); + +[[tpl_jot]] +tpl_jot +~~~~~~~ +This is a quick shortcut for generating a tpl. It can be used instead of the +usual "map, pack, dump, and free" lifecycle. With `tpl_jot` all those steps are +handled for you. It only works for simple formats-- namely, those without +`A(...)` in their format string. Here is how it is used: + + char *hello = "hello", *world = "world"; + tpl_jot( TPL_FILE, "file.tpl", "ss", &hello, &world); + +It supports the three standard modes, `TPL_FILE`, `TPL_FD` and `TPL_MEM`. +It returns -1 on failure (such as a bad format string or error writing the +file) or 0 on success. + +[[hooks]] +tpl_hook +~~~~~~~~ +Most users will just leave these hooks at their default values. You can change +these hook values if you want to modify tpl's internal memory management and +error reporting behavior. + +A global structure called `tpl_hook` encapsulates the hooks. A program can +reconfigure any hook by specifying an alternative function whose prototype +matches the default. For example: + + #include "tpl.h" + extern tpl_hook_t tpl_hook; + + int main() { + tpl_hook.oops = printf; + ... + } + +.Configurable hooks +[width="90%",options="header",cols="m,d,m",grid="none"] +|================================================================================ +|Hook |Description | Default +|tpl_hook.oops |log error messages | tpl_oops +|tpl_hook.malloc |allocate memory | malloc +|tpl_hook.realloc |reallocate memory | realloc +|tpl_hook.free |free memory | free +|tpl_hook.fatal |log fatal message and exit | tpl_fatal +|tpl_hook.gather_max |tpl_gather max image size | 0 (unlimited) +|================================================================================ + +The oops hook +^^^^^^^^^^^^^ +The `oops` has the same prototype as `printf`. The built-in default oops +handling function writes the error message to `stderr`. + +The fatal hook +^^^^^^^^^^^^^^ +The fatal hook is invoked when a tpl function cannot continue because of an out- +of-memory condition or some other usage violation or inconsistency. It has this +prototype: + + void fatal_fcn(char *fmt, ...); + +The `fatal` hook must not return. It must either exit, 'or' if the program needs +to handle the failure and keep executing, `setjmp` and `longjmp` can be used. +The default behavior is to `exit(-1)`. + +.Using longjmp in a fatal error handler +-------------------------------------------------------------------------------- +#include +#include +#include +#include "tpl.h" + +jmp_buf env; +extern tpl_hook_t tpl_hook; + +void catch_fatal(char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + longjmp(env,-1); /* return to setjmp point */ +} + +int main() { + int err; + tpl_node *tn; + tpl_hook.fatal = catch_fatal; /* install fatal handler */ + + err = setjmp(env); /* on error, control will return here */ + if (err) { + printf("caught error!\n"); + return -1; + } + + tn = tpl_map("@"); /* generate a fatal error */ + printf("program ending, without error\n"); + return 0; +} +-------------------------------------------------------------------------------- + +This example is included in `tests/test123.c`. When run, this program prints: + + unsupported option @ + failed to parse @ + caught error! + + +tpl_gather +~~~~~~~~~~ + +.Most programs don't need this +******************************************************************************** +Normally, `tpl_load()` is used to read a tpl image having an expected format +string. A more generic operation is to acquire a tpl image whose format string is +unknown. E.g., a generic message-receiving function might gather tpl images of +varying format and route them to their final destination. This is the purpose of +`tpl_gather`. It produces a memory buffer containing one tpl image. If there +are multiple contiguous images in the input, it gathers exactly one image at a +time. +******************************************************************************** + +The prototype for this function is: + + int tpl_gather( int mode, ...); + +The `mode` argument is one of three constants listed below, which must be +followed by the mode-specific required arguments: + + TPL_GATHER_BLOCKING, int fd, void **img, size_t *sz + TPL_GATHER_NONBLOCKING, int fd, tpl_gather_t **gs, tpl_gather_cb *cb, void *data + TPL_GATHER_MEM, void *addr, size_t sz, tpl_gather_t **gs, tpl_gather_cb *cb, void *data + +[NOTE] +.`tpl_hook.gather_max` +All modes honor `tpl_hook.gather_max`, specifying the maximum byte size for a +tpl image to be gathered (the default is unlimited, signified by 0). If a source +attempts to send a tpl image larger than this maximum, whatever partial image +has been read will be discarded, and no further reading will take place; in this +case `tpl_gather` will return a negative (error) value to inform the caller that +it should stop gathering from this source, and close the originating file +descriptor if there is one. (The whole idea is to prevent untrusted sources from +sending extremely large tpl images which would consume too much memory.) + + +`TPL_GATHER_BLOCKING` +^^^^^^^^^^^^^^^^^^^ +In this mode, `tpl_gather` blocks while reading file descriptor `fd` until one +complete tpl image is read. No bytes past the end of the tpl image will be read. +The address of the buffer containing the image is returned in `img` and its size +is placed in `sz`. The caller is responsible for eventually freeing the buffer. +The function returns 1 on success, 0 on end-of-file, or a negative number on +error. + +`TPL_GATHER_NONBLOCKING` +^^^^^^^^^^^^^^^^^^^^^^ +This mode is for non-blocking, event-driven programs that implement their +own file descriptor readability testing using `select()` or the like. In this +mode, tpl images are gathered in chunks as data becomes readable. Whenever a +full tpl image has been gathered, it invokes a caller-specified callback to do +something with the image. The arguments are the file descriptor `fd` which the +caller has determined to be readable and which must be in non-blocking mode, a +pointer to a file-descriptor-specific handle which the caller has declared +(explained below); a callback to invoke when a tpl image has been read; and an +opaque pointer that will passed to the callback. + +For each file descriptor on which `tpl_gather` will be used, the caller must +declare a `tpl_gather_t*` and initialize it to `NULL`. Thereafter it will be +used internally by `tpl_gather` whenever data is readable on the descriptor. + +The callback will only be invoked whenever `tpl_gather()` has accumulated one +complete tpl image. It must have this prototype: + + int (tpl_gather_cb)(void *img, size_t sz, void *data); + +The callback can do anything with the tpl image but it must not free it. It can +be copied if it needs to survive past the callback's return. The callback should +return 0 under normal circumstances, or a negative number to abort; that is, +returning a negative number causes `tpl_gather` itself to discard any remaining +full or partial tpl images that have been read, and to return a negative number +(-4 in particular) to signal its caller to close the file descriptor. + +The return value of `tpl_gather()` is negative if an error occured or 0 if a +normal EOF was encountered-- both cases require that the caller close the file +descriptor (and stop monitoring it for readability, obviously). If the return +value is positive, the function succeeded in gathering whatever data was +currently readable, which may have been a partial tpl image, or one or more +complete images. + +Typical Usage ++++++++++++++ +The program will have established a file descriptor in non-blocking mode and +be monitoring it for readability, using `select()`. Whenever it's readable, the +program calls `tpl_gather()`. In skeletal terms: + + tpl_gather_t *gt=NULL; + int rc; + + void fd_is_readable(int fd) { + rc = tpl_gather( TPL_GATHER_NONBLOCKING, fd, >, callback, NULL ); + if (rc <= 0) { + close(fd); /* got eof or fatal */ + stop_watching_fd(fd); + } + } + + int callback( void *img, size_t sz, void *data ) { + printf("got a tpl image\n"); /* do something with img. do not free it. */ + return 0; /* normal (no error) */ + } + +`TPL_GATHER_MEM` +^^^^^^^^^^^^^^ +This mode is identical to `TPL_GATHER_NONBLOCKING` except that it gathers from a +memory buffer instead of from a file descriptor. In other words, if some other +layer of code-- say, a decryption function (that is decrypting fixed-size +blocks) produces tpl fragments one-by-one, this mode can be used to reconstitute +the tpl images and invoke the callback for each one. Its parameters are the same +as for the `TPL_GATHER_NONBLOCKING` mode except that instead of a file +descriptor, it takes a buffer address and size. The return values are also the +same as for `TPL_GATHER_NONBLOCKING` noting of course there is no file +descriptor to close on a non-positive return value. + + +// vim: set tw=80 wm=2 syntax=asciidoc: + diff --git a/libs/libtpl-1.5/lang/perl/Tpl.pm b/libs/libtpl-1.5/lang/perl/Tpl.pm new file mode 100755 index 0000000000..b6c41041a1 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/Tpl.pm @@ -0,0 +1,475 @@ +package Tpl; + +# Copyright (c) 2005-2007, Troy Hanson http://tpl.sourceforge.net +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use strict; +use warnings; +use Config; # to get the size of "double" on this platform + +use bytes; # always use byte (not unicode char) offsets w/tpl images + +our $VERSION = 1.1; + +# tpl object is a reference to a hash with these keys: +# +# A(0): +# ... : +# A(n): +# +# where each A(i) refers to an A node, except A(0) is the root node. +# +# For each hash key (A node or root node), the value of that key is +# a list reference. The members are of the list are the node's children. +# They're represented as "Ai" (for A nodes) where i is a positive integer; +# for non-A nodes the representation is [type,addr] e.g. [ "i", \$some_integer] +# +# For example, +# Tpl->map("iA(ib)", \$x, \$y, \$z); +# returns a tpl object which is a reference to a hash with these keys/values: +# +# $self->{A0} = [ [ "i", \$x ], "A1" ]; +# $self->{A1} = [ [ "i", \$y ], [ "b", \$z ] ]; +# +# Now if A1 (that is, the "A(ib)" node) is packed, the tpl object acquires +# another hash key/value: +# $self->{P1} = [ $binary_int, $binary_byte ]; +# and repeated calls to pack A1 append further $binary elements. +# +sub tpl_map { + my $invocant = shift; + my $class = ref($invocant) || $invocant; + my $fmt = shift; + my @astack = (0); # stack of current A node's lineage in tpl tree + my $a_count=0; # running count of A's, thus an index of them + my $self = {}; # populate below + my ($lparen_level,$expect_lparen,$in_structure)=(0,0,0); + for (my $i=0; $i < length $fmt; $i++) { + my $c = substr($fmt,$i,1); + if ($c eq 'A') { + $a_count++; + push @{ $self->{"A" . $astack[-1]} }, "A$a_count"; + push @astack, $a_count; + $expect_lparen=1; + } elsif ($c eq '(') { + die "invalid format $fmt" unless $expect_lparen; + $expect_lparen=0; + $lparen_level++; + } elsif ($c eq ')') { + $lparen_level--; + die "invalid format $fmt" if $lparen_level < 0; + die "invalid format $fmt" if substr($fmt,$i-1,1) eq '('; + if ($in_structure && ($in_structure-1 == $lparen_level)) { + $in_structure=0; + } else { + pop @astack; # rparen ends A() type, not S() type + } + } elsif ($c eq 'S') { + # in perl we just parse and ignore the S() construct + $expect_lparen=1; + $in_structure=1+$lparen_level; # so we can tell where S fmt ends + } elsif ($c =~ /^(i|u|B|s|c|f|I|U)$/) { + die "invalid format $fmt" if $expect_lparen; + my $r = shift; + die "no reference for $c (position $i of $fmt)" unless ref($r); + if (($c eq "f") and ($Config{doublesize} != 8)) { + die "double not 8 bytes on this platform"; + } + if (($c =~ /(U|I)/) and not defined ($Config{use64bitint})) { + die "Tpl.pm: this 32-bit Perl can't pack/unpack 64-bit I/U integers\n"; + } + push @{ $self->{"A" . $astack[-1]} }, [ $c , $r ]; + } elsif ($c eq "#") { + # test for previous iucfIU + die "unallowed length modifer" unless $self->{"A" . $astack[-1]}->[-1]->[0] =~ /^(i|u|c|I|U|f)$/; + my $n = shift; + die "non-numeric # length modifer" unless $n =~ /^\d+$/; + push @{ $self->{"A" . $astack[-1]}->[-1] }, $n; + push @{ $self->{"#"}}, $n; # master array of octothorpe lengths + } else { + die "invalid character $c in format $fmt"; + } + } + die "invalid format $fmt" if $lparen_level != 0; + $self->{fmt} = $fmt; + bless $self; + return $self; +} + +sub tpl_format { + my $self = shift; + return $self->{fmt}; +} + +sub tpl_pack { + my $self = shift; + my $i = shift; + die "invalid index" unless defined $self->{"A$i"}; + die "tpl for unpacking only" if defined $self->{"loaded"}; + $self->{"packed"}++; + $self->{"P$i"} = undef if $i == 0; # node 0 doesn't accumulate + my @bb; + foreach my $node (@{ $self->{"A$i"} }) { + if (ref($node)) { + my ($type,$addr,$fxlen) = @{ $node }; + if (defined $fxlen) { # octothorpic array + push @bb, CORE::pack("l$fxlen",@$addr) if $type eq "i"; # int + push @bb, CORE::pack("L$fxlen",@$addr) if $type eq "u"; # uint + push @bb, CORE::pack("C$fxlen",@$addr) if $type eq "c"; # byte + push @bb, CORE::pack("d$fxlen",@$addr) if $type eq "f"; # double + push @bb, CORE::pack("q$fxlen",@$addr) if $type eq "I"; # int64 + push @bb, CORE::pack("Q$fxlen",@$addr) if $type eq "U"; # uint64 + } else { + # non-octothorpic singleton + push @bb, CORE::pack("l",$$addr) if $type eq "i"; # int + push @bb, CORE::pack("L",$$addr) if $type eq "u"; # uint + push @bb, CORE::pack("C",$$addr) if $type eq "c"; # byte + push @bb, CORE::pack("d",$$addr) if $type eq "f"; # double (8 byte) + push @bb, CORE::pack("q",$$addr) if $type eq "I"; # int64 + push @bb, CORE::pack("Q",$$addr) if $type eq "U"; # uint64 + if ($type =~ /^(B|s)$/) { # string/binary + push @bb, CORE::pack("L", length($$addr)); + push @bb, CORE::pack("a*", $$addr); + } + } + } elsif ($node =~ /^A(\d+)$/) { + # encode array length (int) and the array data into one scalar + my $alen = pack("l", scalar @{ $self->{"P$1"} or [] }); + my $abod = (join "", @{ $self->{"P$1"} or [] }); + push @bb, $alen . $abod; + $self->{"P$1"} = undef; + } else { + die "internal error; invalid node symbol $node"; + } + } + push @{ $self->{"P$i"} }, (join "", @bb); +} + +sub big_endian { + return (CORE::unpack("C", CORE::pack("L",1)) == 1) ? 0 : 1; +} + +sub tpl_dump { + my $self = shift; + my $filename = shift; + + $self->tpl_pack(0) if not defined $self->{"P0"}; + my $format = $self->tpl_format; + my $octothorpe_lens = CORE::pack("L*", @{ $self->{"#"} or [] }); + my $data = (join "", @{ $self->{"P0"} }); + my $ov_len = length($format) + 1 + length($octothorpe_lens) + length($data) + 8; + my $flags = big_endian() ? 1 : 0; + my $preamble = CORE::pack("CLZ*", $flags, $ov_len, $format); + my $tpl = "tpl" . $preamble . $octothorpe_lens . $data; + return $tpl unless $filename; + + # here for file output + open TPL, ">$filename" or die "can't open $filename: $!"; + print TPL $tpl; + close TPL; +} + +sub tpl_peek { + my $invocant = shift; + my $class = ref($invocant) || $invocant; + my $tplhandle = shift; + my $tpl; + + if (ref($tplhandle)) { + $tpl = $$tplhandle; + } else { + open TPL, "<$tplhandle" or die "can't open $tplhandle: $!"; + undef $/; # slurp + $tpl = ; + close TPL; + } + die "invalid tpl file" unless ($tpl =~ /^tpl/); + return (unpack("Z*", substr($tpl,8))); +} + +sub tpl_load { + my $self = shift; + my $tplhandle = shift; + + die "tpl for packing only" if $self->{"packed"}; + die "tpl reloading not supported" if $self->{"loaded"}; + + # read tpl image from file or was it passed directly via ref? + my $tpl; + if (ref($tplhandle)) { + $tpl = $$tplhandle; + } else { + open TPL, "<$tplhandle" or die "can't open $tplhandle: $!"; + undef $/; # slurp + $tpl = ; + close TPL; + } + + $self->{"TI"} = $tpl; + $self->{"TL"} = length $tpl; + # verify preamble + die "invalid image -1" unless length($tpl) >= 9; + die "invalid image -2" unless $tpl =~ /^tpl/; + my $flags = CORE::unpack("C", substr($tpl,3,1)); + $self->{"xendian"} = 1 if (big_endian() != ($flags & 1)); + $self->{"UF"} = ($flags & 1) ? "N" : "V"; + my $ov_len = CORE::unpack($self->{"UF"}, substr($tpl,4,4)); + die "invalid image -3" unless $ov_len == length($tpl); + my $format = CORE::unpack("Z*", substr($tpl,8)); + die "format mismatch" unless $format eq $self->tpl_format(); + my @octothorpe_lens = @{ $self->{"#"} or [] }; + my $ol = 8 + length($format) + 1; # start of octothorpe lengths + for (my $i=0; $i < (scalar @octothorpe_lens); $i++) { + my $len = CORE::unpack($self->{"UF"}, substr($tpl,$ol,4)); + my $olen = $octothorpe_lens[$i]; + die "fixed-length array size mismatch" unless $olen == $len; + $ol += 4; + } + my $dv = $ol; # start of packed data + my $len = $self->serlen("A0",$dv); + die "invalid image -4" if $len == -1; + die "invalid image -5" if (length($tpl) != $len + $dv); + $self->{"C0"} = $dv; + $self->{"loaded"} = 1; + $self->unpackA0; # prepare root child nodes for use +} + +# byte reverse a word (any length) +sub reversi { + my $word = shift; + my @w = split //, $word; + my $r = join "", (reverse @w); + return $r; +} + +# +# while unpacking, the object has these keys in its hash: +# C0 +# C1 +# ... +# C +# These are indices (into the tpl image $self->{"TI"}) from which node n +# is being unpacked. I.e. as array elements of node n are unpacked, C +# advances through the tpl image. +# +# Similarly, elements +# N1 +# N2 +# ... +# N +# refer to the remaining array count for node n. +# +sub tpl_unpack { + my $self = shift; + my $n = shift; + my $ax = "A$n"; + my $cx = "C$n"; + my $nx = "N$n"; + my $rc; + + die "tpl for packing only" if $self->{"packed"}; + die "tpl not loaded" unless $self->{"loaded"}; + + # decrement count for non root array nodes + if ($n > 0) { + return 0 if $self->{$nx} <= 0; + $rc = $self->{$nx}--; + } + + for my $c (@{ $self->{$ax} }) { + if (ref($c)) { + my ($type,$addr,$fxlen) = @$c; + if (defined $fxlen) { # octothorpic unpack + @{ $addr } = (); # empty existing list before pushing elements + for(my $i=0; $i < $fxlen; $i++) { + if ($type eq "u") { # uint + push @{ $addr }, CORE::unpack($self->{"UF"}, + substr($self->{"TI"},$self->{$cx},4)); + $self->{$cx} += 4; + } elsif ($type eq "i") { #int (see note below re:signed int) + my $intbytes = substr($self->{"TI"},$self->{$cx},4); + $intbytes = reversi($intbytes) if $self->{"xendian"}; + push @{ $addr }, CORE::unpack("l", $intbytes); + $self->{$cx} += 4; + } elsif ($type eq "c") { # byte + push @{ $addr }, CORE::unpack("C", + substr($self->{"TI"},$self->{$cx},1)); + $self->{$cx} += 1; + } elsif ($type eq "f") { # double + my $double_bytes = substr($self->{"TI"},$self->{$cx},8); + $double_bytes = reversi($double_bytes) if $self->{"xendian"}; + push @{ $addr }, CORE::unpack("d", $double_bytes ); + $self->{$cx} += 8; + } elsif ($type eq "I") { #int64 + my $intbytes = substr($self->{"TI"},$self->{$cx},8); + $intbytes = reversi($intbytes) if $self->{"xendian"}; + push @{ $addr }, CORE::unpack("q", $intbytes); + $self->{$cx} += 8; + } elsif ($type eq "U") { #uint64 + my $intbytes = substr($self->{"TI"},$self->{$cx},8); + $intbytes = reversi($intbytes) if $self->{"xendian"}; + push @{ $addr }, CORE::unpack("Q", $intbytes); + $self->{$cx} += 8; + } + } + } else { + # non-octothorpe (singleton) + if ($type eq "u") { # uint + ${$addr} = CORE::unpack($self->{"UF"}, + substr($self->{"TI"},$self->{$cx},4)); + $self->{$cx} += 4; + } elsif ($type eq "i") { # int + # while perl's N or V conversions unpack an unsigned + # long from either big or little endian format + # respectively, when it comes to *signed* int, perl + # only has 'l' (which assumes native endianness). + # So we have to manually reverse the bytes in a + # cross-endian 'int' unpacking scenario. + my $intbytes = substr($self->{"TI"},$self->{$cx},4); + $intbytes = reversi($intbytes) if $self->{"xendian"}; + ${$addr} = CORE::unpack("l", $intbytes); + $self->{$cx} += 4; + } elsif ($type eq 'c') { # byte + ${$c->[1]} = CORE::unpack("C", + substr($self->{"TI"},$self->{$cx},1)); + $self->{$cx} += 1; + } elsif ($type eq 'f') { # double + ${$addr} = CORE::unpack("d", + substr($self->{"TI"},$self->{$cx},8)); + $self->{$cx} += 8; + } elsif ($type =~ /^(B|s)$/) { # string/binary + my $slen = CORE::unpack($self->{"UF"}, + substr($self->{"TI"},$self->{$cx},4)); + $self->{$cx} += 4; + ${$addr} = CORE::unpack("a$slen", + substr($self->{"TI"},$self->{$cx},$slen)); + $self->{$cx} += $slen; + } elsif ($type eq "I") { # int64 + my $intbytes = substr($self->{"TI"},$self->{$cx},8); + $intbytes = reversi($intbytes) if $self->{"xendian"}; + ${$addr} = CORE::unpack("q", $intbytes); + $self->{$cx} += 8; + } elsif ($type eq "U") { # uint64 + my $intbytes = substr($self->{"TI"},$self->{$cx},8); + $intbytes = reversi($intbytes) if $self->{"xendian"}; + ${$addr} = CORE::unpack("Q", $intbytes); + $self->{$cx} += 8; + } else { die "internal error"; } + } + } elsif ($c =~ /^A(\d+)$/) { + my $alen = $self->serlen($c,$self->{$cx}); + $self->{"N$1"} = CORE::unpack($self->{"UF"}, + substr($self->{"TI"},$self->{$cx},4)); # get array count + $self->{"C$1"} = $self->{$cx} + 4; # set array node's data start + $self->{$cx} += $alen; # step over array node's data + } else { die "internal error"; } + } + + return $rc; +} + +# specialized function to prepare root's child A nodes for initial use +sub unpackA0 { + my $self = shift; + my $ax = "A0"; + my $cx = "C0"; + my $c0 = $self->{$cx}; + + for my $c (@{ $self->{$ax} }) { + next if ref($c); # skip non-A nodes + if ($c =~ /^A(\d+)$/) { + my $alen = $self->serlen($c,$c0); + $self->{"N$1"} = CORE::unpack($self->{"UF"}, + substr($self->{"TI"},$c0,4)); # get array count + $self->{"C$1"} = $c0 + 4; # set array node's data start + $c0 += $alen; # step over array node's data + } else { die "internal error"; } + } +} + +# ascertain serialized length of given node by walking +sub serlen { + my $self = shift; + my $ax = shift; + my $dv = shift; + + my $len = 0; + + my $num; + if ($ax eq "A0") { + $num = 1; + } else { + return -1 unless $self->{"TL"} >= $dv + 4; + $num = CORE::unpack($self->{"UF"},substr($self->{"TI"},$dv,4)); + $dv += 4; + $len += 4; + } + + while ($num-- > 0) { + for my $c (@{ $self->{$ax} }) { + if (ref($c)) { + my $n = 1; + $n = $c->[2] if (@$c > 2); # octothorpic array length + if ($c->[0] =~ /^(i|u)$/) { # int/uint + return -1 unless $self->{"TL"} >= $dv + 4*$n; + $len += 4*$n; + $dv += 4*$n; + } elsif ($c->[0] eq "c") { # byte + return -1 unless $self->{"TL"} >= $dv + 1*$n; + $len += 1*$n; + $dv += 1*$n; + } elsif ($c->[0] eq "f") { # double + return -1 unless $self->{"TL"} >= $dv + 8*$n; + $len += 8*$n; + $dv += 8*$n; + } elsif ($c->[0] =~ /(I|U)/) { # int64/uint64 + return -1 unless $self->{"TL"} >= $dv + 8*$n; + $len += 8*$n; + $dv += 8*$n; + } elsif ($c->[0] =~ /^(B|s)$/) { # string/binary + return -1 unless $self->{"TL"} >= $dv + 4; + my $slen = CORE::unpack($self->{"UF"}, + substr($self->{"TI"},$dv,4)); + $len += 4; + $dv += 4; + return -1 unless $self->{"TL"} >= $dv + $slen; + $len += $slen; + $dv += $slen; + } else { die "internal error" } + } elsif ($c =~ /^A/) { + my $alen = $self->serlen($c,$dv); + return -1 if $alen == -1; + $dv += $alen; + $len += $alen; + } else { die "internal error"; } + } + } + return $len; +} + +1 diff --git a/libs/libtpl-1.5/lang/perl/tests/Makefile b/libs/libtpl-1.5/lang/perl/tests/Makefile new file mode 100755 index 0000000000..c2dd552aa7 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/Makefile @@ -0,0 +1,9 @@ +all: run_tests + +run_tests: + perl ./do_tests + +.PHONY: clean + +clean: + rm -f test*.out diff --git a/libs/libtpl-1.5/lang/perl/tests/README b/libs/libtpl-1.5/lang/perl/tests/README new file mode 100755 index 0000000000..8f10443645 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/README @@ -0,0 +1,29 @@ +Run 'make' to run the tests. + +Run 'make clean' to clean up the temporary files. + +Description of tests +============================================================================= +test1 pack A(i) to file, unpack +test2 pack A(i) to memory, unpack +test3 pack A(i) to memory, pipe through tplxml (to make XML) +test4 pack A(i) to file, convert to XML, convert back to tpl (using tplxml) +test5 pack A(b) to file, unpack +test6 pack A(b) to memory, pipe through tplxml (to make XML) +test7 pack A(b) to file, convert to XML, convert back to tpl (using tplxml) +test8 pack A(s) (has embedded &, < and > in strings to test quoting in XML) +test9 pack A(u) to file, unpack +test10 pack A(u) to memory, convert via tplxml +test11 pack format B using a four-byte binary buffer, unpack and print +test12 pack A(d) to file, unpack +test13 pack A(d) to memory, convert via tplxml +test14 unpack big-endian i (-2) (on little-endian machine, tests reversi) +test15 unpack little-endian i (-3) (on big-endian machine, tests reversi) +test16 pack to mem format B using a four-byte binary buffer, unpack and print +test17 pack and unpack S(ic) +test18 pack and unpack i# +test19 pack and unpack i#i# +test20 pack A(S(ci#)) to file, convert to XML, then back to tpl (cf test81.c) +test21 Tpl->tpl_peek in-memory image +test22 Tpl->tpl_peek file image +test23 test I/U (only succeeds on 64-bit perl) diff --git a/libs/libtpl-1.5/lang/perl/tests/client.pl b/libs/libtpl-1.5/lang/perl/tests/client.pl new file mode 100755 index 0000000000..4d471e7174 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/client.pl @@ -0,0 +1,31 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use IO::Socket::INET; +use lib ".."; +use Tpl; + +our $port = 2000; + +# construct tpl +my $i; +my $tpl = Tpl->tpl_map("A(i)",\$i); +$tpl->tpl_pack(1) while ($i=shift @ARGV); +my $request = $tpl->tpl_dump(); + +# send to server, get response +my $socket = IO::Socket::INET->new("localhost:$port") or die "can't connect"; +print $socket $request; +shutdown($socket,1); # done writing (half-close) +undef $/; +my $response = <$socket>; # get reply (slurp) + +# decode response (or print error) +my $total; +my $tpl2 = Tpl->tpl_map("i", \$total); +eval { $tpl2->tpl_load(\$response); }; +die "invalid response\n" if $@; +$tpl2->tpl_unpack(0); +print "total is $total\n"; diff --git a/libs/libtpl-1.5/lang/perl/tests/do_tests b/libs/libtpl-1.5/lang/perl/tests/do_tests new file mode 100755 index 0000000000..3ca08bb1e0 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/do_tests @@ -0,0 +1,20 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +my @tests; +for (glob "test*[0-9]") { + push @tests, $_ if -e "$_.ans"; +} + +my $num_failed=0; + +for my $test (@tests) { + `./$test > $test.out`; + `diff $test.out $test.ans`; + print "$test failed\n" if $?; + $num_failed++ if $?; +} + +print scalar @tests . " tests conducted, $num_failed failed.\n"; diff --git a/libs/libtpl-1.5/lang/perl/tests/server.pl b/libs/libtpl-1.5/lang/perl/tests/server.pl new file mode 100755 index 0000000000..4faa9c64b4 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/server.pl @@ -0,0 +1,56 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use IO::Socket::INET; +use lib ".."; +use Tpl; + +$SIG{CHLD} = "IGNORE"; # don't create zombies + +our $port = 2000; + +sub handle_client { + my $client = shift; + + undef $/; + my $request = <$client>; # get request (slurp) + + # read input array, and calculate total + my ($i,$total); + my $tpl = Tpl->tpl_map("A(i)", \$i); + eval { $tpl->tpl_load(\$request); }; + die "received invalid tpl" if $@; + $total += $i while $tpl->tpl_unpack(1) > 0; + + # formulate response and send + my $tpl2 = Tpl->tpl_map("i", \$total); + $tpl2->tpl_pack(0); + my $response = $tpl2->tpl_dump(); + print $client $response; + close $client; +} + +my $server = IO::Socket::INET->new(LocalPort => $port, + Type => SOCK_STREAM, + Reuse => 1, + Listen => 10 ) + or die "Can't listen on port $port: $!\n"; + +while (1) { + my $client = $server->accept(); + next unless $client; + # new connection + my $pid = fork; + die "can't fork: $!\n" unless defined $pid; + if ($pid > 0) { + #p arent + close $client; + } elsif ($pid == 0) { + # child + handle_client($client); + exit(0); + } +} +close ($server); diff --git a/libs/libtpl-1.5/lang/perl/tests/test1 b/libs/libtpl-1.5/lang/perl/tests/test1 new file mode 100755 index 0000000000..f559e4b5d1 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test1 @@ -0,0 +1,23 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $pwd = `pwd`; +chomp $pwd; + +my $tmp1 = "$pwd/$0_1.out"; + +my $i; +my $tpl = Tpl->tpl_map("A(i)",\$i); +for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); } +$tpl->tpl_dump($tmp1); + +my $j; +my $tpl2 = Tpl->tpl_map("A(i)",\$j); +$tpl2->tpl_load($tmp1); +while($tpl2->tpl_unpack(1) > 0) { print "$j\n" } + diff --git a/libs/libtpl-1.5/lang/perl/tests/test1.ans b/libs/libtpl-1.5/lang/perl/tests/test1.ans new file mode 100755 index 0000000000..8b1acc12b6 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test1.ans @@ -0,0 +1,10 @@ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/libs/libtpl-1.5/lang/perl/tests/test10 b/libs/libtpl-1.5/lang/perl/tests/test10 new file mode 100755 index 0000000000..49be955ad6 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test10 @@ -0,0 +1,16 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $i; +my $tpl = Tpl->tpl_map("A(u)",\$i); +for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); } +my $img = $tpl->tpl_dump(); + +open TPLXML, "|../tplxml" or die "can't open tplxml: $!"; +print TPLXML $img; +close TPLXML; diff --git a/libs/libtpl-1.5/lang/perl/tests/test10.ans b/libs/libtpl-1.5/lang/perl/tests/test10.ans new file mode 100755 index 0000000000..4832472dd4 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test10.ans @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + ]> + + + + 0 + + + 1 + + + 2 + + + 3 + + + 4 + + + 5 + + + 6 + + + 7 + + + 8 + + + 9 + + + diff --git a/libs/libtpl-1.5/lang/perl/tests/test11 b/libs/libtpl-1.5/lang/perl/tests/test11 new file mode 100755 index 0000000000..11980150f9 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test11 @@ -0,0 +1,24 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $pwd = `pwd`; +chomp $pwd; + +my $tmp1 = "$pwd/$0_1.out"; + +my $i; +my $tpl = Tpl->tpl_map("B",\$i); +$i = pack("CCCC", 0xA, 0xB, 0xC, 0xD); +$tpl->tpl_pack(0); +$tpl->tpl_dump($tmp1); + + +$tpl = Tpl->tpl_map("B",\$i); +$tpl->tpl_load($tmp1); +$tpl->tpl_unpack(0); +print "$i\n"; diff --git a/libs/libtpl-1.5/lang/perl/tests/test11.ans b/libs/libtpl-1.5/lang/perl/tests/test11.ans new file mode 100755 index 0000000000..b04dd2e52f --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test11.ans @@ -0,0 +1,2 @@ + + diff --git a/libs/libtpl-1.5/lang/perl/tests/test12 b/libs/libtpl-1.5/lang/perl/tests/test12 new file mode 100755 index 0000000000..4dfed01fb7 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test12 @@ -0,0 +1,23 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $pwd = `pwd`; +chomp $pwd; + +my $tmp1 = "$pwd/$0_1.out"; + +my $i; +my $tpl = Tpl->tpl_map("A(f)",\$i); +for($i=0; $i<10.0; $i+=2/3.0) { $tpl->tpl_pack(1); } +$tpl->tpl_dump($tmp1); + +my $j; +my $tpl2 = Tpl->tpl_map("A(f)",\$j); +$tpl2->tpl_load($tmp1); +while($tpl2->tpl_unpack(1) > 0) { printf("%.6f\n", $j); } + diff --git a/libs/libtpl-1.5/lang/perl/tests/test12.ans b/libs/libtpl-1.5/lang/perl/tests/test12.ans new file mode 100755 index 0000000000..3849b4fedd --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test12.ans @@ -0,0 +1,16 @@ +0.000000 +0.666667 +1.333333 +2.000000 +2.666667 +3.333333 +4.000000 +4.666667 +5.333333 +6.000000 +6.666667 +7.333333 +8.000000 +8.666667 +9.333333 +10.000000 diff --git a/libs/libtpl-1.5/lang/perl/tests/test13 b/libs/libtpl-1.5/lang/perl/tests/test13 new file mode 100755 index 0000000000..65f2c37a60 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test13 @@ -0,0 +1,16 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $i; +my $tpl = Tpl->tpl_map("A(f)",\$i); +for($i=0; $i<10.0; $i+=2/3.0) { $tpl->tpl_pack(1); } +my $img = $tpl->tpl_dump(); + +open TPLXML, "|../tplxml" or die "can't open tplxml: $!"; +print TPLXML $img; +close TPLXML; diff --git a/libs/libtpl-1.5/lang/perl/tests/test13.ans b/libs/libtpl-1.5/lang/perl/tests/test13.ans new file mode 100755 index 0000000000..f8b97db31f --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test13.ans @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + ]> + + + + 0 + + + 0.666666666666667 + + + 1.33333333333333 + + + 2 + + + 2.66666666666667 + + + 3.33333333333333 + + + 4 + + + 4.66666666666667 + + + 5.33333333333333 + + + 6 + + + 6.66666666666667 + + + 7.33333333333333 + + + 8 + + + 8.66666666666667 + + + 9.33333333333333 + + + 10 + + + diff --git a/libs/libtpl-1.5/lang/perl/tests/test14 b/libs/libtpl-1.5/lang/perl/tests/test14 new file mode 100755 index 0000000000..920bd80890 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test14 @@ -0,0 +1,17 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $tmp1 = "test14.tpl"; + +my $j; +my $tpl2 = Tpl->tpl_map("i",\$j); +$tpl2->tpl_load($tmp1); +$tpl2->tpl_unpack(0); +print "$j\n"; + + diff --git a/libs/libtpl-1.5/lang/perl/tests/test14.ans b/libs/libtpl-1.5/lang/perl/tests/test14.ans new file mode 100755 index 0000000000..3fbedf693b --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test14.ans @@ -0,0 +1 @@ +-2 diff --git a/libs/libtpl-1.5/lang/perl/tests/test14.tpl b/libs/libtpl-1.5/lang/perl/tests/test14.tpl new file mode 100755 index 0000000000000000000000000000000000000000..f11ee5fae5db852a9b1a5222afbc0eb2fd03095a GIT binary patch literal 14 VcmXRZ$YEq)VBpJS`2YX^KL8#61;hXV literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/lang/perl/tests/test15 b/libs/libtpl-1.5/lang/perl/tests/test15 new file mode 100755 index 0000000000..e65437d700 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test15 @@ -0,0 +1,17 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $tmp1 = "test15.tpl"; + +my $j; +my $tpl2 = Tpl->tpl_map("i",\$j); +$tpl2->tpl_load($tmp1); +$tpl2->tpl_unpack(0); +print "$j\n"; + + diff --git a/libs/libtpl-1.5/lang/perl/tests/test15.ans b/libs/libtpl-1.5/lang/perl/tests/test15.ans new file mode 100755 index 0000000000..a83d1d524c --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test15.ans @@ -0,0 +1 @@ +-3 diff --git a/libs/libtpl-1.5/lang/perl/tests/test15.tpl b/libs/libtpl-1.5/lang/perl/tests/test15.tpl new file mode 100755 index 0000000000000000000000000000000000000000..69249f79a729b78228e65552a7187f8538fda49b GIT binary patch literal 14 VcmXRZ$YJ1PU|`5(`1}9=e*hj91;PLT literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/lang/perl/tests/test16 b/libs/libtpl-1.5/lang/perl/tests/test16 new file mode 100755 index 0000000000..2d24fc766e --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test16 @@ -0,0 +1,22 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $pwd = `pwd`; +chomp $pwd; + +my $i; +my $tpl = Tpl->tpl_map("B",\$i); +$i = pack("CCCC", 0xA, 0xB, 0xC, 0xD); +$tpl->tpl_pack(0); +my $img = $tpl->tpl_dump(); + + +$tpl = Tpl->tpl_map("B",\$i); +$tpl->tpl_load(\$img); +$tpl->tpl_unpack(0); +print "$i\n"; diff --git a/libs/libtpl-1.5/lang/perl/tests/test16.ans b/libs/libtpl-1.5/lang/perl/tests/test16.ans new file mode 100755 index 0000000000..b04dd2e52f --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test16.ans @@ -0,0 +1,2 @@ + + diff --git a/libs/libtpl-1.5/lang/perl/tests/test17 b/libs/libtpl-1.5/lang/perl/tests/test17 new file mode 100755 index 0000000000..18ab7d8221 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test17 @@ -0,0 +1,25 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $pwd = `pwd`; +chomp $pwd; + +my $tmp1 = "$pwd/$0_1.out"; + +my ($i,$j)=(1,ord('a')); +my $tpl = Tpl->tpl_map("S(ic)",\$i, \$j); +$tpl->tpl_pack(0); +$tpl->tpl_dump($tmp1); + +($i,$j)=(-9,"x"); +my $tpl2 = Tpl->tpl_map("S(ic)",\$i,\$j); +$tpl2->tpl_load($tmp1); +$tpl2->tpl_unpack(0); +$j = chr($j); +print "$i,$j\n"; + diff --git a/libs/libtpl-1.5/lang/perl/tests/test17.ans b/libs/libtpl-1.5/lang/perl/tests/test17.ans new file mode 100755 index 0000000000..a441d1808c --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test17.ans @@ -0,0 +1 @@ +1,a diff --git a/libs/libtpl-1.5/lang/perl/tests/test18 b/libs/libtpl-1.5/lang/perl/tests/test18 new file mode 100755 index 0000000000..e6f8e04121 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test18 @@ -0,0 +1,23 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $pwd = `pwd`; +chomp $pwd; + +my $tmp1 = "$pwd/$0_1.out"; + +my @i=(1,2,3,4); +my $tpl = Tpl->tpl_map("i#",\@i, 3); +$tpl->tpl_pack(0); +$tpl->tpl_dump($tmp1); + +my @j; +my $tpl2 = Tpl->tpl_map("i#",\@j,3); +$tpl2->tpl_load($tmp1); +$tpl2->tpl_unpack(0); +print "$_\n" for @j; diff --git a/libs/libtpl-1.5/lang/perl/tests/test18.ans b/libs/libtpl-1.5/lang/perl/tests/test18.ans new file mode 100755 index 0000000000..01e79c32a8 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test18.ans @@ -0,0 +1,3 @@ +1 +2 +3 diff --git a/libs/libtpl-1.5/lang/perl/tests/test19 b/libs/libtpl-1.5/lang/perl/tests/test19 new file mode 100755 index 0000000000..79e8b00fc8 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test19 @@ -0,0 +1,25 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $pwd = `pwd`; +chomp $pwd; + +my $tmp1 = "$pwd/$0_1.out"; + +my @i=(1,2,3,4); +my @j=(-1,-2,-3, -4); +my $tpl = Tpl->tpl_map("i#i#",\@i, 3, \@j, 4); +$tpl->tpl_pack(0); +$tpl->tpl_dump($tmp1); + +my (@x,@y); +my $tpl2 = Tpl->tpl_map("i#i#",\@x, 3, \@y, 4); +$tpl2->tpl_load($tmp1); +$tpl2->tpl_unpack(0); +print "$_\n" for @x; +print "$_\n" for @y; diff --git a/libs/libtpl-1.5/lang/perl/tests/test19.ans b/libs/libtpl-1.5/lang/perl/tests/test19.ans new file mode 100755 index 0000000000..eee553c3a0 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test19.ans @@ -0,0 +1,7 @@ +1 +2 +3 +-1 +-2 +-3 +-4 diff --git a/libs/libtpl-1.5/lang/perl/tests/test2 b/libs/libtpl-1.5/lang/perl/tests/test2 new file mode 100755 index 0000000000..e552cf73fb --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test2 @@ -0,0 +1,18 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $i; +my $tpl = Tpl->tpl_map("A(i)",\$i); +for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); } +my $img = $tpl->tpl_dump(); + +my $j; +my $tpl2 = Tpl->tpl_map("A(i)",\$j); +$tpl2->tpl_load(\$img); +while($tpl2->tpl_unpack(1) > 0) { print "$j\n" } + diff --git a/libs/libtpl-1.5/lang/perl/tests/test2.ans b/libs/libtpl-1.5/lang/perl/tests/test2.ans new file mode 100755 index 0000000000..8b1acc12b6 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test2.ans @@ -0,0 +1,10 @@ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/libs/libtpl-1.5/lang/perl/tests/test20 b/libs/libtpl-1.5/lang/perl/tests/test20 new file mode 100755 index 0000000000..e78edc736f --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test20 @@ -0,0 +1,36 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $pwd = `pwd`; +chomp $pwd; + +my $tmp1 = "$pwd/$0_1.out"; +my $tmp2 = "$pwd/$0_2.out"; +my $tmp3 = "$pwd/$0_3.out"; + +my ($c,@i); +my $tpl = Tpl->tpl_map("A(S(ci#))",\$c,\@i,10); + +# make element 1 +$c = 97; +@i = (0,1,2,3,4,5,6,7,8,9); +$tpl->tpl_pack(1); + +# make element 2 +$c = 98; +@i = (1,2,3,4,5,6,7,8,9,10); +$tpl->tpl_pack(1); + +$tpl->tpl_dump($tmp1); + + +`../tplxml $tmp1 > $tmp2`; # convert tpl to xml +`../tplxml $tmp2 > $tmp3`; # convert xml back to tpl +`diff $tmp1 $tmp3`; +print "tpl files ", ($? ? "differ" : "identical"), "\n"; + diff --git a/libs/libtpl-1.5/lang/perl/tests/test20.ans b/libs/libtpl-1.5/lang/perl/tests/test20.ans new file mode 100755 index 0000000000..1d7404264b --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test20.ans @@ -0,0 +1 @@ +tpl files identical diff --git a/libs/libtpl-1.5/lang/perl/tests/test21 b/libs/libtpl-1.5/lang/perl/tests/test21 new file mode 100755 index 0000000000..814ff1f784 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test21 @@ -0,0 +1,15 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $i; +my $tpl = Tpl->tpl_map("A(i)",\$i); +for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); } +my $img = $tpl->tpl_dump(); + +my $fmt = Tpl->tpl_peek(\$img); +print("$fmt\n"); diff --git a/libs/libtpl-1.5/lang/perl/tests/test21.ans b/libs/libtpl-1.5/lang/perl/tests/test21.ans new file mode 100755 index 0000000000..bc9aa33e28 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test21.ans @@ -0,0 +1 @@ +A(i) diff --git a/libs/libtpl-1.5/lang/perl/tests/test22 b/libs/libtpl-1.5/lang/perl/tests/test22 new file mode 100755 index 0000000000..416978f65e --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test22 @@ -0,0 +1,21 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $pwd = `pwd`; +chomp $pwd; + +my $tmp1 = "$pwd/$0_1.out"; + +my @i=(1,2,3,4); +my @j=(-1,-2,-3, -4); +my $tpl = Tpl->tpl_map("i#i#",\@i, 3, \@j, 4); +$tpl->tpl_pack(0); +$tpl->tpl_dump($tmp1); + +my $fmt = Tpl->tpl_peek($tmp1); +print "$fmt\n"; diff --git a/libs/libtpl-1.5/lang/perl/tests/test22.ans b/libs/libtpl-1.5/lang/perl/tests/test22.ans new file mode 100755 index 0000000000..7dd3f3f100 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test22.ans @@ -0,0 +1 @@ +i#i# diff --git a/libs/libtpl-1.5/lang/perl/tests/test23 b/libs/libtpl-1.5/lang/perl/tests/test23 new file mode 100755 index 0000000000..13c67e912c --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test23 @@ -0,0 +1,21 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +# this test only works on 64-bit Perl + +my ($i,$j) = (-4294967296,4294967296); # 2^32 (can't fit in a 32-bit value) +my $tpl = Tpl->tpl_map("IU",\$i,\$j); +$tpl->tpl_pack(0); +my $img = $tpl->tpl_dump(); + +my ($x,$y); +my $tpl2 = Tpl->tpl_map("IU",\$x,\$y); +$tpl2->tpl_load(\$img); +$tpl2->tpl_unpack(0); +print "$x $y\n"; + diff --git a/libs/libtpl-1.5/lang/perl/tests/test3 b/libs/libtpl-1.5/lang/perl/tests/test3 new file mode 100755 index 0000000000..9bbc0b18fc --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test3 @@ -0,0 +1,16 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $i; +my $tpl = Tpl->tpl_map("A(i)",\$i); +for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); } +my $img = $tpl->tpl_dump(); + +open TPLXML, "|../tplxml" or die "can't open tplxml: $!"; +print TPLXML $img; +close TPLXML; diff --git a/libs/libtpl-1.5/lang/perl/tests/test3.ans b/libs/libtpl-1.5/lang/perl/tests/test3.ans new file mode 100755 index 0000000000..4399a646d1 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test3.ans @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + ]> + + + + 0 + + + 1 + + + 2 + + + 3 + + + 4 + + + 5 + + + 6 + + + 7 + + + 8 + + + 9 + + + diff --git a/libs/libtpl-1.5/lang/perl/tests/test4 b/libs/libtpl-1.5/lang/perl/tests/test4 new file mode 100755 index 0000000000..2a71a25bfd --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test4 @@ -0,0 +1,26 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $pwd = `pwd`; +chomp $pwd; + +my $tmp1 = "$pwd/$0_1.out"; +my $tmp2 = "$pwd/$0_2.out"; +my $tmp3 = "$pwd/$0_3.out"; + +my $i; +my $tpl = Tpl->tpl_map("A(i)",\$i); +for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); } +$tpl->tpl_dump($tmp1); + + +`../tplxml $tmp1 > $tmp2`; # convert tpl to xml +`../tplxml $tmp2 > $tmp3`; # convert xml back to tpl +`diff $tmp1 $tmp3`; +print "tpl files ", ($? ? "differ" : "identical"), "\n"; + diff --git a/libs/libtpl-1.5/lang/perl/tests/test4.ans b/libs/libtpl-1.5/lang/perl/tests/test4.ans new file mode 100755 index 0000000000..1d7404264b --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test4.ans @@ -0,0 +1 @@ +tpl files identical diff --git a/libs/libtpl-1.5/lang/perl/tests/test5 b/libs/libtpl-1.5/lang/perl/tests/test5 new file mode 100755 index 0000000000..06385037fd --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test5 @@ -0,0 +1,23 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $pwd = `pwd`; +chomp $pwd; + +my $tmp1 = "$pwd/$0_1.out"; + +my $i; +my $tpl = Tpl->tpl_map("A(c)",\$i); +for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); } +$tpl->tpl_dump($tmp1); + +my $j; +my $tpl2 = Tpl->tpl_map("A(c)",\$j); +$tpl2->tpl_load($tmp1); +while($tpl2->tpl_unpack(1) > 0) { printf("%d\n", $j); } + diff --git a/libs/libtpl-1.5/lang/perl/tests/test5.ans b/libs/libtpl-1.5/lang/perl/tests/test5.ans new file mode 100755 index 0000000000..8b1acc12b6 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test5.ans @@ -0,0 +1,10 @@ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/libs/libtpl-1.5/lang/perl/tests/test6 b/libs/libtpl-1.5/lang/perl/tests/test6 new file mode 100755 index 0000000000..595a800607 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test6 @@ -0,0 +1,16 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $i; +my $tpl = Tpl->tpl_map("A(c)",\$i); +for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); } +my $img = $tpl->tpl_dump(); + +open TPLXML, "|../tplxml" or die "can't open tplxml: $!"; +print TPLXML $img; +close TPLXML; diff --git a/libs/libtpl-1.5/lang/perl/tests/test6.ans b/libs/libtpl-1.5/lang/perl/tests/test6.ans new file mode 100755 index 0000000000..a84432e414 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test6.ans @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + ]> + + + + 0 + + + 1 + + + 2 + + + 3 + + + 4 + + + 5 + + + 6 + + + 7 + + + 8 + + + 9 + + + diff --git a/libs/libtpl-1.5/lang/perl/tests/test7 b/libs/libtpl-1.5/lang/perl/tests/test7 new file mode 100755 index 0000000000..b6b08507ac --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test7 @@ -0,0 +1,26 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $pwd = `pwd`; +chomp $pwd; + +my $tmp1 = "$pwd/$0_1.out"; +my $tmp2 = "$pwd/$0_2.out"; +my $tmp3 = "$pwd/$0_3.out"; + +my $i; +my $tpl = Tpl->tpl_map("A(c)",\$i); +for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); } +$tpl->tpl_dump($tmp1); + + +`../tplxml $tmp1 > $tmp2`; # convert tpl to xml +`../tplxml $tmp2 > $tmp3`; # convert xml back to tpl +`diff $tmp1 $tmp3`; +print "tpl files ", ($? ? "differ" : "identical"), "\n"; + diff --git a/libs/libtpl-1.5/lang/perl/tests/test7.ans b/libs/libtpl-1.5/lang/perl/tests/test7.ans new file mode 100755 index 0000000000..1d7404264b --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test7.ans @@ -0,0 +1 @@ +tpl files identical diff --git a/libs/libtpl-1.5/lang/perl/tests/test8 b/libs/libtpl-1.5/lang/perl/tests/test8 new file mode 100755 index 0000000000..f6c194fcaa --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test8 @@ -0,0 +1,29 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $pwd = `pwd`; +chomp $pwd; + +my $tmp1 = "$pwd/$0_1.out"; +my $tmp2 = "$pwd/$0_2.out"; +my $tmp3 = "$pwd/$0_3.out"; + +my $i; +my $tpl = Tpl->tpl_map("A(s)",\$i); +for (qw(normal has&ersand )) { + $i = $_; + $tpl->tpl_pack(1); +} +$tpl->tpl_dump($tmp1); + + +`../tplxml $tmp1 > $tmp2`; # convert tpl to xml +`../tplxml $tmp2 > $tmp3`; # convert xml back to tpl +`diff $tmp1 $tmp3`; +print "tpl files ", ($? ? "differ" : "identical"), "\n"; + diff --git a/libs/libtpl-1.5/lang/perl/tests/test8.ans b/libs/libtpl-1.5/lang/perl/tests/test8.ans new file mode 100755 index 0000000000..1d7404264b --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test8.ans @@ -0,0 +1 @@ +tpl files identical diff --git a/libs/libtpl-1.5/lang/perl/tests/test9 b/libs/libtpl-1.5/lang/perl/tests/test9 new file mode 100755 index 0000000000..75ec15e8d8 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test9 @@ -0,0 +1,23 @@ +#!/usr/bin/perl +# +use strict; +use warnings; + +use lib ".."; +use Tpl; + +my $pwd = `pwd`; +chomp $pwd; + +my $tmp1 = "$pwd/$0_1.out"; + +my $i; +my $tpl = Tpl->tpl_map("A(u)",\$i); +for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); } +$tpl->tpl_dump($tmp1); + +my $j; +my $tpl2 = Tpl->tpl_map("A(u)",\$j); +$tpl2->tpl_load($tmp1); +while($tpl2->tpl_unpack(1) > 0) { print "$j\n" } + diff --git a/libs/libtpl-1.5/lang/perl/tests/test9.ans b/libs/libtpl-1.5/lang/perl/tests/test9.ans new file mode 100755 index 0000000000..8b1acc12b6 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tests/test9.ans @@ -0,0 +1,10 @@ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/libs/libtpl-1.5/lang/perl/tplfmt b/libs/libtpl-1.5/lang/perl/tplfmt new file mode 100755 index 0000000000..b3b0603130 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tplfmt @@ -0,0 +1,24 @@ +#!/usr/bin/perl + +# tplfmt +# by Troy Hanson Feb 2006 +# print the format string of a tpl image file + +use strict; +use warnings; + +sub peek_fmt { + my $buf = shift; + die "invalid tpl file" unless ($$buf =~ /^tpl/); + return (unpack("Z*", substr($$buf,8))); +} + +die "usage: $0 [ ...]" unless (@ARGV > 0); + +undef $/; # slurp +for (@ARGV) { + open TPL, "<$_" or die "can't open $_: $!"; + my $tpl = ; + print "$_: ", peek_fmt(\$tpl), "\n"; + close TPL; +} diff --git a/libs/libtpl-1.5/lang/perl/tplxml b/libs/libtpl-1.5/lang/perl/tplxml new file mode 100755 index 0000000000..5037dc3f74 --- /dev/null +++ b/libs/libtpl-1.5/lang/perl/tplxml @@ -0,0 +1,306 @@ +#!/usr/bin/perl + +# tplxml +# by Troy Hanson 27 Feb 2006 +# convert between tpl and XML + +# Copyright (c) 2005-2006, Troy Hanson http://tpl.sourceforge.net +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use strict; +use warnings; +use XML::Parser; +use FindBin; +use lib "$FindBin::Bin"; #locate Tpl.pm in same directory as tplxml +use Tpl; +use bytes; + +sub quote_chars { + my $str = shift; + $$str =~ s/&/&/g; #order matters + $$str =~ s//>/g; +} +sub unquote_chars { + my $str = shift; + $$str =~ s/<//g; + $$str =~ s/&/&/g; +} +sub hex_chars { + my $str = shift; + my $hex; + for(my $i=0; $i < length $$str; $i++) { + my $byte = unpack("C",substr($$str,$i,1)); + $hex .= sprintf("%02x", $byte); + } + $$str = $hex; +} +sub unhex_chars { + my $str = shift; + my $bytes; + for(my $i=0; $i < length $$str; $i+=2) { + my $hexbyte = substr($$str,$i,2); + $bytes .= pack("C", hex($hexbyte)); + } + $$str= $bytes; +} + +sub tpl2xml { + my $src = shift; + my (@out,@args); + + # build list of references to hold output of unpacking + my ($fmt,@fxlens) = peek_fmt($src); + for(my ($i,$j,$k)=(0,0,0);$itpl_map($fmt,@args); + $tpl->tpl_load($src); + $tpl->tpl_unpack(0); + + # construct xml preamble + my $pre = qq{ + + + + + + + + + + + + + + ]>\n}; + print $pre; + my $fxattr = join ",", @fxlens; + print qq{\n}; + tpl2xml_node($tpl,"A0",1); + print qq{\n}; +} + +sub tpl2xml_node { + my $tpl = shift; + my $node = shift; + my $indent = shift; + my $i = " " x $indent; + for my $c (@{ $tpl->{$node} }) { + if (ref($c)) { + my ($type,$addr,$fxlen) = @$c; + quote_chars $addr if $type eq 's'; + hex_chars $addr if $type eq 'B'; + if (not defined $fxlen) { + print qq{$i<$type>$$addr\n}; # singleton + } else { + # all elements of octothorpic fixed-len array + print qq{$i\n}; + print qq{$i <$type>$addr->[$_]\n} for (0..$fxlen-1); + print qq{$i\n}; + } + } else { + # A node + print qq{$i\n}; + my $idx = $1 if $c =~ /^A(\d+)$/; + while($tpl->tpl_unpack($idx) > 0) { + print qq{$i\n}; + tpl2xml_node($tpl,$c,$indent+1); + print qq{$i\n}; + } + print qq{$i\n}; + } + } +} + +sub xml2tpl { + my $src = shift; + my $p = new XML::Parser( Style => 'Tree' ); + my $tree = $p->parse($$src); + die "not a tpl xml document" unless $tree->[0] eq 'tplxml'; + die "no format attribute" unless defined $tree->[1][0]->{format}; + my $fmt = $tree->[1][0]->{format}; + die "no fxlens attribute" unless defined $tree->[1][0]->{fxlens}; + my @fxlens = split /,/, $tree->[1][0]->{fxlens}; + + # build list of references to variables for use in packing + my (@args,@out); + for(my ($i,$j,$k)=(0,0,0);$itpl_map($fmt,@args); + xml2tpl_dfs($tpl,$tree->[1]); + $tpl->tpl_pack(0); + print $tpl->tpl_dump; +} + +sub xml2tpl_dfs { + my $tpl = shift; + my $xml = shift; + + my @next = @$xml; # ($attr,@tagvals) = $$xml; + shift @next; # discard attributes + my @tpltoks = @{ $tpl->{"A0"} }; #expected tokens when parsing + + TAG: while (@next) { + my $xmltag = shift @next; + my $xmlval = shift @next; + + # skip whitespace/newlines embedded between tags + next TAG if ($xmltag eq "0" and $xmlval =~ /^\s+$/); + + # pack if necessary. consume tokens by look-ahead until non-pack token. + while (@tpltoks > 0 and $tpltoks[0] =~ /^P(\d+)$/) { + shift @tpltoks; + $tpl->tpl_pack($1); + } + + # If tpl format specifies a non-array type should appear at this point + # in the XML tree, then validate the type matches the format and assign + # the value from the XML to the variable from which it'll be packed + my $tpltoken = shift @tpltoks; + my $octothorpic=0; + if (ref $tpltoken) { + my ($tpltype,$tpladdr,$fxlen) = @$tpltoken; + + # This block is how we handle octothorpic (fixed length) arrays. + # If $fxlen is defined then an octothorpic node is expected. + # After finding the node we put its subnodes (the array elements) + # onto the @next array for immediate parsing and we use $fxlen:$remaining + # as a signet version of the $fxlen to induce the element-processing loop. + if (defined $fxlen) { + if ($fxlen =~ /^(\d+):(\d+)$/) { # $1==orig $fxlen, $2==remain $fxlen + $octothorpic=1; + unshift @tpltoks, [$tpltype, $tpladdr, $1.":".($2-1)] if $2 > 1; + } else { # octothorpic array expected; look for parent node + die "expected '' but got '<$xmltag>'" unless $xmltag eq 'fx'; + @{ $tpladdr } = (); # Empty accumulator array for octothorpic values + unshift @tpltoks, [$tpltype, $tpladdr, "$fxlen:$fxlen"]; # x:x signet + shift @$xmlval; # discard 'A' attributes + unshift @next, @$xmlval; #parse xml subtree now (dfs) + next TAG; # proceed to children of node + } + } + + if ($tpltype ne $xmltag) { + die "mismatch: xml has '$xmltag' where format specifies '$tpltype'"; + } + # expect @$xmlval to be ({},0,'value') i.e. a single, terminal text node + if (@$xmlval > 3 || $xmlval->[1] ne '0') { + die "error: xml tag '$xmltag' cannot enclose sub-tags"; + } + if ($octothorpic) { + push @{ $tpladdr }, $xmlval->[2]; + } else { + $$tpladdr = $xmlval->[2]; + } + unquote_chars $tpladdr if $tpltype eq 's'; + unhex_chars $tpladdr if $tpltype eq 'B'; + } elsif ($tpltoken =~ /^A(\d+)$/) { + # tpl format specifies an array should appear at this point in the XML + if ($xmltag ne 'A') { + die "mismatch: xml has '$xmltag' where format specifies 'A'"; + } + shift @$xmlval; # discard 'A' attributes + + # form token that means "replace me with tokens from A(n), x times" + # (where x is the number of elements contained by this array). + my $array_count=0; + for(my $i=0; $i < @$xmlval; $i+=2) { + $array_count++ if $xmlval->[$i] eq 'el'; + } + + unshift @tpltoks, "N$1:$array_count" if $array_count > 0; + unshift @next, @$xmlval; #parse xml subtree now (dfs) + } elsif ($tpltoken =~ /^N(\d+):(\d+)$/) { + if ($xmltag ne "el") { + die "mismatch: xml has '$xmltag' where array 'el' is expected"; + } + # prepend A$1's tokens (and decremented N:count) to expected tokens + my ($n,$elsleft) = ($1, ($2 - 1)); + unshift @tpltoks, "N$n:$elsleft" if $elsleft > 0; + unshift @tpltoks, "P$n"; # "pack me now" token + unshift @tpltoks, @{ $tpl->{"A$1"} }; + + shift @$xmlval; # discard 'el' attributes + unshift @next, @$xmlval; # proceed to parse el subtree (dfs) + } else { + die "internal error, unexpected token $tpltoken"; + } + } + + # pack if necessary. consume tokens by look-ahead until non-pack token. + while (@tpltoks > 0 and $tpltoks[0] =~ /^P(\d+)$/) { + shift @tpltoks; + $tpl->tpl_pack($1); + } + + if (@tpltoks > 0) { + die "error: end of xml document reached but format requires more data"; + } +} + +sub peek_fmt { + my $buf = shift; + die "invalid tpl file" unless ($$buf =~ /^tpl/); + my $flags = CORE::unpack("C", substr($$buf,3,1)); + my $UF = ($flags & 1) ? "N" : "V"; # big or little endian fxlens + my $fmt = (CORE::unpack("Z*", substr($$buf,8))); + my $num_octothorpes = scalar (my @o = ($fmt =~ /#/g)); + my @fxlens; + my $fx = 8 + length($fmt) + 1; + for(my $i=0; $i < $num_octothorpes; $i++) { + my $fxlen_bytes = substr($$buf,$fx,4); + my $fxlen = unpack($UF, $fxlen_bytes); + push @fxlens, $fxlen; + $fx += 4; + } + return ($fmt,@fxlens); +} + +########################################################################## +# Slurp input file, auto-detect if conversion is to tpl or XML, and run. +########################################################################## + +undef $/; +my $src = <>; +our $to = (substr($src,0,3) eq "tpl") ? "xml" : "tpl"; +xml2tpl(\$src) if $to eq "tpl"; +tpl2xml(\$src) if $to eq "xml"; + diff --git a/libs/libtpl-1.5/src/Makefile.am b/libs/libtpl-1.5/src/Makefile.am new file mode 100755 index 0000000000..5719afcc67 --- /dev/null +++ b/libs/libtpl-1.5/src/Makefile.am @@ -0,0 +1,7 @@ +SUBDIRS = win +lib_LTLIBRARIES = libtpl.la +libtpl_la_SOURCES = tpl.c +include_HEADERS = tpl.h +libtpl_la_LDFLAGS = -no-undefined -version-info 0:0:0 +libtpl_la_LIBADD = win/libwinmmap.la + diff --git a/libs/libtpl-1.5/src/Makefile.in b/libs/libtpl-1.5/src/Makefile.in new file mode 100644 index 0000000000..e38aed54d7 --- /dev/null +++ b/libs/libtpl-1.5/src/Makefile.in @@ -0,0 +1,607 @@ +# Makefile.in generated by automake 1.10.2 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src +DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config/config.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" +libLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(lib_LTLIBRARIES) +libtpl_la_DEPENDENCIES = win/libwinmmap.la +am_libtpl_la_OBJECTS = tpl.lo +libtpl_la_OBJECTS = $(am_libtpl_la_OBJECTS) +libtpl_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libtpl_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/config +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libtpl_la_SOURCES) +DIST_SOURCES = $(libtpl_la_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +includeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(include_HEADERS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = win +lib_LTLIBRARIES = libtpl.la +libtpl_la_SOURCES = tpl.c +include_HEADERS = tpl.h +libtpl_la_LDFLAGS = -no-undefined -version-info 0:0:0 +libtpl_la_LIBADD = win/libwinmmap.la +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libtpl.la: $(libtpl_la_OBJECTS) $(libtpl_la_DEPENDENCIES) + $(libtpl_la_LINK) -rpath $(libdir) $(libtpl_la_OBJECTS) $(libtpl_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tpl.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" + @list='$(include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \ + $(includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \ + done + +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_HEADERS)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \ + rm -f "$(DESTDIR)$(includedir)/$$f"; \ + done + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + distdir=`$(am__cd) $(distdir) && pwd`; \ + top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$top_distdir" \ + distdir="$$distdir/$$subdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: install-includeHEADERS + +install-dvi: install-dvi-recursive + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-recursive + +install-info: install-info-recursive + +install-man: + +install-pdf: install-pdf-recursive + +install-ps: install-ps-recursive + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \ + install-strip + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags ctags-recursive \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am \ + install-includeHEADERS install-info install-info-am \ + install-libLTLIBRARIES install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am \ + uninstall-includeHEADERS uninstall-libLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libs/libtpl-1.5/src/tpl.c b/libs/libtpl-1.5/src/tpl.c new file mode 100755 index 0000000000..24a9383a2e --- /dev/null +++ b/libs/libtpl-1.5/src/tpl.c @@ -0,0 +1,2472 @@ +/* +Copyright (c) 2005-2010, Troy D. Hanson http://tpl.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define TPL_VERSION 1.5 + +static const char id[]="$Id: tpl.c 192 2009-04-24 10:35:30Z thanson $"; + + +#include /* malloc */ +#include /* va_list */ +#include /* memcpy, memset, strchr */ +#include /* printf (tpl_hook.oops default function) */ + +#ifndef _WIN32 +#include /* for ftruncate */ +#else +#include +#define ftruncate(x,y) _chsize(x,y) +#endif +#include /* for 'open' */ +#include /* for 'open' */ +#include /* for 'open' */ +#include +#ifndef _WIN32 +#include /* uint32_t, uint64_t, etc */ +#else +typedef unsigned short ushort; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#endif + + +#if ( defined __CYGWIN__ || defined __MINGW32__ || defined _WIN32 ) +#include "win/mman.h" /* mmap */ +#else +#include /* mmap */ +#endif + +#include "tpl.h" + +#define TPL_GATHER_BUFLEN 8192 +#define TPL_MAGIC "tpl" + +/* macro to add a structure to a doubly-linked list */ +#define DL_ADD(head,add) \ + do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (head)->prev->next = (add); \ + (head)->prev = (add); \ + (add)->next = NULL; \ + } else { \ + (head)=(add); \ + (head)->prev = (head); \ + (head)->next = NULL; \ + } \ + } while (0); + +#define fatal_oom() tpl_hook.fatal("out of memory\n") + +/* bit flags (internal). preceded by the external flags in tpl.h */ +#define TPL_WRONLY (1 << 9) /* app has initiated tpl packing */ +#define TPL_RDONLY (1 << 10) /* tpl was loaded (for unpacking) */ +#define TPL_XENDIAN (1 << 11) /* swap endianness when unpacking */ +#define TPL_OLD_STRING_FMT (1 << 12) /* tpl has strings in 1.2 format */ + +/* values for the flags byte that appears after the magic prefix */ +#define TPL_SUPPORTED_BITFLAGS 3 +#define TPL_FL_BIGENDIAN (1 << 0) +#define TPL_FL_NULLSTRINGS (1 << 1) + +/* char values for node type */ +#define TPL_TYPE_ROOT 0 +#define TPL_TYPE_INT32 1 +#define TPL_TYPE_UINT32 2 +#define TPL_TYPE_BYTE 3 +#define TPL_TYPE_STR 4 +#define TPL_TYPE_ARY 5 +#define TPL_TYPE_BIN 6 +#define TPL_TYPE_DOUBLE 7 +#define TPL_TYPE_INT64 8 +#define TPL_TYPE_UINT64 9 +#define TPL_TYPE_INT16 10 +#define TPL_TYPE_UINT16 11 +#define TPL_TYPE_POUND 12 + +/* error codes */ +#define ERR_NOT_MINSIZE (-1) +#define ERR_MAGIC_MISMATCH (-2) +#define ERR_INCONSISTENT_SZ (-3) +#define ERR_FMT_INVALID (-4) +#define ERR_FMT_MISSING_NUL (-5) +#define ERR_FMT_MISMATCH (-6) +#define ERR_FLEN_MISMATCH (-7) +#define ERR_INCONSISTENT_SZ2 (-8) +#define ERR_INCONSISTENT_SZ3 (-9) +#define ERR_INCONSISTENT_SZ4 (-10) +#define ERR_UNSUPPORTED_FLAGS (-11) + +/* access to A(...) nodes by index */ +typedef struct tpl_pidx { + struct tpl_node *node; + struct tpl_pidx *next,*prev; +} tpl_pidx; + +/* A(...) node datum */ +typedef struct tpl_atyp { + uint32_t num; /* num elements */ + size_t sz; /* size of each backbone's datum */ + struct tpl_backbone *bb,*bbtail; + void *cur; +} tpl_atyp; + +/* backbone to extend A(...) lists dynamically */ +typedef struct tpl_backbone { + struct tpl_backbone *next; + /* when this structure is malloc'd, extra space is alloc'd at the + * end to store the backbone "datum", and data points to it. */ +#if __STDC_VERSION__ < 199901 + char *data; +#else + char data[]; +#endif +} tpl_backbone; + +/* mmap record */ +typedef struct tpl_mmap_rec { + int fd; + void *text; + size_t text_sz; +} tpl_mmap_rec; + +/* root node datum */ +typedef struct tpl_root_data { + int flags; + tpl_pidx *pidx; + tpl_mmap_rec mmap; + char *fmt; + int *fxlens, num_fxlens; +} tpl_root_data; + +/* node type to size mapping */ +struct tpl_type_t { + char c; + int sz; +}; + + +/* Internal prototypes */ +static tpl_node *tpl_node_new(tpl_node *parent); +static tpl_node *tpl_find_i(tpl_node *n, int i); +static void *tpl_cpv(void *datav, void *data, size_t sz); +static void *tpl_extend_backbone(tpl_node *n); +static char *tpl_fmt(tpl_node *r); +static void *tpl_dump_atyp(tpl_node *n, tpl_atyp* at, void *dv); +static size_t tpl_ser_osz(tpl_node *n); +static void tpl_free_atyp(tpl_node *n,tpl_atyp *atyp); +static int tpl_dump_to_mem(tpl_node *r, void *addr, size_t sz); +static int tpl_mmap_file(char *filename, tpl_mmap_rec *map_rec); +static int tpl_mmap_output_file(char *filename, size_t sz, void **text_out); +static int tpl_cpu_bigendian(void); +static int tpl_needs_endian_swap(void *); +static void tpl_byteswap(void *word, int len); +static void tpl_fatal(char *fmt, ...); +static int tpl_serlen(tpl_node *r, tpl_node *n, void *dv, size_t *serlen); +static int tpl_unpackA0(tpl_node *r); +static int tpl_oops(const char *fmt, ...); +static int tpl_gather_mem( char *buf, size_t len, tpl_gather_t **gs, tpl_gather_cb *cb, void *data); +static int tpl_gather_nonblocking( int fd, tpl_gather_t **gs, tpl_gather_cb *cb, void *data); +static int tpl_gather_blocking(int fd, void **img, size_t *sz); +static tpl_node *tpl_map_va(char *fmt, va_list ap); + +/* This is used internally to help calculate padding when a 'double' + * follows a smaller datatype in a structure. Normally under gcc + * on x86, d will be aligned at +4, however use of -malign-double + * causes d to be aligned at +8 (this is actually faster on x86). + * Also SPARC and x86_64 seem to align always on +8. + */ +struct tpl_double_alignment_detector { + char a; + double d; /* some platforms align this on +4, others on +8 */ +}; + +/* this is another case where alignment varies. mac os x/gcc was observed + * to align the int64_t at +4 under -m32 and at +8 under -m64 */ +struct tpl_int64_alignment_detector { + int i; + int64_t j; /* some platforms align this on +4, others on +8 */ +}; + +typedef struct { + size_t inter_elt_len; /* padded inter-element len; i.e. &a[1].field - &a[0].field */ + tpl_node *iter_start_node; /* node to jump back to, as we start each new iteration */ + size_t iternum; /* current iteration number (total req'd. iter's in n->num) */ +} tpl_pound_data; + +/* Hooks for customizing tpl mem alloc, error handling, etc. Set defaults. */ +tpl_hook_t tpl_hook = { + /* .oops = */ tpl_oops, + /* .malloc = */ malloc, + /* .realloc = */ realloc, + /* .free = */ free, + /* .fatal = */ tpl_fatal, + /* .gather_max = */ 0 /* max tpl size (bytes) for tpl_gather */ +}; + +static const char tpl_fmt_chars[] = "AS($)BiucsfIUjv#"; /* valid format chars */ +static const char tpl_S_fmt_chars[] = "iucsfIUjv#$()"; /* valid within S(...) */ +static const char tpl_datapeek_ok_chars[] = "iucsfIUjv"; /* valid in datapeek */ +static const struct tpl_type_t tpl_types[] = { + /* [TPL_TYPE_ROOT] = */ {'r', 0}, + /* [TPL_TYPE_INT32] = */ {'i', sizeof(int32_t)}, + /* [TPL_TYPE_UINT32] = */ {'u', sizeof(uint32_t)}, + /* [TPL_TYPE_BYTE] = */ {'c', sizeof(char)}, + /* [TPL_TYPE_STR] = */ {'s', sizeof(char*)}, + /* [TPL_TYPE_ARY] = */ {'A', 0}, + /* [TPL_TYPE_BIN] = */ {'B', 0}, + /* [TPL_TYPE_DOUBLE] = */ {'f', 8}, /* not sizeof(double) as that varies */ + /* [TPL_TYPE_INT64] = */ {'I', sizeof(int64_t)}, + /* [TPL_TYPE_UINT64] = */ {'U', sizeof(uint64_t)}, + /* [TPL_TYPE_INT16] = */ {'j', sizeof(int16_t)}, + /* [TPL_TYPE_UINT16] = */ {'v', sizeof(uint16_t)}, + /* [TPL_TYPE_POUND] = */ {'#', 0}, +}; + +/* default error-reporting function. Just writes to stderr. */ +static int tpl_oops(const char *fmt, ...) { + va_list ap; + va_start(ap,fmt); + vfprintf(stderr,fmt,ap); + va_end(ap); + return 0; +} + + +static tpl_node *tpl_node_new(tpl_node *parent) { + tpl_node *n; + if ((n=tpl_hook.malloc(sizeof(tpl_node))) == NULL) { + fatal_oom(); + } + n->addr=NULL; + n->data=NULL; + n->num=1; + n->ser_osz=0; + n->children=NULL; + n->next=NULL; + n->parent=parent; + return n; +} + +/* Used in S(..) formats to pack several fields from a structure based on + * only the structure address. We need to calculate field addresses + * manually taking into account the size of the fields and intervening padding. + * The wrinkle is that double is not normally aligned on x86-32 but the + * -malign-double compiler option causes it to be. Double are aligned + * on Sparc, and apparently on 64 bit x86. We use a helper structure + * to detect whether double is aligned in this compilation environment. + */ +char *calc_field_addr(tpl_node *parent, int type,char *struct_addr, int ordinal) { + tpl_node *prev; + int offset; + int align_sz; + + if (ordinal == 1) return struct_addr; /* first field starts on structure address */ + + /* generate enough padding so field addr is divisible by it's align_sz. 4, 8, etc */ + prev = parent->children->prev; + switch(type) { + case TPL_TYPE_DOUBLE: + align_sz = sizeof(struct tpl_double_alignment_detector) > 12 ? 8 : 4; + break; + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + align_sz = sizeof(struct tpl_int64_alignment_detector) > 12 ? 8 : 4; + break; + default: + align_sz = tpl_types[type].sz; + break; + } + offset = ((uintptr_t)prev->addr - (uintptr_t)struct_addr) + + (tpl_types[prev->type].sz * prev->num); + offset = (offset + align_sz - 1) / align_sz * align_sz; + return struct_addr + offset; +} + +TPL_API tpl_node *tpl_map(char *fmt,...) { + va_list ap; + tpl_node *tn; + + va_start(ap,fmt); + tn = tpl_map_va(fmt, ap); + va_end(ap); + return tn; +} + +static tpl_node *tpl_map_va(char *fmt, va_list ap) { + int lparen_level=0,expect_lparen=0,t=0,in_structure=0,ordinal=0; + int in_nested_structure=0; + char *c, *peek, *struct_addr=NULL, *struct_next; + tpl_node *root,*parent,*n=NULL,*preceding,*iter_start_node=NULL, + *struct_widest_node=NULL, *np; tpl_pidx *pidx; + tpl_pound_data *pd; + int *fxlens, num_fxlens, pound_num, pound_prod, applies_to_struct; + int contig_fxlens[10]; /* temp space for contiguous fxlens */ + int num_contig_fxlens, i, j; + ptrdiff_t inter_elt_len=0; /* padded element length of contiguous structs in array */ + + + root = tpl_node_new(NULL); + root->type = TPL_TYPE_ROOT; + root->data = (tpl_root_data*)tpl_hook.malloc(sizeof(tpl_root_data)); + if (!root->data) fatal_oom(); + memset((tpl_root_data*)root->data,0,sizeof(tpl_root_data)); + + /* set up root nodes special ser_osz to reflect overhead of preamble */ + root->ser_osz = sizeof(uint32_t); /* tpl leading length */ + root->ser_osz += strlen(fmt) + 1; /* fmt + NUL-terminator */ + root->ser_osz += 4; /* 'tpl' magic prefix + flags byte */ + + parent=root; + + c=fmt; + while (*c != '\0') { + switch (*c) { + case 'c': + case 'i': + case 'u': + case 'j': + case 'v': + case 'I': + case 'U': + case 'f': + if (*c=='c') t=TPL_TYPE_BYTE; + else if (*c=='i') t=TPL_TYPE_INT32; + else if (*c=='u') t=TPL_TYPE_UINT32; + else if (*c=='j') t=TPL_TYPE_INT16; + else if (*c=='v') t=TPL_TYPE_UINT16; + else if (*c=='I') t=TPL_TYPE_INT64; + else if (*c=='U') t=TPL_TYPE_UINT64; + else if (*c=='f') t=TPL_TYPE_DOUBLE; + + if (expect_lparen) goto fail; + n = tpl_node_new(parent); + n->type = t; + if (in_structure) { + if (ordinal == 1) { + /* for S(...)# iteration. Apply any changes to case 's' too!!! */ + iter_start_node = n; + struct_widest_node = n; + } + if (tpl_types[n->type].sz > tpl_types[struct_widest_node->type].sz) { + struct_widest_node = n; + } + n->addr = calc_field_addr(parent,n->type,struct_addr,ordinal++); + } else n->addr = (void*)va_arg(ap,void*); + n->data = tpl_hook.malloc(tpl_types[t].sz); + if (!n->data) fatal_oom(); + if (n->parent->type == TPL_TYPE_ARY) + ((tpl_atyp*)(n->parent->data))->sz += tpl_types[t].sz; + DL_ADD(parent->children,n); + break; + case 's': + if (expect_lparen) goto fail; + n = tpl_node_new(parent); + n->type = TPL_TYPE_STR; + if (in_structure) { + if (ordinal == 1) { + iter_start_node = n; /* for S(...)# iteration */ + struct_widest_node = n; + } + if (tpl_types[n->type].sz > tpl_types[struct_widest_node->type].sz) { + struct_widest_node = n; + } + n->addr = calc_field_addr(parent,n->type,struct_addr,ordinal++); + } else n->addr = (void*)va_arg(ap,void*); + n->data = tpl_hook.malloc(sizeof(char*)); + if (!n->data) fatal_oom(); + *(char**)(n->data) = NULL; + if (n->parent->type == TPL_TYPE_ARY) + ((tpl_atyp*)(n->parent->data))->sz += sizeof(void*); + DL_ADD(parent->children,n); + break; + case '#': + /* apply a 'num' to preceding atom */ + if (!parent->children) goto fail; + preceding = parent->children->prev; /* first child's prev is 'last child'*/ + t = preceding->type; + applies_to_struct = (*(c-1) == ')') ? 1 : 0; + if (!applies_to_struct) { + if (!(t == TPL_TYPE_BYTE || t == TPL_TYPE_INT32 || + t == TPL_TYPE_UINT32 || t == TPL_TYPE_DOUBLE || + t == TPL_TYPE_UINT64 || t == TPL_TYPE_INT64 || + t == TPL_TYPE_UINT16 || t == TPL_TYPE_INT16 || + t == TPL_TYPE_STR )) goto fail; + } + /* count up how many contiguous # and form their product */ + pound_prod=1; + num_contig_fxlens=0; + for(peek=c; *peek == '#'; peek++) { + pound_num = va_arg(ap, int); + if (pound_num < 1) { + tpl_hook.fatal("non-positive iteration count %d\n", pound_num); + } + if (num_contig_fxlens >= (sizeof(contig_fxlens)/sizeof(contig_fxlens[0]))) { + tpl_hook.fatal("contiguous # exceeds hardcoded limit\n"); + } + contig_fxlens[num_contig_fxlens++] = pound_num; + pound_prod *= pound_num; + } + /* increment c to skip contiguous # so its points to last one */ + c = peek-1; + /* differentiate atom-# from struct-# by noting preceding rparen */ + if (applies_to_struct) { /* insert # node to induce looping */ + n = tpl_node_new(parent); + n->type = TPL_TYPE_POUND; + n->num = pound_prod; + n->data = tpl_hook.malloc(sizeof(tpl_pound_data)); + if (!n->data) fatal_oom(); + pd = (tpl_pound_data*)n->data; + pd->inter_elt_len = inter_elt_len; + pd->iter_start_node = iter_start_node; + pd->iternum = 0; + DL_ADD(parent->children,n); + /* multiply the 'num' and data space on each atom in the structure */ + for(np = iter_start_node; np != n; np = np->next) { + if (n->parent->type == TPL_TYPE_ARY) { + ((tpl_atyp*)(n->parent->data))->sz += + tpl_types[np->type].sz * (np->num * (n->num - 1)); + } + np->data = tpl_hook.realloc(np->data, tpl_types[np->type].sz * + np->num * n->num); + if (!np->data) fatal_oom(); + memset(np->data, 0, tpl_types[np->type].sz * np->num * n->num); + } + } else { /* simple atom-# form does not require a loop */ + preceding->num = pound_prod; + preceding->data = tpl_hook.realloc(preceding->data, + tpl_types[t].sz * preceding->num); + if (!preceding->data) fatal_oom(); + memset(preceding->data,0,tpl_types[t].sz * preceding->num); + if (n->parent->type == TPL_TYPE_ARY) { + ((tpl_atyp*)(n->parent->data))->sz += tpl_types[t].sz * + (preceding->num-1); + } + } + root->ser_osz += (sizeof(uint32_t) * num_contig_fxlens); + + j = ((tpl_root_data*)root->data)->num_fxlens; /* before incrementing */ + (((tpl_root_data*)root->data)->num_fxlens) += num_contig_fxlens; + num_fxlens = ((tpl_root_data*)root->data)->num_fxlens; /* new value */ + fxlens = ((tpl_root_data*)root->data)->fxlens; + fxlens = tpl_hook.realloc(fxlens, sizeof(int) * num_fxlens); + if (!fxlens) fatal_oom(); + ((tpl_root_data*)root->data)->fxlens = fxlens; + for(i=0; i < num_contig_fxlens; i++) fxlens[j++] = contig_fxlens[i]; + + break; + case 'B': + if (expect_lparen) goto fail; + if (in_structure) goto fail; + n = tpl_node_new(parent); + n->type = TPL_TYPE_BIN; + n->addr = (tpl_bin*)va_arg(ap,void*); + n->data = tpl_hook.malloc(sizeof(tpl_bin*)); + if (!n->data) fatal_oom(); + *((tpl_bin**)n->data) = NULL; + if (n->parent->type == TPL_TYPE_ARY) + ((tpl_atyp*)(n->parent->data))->sz += sizeof(tpl_bin); + DL_ADD(parent->children,n); + break; + case 'A': + if (in_structure) goto fail; + n = tpl_node_new(parent); + n->type = TPL_TYPE_ARY; + DL_ADD(parent->children,n); + parent = n; + expect_lparen=1; + pidx = (tpl_pidx*)tpl_hook.malloc(sizeof(tpl_pidx)); + if (!pidx) fatal_oom(); + pidx->node = n; + pidx->next = NULL; + DL_ADD(((tpl_root_data*)(root->data))->pidx,pidx); + /* set up the A's tpl_atyp */ + n->data = (tpl_atyp*)tpl_hook.malloc(sizeof(tpl_atyp)); + if (!n->data) fatal_oom(); + ((tpl_atyp*)(n->data))->num = 0; + ((tpl_atyp*)(n->data))->sz = 0; + ((tpl_atyp*)(n->data))->bb = NULL; + ((tpl_atyp*)(n->data))->bbtail = NULL; + ((tpl_atyp*)(n->data))->cur = NULL; + if (n->parent->type == TPL_TYPE_ARY) + ((tpl_atyp*)(n->parent->data))->sz += sizeof(void*); + break; + case 'S': + if (in_structure) goto fail; + expect_lparen=1; + ordinal=1; /* index upcoming atoms in S(..) */ + in_structure=1+lparen_level; /* so we can tell where S fmt ends */ + struct_addr = (char*)va_arg(ap,void*); + break; + case '$': /* nested structure */ + if (!in_structure) goto fail; + expect_lparen=1; + in_nested_structure++; + break; + case ')': + lparen_level--; + if (lparen_level < 0) goto fail; + if (*(c-1) == '(') goto fail; + if (in_nested_structure) in_nested_structure--; + else if (in_structure && (in_structure-1 == lparen_level)) { + /* calculate delta between contiguous structures in array */ + struct_next = calc_field_addr(parent, struct_widest_node->type, + struct_addr, ordinal++); + inter_elt_len = struct_next - struct_addr; + in_structure=0; + } + else parent = parent->parent; /* rparen ends A() type, not S() type */ + break; + case '(': + if (!expect_lparen) goto fail; + expect_lparen=0; + lparen_level++; + break; + default: + tpl_hook.oops("unsupported option %c\n", *c); + goto fail; + } + c++; + } + if (lparen_level != 0) goto fail; + + /* copy the format string, save for convenience */ + ((tpl_root_data*)(root->data))->fmt = tpl_hook.malloc(strlen(fmt)+1); + if (((tpl_root_data*)(root->data))->fmt == NULL) + fatal_oom(); + memcpy(((tpl_root_data*)(root->data))->fmt,fmt,strlen(fmt)+1); + + return root; + +fail: + tpl_hook.oops("failed to parse %s\n", fmt); + tpl_free(root); + return NULL; +} + +static int tpl_unmap_file( tpl_mmap_rec *mr) { + + if ( munmap( mr->text, mr->text_sz ) == -1 ) { + tpl_hook.oops("Failed to munmap: %s\n", strerror(errno)); + } + close(mr->fd); + mr->text = NULL; + mr->text_sz = 0; + return 0; +} + +static void tpl_free_keep_map(tpl_node *r) { + int mmap_bits = (TPL_RDONLY|TPL_FILE); + int ufree_bits = (TPL_MEM|TPL_UFREE); + tpl_node *nxtc,*c; + int find_next_node=0,looking,i; + size_t sz; + + /* For mmap'd files, or for 'ufree' memory images , do appropriate release */ + if ((((tpl_root_data*)(r->data))->flags & mmap_bits) == mmap_bits) { + tpl_unmap_file( &((tpl_root_data*)(r->data))->mmap); + } else if ((((tpl_root_data*)(r->data))->flags & ufree_bits) == ufree_bits) { + tpl_hook.free( ((tpl_root_data*)(r->data))->mmap.text ); + } + + c = r->children; + if (c) { + while(c->type != TPL_TYPE_ROOT) { /* loop until we come back to root node */ + switch (c->type) { + case TPL_TYPE_BIN: + /* free any binary buffer hanging from tpl_bin */ + if ( *((tpl_bin**)(c->data)) ) { + if ( (*((tpl_bin**)(c->data)))->addr ) { + tpl_hook.free( (*((tpl_bin**)(c->data)))->addr ); + } + *((tpl_bin**)c->data) = NULL; /* reset tpl_bin */ + } + find_next_node=1; + break; + case TPL_TYPE_STR: + /* free any packed (copied) string */ + for(i=0; i < c->num; i++) { + char *str = ((char**)c->data)[i]; + if (str) { + tpl_hook.free(str); + ((char**)c->data)[i] = NULL; + } + } + find_next_node=1; + break; + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + case TPL_TYPE_POUND: + find_next_node=1; + break; + case TPL_TYPE_ARY: + c->ser_osz = 0; /* zero out the serialization output size */ + + sz = ((tpl_atyp*)(c->data))->sz; /* save sz to use below */ + tpl_free_atyp(c,c->data); + + /* make new atyp */ + c->data = (tpl_atyp*)tpl_hook.malloc(sizeof(tpl_atyp)); + if (!c->data) fatal_oom(); + ((tpl_atyp*)(c->data))->num = 0; + ((tpl_atyp*)(c->data))->sz = sz; /* restore bb datum sz */ + ((tpl_atyp*)(c->data))->bb = NULL; + ((tpl_atyp*)(c->data))->bbtail = NULL; + ((tpl_atyp*)(c->data))->cur = NULL; + + c = c->children; + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + + if (find_next_node) { + find_next_node=0; + looking=1; + while(looking) { + if (c->next) { + nxtc=c->next; + c=nxtc; + looking=0; + } else { + if (c->type == TPL_TYPE_ROOT) break; /* root node */ + else { + nxtc=c->parent; + c=nxtc; + } + } + } + } + } + } + + ((tpl_root_data*)(r->data))->flags = 0; /* reset flags */ +} + +TPL_API void tpl_free(tpl_node *r) { + int mmap_bits = (TPL_RDONLY|TPL_FILE); + int ufree_bits = (TPL_MEM|TPL_UFREE); + tpl_node *nxtc,*c; + int find_next_node=0,looking,i; + tpl_pidx *pidx,*pidx_nxt; + + /* For mmap'd files, or for 'ufree' memory images , do appropriate release */ + if ((((tpl_root_data*)(r->data))->flags & mmap_bits) == mmap_bits) { + tpl_unmap_file( &((tpl_root_data*)(r->data))->mmap); + } else if ((((tpl_root_data*)(r->data))->flags & ufree_bits) == ufree_bits) { + tpl_hook.free( ((tpl_root_data*)(r->data))->mmap.text ); + } + + c = r->children; + if (c) { + while(c->type != TPL_TYPE_ROOT) { /* loop until we come back to root node */ + switch (c->type) { + case TPL_TYPE_BIN: + /* free any binary buffer hanging from tpl_bin */ + if ( *((tpl_bin**)(c->data)) ) { + if ( (*((tpl_bin**)(c->data)))->sz != 0 ) { + tpl_hook.free( (*((tpl_bin**)(c->data)))->addr ); + } + tpl_hook.free(*((tpl_bin**)c->data)); /* free tpl_bin */ + } + tpl_hook.free(c->data); /* free tpl_bin* */ + find_next_node=1; + break; + case TPL_TYPE_STR: + /* free any packed (copied) string */ + for(i=0; i < c->num; i++) { + char *str = ((char**)c->data)[i]; + if (str) { + tpl_hook.free(str); + ((char**)c->data)[i] = NULL; + } + } + tpl_hook.free(c->data); + find_next_node=1; + break; + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + case TPL_TYPE_POUND: + tpl_hook.free(c->data); + find_next_node=1; + break; + case TPL_TYPE_ARY: + tpl_free_atyp(c,c->data); + if (c->children) c = c->children; /* normal case */ + else find_next_node=1; /* edge case, handle bad format A() */ + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + + if (find_next_node) { + find_next_node=0; + looking=1; + while(looking) { + if (c->next) { + nxtc=c->next; + tpl_hook.free(c); + c=nxtc; + looking=0; + } else { + if (c->type == TPL_TYPE_ROOT) break; /* root node */ + else { + nxtc=c->parent; + tpl_hook.free(c); + c=nxtc; + } + } + } + } + } + } + + /* free root */ + for(pidx=((tpl_root_data*)(r->data))->pidx; pidx; pidx=pidx_nxt) { + pidx_nxt = pidx->next; + tpl_hook.free(pidx); + } + tpl_hook.free(((tpl_root_data*)(r->data))->fmt); + if (((tpl_root_data*)(r->data))->num_fxlens > 0) { + tpl_hook.free(((tpl_root_data*)(r->data))->fxlens); + } + tpl_hook.free(r->data); /* tpl_root_data */ + tpl_hook.free(r); +} + + +/* Find the i'th packable ('A' node) */ +static tpl_node *tpl_find_i(tpl_node *n, int i) { + int j=0; + tpl_pidx *pidx; + if (n->type != TPL_TYPE_ROOT) return NULL; + if (i == 0) return n; /* packable 0 is root */ + for(pidx=((tpl_root_data*)(n->data))->pidx; pidx; pidx=pidx->next) { + if (++j == i) return pidx->node; + } + return NULL; +} + +static void *tpl_cpv(void *datav, void *data, size_t sz) { + if (sz>0) memcpy(datav,data,sz); + return (void*)((uintptr_t)datav + sz); +} + +static void *tpl_extend_backbone(tpl_node *n) { + tpl_backbone *bb; + bb = (tpl_backbone*)tpl_hook.malloc(sizeof(tpl_backbone) + + ((tpl_atyp*)(n->data))->sz ); /* datum hangs on coattails of bb */ + if (!bb) fatal_oom(); +#if __STDC_VERSION__ < 199901 + bb->data = (char*)((uintptr_t)bb + sizeof(tpl_backbone)); +#endif + memset(bb->data,0,((tpl_atyp*)(n->data))->sz); + bb->next = NULL; + /* Add the new backbone to the tail, also setting head if necessary */ + if (((tpl_atyp*)(n->data))->bb == NULL) { + ((tpl_atyp*)(n->data))->bb = bb; + ((tpl_atyp*)(n->data))->bbtail = bb; + } else { + ((tpl_atyp*)(n->data))->bbtail->next = bb; + ((tpl_atyp*)(n->data))->bbtail = bb; + } + + ((tpl_atyp*)(n->data))->num++; + return bb->data; +} + +/* Get the format string corresponding to a given tpl (root node) */ +static char *tpl_fmt(tpl_node *r) { + return ((tpl_root_data*)(r->data))->fmt; +} + +/* Get the fmt # lengths as a contiguous buffer of ints (length num_fxlens) */ +static int *tpl_fxlens(tpl_node *r, int *num_fxlens) { + *num_fxlens = ((tpl_root_data*)(r->data))->num_fxlens; + return ((tpl_root_data*)(r->data))->fxlens; +} + +/* called when serializing an 'A' type node into a buffer which has + * already been set up with the proper space. The backbone is walked + * which was obtained from the tpl_atyp header passed in. + */ +static void *tpl_dump_atyp(tpl_node *n, tpl_atyp* at, void *dv) { + tpl_backbone *bb; + tpl_node *c; + void *datav; + uint32_t slen; + tpl_bin *binp; + char *strp; + tpl_atyp *atypp; + tpl_pound_data *pd; + int i; + size_t itermax; + + /* handle 'A' nodes */ + dv = tpl_cpv(dv,&at->num,sizeof(uint32_t)); /* array len */ + for(bb=at->bb; bb; bb=bb->next) { + datav = bb->data; + c=n->children; + while(c) { + switch (c->type) { + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + dv = tpl_cpv(dv,datav,tpl_types[c->type].sz * c->num); + datav = (void*)((uintptr_t)datav + tpl_types[c->type].sz * c->num); + break; + case TPL_TYPE_BIN: + /* dump the buffer length followed by the buffer */ + memcpy(&binp,datav,sizeof(tpl_bin*)); /* cp to aligned */ + slen = binp->sz; + dv = tpl_cpv(dv,&slen,sizeof(uint32_t)); + dv = tpl_cpv(dv,binp->addr,slen); + datav = (void*)((uintptr_t)datav + sizeof(tpl_bin*)); + break; + case TPL_TYPE_STR: + /* dump the string length followed by the string */ + for(i=0; i < c->num; i++) { + memcpy(&strp,datav,sizeof(char*)); /* cp to aligned */ + slen = strp ? (strlen(strp)+1) : 0; + dv = tpl_cpv(dv,&slen,sizeof(uint32_t)); + if (slen > 1) dv = tpl_cpv(dv,strp,slen-1); + datav = (void*)((uintptr_t)datav + sizeof(char*)); + } + break; + case TPL_TYPE_ARY: + memcpy(&atypp,datav,sizeof(tpl_atyp*)); /* cp to aligned */ + dv = tpl_dump_atyp(c,atypp,dv); + datav = (void*)((uintptr_t)datav + sizeof(void*)); + break; + case TPL_TYPE_POUND: + /* iterate over the preceding nodes */ + pd = (tpl_pound_data*)c->data; + itermax = c->num; + if (++(pd->iternum) < itermax) { + c = pd->iter_start_node; + continue; + } else { /* loop complete. */ + pd->iternum = 0; + } + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + c=c->next; + } + } + return dv; +} + +/* figure the serialization output size needed for tpl whose root is n*/ +static size_t tpl_ser_osz(tpl_node *n) { + tpl_node *c, *np; + size_t sz, itermax; + tpl_bin *binp; + char *strp; + tpl_pound_data *pd; + int i; + + /* handle the root node ONLY (subtree's ser_osz have been bubbled-up) */ + if (n->type != TPL_TYPE_ROOT) { + tpl_hook.fatal("internal error: tpl_ser_osz on non-root node\n"); + } + + sz = n->ser_osz; /* start with fixed overhead, already stored */ + c=n->children; + while (c) { + switch (c->type) { + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + sz += tpl_types[c->type].sz * c->num; + break; + case TPL_TYPE_BIN: + sz += sizeof(uint32_t); /* binary buf len */ + memcpy(&binp,c->data,sizeof(tpl_bin*)); /* cp to aligned */ + sz += binp->sz; + break; + case TPL_TYPE_STR: + for(i=0; i < c->num; i++) { + sz += sizeof(uint32_t); /* string len */ + memcpy(&strp,&((char**)c->data)[i],sizeof(char*)); /* cp to aligned */ + sz += strp ? strlen(strp) : 0; + } + break; + case TPL_TYPE_ARY: + sz += sizeof(uint32_t); /* array len */ + sz += c->ser_osz; /* bubbled-up child array ser_osz */ + break; + case TPL_TYPE_POUND: + /* iterate over the preceding nodes */ + itermax = c->num; + pd = (tpl_pound_data*)c->data; + if (++(pd->iternum) < itermax) { + for(np=pd->iter_start_node; np != c; np = np->next) { + np->data = (char*)(np->data) + + (tpl_types[np->type].sz * np->num); + } + c = pd->iter_start_node; + continue; + } else { /* loop complete. */ + pd->iternum = 0; + for(np=pd->iter_start_node; np != c; np = np->next) { + np->data = (char*)(np->data) - ((itermax-1) * + tpl_types[np->type].sz * + np->num); + } + } + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + c=c->next; + } + return sz; +} + + +TPL_API int tpl_dump(tpl_node *r, int mode, ...) { + va_list ap; + char *filename, *bufv; + void **addr_out,*buf, *pa_addr; + int fd,rc=0; + size_t sz,*sz_out, pa_sz; + + if (((tpl_root_data*)(r->data))->flags & TPL_RDONLY) { /* unusual */ + tpl_hook.oops("error: tpl_dump called for a loaded tpl\n"); + return -1; + } + + sz = tpl_ser_osz(r); /* compute the size needed to serialize */ + + va_start(ap,mode); + if (mode & TPL_FILE) { + filename = va_arg(ap,char*); + fd = tpl_mmap_output_file(filename, sz, &buf); + if (fd == -1) rc = -1; + else { + rc = tpl_dump_to_mem(r,buf,sz); + if (msync(buf,sz,MS_SYNC) == -1) { + tpl_hook.oops("msync failed on fd %d: %s\n", fd, strerror(errno)); + } + if (munmap(buf, sz) == -1) { + tpl_hook.oops("munmap failed on fd %d: %s\n", fd, strerror(errno)); + } + close(fd); + } + } else if (mode & TPL_FD) { + fd = va_arg(ap, int); + if ( (buf = tpl_hook.malloc(sz)) == NULL) fatal_oom(); + tpl_dump_to_mem(r,buf,sz); + bufv = buf; + do { + rc = write(fd,bufv,sz); + if (rc > 0) { + sz -= rc; + bufv += rc; + } else if (rc == -1) { + if (errno == EINTR || errno == EAGAIN) continue; + tpl_hook.oops("error writing to fd %d: %s\n", fd, strerror(errno)); + free(buf); + return -1; + } + } while (sz > 0); + free(buf); + rc = 0; + } else if (mode & TPL_MEM) { + if (mode & TPL_PREALLOCD) { /* caller allocated */ + pa_addr = (void*)va_arg(ap, void*); + pa_sz = va_arg(ap, size_t); + if (pa_sz < sz) { + tpl_hook.oops("tpl_dump: buffer too small, need %d bytes\n", sz); + return -1; + } + rc=tpl_dump_to_mem(r,pa_addr,sz); + } else { /* we allocate */ + addr_out = (void**)va_arg(ap, void*); + sz_out = va_arg(ap, size_t*); + if ( (buf = tpl_hook.malloc(sz)) == NULL) fatal_oom(); + *sz_out = sz; + *addr_out = buf; + rc=tpl_dump_to_mem(r,buf,sz); + } + } else if (mode & TPL_GETSIZE) { + sz_out = va_arg(ap, size_t*); + *sz_out = sz; + } else { + tpl_hook.oops("unsupported tpl_dump mode %d\n", mode); + rc=-1; + } + va_end(ap); + return rc; +} + +/* This function expects the caller to have set up a memory buffer of + * adequate size to hold the serialized tpl. The sz parameter must be + * the result of tpl_ser_osz(r). + */ +static int tpl_dump_to_mem(tpl_node *r,void *addr,size_t sz) { + uint32_t slen, sz32; + int *fxlens, num_fxlens, i; + void *dv; + char *fmt,flags; + tpl_node *c, *np; + tpl_pound_data *pd; + size_t itermax; + + fmt = tpl_fmt(r); + flags = 0; + if (tpl_cpu_bigendian()) flags |= TPL_FL_BIGENDIAN; + if (strchr(fmt,'s')) flags |= TPL_FL_NULLSTRINGS; + sz32 = sz; + + dv = addr; + dv = tpl_cpv(dv,TPL_MAGIC,3); /* copy tpl magic prefix */ + dv = tpl_cpv(dv,&flags,1); /* copy flags byte */ + dv = tpl_cpv(dv,&sz32,sizeof(uint32_t));/* overall length (inclusive) */ + dv = tpl_cpv(dv,fmt,strlen(fmt)+1); /* copy format with NUL-term */ + fxlens = tpl_fxlens(r,&num_fxlens); + dv = tpl_cpv(dv,fxlens,num_fxlens*sizeof(uint32_t));/* fmt # lengths */ + + /* serialize the tpl content, iterating over direct children of root */ + c = r->children; + while (c) { + switch (c->type) { + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + dv = tpl_cpv(dv,c->data,tpl_types[c->type].sz * c->num); + break; + case TPL_TYPE_BIN: + slen = (*(tpl_bin**)(c->data))->sz; + dv = tpl_cpv(dv,&slen,sizeof(uint32_t)); /* buffer len */ + dv = tpl_cpv(dv,(*(tpl_bin**)(c->data))->addr,slen); /* buf */ + break; + case TPL_TYPE_STR: + for(i=0; i < c->num; i++) { + char *str = ((char**)c->data)[i]; + slen = str ? strlen(str)+1 : 0; + dv = tpl_cpv(dv,&slen,sizeof(uint32_t)); /* string len */ + if (slen>1) dv = tpl_cpv(dv,str,slen-1); /*string*/ + } + break; + case TPL_TYPE_ARY: + dv = tpl_dump_atyp(c,(tpl_atyp*)c->data,dv); + break; + case TPL_TYPE_POUND: + pd = (tpl_pound_data*)c->data; + itermax = c->num; + if (++(pd->iternum) < itermax) { + + /* in start or midst of loop. advance data pointers. */ + for(np=pd->iter_start_node; np != c; np = np->next) { + np->data = (char*)(np->data) + + (tpl_types[np->type].sz * np->num); + } + /* do next iteration */ + c = pd->iter_start_node; + continue; + + } else { /* loop complete. */ + + /* reset iteration index and addr/data pointers. */ + pd->iternum = 0; + for(np=pd->iter_start_node; np != c; np = np->next) { + np->data = (char*)(np->data) - ((itermax-1) * + tpl_types[np->type].sz * + np->num); + } + + } + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + c = c->next; + } + + return 0; +} + +static int tpl_cpu_bigendian() { + unsigned i = 1; + char *c; + c = (char*)&i; + return (c[0] == 1 ? 0 : 1); +} + + +/* + * algorithm for sanity-checking a tpl image: + * scan the tpl whilst not exceeding the buffer size (bufsz) , + * formulating a calculated (expected) size of the tpl based + * on walking its data. When calcsize has been calculated it + * should exactly match the buffer size (bufsz) and the internal + * recorded size (intlsz) + */ +static int tpl_sanity(tpl_node *r, int excess_ok) { + uint32_t intlsz; + int found_nul=0,rc, octothorpes=0, num_fxlens, *fxlens, flen; + void *d, *dv; + char intlflags, *fmt, c, *mapfmt; + size_t bufsz, serlen; + + d = ((tpl_root_data*)(r->data))->mmap.text; + bufsz = ((tpl_root_data*)(r->data))->mmap.text_sz; + + dv = d; + if (bufsz < (4 + sizeof(uint32_t) + 1)) return ERR_NOT_MINSIZE; /* min sz: magic+flags+len+nul */ + if (memcmp(dv,TPL_MAGIC, 3) != 0) return ERR_MAGIC_MISMATCH; /* missing tpl magic prefix */ + if (tpl_needs_endian_swap(dv)) ((tpl_root_data*)(r->data))->flags |= TPL_XENDIAN; + dv = (void*)((uintptr_t)dv + 3); + memcpy(&intlflags,dv,sizeof(char)); /* extract flags */ + if (intlflags & ~TPL_SUPPORTED_BITFLAGS) return ERR_UNSUPPORTED_FLAGS; + /* TPL1.3 stores strings with a "length+1" prefix to discern NULL strings from + empty strings from non-empty strings; TPL1.2 only handled the latter two. + So we need to be mindful of which string format we're reading from. */ + if (!(intlflags & TPL_FL_NULLSTRINGS)) { + ((tpl_root_data*)(r->data))->flags |= TPL_OLD_STRING_FMT; + } + dv = (void*)((uintptr_t)dv + 1); + memcpy(&intlsz,dv,sizeof(uint32_t)); /* extract internal size */ + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) tpl_byteswap(&intlsz, sizeof(uint32_t)); + if (!excess_ok && (intlsz != bufsz)) return ERR_INCONSISTENT_SZ; /* inconsisent buffer/internal size */ + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + + /* dv points to the start of the format string. Look for nul w/in buf sz */ + fmt = (char*)dv; + while ((uintptr_t)dv-(uintptr_t)d < bufsz && !found_nul) { + if ( (c = *(char*)dv) != '\0') { + if (strchr(tpl_fmt_chars,c) == NULL) + return ERR_FMT_INVALID; /* invalid char in format string */ + if ( (c = *(char*)dv) == '#') octothorpes++; + dv = (void*)((uintptr_t)dv + 1); + } + else found_nul = 1; + } + if (!found_nul) return ERR_FMT_MISSING_NUL; /* runaway format string */ + dv = (void*)((uintptr_t)dv + 1); /* advance to octothorpe lengths buffer */ + + /* compare the map format to the format of this tpl image */ + mapfmt = tpl_fmt(r); + rc = strcmp(mapfmt,fmt); + if (rc != 0) return ERR_FMT_MISMATCH; + + /* compare octothorpe lengths in image to the mapped values */ + if ((((uintptr_t)dv + (octothorpes * 4)) - (uintptr_t)d) > bufsz) return ERR_INCONSISTENT_SZ4; + fxlens = tpl_fxlens(r,&num_fxlens); /* mapped fxlens */ + while(num_fxlens--) { + memcpy(&flen,dv,sizeof(uint32_t)); /* stored flen */ + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) tpl_byteswap(&flen, sizeof(uint32_t)); + if (flen != *fxlens) return ERR_FLEN_MISMATCH; + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + fxlens++; + } + + /* dv now points to beginning of data */ + rc = tpl_serlen(r,r,dv,&serlen); /* get computed serlen of data part */ + if (rc == -1) return ERR_INCONSISTENT_SZ2; /* internal inconsistency in tpl image */ + serlen += ((uintptr_t)dv - (uintptr_t)d); /* add back serlen of preamble part */ + if (excess_ok && (bufsz < serlen)) return ERR_INCONSISTENT_SZ3; + if (!excess_ok && (serlen != bufsz)) return ERR_INCONSISTENT_SZ3; /* buffer/internal sz exceeds serlen */ + return 0; +} + +static void *tpl_find_data_start(void *d) { + int octothorpes=0; + d = (void*)((uintptr_t)d + 4); /* skip TPL_MAGIC and flags byte */ + d = (void*)((uintptr_t)d + 4); /* skip int32 overall len */ + while(*(char*)d != '\0') { + if (*(char*)d == '#') octothorpes++; + d = (void*)((uintptr_t)d + 1); + } + d = (void*)((uintptr_t)d + 1); /* skip NUL */ + d = (void*)((uintptr_t)d + (octothorpes * sizeof(uint32_t))); /* skip # array lens */ + return d; +} + +static int tpl_needs_endian_swap(void *d) { + char *c; + int cpu_is_bigendian; + c = (char*)d; + cpu_is_bigendian = tpl_cpu_bigendian(); + return ((c[3] & TPL_FL_BIGENDIAN) == cpu_is_bigendian) ? 0 : 1; +} + +static size_t tpl_size_for(char c) { + int i; + for(i=0; i < sizeof(tpl_types)/sizeof(tpl_types[0]); i++) { + if (tpl_types[i].c == c) return tpl_types[i].sz; + } + return 0; +} + +TPL_API char* tpl_peek(int mode, ...) { + va_list ap; + int xendian=0,found_nul=0,old_string_format=0; + char *filename=NULL, *datapeek_f=NULL, *datapeek_c, *datapeek_s; + void *addr=NULL, *dv, *datapeek_p=NULL; + size_t sz=0, fmt_len, first_atom, num_fxlens=0; + uint32_t datapeek_ssz, datapeek_csz, datapeek_flen; + tpl_mmap_rec mr = {0,NULL,0}; + char *fmt,*fmt_cpy=NULL,c; + uint32_t intlsz, **fxlens=NULL, *num_fxlens_out=NULL, *fxlensv; + + va_start(ap,mode); + if ((mode & TPL_FXLENS) && (mode & TPL_DATAPEEK)) { + tpl_hook.oops("TPL_FXLENS and TPL_DATAPEEK mutually exclusive\n"); + goto fail; + } + if (mode & TPL_FILE) filename = va_arg(ap,char *); + else if (mode & TPL_MEM) { + addr = va_arg(ap,void *); + sz = va_arg(ap,size_t); + } else { + tpl_hook.oops("unsupported tpl_peek mode %d\n", mode); + goto fail; + } + if (mode & TPL_DATAPEEK) { + datapeek_f = va_arg(ap, char*); + } + if (mode & TPL_FXLENS) { + num_fxlens_out = va_arg(ap,uint32_t *); + fxlens = va_arg(ap,uint32_t **); + *num_fxlens_out = 0; + *fxlens = NULL; + } + + if (mode & TPL_FILE) { + if (tpl_mmap_file(filename, &mr) != 0) { + tpl_hook.oops("tpl_peek failed for file %s\n", filename); + goto fail; + } + addr = mr.text; + sz = mr.text_sz; + } + + dv = addr; + if (sz < (4 + sizeof(uint32_t) + 1)) goto fail; /* min sz */ + if (memcmp(dv,TPL_MAGIC, 3) != 0) goto fail; /* missing tpl magic prefix */ + if (tpl_needs_endian_swap(dv)) xendian=1; + if ((((char*)dv)[3] & TPL_FL_NULLSTRINGS)==0) old_string_format=1; + dv = (void*)((uintptr_t)dv + 4); + memcpy(&intlsz,dv,sizeof(uint32_t)); /* extract internal size */ + if (xendian) tpl_byteswap(&intlsz, sizeof(uint32_t)); + if (intlsz != sz) goto fail; /* inconsisent buffer/internal size */ + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + + /* dv points to the start of the format string. Look for nul w/in buf sz */ + fmt = (char*)dv; + while ((uintptr_t)dv-(uintptr_t)addr < sz && !found_nul) { + if ( (c = *(char*)dv) == '\0') { + found_nul = 1; + } else if (c == '#') { + num_fxlens++; + } + dv = (void*)((uintptr_t)dv + 1); + } + if (!found_nul) goto fail; /* runaway format string */ + fmt_len = (char*)dv - fmt; /* include space for \0 */ + fmt_cpy = tpl_hook.malloc(fmt_len); + if (fmt_cpy == NULL) { + fatal_oom(); + } + memcpy(fmt_cpy, fmt, fmt_len); + + /* retrieve the octothorpic lengths if requested */ + if (num_fxlens > 0) { + if (sz < ((uintptr_t)dv + (num_fxlens * sizeof(uint32_t)) - (uintptr_t)addr)) { + goto fail; + } + } + if ((mode & TPL_FXLENS) && (num_fxlens > 0)) { + *fxlens = tpl_hook.malloc(num_fxlens * sizeof(uint32_t)); + if (*fxlens == NULL) tpl_hook.fatal("out of memory"); + *num_fxlens_out = num_fxlens; + fxlensv = *fxlens; + while(num_fxlens--) { + memcpy(fxlensv,dv,sizeof(uint32_t)); + if (xendian) tpl_byteswap(fxlensv, sizeof(uint32_t)); + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + fxlensv++; + } + } + /* if caller requested, peek into the specified data elements */ + if (mode & TPL_DATAPEEK) { + + first_atom = strspn(fmt, "S()"); /* skip any leading S() */ + + datapeek_flen = strlen(datapeek_f); + if (strspn(datapeek_f, tpl_datapeek_ok_chars) < datapeek_flen) { + tpl_hook.oops("invalid TPL_DATAPEEK format: %s\n", datapeek_f); + tpl_hook.free(fmt_cpy); fmt_cpy = NULL; /* fail */ + goto fail; + } + + if (strncmp( &fmt[first_atom], datapeek_f, datapeek_flen) != 0) { + tpl_hook.oops("TPL_DATAPEEK format mismatches tpl iamge\n"); + tpl_hook.free(fmt_cpy); fmt_cpy = NULL; /* fail */ + goto fail; + } + + /* advance to data start, then copy out requested elements */ + dv = (void*)((uintptr_t)dv + (num_fxlens * sizeof(uint32_t))); + for(datapeek_c = datapeek_f; *datapeek_c != '\0'; datapeek_c++) { + datapeek_p = va_arg(ap, void*); + if (*datapeek_c == 's') { /* special handling for strings */ + if ((uintptr_t)dv-(uintptr_t)addr + sizeof(uint32_t) > sz) { + tpl_hook.oops("tpl_peek: tpl has insufficient length\n"); + tpl_hook.free(fmt_cpy); fmt_cpy = NULL; /* fail */ + goto fail; + } + memcpy(&datapeek_ssz,dv,sizeof(uint32_t)); /* get slen */ + if (xendian) tpl_byteswap(&datapeek_ssz, sizeof(uint32_t)); + if (old_string_format) datapeek_ssz++; + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); /* adv. to str */ + if (datapeek_ssz == 0) datapeek_s = NULL; + else { + if ((uintptr_t)dv-(uintptr_t)addr + datapeek_ssz-1 > sz) { + tpl_hook.oops("tpl_peek: tpl has insufficient length\n"); + tpl_hook.free(fmt_cpy); fmt_cpy = NULL; /* fail */ + goto fail; + } + datapeek_s = tpl_hook.malloc(datapeek_ssz); + if (datapeek_s == NULL) fatal_oom(); + memcpy(datapeek_s, dv, datapeek_ssz-1); + datapeek_s[datapeek_ssz-1] = '\0'; + dv = (void*)((uintptr_t)dv + datapeek_ssz-1); + } + *(char**)datapeek_p = datapeek_s; + } else { + datapeek_csz = tpl_size_for(*datapeek_c); + if ((uintptr_t)dv-(uintptr_t)addr + datapeek_csz > sz) { + tpl_hook.oops("tpl_peek: tpl has insufficient length\n"); + tpl_hook.free(fmt_cpy); fmt_cpy = NULL; /* fail */ + goto fail; + } + memcpy(datapeek_p, dv, datapeek_csz); + if (xendian) tpl_byteswap(datapeek_p, datapeek_csz); + dv = (void*)((uintptr_t)dv + datapeek_csz); + } + } + } + +fail: + va_end(ap); + if ((mode & TPL_FILE) && mr.text != NULL) tpl_unmap_file( &mr ); + return fmt_cpy; +} + +/* tpl_jot(TPL_FILE, "file.tpl", "si", &s, &i); */ +/* tpl_jot(TPL_MEM, &buf, &sz, "si", &s, &i); */ +/* tpl_jot(TPL_FD, fd, "si", &s, &i); */ +TPL_API int tpl_jot(int mode, ...) { + va_list ap; + char *filename, *fmt; + size_t *sz; + int fd, rc=0; + void **buf; + tpl_node *tn; + + va_start(ap,mode); + if (mode & TPL_FILE) { + filename = va_arg(ap,char*); + fmt = va_arg(ap,char*); + tn = tpl_map_va(fmt, ap); + if (tn == NULL) { rc=-1; goto fail;} + tpl_pack(tn, 0); + rc = tpl_dump(tn, TPL_FILE, filename); + tpl_free(tn); + } else if (mode & TPL_MEM) { + buf = va_arg(ap,void*); + sz = va_arg(ap,size_t*); + fmt = va_arg(ap,char*); + tn = tpl_map_va(fmt,ap); + if (tn == NULL) { rc=-1; goto fail;} + tpl_pack(tn,0); + rc = tpl_dump(tn, TPL_MEM, buf, sz); + tpl_free(tn); + } else if (mode & TPL_FD) { + fd = va_arg(ap,int); + fmt = va_arg(ap,char*); + tn = tpl_map_va(fmt,ap); + if (tn == NULL) { rc=-1; goto fail;} + tpl_pack(tn,0); + rc = tpl_dump(tn, TPL_FD, fd); + tpl_free(tn); + } else { + tpl_hook.fatal("invalid tpl_jot mode\n"); + } + +fail: + va_end(ap); + return rc; +} + +TPL_API int tpl_load(tpl_node *r, int mode, ...) { + va_list ap; + int rc=0,fd=0; + char *filename=NULL; + void *addr; + size_t sz; + + va_start(ap,mode); + if (mode & TPL_FILE) filename = va_arg(ap,char *); + else if (mode & TPL_MEM) { + addr = va_arg(ap,void *); + sz = va_arg(ap,size_t); + } else if (mode & TPL_FD) { + fd = va_arg(ap,int); + } else { + tpl_hook.oops("unsupported tpl_load mode %d\n", mode); + return -1; + } + va_end(ap); + + if (r->type != TPL_TYPE_ROOT) { + tpl_hook.oops("error: tpl_load to non-root node\n"); + return -1; + } + if (((tpl_root_data*)(r->data))->flags & (TPL_WRONLY|TPL_RDONLY)) { + /* already packed or loaded, so reset it as if newly mapped */ + tpl_free_keep_map(r); + } + if (mode & TPL_FILE) { + if (tpl_mmap_file(filename, &((tpl_root_data*)(r->data))->mmap) != 0) { + tpl_hook.oops("tpl_load failed for file %s\n", filename); + return -1; + } + if ( (rc = tpl_sanity(r, (mode & TPL_EXCESS_OK))) != 0) { + if (rc == ERR_FMT_MISMATCH) { + tpl_hook.oops("%s: format signature mismatch\n", filename); + } else if (rc == ERR_FLEN_MISMATCH) { + tpl_hook.oops("%s: array lengths mismatch\n", filename); + } else { + tpl_hook.oops("%s: not a valid tpl file\n", filename); + } + tpl_unmap_file( &((tpl_root_data*)(r->data))->mmap ); + return -1; + } + ((tpl_root_data*)(r->data))->flags = (TPL_FILE | TPL_RDONLY); + } else if (mode & TPL_MEM) { + ((tpl_root_data*)(r->data))->mmap.text = addr; + ((tpl_root_data*)(r->data))->mmap.text_sz = sz; + if ( (rc = tpl_sanity(r, (mode & TPL_EXCESS_OK))) != 0) { + if (rc == ERR_FMT_MISMATCH) { + tpl_hook.oops("format signature mismatch\n"); + } else { + tpl_hook.oops("not a valid tpl file\n"); + } + return -1; + } + ((tpl_root_data*)(r->data))->flags = (TPL_MEM | TPL_RDONLY); + if (mode & TPL_UFREE) ((tpl_root_data*)(r->data))->flags |= TPL_UFREE; + } else if (mode & TPL_FD) { + /* if fd read succeeds, resulting mem img is used for load */ + if (tpl_gather(TPL_GATHER_BLOCKING,fd,&addr,&sz) > 0) { + return tpl_load(r, TPL_MEM|TPL_UFREE, addr, sz); + } else return -1; + } else { + tpl_hook.oops("invalid tpl_load mode %d\n", mode); + return -1; + } + /* this applies to TPL_MEM or TPL_FILE */ + if (tpl_needs_endian_swap(((tpl_root_data*)(r->data))->mmap.text)) + ((tpl_root_data*)(r->data))->flags |= TPL_XENDIAN; + tpl_unpackA0(r); /* prepare root A nodes for use */ + return 0; +} + +TPL_API int tpl_Alen(tpl_node *r, int i) { + tpl_node *n; + + n = tpl_find_i(r,i); + if (n == NULL) { + tpl_hook.oops("invalid index %d to tpl_unpack\n", i); + return -1; + } + if (n->type != TPL_TYPE_ARY) return -1; + return ((tpl_atyp*)(n->data))->num; +} + +static void tpl_free_atyp(tpl_node *n, tpl_atyp *atyp) { + tpl_backbone *bb,*bbnxt; + tpl_node *c; + void *dv; + tpl_bin *binp; + tpl_atyp *atypp; + char *strp; + size_t itermax; + tpl_pound_data *pd; + int i; + + bb = atyp->bb; + while (bb) { + bbnxt = bb->next; + dv = bb->data; + c=n->children; + while (c) { + switch (c->type) { + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz*c->num); + break; + case TPL_TYPE_BIN: + memcpy(&binp,dv,sizeof(tpl_bin*)); /* cp to aligned */ + if (binp->addr) tpl_hook.free( binp->addr ); /* free buf */ + tpl_hook.free(binp); /* free tpl_bin */ + dv = (void*)((uintptr_t)dv + sizeof(tpl_bin*)); + break; + case TPL_TYPE_STR: + for(i=0; i < c->num; i++) { + memcpy(&strp,dv,sizeof(char*)); /* cp to aligned */ + if (strp) tpl_hook.free(strp); /* free string */ + dv = (void*)((uintptr_t)dv + sizeof(char*)); + } + break; + case TPL_TYPE_POUND: + /* iterate over the preceding nodes */ + itermax = c->num; + pd = (tpl_pound_data*)c->data; + if (++(pd->iternum) < itermax) { + c = pd->iter_start_node; + continue; + } else { /* loop complete. */ + pd->iternum = 0; + } + break; + case TPL_TYPE_ARY: + memcpy(&atypp,dv,sizeof(tpl_atyp*)); /* cp to aligned */ + tpl_free_atyp(c,atypp); /* free atyp */ + dv = (void*)((uintptr_t)dv + sizeof(void*)); + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + c=c->next; + } + tpl_hook.free(bb); + bb = bbnxt; + } + tpl_hook.free(atyp); +} + +/* determine (by walking) byte length of serialized r/A node at address dv + * returns 0 on success, or -1 if the tpl isn't trustworthy (fails consistency) + */ +static int tpl_serlen(tpl_node *r, tpl_node *n, void *dv, size_t *serlen) { + uint32_t slen; + int num,fidx; + tpl_node *c; + size_t len=0, alen, buf_past, itermax; + tpl_pound_data *pd; + + buf_past = ((uintptr_t)((tpl_root_data*)(r->data))->mmap.text + + ((tpl_root_data*)(r->data))->mmap.text_sz); + + if (n->type == TPL_TYPE_ROOT) num = 1; + else if (n->type == TPL_TYPE_ARY) { + if ((uintptr_t)dv + sizeof(uint32_t) > buf_past) return -1; + memcpy(&num,dv,sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) + tpl_byteswap(&num, sizeof(uint32_t)); + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + len += sizeof(uint32_t); + } else tpl_hook.fatal("internal error in tpl_serlen\n"); + + while (num-- > 0) { + c=n->children; + while (c) { + switch (c->type) { + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + for(fidx=0; fidx < c->num; fidx++) { /* octothorpe support */ + if ((uintptr_t)dv + tpl_types[c->type].sz > buf_past) return -1; + dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz); + len += tpl_types[c->type].sz; + } + break; + case TPL_TYPE_BIN: + len += sizeof(uint32_t); + if ((uintptr_t)dv + sizeof(uint32_t) > buf_past) return -1; + memcpy(&slen,dv,sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) + tpl_byteswap(&slen, sizeof(uint32_t)); + len += slen; + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + if ((uintptr_t)dv + slen > buf_past) return -1; + dv = (void*)((uintptr_t)dv + slen); + break; + case TPL_TYPE_STR: + for(fidx=0; fidx < c->num; fidx++) { /* octothorpe support */ + len += sizeof(uint32_t); + if ((uintptr_t)dv + sizeof(uint32_t) > buf_past) return -1; + memcpy(&slen,dv,sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) + tpl_byteswap(&slen, sizeof(uint32_t)); + if (!(((tpl_root_data*)(r->data))->flags & TPL_OLD_STRING_FMT)) + slen = (slen>1) ? (slen-1) : 0; + len += slen; + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + if ((uintptr_t)dv + slen > buf_past) return -1; + dv = (void*)((uintptr_t)dv + slen); + } + break; + case TPL_TYPE_ARY: + if ( tpl_serlen(r,c,dv, &alen) == -1) return -1; + dv = (void*)((uintptr_t)dv + alen); + len += alen; + break; + case TPL_TYPE_POUND: + /* iterate over the preceding nodes */ + itermax = c->num; + pd = (tpl_pound_data*)c->data; + if (++(pd->iternum) < itermax) { + c = pd->iter_start_node; + continue; + } else { /* loop complete. */ + pd->iternum = 0; + } + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + c=c->next; + } + } + *serlen = len; + return 0; +} + +static int tpl_mmap_output_file(char *filename, size_t sz, void **text_out) { + void *text; + int fd,perms; + +#ifndef _WIN32 + perms = S_IRUSR|S_IWUSR|S_IWGRP|S_IRGRP|S_IROTH; /* ug+w o+r */ + fd=open(filename,O_CREAT|O_TRUNC|O_RDWR,perms); +#else + perms = _S_IWRITE; + fd=_open(filename,_O_CREAT|_O_TRUNC|_O_RDWR,perms); +#endif + + if ( fd == -1 ) { + tpl_hook.oops("Couldn't open file %s: %s\n", filename, strerror(errno)); + return -1; + } + + text = mmap(0, sz, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (text == MAP_FAILED) { + tpl_hook.oops("Failed to mmap %s: %s\n", filename, strerror(errno)); + close(fd); + return -1; + } + if (ftruncate(fd,sz) == -1) { + tpl_hook.oops("ftruncate failed: %s\n", strerror(errno)); + munmap( text, sz ); + close(fd); + return -1; + } + *text_out = text; + return fd; +} + +static int tpl_mmap_file(char *filename, tpl_mmap_rec *mr) { + struct stat stat_buf; + + if ( (mr->fd = open(filename, O_RDONLY)) == -1 ) { + tpl_hook.oops("Couldn't open file %s: %s\n", filename, strerror(errno)); + return -1; + } + + if ( fstat(mr->fd, &stat_buf) == -1) { + close(mr->fd); + tpl_hook.oops("Couldn't stat file %s: %s\n", filename, strerror(errno)); + return -1; + } + + mr->text_sz = (size_t)stat_buf.st_size; + mr->text = mmap(0, stat_buf.st_size, PROT_READ, MAP_PRIVATE, mr->fd, 0); + if (mr->text == MAP_FAILED) { + close(mr->fd); + tpl_hook.oops("Failed to mmap %s: %s\n", filename, strerror(errno)); + return -1; + } + + return 0; +} + +TPL_API int tpl_pack(tpl_node *r, int i) { + tpl_node *n, *child, *np; + void *datav=NULL; + size_t sz, itermax; + uint32_t slen; + char *str; + tpl_bin *bin; + tpl_pound_data *pd; + int fidx; + + n = tpl_find_i(r,i); + if (n == NULL) { + tpl_hook.oops("invalid index %d to tpl_pack\n", i); + return -1; + } + + if (((tpl_root_data*)(r->data))->flags & TPL_RDONLY) { + /* convert to an writeable tpl, initially empty */ + tpl_free_keep_map(r); + } + + ((tpl_root_data*)(r->data))->flags |= TPL_WRONLY; + + if (n->type == TPL_TYPE_ARY) datav = tpl_extend_backbone(n); + child = n->children; + while(child) { + switch(child->type) { + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + /* no need to use fidx iteration here; we can copy multiple values in one memcpy */ + memcpy(child->data,child->addr,tpl_types[child->type].sz * child->num); + if (datav) datav = tpl_cpv(datav,child->data,tpl_types[child->type].sz * child->num); + if (n->type == TPL_TYPE_ARY) n->ser_osz += tpl_types[child->type].sz * child->num; + break; + case TPL_TYPE_BIN: + /* copy the buffer to be packed */ + slen = ((tpl_bin*)child->addr)->sz; + if (slen >0) { + str = tpl_hook.malloc(slen); + if (!str) fatal_oom(); + memcpy(str,((tpl_bin*)child->addr)->addr,slen); + } else str = NULL; + /* and make a tpl_bin to point to it */ + bin = tpl_hook.malloc(sizeof(tpl_bin)); + if (!bin) fatal_oom(); + bin->addr = str; + bin->sz = slen; + /* now pack its pointer, first deep freeing any pre-existing bin */ + if (*(tpl_bin**)(child->data) != NULL) { + if ((*(tpl_bin**)(child->data))->sz != 0) { + tpl_hook.free( (*(tpl_bin**)(child->data))->addr ); + } + tpl_hook.free(*(tpl_bin**)(child->data)); + } + memcpy(child->data,&bin,sizeof(tpl_bin*)); + if (datav) { + datav = tpl_cpv(datav, &bin, sizeof(tpl_bin*)); + *(tpl_bin**)(child->data) = NULL; + } + if (n->type == TPL_TYPE_ARY) { + n->ser_osz += sizeof(uint32_t); /* binary buf len word */ + n->ser_osz += bin->sz; /* binary buf */ + } + break; + case TPL_TYPE_STR: + for(fidx=0; fidx < child->num; fidx++) { + /* copy the string to be packed. slen includes \0. this + block also works if the string pointer is NULL. */ + char *caddr = ((char**)child->addr)[fidx]; + char **cdata = &((char**)child->data)[fidx]; + slen = caddr ? (strlen(caddr) + 1) : 0; + if (slen) { + str = tpl_hook.malloc(slen); + if (!str) fatal_oom(); + memcpy(str,caddr,slen); /* include \0 */ + } else { + str = NULL; + } + /* now pack its pointer, first freeing any pre-existing string */ + if (*cdata != NULL) { + tpl_hook.free(*cdata); + } + memcpy(cdata,&str,sizeof(char*)); + if (datav) { + datav = tpl_cpv(datav, &str, sizeof(char*)); + *cdata = NULL; + } + if (n->type == TPL_TYPE_ARY) { + n->ser_osz += sizeof(uint32_t); /* string len word */ + if (slen>1) n->ser_osz += slen-1;/* string (without nul) */ + } + } + break; + case TPL_TYPE_ARY: + /* copy the child's tpl_atype* and reset it to empty */ + if (datav) { + sz = ((tpl_atyp*)(child->data))->sz; + datav = tpl_cpv(datav, &child->data, sizeof(void*)); + child->data = tpl_hook.malloc(sizeof(tpl_atyp)); + if (!child->data) fatal_oom(); + ((tpl_atyp*)(child->data))->num = 0; + ((tpl_atyp*)(child->data))->sz = sz; + ((tpl_atyp*)(child->data))->bb = NULL; + ((tpl_atyp*)(child->data))->bbtail = NULL; + } + /* parent is array? then bubble up child array's ser_osz */ + if (n->type == TPL_TYPE_ARY) { + n->ser_osz += sizeof(uint32_t); /* array len word */ + n->ser_osz += child->ser_osz; /* child array ser_osz */ + child->ser_osz = 0; /* reset child array ser_osz */ + } + break; + + case TPL_TYPE_POUND: + /* we need to iterate n times over preceding nodes in S(...). + * we may be in the midst of an iteration each time or starting. */ + pd = (tpl_pound_data*)child->data; + itermax = child->num; + + /* itermax is total num of iterations needed */ + /* pd->iternum is current iteration index */ + /* pd->inter_elt_len is element-to-element len of contiguous structs */ + /* pd->iter_start_node is where we jump to at each iteration. */ + + if (++(pd->iternum) < itermax) { + + /* in start or midst of loop. advance addr/data pointers. */ + for(np=pd->iter_start_node; np != child; np = np->next) { + np->data = (char*)(np->data) + + (tpl_types[np->type].sz * np->num); + np->addr = (char*)(np->addr) + pd->inter_elt_len; + } + /* do next iteration */ + child = pd->iter_start_node; + continue; + + } else { /* loop complete. */ + + /* reset iteration index and addr/data pointers. */ + pd->iternum = 0; + for(np=pd->iter_start_node; np != child; np = np->next) { + np->data = (char*)(np->data) - ((itermax-1) * + tpl_types[np->type].sz * + np->num); + np->addr = (char*)(np->addr) - ((itermax-1) * pd->inter_elt_len); + } + + } + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + child=child->next; + } + return 0; +} + +TPL_API int tpl_unpack(tpl_node *r, int i) { + tpl_node *n, *c, *np; + uint32_t slen; + int rc=1, fidx; + char *str; + void *dv=NULL, *caddr; + size_t A_bytes, itermax; + tpl_pound_data *pd; + void *img; + size_t sz; + + + /* handle unusual case of tpl_pack,tpl_unpack without an + * intervening tpl_dump. do a dump/load implicitly. */ + if (((tpl_root_data*)(r->data))->flags & TPL_WRONLY) { + if (tpl_dump(r,TPL_MEM,&img,&sz) != 0) return -1; + if (tpl_load(r,TPL_MEM|TPL_UFREE,img,sz) != 0) { + tpl_hook.free(img); + return -1; + }; + } + + n = tpl_find_i(r,i); + if (n == NULL) { + tpl_hook.oops("invalid index %d to tpl_unpack\n", i); + return -1; + } + + /* either root node or an A node */ + if (n->type == TPL_TYPE_ROOT) { + dv = tpl_find_data_start( ((tpl_root_data*)(n->data))->mmap.text ); + } else if (n->type == TPL_TYPE_ARY) { + if (((tpl_atyp*)(n->data))->num <= 0) return 0; /* array consumed */ + else rc = ((tpl_atyp*)(n->data))->num--; + dv = ((tpl_atyp*)(n->data))->cur; + if (!dv) tpl_hook.fatal("must unpack parent of node before node itself\n"); + } + + c = n->children; + while (c) { + switch (c->type) { + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + /* unpack elements of cross-endian octothorpic array individually */ + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) { + for(fidx=0; fidx < c->num; fidx++) { + caddr = (void*)((uintptr_t)c->addr + (fidx * tpl_types[c->type].sz)); + memcpy(caddr,dv,tpl_types[c->type].sz); + tpl_byteswap(caddr, tpl_types[c->type].sz); + dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz); + } + } else { + /* bulk unpack ok if not cross-endian */ + memcpy(c->addr, dv, tpl_types[c->type].sz * c->num); + dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz * c->num); + } + break; + case TPL_TYPE_BIN: + memcpy(&slen,dv,sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) + tpl_byteswap(&slen, sizeof(uint32_t)); + if (slen > 0) { + str = (char*)tpl_hook.malloc(slen); + if (!str) fatal_oom(); + } else str=NULL; + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + if (slen>0) memcpy(str,dv,slen); + memcpy(&(((tpl_bin*)c->addr)->addr),&str,sizeof(void*)); + memcpy(&(((tpl_bin*)c->addr)->sz),&slen,sizeof(uint32_t)); + dv = (void*)((uintptr_t)dv + slen); + break; + case TPL_TYPE_STR: + for(fidx=0; fidx < c->num; fidx++) { + memcpy(&slen,dv,sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) + tpl_byteswap(&slen, sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_OLD_STRING_FMT) + slen += 1; + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + if (slen) { /* slen includes \0 */ + str = (char*)tpl_hook.malloc(slen); + if (!str) fatal_oom(); + if (slen>1) memcpy(str,dv,slen-1); + str[slen-1] = '\0'; /* nul terminate */ + dv = (void*)((uintptr_t)dv + slen-1); + } else str=NULL; + memcpy(&((char**)c->addr)[fidx],&str,sizeof(char*)); + } + break; + case TPL_TYPE_POUND: + /* iterate over preceding nodes */ + pd = (tpl_pound_data*)c->data; + itermax = c->num; + if (++(pd->iternum) < itermax) { + /* in start or midst of loop. advance addr/data pointers. */ + for(np=pd->iter_start_node; np != c; np = np->next) { + np->addr = (char*)(np->addr) + pd->inter_elt_len; + } + /* do next iteration */ + c = pd->iter_start_node; + continue; + + } else { /* loop complete. */ + + /* reset iteration index and addr/data pointers. */ + pd->iternum = 0; + for(np=pd->iter_start_node; np != c; np = np->next) { + np->addr = (char*)(np->addr) - ((itermax-1) * pd->inter_elt_len); + } + + } + break; + case TPL_TYPE_ARY: + if (tpl_serlen(r,c,dv, &A_bytes) == -1) + tpl_hook.fatal("internal error in unpack\n"); + memcpy( &((tpl_atyp*)(c->data))->num, dv, sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) + tpl_byteswap(&((tpl_atyp*)(c->data))->num, sizeof(uint32_t)); + ((tpl_atyp*)(c->data))->cur = (void*)((uintptr_t)dv+sizeof(uint32_t)); + dv = (void*)((uintptr_t)dv + A_bytes); + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + + c = c->next; + } + if (n->type == TPL_TYPE_ARY) ((tpl_atyp*)(n->data))->cur = dv; /* next element */ + return rc; +} + +/* Specialized function that unpacks only the root's A nodes, after tpl_load */ +static int tpl_unpackA0(tpl_node *r) { + tpl_node *n, *c; + uint32_t slen; + int rc=1,fidx,i; + void *dv; + size_t A_bytes, itermax; + tpl_pound_data *pd; + + n = r; + dv = tpl_find_data_start( ((tpl_root_data*)(r->data))->mmap.text); + + c=n->children; + while (c) { + switch (c->type) { + case TPL_TYPE_BYTE: + case TPL_TYPE_DOUBLE: + case TPL_TYPE_INT32: + case TPL_TYPE_UINT32: + case TPL_TYPE_INT64: + case TPL_TYPE_UINT64: + case TPL_TYPE_INT16: + case TPL_TYPE_UINT16: + for(fidx=0;fidx < c->num; fidx++) { + dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz); + } + break; + case TPL_TYPE_BIN: + memcpy(&slen,dv,sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) + tpl_byteswap(&slen, sizeof(uint32_t)); + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + dv = (void*)((uintptr_t)dv + slen); + break; + case TPL_TYPE_STR: + for(i=0; inum; i++) { + memcpy(&slen,dv,sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) + tpl_byteswap(&slen, sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_OLD_STRING_FMT) + slen += 1; + dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); + if (slen>1) dv = (void*)((uintptr_t)dv + slen-1); + } + break; + case TPL_TYPE_POUND: + /* iterate over the preceding nodes */ + itermax = c->num; + pd = (tpl_pound_data*)c->data; + if (++(pd->iternum) < itermax) { + c = pd->iter_start_node; + continue; + } else { /* loop complete. */ + pd->iternum = 0; + } + break; + case TPL_TYPE_ARY: + if ( tpl_serlen(r,c,dv, &A_bytes) == -1) + tpl_hook.fatal("internal error in unpackA0\n"); + memcpy( &((tpl_atyp*)(c->data))->num, dv, sizeof(uint32_t)); + if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) + tpl_byteswap(&((tpl_atyp*)(c->data))->num, sizeof(uint32_t)); + ((tpl_atyp*)(c->data))->cur = (void*)((uintptr_t)dv+sizeof(uint32_t)); + dv = (void*)((uintptr_t)dv + A_bytes); + break; + default: + tpl_hook.fatal("unsupported format character\n"); + break; + } + c=c->next; + } + return rc; +} + +/* In-place byte order swapping of a word of length "len" bytes */ +static void tpl_byteswap(void *word, int len) { + int i; + char c, *w; + w = (char*)word; + for(i=0; i0) ? rc : 0; + } while ((rc==-1 && (errno==EINTR||errno==EAGAIN)) || (rc>0 && i<8)); + + if (rc<0) { + tpl_hook.oops("tpl_gather_fd_blocking failed: %s\n", strerror(errno)); + return -1; + } else if (rc == 0) { + /* tpl_hook.oops("tpl_gather_fd_blocking: eof\n"); */ + return 0; + } else if (i != 8) { + tpl_hook.oops("internal error\n"); + return -1; + } + + if (preamble[0] == 't' && preamble[1] == 'p' && preamble[2] == 'l') { + memcpy(&tpllen,&preamble[4],4); + if (tpl_needs_endian_swap(preamble)) tpl_byteswap(&tpllen,4); + } else { + tpl_hook.oops("tpl_gather_fd_blocking: non-tpl input\n"); + return -1; + } + + /* malloc space for remainder of tpl image (overall length tpllen) + * and read it in + */ + if (tpl_hook.gather_max > 0 && + tpllen > tpl_hook.gather_max) { + tpl_hook.oops("tpl exceeds max length %d\n", + tpl_hook.gather_max); + return -2; + } + *sz = tpllen; + if ( (*img = tpl_hook.malloc(tpllen)) == NULL) { + fatal_oom(); + } + + memcpy(*img,preamble,8); /* copy preamble to output buffer */ + i=8; + do { + rc = read(fd,&((*(char**)img)[i]),tpllen-i); + i += (rc>0) ? rc : 0; + } while ((rc==-1 && (errno==EINTR||errno==EAGAIN)) || (rc>0 && iimg); + tpl_hook.free(*gs); + *gs = NULL; + } + return -1; /* error, caller should close fd */ + } + } else if (rc == 0) { + if (*gs) { + tpl_hook.oops("tpl_gather: partial tpl image precedes EOF\n"); + tpl_hook.free((*gs)->img); + tpl_hook.free(*gs); + *gs = NULL; + } + return 0; /* EOF, caller should close fd */ + } else { + /* concatenate any partial tpl from last read with new buffer */ + if (*gs) { + catlen = (*gs)->len + rc; + if (tpl_hook.gather_max > 0 && + catlen > tpl_hook.gather_max) { + tpl_hook.free( (*gs)->img ); + tpl_hook.free( (*gs) ); + *gs = NULL; + tpl_hook.oops("tpl exceeds max length %d\n", + tpl_hook.gather_max); + return -2; /* error, caller should close fd */ + } + if ( (img = tpl_hook.realloc((*gs)->img, catlen)) == NULL) { + fatal_oom(); + } + memcpy(img + (*gs)->len, buf, rc); + tpl_hook.free(*gs); + *gs = NULL; + } else { + img = buf; + catlen = rc; + } + /* isolate any full tpl(s) in img and invoke cb for each */ + tpl = img; + keep_looping = (tpl+8 < img+catlen) ? 1 : 0; + while (keep_looping) { + if (strncmp("tpl", tpl, 3) != 0) { + tpl_hook.oops("tpl prefix invalid\n"); + if (img != buf) tpl_hook.free(img); + tpl_hook.free(*gs); + *gs = NULL; + return -3; /* error, caller should close fd */ + } + memcpy(&tpllen,&tpl[4],4); + if (tpl_needs_endian_swap(tpl)) tpl_byteswap(&tpllen,4); + if (tpl+tpllen <= img+catlen) { + cbrc = (cb)(tpl,tpllen,data); /* invoke cb for tpl image */ + tpl += tpllen; /* point to next tpl image */ + if (cbrc < 0) keep_looping = 0; + else keep_looping = (tpl+8 < img+catlen) ? 1 : 0; + } else keep_looping=0; + } + /* check if app callback requested closure of tpl source */ + if (cbrc < 0) { + tpl_hook.oops("tpl_fd_gather aborted by app callback\n"); + if (img != buf) tpl_hook.free(img); + if (*gs) tpl_hook.free(*gs); + *gs = NULL; + return -4; + } + /* store any leftover, partial tpl fragment for next read */ + if (tpl == img && img != buf) { + /* consumed nothing from img!=buf */ + if ( (*gs = tpl_hook.malloc(sizeof(tpl_gather_t))) == NULL ) { + fatal_oom(); + } + (*gs)->img = tpl; + (*gs)->len = catlen; + } else if (tpl < img+catlen) { + /* consumed 1+ tpl(s) from img!=buf or 0 from img==buf */ + if ( (*gs = tpl_hook.malloc(sizeof(tpl_gather_t))) == NULL ) { + fatal_oom(); + } + if ( ((*gs)->img = tpl_hook.malloc(img+catlen - tpl)) == NULL ) { + fatal_oom(); + } + (*gs)->len = img+catlen - tpl; + memcpy( (*gs)->img, tpl, img+catlen - tpl); + /* free partially consumed concat buffer if used */ + if (img != buf) tpl_hook.free(img); + } else { /* tpl(s) fully consumed */ + /* free consumed concat buffer if used */ + if (img != buf) tpl_hook.free(img); + } + } + } +} + +/* gather tpl piecemeal from memory buffer (not fd) e.g., from a lower-level api */ +static int tpl_gather_mem( char *buf, size_t len, tpl_gather_t **gs, tpl_gather_cb *cb, void *data) { + char *img, *tpl; + int keep_looping, cbrc=0; + size_t catlen; + uint32_t tpllen; + + /* concatenate any partial tpl from last read with new buffer */ + if (*gs) { + catlen = (*gs)->len + len; + if (tpl_hook.gather_max > 0 && + catlen > tpl_hook.gather_max) { + tpl_hook.free( (*gs)->img ); + tpl_hook.free( (*gs) ); + *gs = NULL; + tpl_hook.oops("tpl exceeds max length %d\n", + tpl_hook.gather_max); + return -2; /* error, caller should stop accepting input from source*/ + } + if ( (img = tpl_hook.realloc((*gs)->img, catlen)) == NULL) { + fatal_oom(); + } + memcpy(img + (*gs)->len, buf, len); + tpl_hook.free(*gs); + *gs = NULL; + } else { + img = buf; + catlen = len; + } + /* isolate any full tpl(s) in img and invoke cb for each */ + tpl = img; + keep_looping = (tpl+8 < img+catlen) ? 1 : 0; + while (keep_looping) { + if (strncmp("tpl", tpl, 3) != 0) { + tpl_hook.oops("tpl prefix invalid\n"); + if (img != buf) tpl_hook.free(img); + tpl_hook.free(*gs); + *gs = NULL; + return -3; /* error, caller should stop accepting input from source*/ + } + memcpy(&tpllen,&tpl[4],4); + if (tpl_needs_endian_swap(tpl)) tpl_byteswap(&tpllen,4); + if (tpl+tpllen <= img+catlen) { + cbrc = (cb)(tpl,tpllen,data); /* invoke cb for tpl image */ + tpl += tpllen; /* point to next tpl image */ + if (cbrc < 0) keep_looping = 0; + else keep_looping = (tpl+8 < img+catlen) ? 1 : 0; + } else keep_looping=0; + } + /* check if app callback requested closure of tpl source */ + if (cbrc < 0) { + tpl_hook.oops("tpl_mem_gather aborted by app callback\n"); + if (img != buf) tpl_hook.free(img); + if (*gs) tpl_hook.free(*gs); + *gs = NULL; + return -4; + } + /* store any leftover, partial tpl fragment for next read */ + if (tpl == img && img != buf) { + /* consumed nothing from img!=buf */ + if ( (*gs = tpl_hook.malloc(sizeof(tpl_gather_t))) == NULL ) { + fatal_oom(); + } + (*gs)->img = tpl; + (*gs)->len = catlen; + } else if (tpl < img+catlen) { + /* consumed 1+ tpl(s) from img!=buf or 0 from img==buf */ + if ( (*gs = tpl_hook.malloc(sizeof(tpl_gather_t))) == NULL ) { + fatal_oom(); + } + if ( ((*gs)->img = tpl_hook.malloc(img+catlen - tpl)) == NULL ) { + fatal_oom(); + } + (*gs)->len = img+catlen - tpl; + memcpy( (*gs)->img, tpl, img+catlen - tpl); + /* free partially consumed concat buffer if used */ + if (img != buf) tpl_hook.free(img); + } else { /* tpl(s) fully consumed */ + /* free consumed concat buffer if used */ + if (img != buf) tpl_hook.free(img); + } + return 1; +} diff --git a/libs/libtpl-1.5/src/tpl.h b/libs/libtpl-1.5/src/tpl.h new file mode 100755 index 0000000000..e23953b7ef --- /dev/null +++ b/libs/libtpl-1.5/src/tpl.h @@ -0,0 +1,133 @@ +/* +Copyright (c) 2005-2010, Troy D. Hanson http://tpl.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef TPL_H +#define TPL_H + +#include /* size_t */ + +#ifdef __INTEL_COMPILER +#include +#endif /* Intel Compiler efficient memcpy etc */ + +#ifdef _MSC_VER +typedef unsigned int uint32_t; +#else +#include /* uint32_t */ +#endif + +#if defined __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +#ifdef TPL_EXPORTS +#define TPL_API __declspec(dllexport) +#else /* */ +#ifdef TPL_NOLIB +#define TPL_API +#else +#define TPL_API __declspec(dllimport) +#endif /* TPL_NOLIB */ +#endif /* TPL_EXPORTS*/ +#else +#define TPL_API +#endif + +/* bit flags (external) */ +#define TPL_FILE (1 << 0) +#define TPL_MEM (1 << 1) +#define TPL_PREALLOCD (1 << 2) +#define TPL_EXCESS_OK (1 << 3) +#define TPL_FD (1 << 4) +#define TPL_UFREE (1 << 5) +#define TPL_DATAPEEK (1 << 6) +#define TPL_FXLENS (1 << 7) +#define TPL_GETSIZE (1 << 8) +/* do not add flags here without renumbering the internal flags! */ + +/* flags for tpl_gather mode */ +#define TPL_GATHER_BLOCKING 1 +#define TPL_GATHER_NONBLOCKING 2 +#define TPL_GATHER_MEM 3 + +/* Hooks for error logging, memory allocation functions and fatal */ +typedef int (tpl_print_fcn)(const char *fmt, ...); +typedef void *(tpl_malloc_fcn)(size_t sz); +typedef void *(tpl_realloc_fcn)(void *ptr, size_t sz); +typedef void (tpl_free_fcn)(void *ptr); +typedef void (tpl_fatal_fcn)(char *fmt, ...); + +typedef struct tpl_hook_t { + tpl_print_fcn *oops; + tpl_malloc_fcn *malloc; + tpl_realloc_fcn *realloc; + tpl_free_fcn *free; + tpl_fatal_fcn *fatal; + size_t gather_max; +} tpl_hook_t; + +typedef struct tpl_node { + int type; + void *addr; + void *data; /* r:tpl_root_data*. A:tpl_atyp*. ow:szof type */ + int num; /* length of type if its a C array */ + size_t ser_osz; /* serialization output size for subtree */ + struct tpl_node *children; /* my children; linked-list */ + struct tpl_node *next,*prev; /* my siblings (next child of my parent) */ + struct tpl_node *parent; /* my parent */ +} tpl_node; + +/* used when un/packing 'B' type (binary buffers) */ +typedef struct tpl_bin { + void *addr; + uint32_t sz; +} tpl_bin; + +/* for async/piecemeal reading of tpl images */ +typedef struct tpl_gather_t { + char *img; + int len; +} tpl_gather_t; + +/* Callback used when tpl_gather has read a full tpl image */ +typedef int (tpl_gather_cb)(void *img, size_t sz, void *data); + +/* Prototypes */ +TPL_API tpl_node *tpl_map(char *fmt,...); /* define tpl using format */ +TPL_API void tpl_free(tpl_node *r); /* free a tpl map */ +TPL_API int tpl_pack(tpl_node *r, int i); /* pack the n'th packable */ +TPL_API int tpl_unpack(tpl_node *r, int i); /* unpack the n'th packable */ +TPL_API int tpl_dump(tpl_node *r, int mode, ...); /* serialize to mem/file */ +TPL_API int tpl_load(tpl_node *r, int mode, ...); /* set mem/file to unpack */ +TPL_API int tpl_Alen(tpl_node *r, int i); /* array len of packable i */ +TPL_API char* tpl_peek(int mode, ...); /* sneak peek at format string */ +TPL_API int tpl_gather( int mode, ...); /* non-blocking image gather */ +TPL_API int tpl_jot(int mode, ...); /* quick write a simple tpl */ + +#if defined __cplusplus + } +#endif + +#endif /* TPL_H */ + diff --git a/libs/libtpl-1.5/src/win/Makefile.am b/libs/libtpl-1.5/src/win/Makefile.am new file mode 100755 index 0000000000..8282237e61 --- /dev/null +++ b/libs/libtpl-1.5/src/win/Makefile.am @@ -0,0 +1,4 @@ +noinst_LTLIBRARIES = libwinmmap.la +noinst_HEADERS = mman.h +libwinmmap_la_SOURCES = nonempty.c +libwinmmap_la_LIBADD = @LTLIBOBJS@ diff --git a/libs/libtpl-1.5/src/win/Makefile.in b/libs/libtpl-1.5/src/win/Makefile.in new file mode 100644 index 0000000000..9ff433e07d --- /dev/null +++ b/libs/libtpl-1.5/src/win/Makefile.in @@ -0,0 +1,440 @@ +# Makefile.in generated by automake 1.10.2 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/win +DIST_COMMON = README $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in mmap.c +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libwinmmap_la_DEPENDENCIES = @LTLIBOBJS@ +am_libwinmmap_la_OBJECTS = nonempty.lo +libwinmmap_la_OBJECTS = $(am_libwinmmap_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/config +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libwinmmap_la_SOURCES) +DIST_SOURCES = $(libwinmmap_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = libwinmmap.la +noinst_HEADERS = mman.h +libwinmmap_la_SOURCES = nonempty.c +libwinmmap_la_LIBADD = @LTLIBOBJS@ +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/win/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/win/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libwinmmap.la: $(libwinmmap_la_OBJECTS) $(libwinmmap_la_DEPENDENCIES) + $(LINK) $(libwinmmap_la_OBJECTS) $(libwinmmap_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/mmap.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nonempty.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf $(DEPDIR) ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf $(DEPDIR) ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libs/libtpl-1.5/src/win/README b/libs/libtpl-1.5/src/win/README new file mode 100755 index 0000000000..4d055c1ef1 --- /dev/null +++ b/libs/libtpl-1.5/src/win/README @@ -0,0 +1,11 @@ +This directory contains functions that are missing on the Windows platform. In +particular, mmap, munmap, and msync are not available on Windows. These +replacements are used on both Cygwin and MinGW. (On Cygwin the built-in mmap +has no write support, and is not used). + +mmap.c +mman.h + +Special thanks to Horea Haitonic for contributing mmap.c and mman.h. + +April 2007 diff --git a/libs/libtpl-1.5/src/win/mman.h b/libs/libtpl-1.5/src/win/mman.h new file mode 100755 index 0000000000..9f97ac06bd --- /dev/null +++ b/libs/libtpl-1.5/src/win/mman.h @@ -0,0 +1,52 @@ +#ifndef _MMAN_H_ +#define _MMAN_H_ + +/* Protections */ +#define PROT_NONE 0x00 /* no permissions */ +#define PROT_READ 0x01 /* pages can be read */ +#define PROT_WRITE 0x02 /* pages can be written */ +#define PROT_EXEC 0x04 /* pages can be executed */ + +/* Sharing type and options */ +#define MAP_SHARED 0x0001 /* share changes */ +#define MAP_PRIVATE 0x0002 /* changes are private */ +#define MAP_COPY MAP_PRIVATE /* Obsolete */ +#define MAP_FIXED 0x0010 /* map addr must be exactly as requested */ +#define MAP_RENAME 0x0020 /* Sun: rename private pages to file */ +#define MAP_NORESERVE 0x0040 /* Sun: don't reserve needed swap area */ +#define MAP_INHERIT 0x0080 /* region is retained after exec */ +#define MAP_NOEXTEND 0x0100 /* for MAP_FILE, don't change file size */ +#define MAP_HASSEMAPHORE 0x0200 /* region may contain semaphores */ +#define MAP_STACK 0x0400 /* region grows down, like a stack */ + +/* Error returned from mmap() */ +#define MAP_FAILED ((void *)-1) + +/* Flags to msync */ +#define MS_ASYNC 0x01 /* perform asynchronous writes */ +#define MS_SYNC 0x02 /* perform synchronous writes */ +#define MS_INVALIDATE 0x04 /* invalidate cached data */ + +/* File modes for 'open' not defined in MinGW32 (not used by mmap) */ +#ifndef S_IWGRP +#define S_IWGRP 0 +#define S_IRGRP 0 +#define S_IROTH 0 +#endif + +/** + * Map a file to a memory region + */ +void *mmap(void *addr, unsigned int len, int prot, int flags, int fd, unsigned int offset); + +/** + * Unmap a memory region + */ +int munmap(void *addr, int len); + +/** + * Synchronize a mapped region + */ +int msync(char *addr, int len, int flags); + +#endif /* _MMAN_H_ */ diff --git a/libs/libtpl-1.5/src/win/mmap.c b/libs/libtpl-1.5/src/win/mmap.c new file mode 100755 index 0000000000..b06cd35c63 --- /dev/null +++ b/libs/libtpl-1.5/src/win/mmap.c @@ -0,0 +1,170 @@ +#include +#include +#ifdef _WIN32 +#include +#endif +#include +#include "mman.h" + +static const char id[]="$Id: tpl.c 107 2007-04-20 17:11:29Z thanson $"; + +/** + * @brief Map a file to a memory region + * + * This function emulates the POSIX mmap() using CreateFileMapping() and + * MapViewOfFile() + * + * @param addr the suggested start address (if != 0) + * @param len length of the region + * @param prot region accesibility, bitwise OR of PROT_READ, PROT_WRITE, PROT_EXEC + * @param flags mapping type and options (ignored) + * @param fd object to be mapped into memory + * @param offset offset into mapped object + * @return pointer to the memory region, or NULL in case of error + */ +void *mmap(void *addr, unsigned int len, int prot, int flags, int fd, unsigned int offset) +{ + DWORD wprot; + DWORD waccess; + HANDLE h; + void *region; + + /* Translate read/write/exec flags into WIN32 constants */ + switch (prot) { + case PROT_READ: + wprot = PAGE_READONLY; + break; + case PROT_EXEC: + wprot = PAGE_EXECUTE_READ; + break; + case PROT_READ | PROT_EXEC: + wprot = PAGE_EXECUTE_READ; + break; + case PROT_WRITE: + wprot = PAGE_READWRITE; + break; + case PROT_READ | PROT_WRITE: + wprot = PAGE_READWRITE; + break; + case PROT_READ | PROT_WRITE | PROT_EXEC: + wprot = PAGE_EXECUTE_READWRITE; + break; + case PROT_WRITE | PROT_EXEC: + wprot = PAGE_EXECUTE_READWRITE; + break; + } + + /* Obtaing handle to map region */ + h = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, wprot, 0, len, 0); + if (h == NULL) { + DWORD error = GetLastError(); + + /* Try and translate some error codes */ + switch (error) { + case ERROR_ACCESS_DENIED: + case ERROR_INVALID_ACCESS: + errno = EACCES; + break; + case ERROR_OUTOFMEMORY: + case ERROR_NOT_ENOUGH_MEMORY: + errno = ENOMEM; + break; + default: + errno = EINVAL; + break; + } + return MAP_FAILED; + } + + + /* Translate sharing options into WIN32 constants */ + switch (wprot) { + case PAGE_READONLY: + waccess = FILE_MAP_READ; + break; + case PAGE_READWRITE: + waccess = FILE_MAP_WRITE; + break; + } + + /* Map file and return pointer */ + region = MapViewOfFile(h, waccess, 0, 0, 0); + if (region == NULL) { + DWORD error = GetLastError(); + + /* Try and translate some error codes */ + switch (error) { + case ERROR_ACCESS_DENIED: + case ERROR_INVALID_ACCESS: + errno = EACCES; + break; + case ERROR_INVALID_HANDLE: + errno = EBADF; + break; + default: + errno = EINVAL; + break; + } + CloseHandle(h); + return MAP_FAILED; + } + + /* All fine */ + return region; +} + + +/** + * @brief Unmap a memory region + * + * This is a wrapper around UnmapViewOfFile in the win32 API + * + * @param addr start address + * @param len length of the region + * @return 0 for success, -1 for error + */ +int munmap(void *addr, int len) +{ + if (UnmapViewOfFile(addr)) { + return 0; + } + else { + errno = EINVAL; + return -1; + } +} + + +/** + * Synchronize a mapped region + * + * This is a wrapper around FlushViewOfFile + * + * @param addr start address + * @param len number of bytes to flush + * @param flags sync options -- currently ignored + * @return 0 for success, -1 for error + */ +int msync(char *addr, int len, int flags) +{ + if (FlushViewOfFile(addr, len) == 0) { + DWORD error = GetLastError(); + + /* Try and translate some error codes */ + switch (error) { + case ERROR_INVALID_PARAMETER: + errno = EINVAL; + break; + case ERROR_WRITE_FAULT: + errno = EIO; + break; + default: + errno = EINVAL; + break; + } + return -1; + } + + /* Success */ + return 0; +} diff --git a/libs/libtpl-1.5/src/win/nonempty.c b/libs/libtpl-1.5/src/win/nonempty.c new file mode 100755 index 0000000000..5c02f1685a --- /dev/null +++ b/libs/libtpl-1.5/src/win/nonempty.c @@ -0,0 +1,6 @@ +/* This function exists solely to prevent libwinmmap.la from being empty. Empty + * libraries cause problems on some platforms, e.g. Mac OS X. */ + +int tpl_nonempty(int i) { + return i+1; +} diff --git a/libs/libtpl-1.5/tests/Makefile b/libs/libtpl-1.5/tests/Makefile new file mode 100755 index 0000000000..6ebd127af6 --- /dev/null +++ b/libs/libtpl-1.5/tests/Makefile @@ -0,0 +1,88 @@ +# Makefile for tpl built-in test suite +# +# This Makefile has three useful targets: +# +# all (default): +# Build and run all self-tests by compiling tpl into each test. +# +# Note: On Cygwin/MinGW, compiling the tpl source directly into the tests is +# not supported (as they use 'replacement' functions which get included only +# in libtpl), so on these platforms the 'alt' target is the default. +# +# alt: +# Build and run all the self-tests by linking them with libtpl, which must +# have been created beforehand (by running 'configure; make' in the +# top-level directory); a reminder will be printed if you have not done so. +# +# Note, libtool will create wrappers around each test to accomodate the +# pre-installed state of ../src/libtpl.la. In a real program, you'd link +# against an installed libtpl.la, and these wrappers would not be used. +# +# clean: +# Clean up all the compiled bits. +# +PROGS = test1 test2 test3 test4 test5 test6 test7 test8 \ + test9 test10 test11 test12 test13 test14 test15 test16 \ + test17 test18 test19 test20 test21 test22 test23 test24 \ + test25 test26 test27 test28 test29 test30 test31 test32 \ + test33 test34 test35 test36 test37 test38 test39 test40 \ + test41 test42 test43 test44 test45 test46 test47 test48 \ + test49 test50 test51 test52 test53 test54 test55 test56 \ + test57 test58 test59 test60 test61 test62 test63 test64 \ + test65 test66 test67 test68 test69 test70 test71 test72 \ + test73 test74 test75 test76 test77 test78 test79 test80 \ + test81 test82 test83 test84 test85 test86 test87 test88 \ + test89 test90 test91 test92 test93 test94 test95 test96 \ + test97 test98 test99 test100 test101 test102 test103 test104 \ + test105 test106 test107 test108 test109 test110 test111 test112 \ + test113 test114 test115 test116 test117 test118 test119 test120 \ + test121 test122 test123 test124 + +TPLSRC = ../src +CFLAGS = -I$(TPLSRC) -g +CFLAGS += -pedantic +CFLAGS += -Wall +#CFLAGS += -m32 +#CFLAGS += -m64 +CFLAGS += -O3 +#For testing without C99 feature support +#CFLAGS += -std=c89 + +# Prefer 64-bit compilation on Mac OS X (not necessary, just faster) +ifneq ($(strip $(shell $(CC) -v 2>&1 |egrep "i[0-9]+-apple-darwin")),) + CFLAGS += -m64 +endif + +# detect Cygwin or MinGW +ifneq ($(strip $(shell $(CC) -v 2>&1 |egrep "cygwin|mingw")),) + TESTS=./do_tests.cygwin + # divert to the alt target; use tpl as a lib for Cygwin/Mingw + TARGET=alt +else + TESTS=./do_tests + TARGET=$(PROGS) run_tests +endif + +all: $(TARGET) + +tpl.o : $(TPLSRC)/tpl.c $(TPLSRC)/tpl.h + $(CC) -c $(CFLAGS) $(TPLSRC)/tpl.c + +$(PROGS) : tpl.o + $(CC) $(CFLAGS) -o $@ $(@).c tpl.o + +run_tests: + perl $(TESTS) + +# This target can be used to compile the tests as dependent on +# the tpl library (rather than compiling in the tpl source). +alt: mkalttests run_tests + +mkalttests: + @$(MAKE) -f Makefile.alt PROGS="$(PROGS)" + +.PHONY: clean + +clean: + rm -f $(PROGS) tpl.o test*.out test*.err test*.exe + rm -rf $(PROGS) test*.dSYM diff --git a/libs/libtpl-1.5/tests/Makefile.alt b/libs/libtpl-1.5/tests/Makefile.alt new file mode 100755 index 0000000000..054b678b59 --- /dev/null +++ b/libs/libtpl-1.5/tests/Makefile.alt @@ -0,0 +1,31 @@ +# This Makefile.alt is subordinate to Makefile (usage: make alt) +# Its distinction is that it builds the test programs by linking +# them with libtpl rather than by compiling tpl.c into the tests. +SRC = ../src +LIBTOOL = ../libtool +LTLIB = $(SRC)/libtpl.la +CFLAGS = -I$(SRC) -g + +# We have an alternate basic test for MinGW +ifneq ($(strip $(shell $(CC) -v 2>&1 |grep "mingw")),) + TARGET=mingw +else + TARGET=$(PROGS) +endif + +all: $(TARGET) + + +$(PROGS) : $(LTLIB) + $(CC) -c $(CFLAGS) $(@).c + $(LIBTOOL) --mode=link --tag=CC $(CC) -o $@ $(@).o $(LTLIB) + +$(LTLIB) : + @echo "you must first run 'configure; make' in the top-level directory" + @exit 1 + +mingw : + @echo "" + @echo "MinGW has its own test suite. Please run make -f Makefile.mingw" + @echo "" + @exit 1 diff --git a/libs/libtpl-1.5/tests/Makefile.mingw b/libs/libtpl-1.5/tests/Makefile.mingw new file mode 100755 index 0000000000..dbf790658a --- /dev/null +++ b/libs/libtpl-1.5/tests/Makefile.mingw @@ -0,0 +1,25 @@ +# This makes a small Mingw test program. The standard test suite +# is incompatible with MinGW because it uses UNIX facilities such +# as pipe/fork and the /tmp directory, not features of Windows. +SRC = ../src +LIBTOOL = ../libtool +LTLIB = $(SRC)/libtpl.la +CFLAGS = -I$(SRC) -g + +PROG = mgwtest + +all: $(PROG) + +$(PROG) : $(LTLIB) + $(CC) -c $(CFLAGS) $(@).c + $(LIBTOOL) --mode=link --tag=CC $(CC) -o $@ $(@).o $(LTLIB) -mwindows + @echo "you can now run windows application: $@" + +$(LTLIB) : + @echo "you must first run 'configure; make' in the top-level directory" + @exit 1 + +.PHONY: clean + +clean: + rm $(PROG) $(PROG).exe $(PROG).o $(PROG).tpl diff --git a/libs/libtpl-1.5/tests/README b/libs/libtpl-1.5/tests/README new file mode 100755 index 0000000000..eef1f1768e --- /dev/null +++ b/libs/libtpl-1.5/tests/README @@ -0,0 +1,125 @@ +Run "make" in this directory to build the tests and run them. + +test1: serialize int into memory, unserialize +test2: serialize int into file, unserialize +test3: serialize A(i) into file, unserialize +test4: serialize A(i) into memory, unserialize +test5: serialize A(A(i)) into memory, unserialize +test6: serialize string into memory, unserialize +test7: serialize A(s) into file, unserialize +test8: serialize cA(c) into file, unserialize +test9: unpack big-endian tpl data file of A(i) +test10: unpack little-endian tpl data file of A(i) +test11: try to load a corrupt tpl image w/invalid chars +test12: try to load a corrupt tpl image w/runaway format string +test13: try to load a corrupt tpl image w/internal A length -1 +test14: try to load a corrupt tpl image w/internal A length +1 +test15: try to load a corrupt tpl image w/invalid magic +test16: try to load a corrupt tpl image w/invalid len +test17: try to load a good tpl but whose format mismatches map +test18: try to map a tpl with malformed format- unbalanced parens: missing ) +test19: try to map a tpl with malformed format- unbalanced parens: extra ) +test20: try to map a tpl with malformed format- empty A() +test21: serialize A(ii) into file, unserialize +test22: serialize A(u) into file, unserialize +test23: serialize A(u) into file, read tpl from fd using TPL_FD +test24: read A(u) tpl file with extra trailing bytes, ok in TPL_FD mode +test25: same A(u) tpl file with extra trailing bytes, not ok in TPL_FILE mode +test26: test non-blocking tpl_gather using async read of 3 tpls across 2 pipes +test27: test tpl_dump() of A(u) to file using TPL_FD, unserialize +test28: parent writes A(u) tpl to child through pipe, both use TPL_FD mode +test29: parent writes consecutive A(u) tpl then A(c) tpl to child through pipe +test30: test pack B (binary buffer) and unpack +test31: test pack B (binary buffer) of 0-length and unpack +test32: test pack A(B) and unpack +test33: test pack f (double) and unpack +test34: test pack A(f) and unpack +test35: pack A(is) +test36: unpack A(is) +test37: pack A(A(i)) [example from man page] +test38: unpack A(A(i)) [example from man page] +test39: try to load a tpl with an unsupported bit flag set +test40: pack char array - userguide example +test41: unpack char arrray - userguide example +test42: test non-aligned pointers in backbone (under Solaris dbx, check -all) +test43: test non-aligned pointers in backbone (under Solaris dbx, check -all) +test44: test non-aligned pointers in backbone (under Solaris dbx, check -all) +test46: test correct-size of backbone "double" datum (Solaris dbx, check -all) +test47: store A(i) to file - userguide example +test48: read A(i) from file - userguide example +test49: write A(s) - userguide example +test50: read A(s) - userguide example +test51: test tpl_mem_gather (_0: 1 tpl; _1: 2 tpls; _2/_3/_4: 1 tpl in 3 parts) +test52: A(A(i)): pack an int; pack parent; pack int; don't pack parent; ser_osz +test53: A(A(i)): pack an int; pack parent; pack parent; 0-length 2nd parent el. +test54: test callback negative return value for tpl_mem_gather +test55: test callback negative return value for tpl_fd_gather +test56: test static string using c# format pack/unpack in mem +test57: test pack static string using c# to file +test58: test unpack static string using c# from file +test59: test alignment using cc#cc# pack/unpack in mem +test60: test pack-then-load (implicit intervening free, using tpl_free_keep_map) +test61: test load-then-load (implicit intervening free, using tpl_free_keep_map) +test62: test load-then-pack (implicit intervening free, using tpl_free_keep_map) +test63: test pack-then-unpack (implicit dump/load) then pack-then-unpack again +test64: pack level 0 types, change and re-pack level 0 types, test implicit free +test65: pack int[] using format character # +test66: pack two separate int[] using format character # +test67: test expected failure if format strings agree but array lengths mismatch +test68: test octothorpe support by packing,unpacking two fixed lengths arrays +test69: test octothorpic array support A(i#i#) +test70: test S(...) structure pack and unpack +test71: test cS(...) pack/unpack when preceded by non-structure byte +test72: test wildcard structure unpack +test73: test wildcard structure unpack +test74: test wildcard structure unpack +test75: test sc# (string and byte array) +test76: test S(sc#) (structure of last) +test77: test S(sc#) (structure of last) with wildcard unpack +test78: pack A(i)c +test79: unpack A(i)c +test80: pack and unpack A(S(ci#)) +test81: pack and unpack A(S(ci#)) +test82: pack cA(i#)S(cf#)A(ci#) +test83: unpack cA(i#)S(cf#)A(ci#) +test84: repeat test83 with both big and little endian input files +test85: tpl_peek at file +test86: tpl_peek at in-memory tpl +test87: test tpl_gather(TPL_GATHER_FD_BLOCKING) +test88: test packing S(ic#f) +test89: test unpacking S(ic#f) as S(*) +test90: pack and unpack I +test91: pack and unpack U +test92: pack and unpack A(cIcU) +test93: pack and unpack NULL string +test94: pack and unpack A(s) with some null +test95: pack and unpack null string, empty string, non-empty string +test96: pack and unpack A(null string, empty string, non-empty string) +test97: pack and unapck 16-bit int/uint (j,v) +test98: pack and unapck 16-bit int/uint A(j,v) +test99: data peek at c in complex format +test100: data peek at i inside S(ic) +test101: data peek at c inside S(ic) [expected failure test] +test102: data peek at c in simple format c +test103: data peek at iscsi in S(iscsiu) +test104: data peek at iscsi in S(iscsiu) with NULL string pointer +test105: tpl_jot then unpack by normal then by tpl_peek +test106: test IS(Iiuijc#)#iiii +test107: test S(ic#)# +test108: test IS(Iiuijc#)#iiii +test109: test S(cijc)# where next structure elt alignment based on i +test110: test ssssiiiiiiiiiiiiiiiiiiiiiiiiiiiiifffiiii +test111: test S(icfv#)# +test112: test S(ic#fv#)# +test113: test icS(ic#fv#)#ci +test114: test multi-dimension i## +test115: test S(s)#, S(si)#, S(c#si)# +test116: test cs#i +test117: test cA(s#)i +test118: test tpl_peek(TPL_FXLENS) with cA(i#)S(cf#)A(ci#) +test119: test tpl_dump(tn,TPL_GETSIZE,&sz); +test120: test TPL_PREALLOCD and TPL_EXCESS_OK flags +test121: test s## +test122: test S(ic#f$(ci)) +test123: setjmp/longjmp based fatal error handler +test124: test A(S(c#)s) as per bug report from Eric Rose diff --git a/libs/libtpl-1.5/tests/dbx.sh b/libs/libtpl-1.5/tests/dbx.sh new file mode 100755 index 0000000000..c9fd876cf2 --- /dev/null +++ b/libs/libtpl-1.5/tests/dbx.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +# This script works with Solaris Studio 11 +# version of dbx which supports "check -all" and +# "check -access" run modes, at least on Sparc. +# These detect access or alignment violations or +# leftover unfreed memory. TDH 29Dec06 + +DBX=/opt/SUNWspro/bin/dbx +OUT=/tmp/dbx.out.$$ + +echo "Writing $OUT..." + +for f in test? test?? +do + echo $f + ${DBX} $f 1>>${OUT} 2>&1 < $test.out 2> $test.err`; + `diff $test.out $test.ans`; + print "$test failed\n" if $?; + $num_failed++ if $?; + unlink "$test.err" if -z "$test.err"; +} + +print scalar @tests . " tests conducted, $num_failed failed.\n"; +exit $num_failed; diff --git a/libs/libtpl-1.5/tests/do_tests.cygwin b/libs/libtpl-1.5/tests/do_tests.cygwin new file mode 100755 index 0000000000..a9b72e0d04 --- /dev/null +++ b/libs/libtpl-1.5/tests/do_tests.cygwin @@ -0,0 +1,21 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +my @tests; +for (glob "test*[0-9].exe") { + push @tests, "$_" if -e substr($_, 0, - 4).".ans"; +} + +my $num_failed=0; + +for my $test (@tests) { + `./$test > $test.out`; + my $ansfile = substr($test, 0, - 4).".ans"; + `diff $test.out $ansfile`; + print "$test failed\n" if $?; + $num_failed++ if $?; +} + +print scalar @tests . " tests conducted, $num_failed failed.\n"; diff --git a/libs/libtpl-1.5/tests/int64_align.c b/libs/libtpl-1.5/tests/int64_align.c new file mode 100755 index 0000000000..a1a7bfcbb8 --- /dev/null +++ b/libs/libtpl-1.5/tests/int64_align.c @@ -0,0 +1,19 @@ +#include +#include + +/* try compiling this with -m32 vs -m64 + * + * with mac os x and gcc, + * on -m32 the int64_t gets aligned at +4 + * on -m64 the int64_t gets aligned at +8 + */ + +static const struct s_t { + int i; + int64_t j; +} s; + +int main() { + if ((long)&s.j % 8 != 0) printf("non-aligned int64\n"); + else printf("aligned int64\n"); +} diff --git a/libs/libtpl-1.5/tests/malign.c b/libs/libtpl-1.5/tests/malign.c new file mode 100755 index 0000000000..c3a32289d6 --- /dev/null +++ b/libs/libtpl-1.5/tests/malign.c @@ -0,0 +1,20 @@ +#include + +/* try compiling this with and without aligned doubles + * + * cc -malign-double -o malign malign.c + * cc -mno-align-double -o malign malign.c + * + * on x86, double is not normally aligned (unless -malign-double is used). + * but on Sparc, or x86-64, double is aligned. + */ + +static const struct s_t { + char a; + double d; +} s; + +int main() { + if ((long)&s.d % 8 != 0) printf("-mno-align-double\n"); + else printf("-malign-double\n"); +} diff --git a/libs/libtpl-1.5/tests/mgwtest.c b/libs/libtpl-1.5/tests/mgwtest.c new file mode 100755 index 0000000000..47528fc2f1 --- /dev/null +++ b/libs/libtpl-1.5/tests/mgwtest.c @@ -0,0 +1,56 @@ +#include +#include "tpl.h" + +int WINAPI WinMain (HINSTANCE hInstance, + HINSTANCE hPrevInstance, + PSTR szCmdLine, + int iCmdShow) +{ + char *status; + int rc=0,i,j; + tpl_node *tn; + void *img; + size_t sz; + + tn = tpl_map("A(i)", &i); + for(i=0; i<10; i++) tpl_pack(tn,1); + tpl_dump(tn,TPL_MEM,&img, &sz); + tpl_free(tn); + + j=0; + tn = tpl_map("A(i)", &i); + tpl_load(tn,TPL_MEM,img,sz); + while(tpl_unpack(tn,1) > 0) { + if (i != j++) { + rc = -1; + break; + } + } + tpl_free(tn); + + MessageBox (NULL, (rc==0)?"Test1 passed":"Test1 failed", + "MinGW Tpl Test", MB_OK); + + /* Test 2 */ + tn = tpl_map("A(i)", &i); + for(i=0; i<10; i++) tpl_pack(tn,1); + tpl_dump(tn,TPL_FILE,"mgwtest.tpl"); + tpl_free(tn); + + j=0; + tn = tpl_map("A(i)", &i); + tpl_load(tn,TPL_FILE,"mgwtest.tpl"); + while(tpl_unpack(tn,1) > 0) { + if (i != j++) { + rc = -1; + break; + } + } + tpl_free(tn); + + MessageBox (NULL, (rc==0)?"Test2 passed":"Test2 failed", + "MinGW Tpl Test", MB_OK); + + return (0); +} + diff --git a/libs/libtpl-1.5/tests/other/Makefile b/libs/libtpl-1.5/tests/other/Makefile new file mode 100755 index 0000000000..04cbb2d4b5 --- /dev/null +++ b/libs/libtpl-1.5/tests/other/Makefile @@ -0,0 +1,21 @@ +SRCDIR=../../src +CPPFLAGS = -I$(SRCDIR) + +PROGS = other1 +all: $(PROGS) run_tests + +tpl.c: + cp $(SRCDIR)/tpl.c . + +other1: other1.o tpl.o + g++ -o other1 other1.o tpl.o + + +.PHONY: clean run_tests + +clean: + rm -f *.o $(PROGS) *.out + rm -f tpl.c + +run_tests: + perl ./do_tests diff --git a/libs/libtpl-1.5/tests/other/README b/libs/libtpl-1.5/tests/other/README new file mode 100755 index 0000000000..d3fd75745e --- /dev/null +++ b/libs/libtpl-1.5/tests/other/README @@ -0,0 +1,2 @@ +Assorted other tests that are not part of the standard test suite. +other1: a C++ program using "this" as a structure pointer diff --git a/libs/libtpl-1.5/tests/other/do_tests b/libs/libtpl-1.5/tests/other/do_tests new file mode 100755 index 0000000000..0b62640a72 --- /dev/null +++ b/libs/libtpl-1.5/tests/other/do_tests @@ -0,0 +1,22 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +my @tests; +for (glob "other*[0-9]") { + push @tests, $_ if -e "$_.ans"; +} + +my $num_failed=0; + +for my $test (@tests) { + `./$test > $test.out 2> $test.err`; + `diff $test.out $test.ans`; + print "$test failed\n" if $?; + $num_failed++ if $?; + unlink "$test.err" if -z "$test.err"; +} + +print scalar @tests . " tests conducted, $num_failed failed.\n"; +exit $num_failed; diff --git a/libs/libtpl-1.5/tests/other/other1.ans b/libs/libtpl-1.5/tests/other/other1.ans new file mode 100755 index 0000000000..f32671aac3 --- /dev/null +++ b/libs/libtpl-1.5/tests/other/other1.ans @@ -0,0 +1,3 @@ +buffer: tpl +i: 9999 +c: this is a test string. diff --git a/libs/libtpl-1.5/tests/other/other1.cpp b/libs/libtpl-1.5/tests/other/other1.cpp new file mode 100755 index 0000000000..ce7f7ba440 --- /dev/null +++ b/libs/libtpl-1.5/tests/other/other1.cpp @@ -0,0 +1,40 @@ +#include +#include +#include "tpl.h" +main() { +void *buffer; +size_t bsize; + +struct ci { + int i; + char c[30]; + + void pack( void **buffer, size_t *size ) + { + tpl_node *tn = tpl_map("S(ic#)", this, 30); /* pass structure address */ + tpl_pack(tn, 0); + tpl_dump(tn, TPL_MEM, buffer, size); + tpl_free(tn); + } + + void unpack( void *buffer, size_t size ) + { + tpl_node *tn = tpl_map("S(ic#)", this, 30); + tpl_load(tn, TPL_MEM, buffer, size); + tpl_unpack( tn, 0 ); + tpl_free(tn); + } +}; + +struct ci s = {9999, "this is a test string."}; + +s.pack(&buffer, &bsize); +printf("buffer: %s\n", (char *)buffer); + +struct ci b = { -1, "" }; + +b.unpack(buffer, bsize); + +printf("i: %d\n", b.i); +printf("c: %s\n", b.c); +} diff --git a/libs/libtpl-1.5/tests/sizes b/libs/libtpl-1.5/tests/sizes new file mode 100755 index 0000000000..1c16449038 --- /dev/null +++ b/libs/libtpl-1.5/tests/sizes @@ -0,0 +1,23 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Config; + +#print "$_: ", ($Config{$_} or ""), "\n" for keys %Config; +#exit; + +my @types = qw(char short int long longlong double); +for (@types) { + my $bytes = $Config{"${_}size"}; + my $bits = $bytes * 8; + printf "size of %-10s: %5d bytes (%d bits)\n", $_, $bytes, $bits;; +} + +print qq/ + These sizes reflect the platform and compiler options with + which Perl was built on this system. The sizes may change + if different compiler options are used. +/; + diff --git a/libs/libtpl-1.5/tests/test1 b/libs/libtpl-1.5/tests/test1 new file mode 100755 index 0000000000000000000000000000000000000000..611d57af28b565f83d83890198b906e407eff127 GIT binary patch literal 127742 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В)}qZ1hRxfam+9SwX!k!mWZV2Z|aQ->nWj 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test1-mingw.c b/libs/libtpl-1.5/tests/test1-mingw.c new file mode 100755 index 0000000000..1a1f20b849 --- /dev/null +++ b/libs/libtpl-1.5/tests/test1-mingw.c @@ -0,0 +1,12 @@ +#include +#include "tpl.h" + +int WINAPI WinMain (HINSTANCE hInstance, + HINSTANCE hPrevInstance, + PSTR szCmdLine, + int iCmdShow) +{ + MessageBox (NULL, "Hello", "Hello Demo", MB_OK); + return (0); +} + diff --git a/libs/libtpl-1.5/tests/test1.ans b/libs/libtpl-1.5/tests/test1.ans new file mode 100755 index 0000000000..858b8f6d24 --- /dev/null +++ b/libs/libtpl-1.5/tests/test1.ans @@ -0,0 +1 @@ +j is 1 diff --git a/libs/libtpl-1.5/tests/test1.c b/libs/libtpl-1.5/tests/test1.c new file mode 100755 index 0000000000..2e23fe4115 --- /dev/null +++ b/libs/libtpl-1.5/tests/test1.c @@ -0,0 +1,24 @@ +#include +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + int i,j=-1; + void *addr; + size_t sz; + + tn = tpl_map("i",&i); + i=1; + tpl_pack(tn,0); + tpl_dump(tn,TPL_MEM,&addr,&sz); + tpl_free(tn); + + tn = tpl_map("i",&j); + tpl_load(tn,TPL_MEM,addr,sz); + tpl_unpack(tn,0); + printf("j is %d\n", j); + tpl_free(tn); + free(addr); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test1.out b/libs/libtpl-1.5/tests/test1.out new file mode 100644 index 0000000000..858b8f6d24 --- /dev/null +++ b/libs/libtpl-1.5/tests/test1.out @@ -0,0 +1 @@ +j is 1 diff --git a/libs/libtpl-1.5/tests/test10 b/libs/libtpl-1.5/tests/test10 new file mode 100755 index 0000000000000000000000000000000000000000..a16c6d9f3cb36c89d720e5772e4cc12b8df554a8 GIT binary patch literal 127327 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 bcU=eBLb_kcaL7a|cvWU5tQ?cs;vM-vmK_$r literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test10.ans b/libs/libtpl-1.5/tests/test10.ans new file mode 100755 index 0000000000..903c08cf1f --- /dev/null +++ b/libs/libtpl-1.5/tests/test10.ans @@ -0,0 +1,10 @@ +i is 0 +i is 1 +i is 2 +i is 3 +i is 4 +i is 5 +i is 6 +i is 7 +i is 8 +i is 9 diff --git a/libs/libtpl-1.5/tests/test10.c b/libs/libtpl-1.5/tests/test10.c new file mode 100755 index 0000000000..5e2bb03b8a --- /dev/null +++ b/libs/libtpl-1.5/tests/test10.c @@ -0,0 +1,13 @@ +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + int i; + + tn = tpl_map("A(i)",&i); + tpl_load(tn,TPL_FILE,"test10.tpl"); + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test10.out b/libs/libtpl-1.5/tests/test10.out new file mode 100644 index 0000000000..903c08cf1f --- /dev/null +++ b/libs/libtpl-1.5/tests/test10.out @@ -0,0 +1,10 @@ +i is 0 +i is 1 +i is 2 +i is 3 +i is 4 +i is 5 +i is 6 +i is 7 +i is 8 +i is 9 diff --git a/libs/libtpl-1.5/tests/test10.tpl b/libs/libtpl-1.5/tests/test10.tpl new file mode 100755 index 0000000000000000000000000000000000000000..a811f623c7fedbaa51321b3789b96174f6ca0d44 GIT binary patch literal 57 ucmXRZ$YHQ#U|?|6$kb%u0y02=5r~<9m>Gy!fS47C*?^cGh&h0m6Nmwba00vl literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test100 b/libs/libtpl-1.5/tests/test100 new file mode 100755 index 0000000000000000000000000000000000000000..b9d6dad98728fb92f8c8f36d84665df6bcee551e GIT binary patch literal 127649 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 + +const char *filename = "/tmp/test100.tpl"; +int main() { + tpl_node *tn; + struct { + int i; + char c; + } s; + int p; + char *fmt; + + tn = tpl_map("S(ic)", &s); + s.i = 1; s.c = '^'; + tpl_pack(tn, 0); + tpl_dump(tn, TPL_FILE, filename); + tpl_free(tn); + + fmt = tpl_peek(TPL_FILE|TPL_DATAPEEK, filename, "i", &p); + if (fmt) { + printf("fmt: %s\n", fmt); + printf("p: %d\n", p); + } + + return 0; +} diff --git a/libs/libtpl-1.5/tests/test100.out b/libs/libtpl-1.5/tests/test100.out new file mode 100644 index 0000000000..402ddaef7b --- /dev/null +++ b/libs/libtpl-1.5/tests/test100.out @@ -0,0 +1,2 @@ +fmt: S(ic) +p: 1 diff --git a/libs/libtpl-1.5/tests/test101 b/libs/libtpl-1.5/tests/test101 new file mode 100755 index 0000000000000000000000000000000000000000..ce2746653c1377371457d5469881f13e42e2322d GIT binary patch literal 128363 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 Iq~OT^0__6f7ytkO literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test101.ans b/libs/libtpl-1.5/tests/test101.ans new file mode 100755 index 0000000000..68bece6d85 --- /dev/null +++ b/libs/libtpl-1.5/tests/test101.ans @@ -0,0 +1,2 @@ +TPL_DATAPEEK format mismatches tpl iamge +peek failed diff --git a/libs/libtpl-1.5/tests/test101.c b/libs/libtpl-1.5/tests/test101.c new file mode 100755 index 0000000000..833657a5fd --- /dev/null +++ b/libs/libtpl-1.5/tests/test101.c @@ -0,0 +1,30 @@ +#include "tpl.h" +#include + +extern tpl_hook_t tpl_hook; +const char *filename = "/tmp/test101.tpl"; +int main() { + tpl_node *tn; + struct { + int i; + char c; + } s; + char *fmt, q; + tpl_hook.oops = printf; + + tn = tpl_map("S(ic)", &s); + s.i = 1; s.c = '^'; + tpl_pack(tn, 0); + tpl_dump(tn, TPL_FILE, filename); + tpl_free(tn); + + fmt = tpl_peek(TPL_FILE|TPL_DATAPEEK, filename, "c", &q); + if (fmt) { + printf("fmt: %s\n", fmt); + printf("q: %c\n", q); + } else { + printf("peek failed\n"); + } + + return 0; +} diff --git a/libs/libtpl-1.5/tests/test101.out b/libs/libtpl-1.5/tests/test101.out new file mode 100644 index 0000000000..68bece6d85 --- /dev/null +++ b/libs/libtpl-1.5/tests/test101.out @@ -0,0 +1,2 @@ +TPL_DATAPEEK format mismatches tpl iamge +peek failed diff --git a/libs/libtpl-1.5/tests/test102 b/libs/libtpl-1.5/tests/test102 new file mode 100755 index 0000000000000000000000000000000000000000..c5e6804fdea265dd78cec67f373bc8ab4f3b511f GIT binary patch literal 127633 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 U(74cy$~onxW-cA0Y2zIEUsl~%eE + +const char *filename = "/tmp/test102.tpl"; +int main() { + tpl_node *tn; + char *fmt,p,q; + + tn = tpl_map("c", &p); + p = '!'; + tpl_pack(tn, 0); + tpl_dump(tn, TPL_FILE, filename); + tpl_free(tn); + + fmt = tpl_peek(TPL_FILE|TPL_DATAPEEK, filename, "c", &q); + if (fmt) { + printf("fmt: %s\n", fmt); + printf("q: %c\n", q); + } + + return 0; +} diff --git a/libs/libtpl-1.5/tests/test102.out b/libs/libtpl-1.5/tests/test102.out new file mode 100644 index 0000000000..a29caa72ee --- /dev/null +++ b/libs/libtpl-1.5/tests/test102.out @@ -0,0 +1,2 @@ +fmt: c +q: ! diff --git a/libs/libtpl-1.5/tests/test103 b/libs/libtpl-1.5/tests/test103 new file mode 100755 index 0000000000000000000000000000000000000000..a2c1618b8fdcbf3adc523edd24683859d49bd30d GIT binary patch literal 128483 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test103.ans b/libs/libtpl-1.5/tests/test103.ans new file mode 100755 index 0000000000..3763fdf0e7 --- /dev/null +++ b/libs/libtpl-1.5/tests/test103.ans @@ -0,0 +1,2 @@ +fmt: S(iscsiu) +pi: 1, ps: hello, pc: ^, pt: world, pi: 2 diff --git a/libs/libtpl-1.5/tests/test103.c b/libs/libtpl-1.5/tests/test103.c new file mode 100755 index 0000000000..006b3886fa --- /dev/null +++ b/libs/libtpl-1.5/tests/test103.c @@ -0,0 +1,33 @@ +#include "tpl.h" +#include + +const char *filename = "/tmp/test103.tpl"; +int main() { + tpl_node *tn; + struct { + int i; + char *s; + char c; + char *t; + int j; + unsigned u; + } s; + char *fmt, *ps, pc, *pt; + int pi, pj; + + tn = tpl_map("S(iscsiu)", &s); + s.i = 1; s.s = "hello"; s.c = '^'; s.t = "world"; s.j = 2; s.u = 3; + tpl_pack(tn, 0); + tpl_dump(tn, TPL_FILE, filename); + tpl_free(tn); + + fmt = tpl_peek(TPL_FILE|TPL_DATAPEEK, filename, "iscsi",&pi,&ps,&pc,&pt,&pj); + if (fmt) { + printf("fmt: %s\n", fmt); + printf("pi: %d, ps: %s, pc: %c, pt: %s, pi: %d\n", pi,ps,pc,pt,pj); + } else { + printf("peek failed\n"); + } + + return 0; +} diff --git a/libs/libtpl-1.5/tests/test103.out b/libs/libtpl-1.5/tests/test103.out new file mode 100644 index 0000000000..3763fdf0e7 --- /dev/null +++ b/libs/libtpl-1.5/tests/test103.out @@ -0,0 +1,2 @@ +fmt: S(iscsiu) +pi: 1, ps: hello, pc: ^, pt: world, pi: 2 diff --git a/libs/libtpl-1.5/tests/test104 b/libs/libtpl-1.5/tests/test104 new file mode 100755 index 0000000000000000000000000000000000000000..10be0c7dcd4354d557b6728aeb4b9cc61ea7394b GIT binary patch literal 128483 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 + +const char *filename = "/tmp/test104.tpl"; +int main() { + tpl_node *tn; + struct { + int i; + char *s; + char c; + char *t; + int j; + unsigned u; + } s; + char *fmt, *ps, pc, *pt; + int pi, pj; + + tn = tpl_map("S(iscsiu)", &s); + s.i = 1; s.s = NULL; s.c = '^'; s.t = "world"; s.j = 2; s.u = 3; + tpl_pack(tn, 0); + tpl_dump(tn, TPL_FILE, filename); + tpl_free(tn); + + fmt = tpl_peek(TPL_FILE|TPL_DATAPEEK, filename, "iscsi",&pi,&ps,&pc,&pt,&pj); + if (fmt) { + printf("fmt: %s\n", fmt); + printf("pi: %d, ps: %s, pc: %c, pt: %s, pi: %d\n",pi,ps?ps:"NULL",pc,pt,pj); + } else { + printf("peek failed\n"); + } + + return 0; +} diff --git a/libs/libtpl-1.5/tests/test104.out b/libs/libtpl-1.5/tests/test104.out new file mode 100644 index 0000000000..5e79c697de --- /dev/null +++ b/libs/libtpl-1.5/tests/test104.out @@ -0,0 +1,2 @@ +fmt: S(iscsiu) +pi: 1, ps: NULL, pc: ^, pt: world, pi: 2 diff --git a/libs/libtpl-1.5/tests/test105 b/libs/libtpl-1.5/tests/test105 new file mode 100755 index 0000000000000000000000000000000000000000..abeb3d1d24a4f962681331f19d3736ba9fc0a03f GIT binary patch literal 128049 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

GP1# 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%0AnTBWLDm5TAf#j*jkJO40tY0!j+Q(S$%@A7c) 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test105.ans b/libs/libtpl-1.5/tests/test105.ans new file mode 100755 index 0000000000..811209f0e6 --- /dev/null +++ b/libs/libtpl-1.5/tests/test105.ans @@ -0,0 +1,2 @@ +i: 1, s: hello, w: world, c: $ +i: 1, s: hello, w: world, c: $ diff --git a/libs/libtpl-1.5/tests/test105.c b/libs/libtpl-1.5/tests/test105.c new file mode 100755 index 0000000000..c8e6411eed --- /dev/null +++ b/libs/libtpl-1.5/tests/test105.c @@ -0,0 +1,29 @@ +#include "tpl.h" +#include + +const char *filename = "/tmp/test105.tpl"; + +int main() { + int i=1; + char *s="hello",*w="world",c='$', *fmt; + tpl_node *tn; + + tpl_jot(TPL_FILE, filename, "issc", &i, &s, &w, &c); + + i = 0; s = NULL; w = NULL; c = 0; + + /* unpack the normal way */ + tn = tpl_map("issc", &i, &s, &w, &c); + tpl_load(tn, TPL_FILE, filename); + tpl_unpack(tn,0); + tpl_free(tn); + printf("i: %d, s: %s, w: %s, c: %c\n", i, s, w, c); + + i = 0; s = NULL; w = NULL; c = 0; + + /* unpack the quick way */ + fmt = tpl_peek(TPL_FILE|TPL_DATAPEEK, filename, "issc", &i, &s, &w, &c); + printf("i: %d, s: %s, w: %s, c: %c\n", i, s, w, c); + + return 0; +} diff --git a/libs/libtpl-1.5/tests/test105.out b/libs/libtpl-1.5/tests/test105.out new file mode 100644 index 0000000000..811209f0e6 --- /dev/null +++ b/libs/libtpl-1.5/tests/test105.out @@ -0,0 +1,2 @@ +i: 1, s: hello, w: world, c: $ +i: 1, s: hello, w: world, c: $ diff --git a/libs/libtpl-1.5/tests/test106 b/libs/libtpl-1.5/tests/test106 new file mode 100755 index 0000000000000000000000000000000000000000..5eb13319719cc8c6026e64fe9fd7baa1bffb1d39 GIT binary patch literal 132711 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 M=d~P@N#z~+UyR~+9{>OV literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test106.ans b/libs/libtpl-1.5/tests/test106.ans new file mode 100755 index 0000000000..e8aff5bafe --- /dev/null +++ b/libs/libtpl-1.5/tests/test106.ans @@ -0,0 +1,24 @@ +testing with TPL_FILE: +1000 + 0, 0, 0, 5000, 15, Deepak + 1, 5, 10, 6000, 18, Deepak + 2, 10, 20, 7000, 21, Deepak + 3, 15, 30, 8000, 24, Deepak + 4, 20, 40, 9000, 27, Deepak + 5, 25, 50, 10000, 30, Deepak + 6, 30, 60, 11000, 33, Deepak + 7, 35, 70, 12000, 36, Deepak + 8, 40, 80, 13000, 39, Deepak +9,23,43,16 +testing with TPL_FD: +1000 + 0, 0, 0, 5000, 15, Deepak + 1, 5, 10, 6000, 18, Deepak + 2, 10, 20, 7000, 21, Deepak + 3, 15, 30, 8000, 24, Deepak + 4, 20, 40, 9000, 27, Deepak + 5, 25, 50, 10000, 30, Deepak + 6, 30, 60, 11000, 33, Deepak + 7, 35, 70, 12000, 36, Deepak + 8, 40, 80, 13000, 39, Deepak +9,23,43,16 diff --git a/libs/libtpl-1.5/tests/test106.c b/libs/libtpl-1.5/tests/test106.c new file mode 100755 index 0000000000..ea0ef453a5 --- /dev/null +++ b/libs/libtpl-1.5/tests/test106.c @@ -0,0 +1,126 @@ +#include "tpl.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#define SUM_LENGTH 16 +#define MS_COUNT 9 +struct sum_buf { + int64_t offset; + int len; + uint32_t sum1; + int chain; + uint16_t flags; + char sum2[SUM_LENGTH]; +}; + +struct sum_struct { + int64_t flength; + struct sum_buf *sums; + int count; + int blength; + int remainder; + int s2length; +}; + +const char *filename = "/tmp/test106.tpl"; + +int pack(int use_fd) +{ + tpl_node *tn; + struct sum_struct ms; + int fd=-1,j; + unsigned perms; + + perms = S_IRUSR|S_IWUSR; + if (use_fd) { + if ( (fd=open( filename,O_WRONLY|O_CREAT,perms)) == -1) { + printf("failed to open %s: %s", filename, strerror(errno)); + return(-1); + } + } + + ms.flength = 1000; + ms.count = MS_COUNT; + ms.blength = 23; + ms.remainder = 43; + ms.s2length = 16; + + ms.sums = (struct sum_buf*) malloc((sizeof(struct sum_buf))*ms.count); + + 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test107.ans b/libs/libtpl-1.5/tests/test107.ans new file mode 100755 index 0000000000..02bf39a506 --- /dev/null +++ b/libs/libtpl-1.5/tests/test107.ans @@ -0,0 +1,5 @@ +0 cat +1 dog +2 eel +3 emu +4 ant diff --git a/libs/libtpl-1.5/tests/test107.c b/libs/libtpl-1.5/tests/test107.c new file mode 100755 index 0000000000..e936e27c7a --- /dev/null +++ b/libs/libtpl-1.5/tests/test107.c @@ -0,0 +1,38 @@ +#include "tpl.h" +#include +#include + +typedef struct { + int i; + char c[4]; +} test_t; + +const char *filename = "/tmp/test107.tpl"; + +int main() { + test_t s[5], t[5]; + tpl_node *tn; + int i; + + s[0].i = 0; strcpy(s[0].c, "cat"); + s[1].i = 1; strcpy(s[1].c, "dog"); + s[2].i = 2; strcpy(s[2].c, "eel"); + s[3].i = 3; strcpy(s[3].c, "emu"); + s[4].i = 4; strcpy(s[4].c, "ant"); + + tn = tpl_map("S(ic#)#", &s, 4, 5); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,filename); + tpl_free(tn); + + tn = tpl_map("S(ic#)#", &t, 4, 5); + tpl_load(tn,TPL_FILE,filename); + tpl_unpack(tn,0); + tpl_free(tn); + + for(i=0; i < 5; i++) { + printf("%d %s\n", s[i].i, s[i].c); + } + + return 0; +} diff --git a/libs/libtpl-1.5/tests/test107.out b/libs/libtpl-1.5/tests/test107.out new file mode 100644 index 0000000000..02bf39a506 --- /dev/null +++ b/libs/libtpl-1.5/tests/test107.out @@ -0,0 +1,5 @@ +0 cat +1 dog +2 eel +3 emu +4 ant diff --git a/libs/libtpl-1.5/tests/test108 b/libs/libtpl-1.5/tests/test108 new file mode 100755 index 0000000000000000000000000000000000000000..df948b47311accbf45a8a2e2b03d1f2a00a78233 GIT binary patch literal 129567 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≈QIXqPP2N)?ohY21m949 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test108.ans b/libs/libtpl-1.5/tests/test108.ans new file mode 100755 index 0000000000..ff0ab00b11 --- /dev/null +++ b/libs/libtpl-1.5/tests/test108.ans @@ -0,0 +1,2 @@ +structure matches original +other fields match original diff --git a/libs/libtpl-1.5/tests/test108.c b/libs/libtpl-1.5/tests/test108.c new file mode 100755 index 0000000000..5a12589b66 --- /dev/null +++ b/libs/libtpl-1.5/tests/test108.c @@ -0,0 +1,49 @@ +#include "tpl.h" +#include +#include +#include + +typedef struct { + int64_t j; + int l1; + unsigned l2; + int i; + int16_t h; + char c[4]; +} test_t; + +const char *filename = "/tmp/test108.tpl"; + +int main() { + test_t s[5], t[5]; + tpl_node *tn; + int w=10,x=20,y=30,z=40,W,X,Y,Z; + uint64_t b=10,B; + + memset(s, 0, sizeof(s)); + memset(t, 0, sizeof(t)); + + s[0].j=0; s[0].i=0; s[0].l1= 0; s[0].l2=0; s[0].h= 0; strcpy(s[0].c, "cat"); + s[1].j=100; s[1].i=1; s[1].l1=-1; s[1].l2=10; s[1].h=1000; strcpy(s[1].c, "dog"); + s[2].j=200; s[2].i=2; s[2].l1=-2; s[2].l2=20; s[2].h=2000; strcpy(s[2].c, "eel"); + s[3].j=300; s[3].i=3; s[3].l1=-3; s[3].l2=30; s[3].h=3000; strcpy(s[3].c, "emu"); + s[4].j=400; s[4].i=4; s[4].l1=-4; s[4].l2=40; s[4].h=4000; strcpy(s[4].c, "ant"); + + tn = tpl_map("IS(Iiuijc#)#iiii", &b, s, 4, 5, &w, &x, &y, &z); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,filename); + tpl_free(tn); + + tn = tpl_map("IS(Iiuijc#)#iiii", &B, t, 4, 5, &W, &X, &Y, &Z); + tpl_load(tn,TPL_FILE,filename); + tpl_unpack(tn,0); + tpl_free(tn); + + if (memcmp(t,s,sizeof(t)) == 0) printf("structure matches original\n"); + else printf("structure mismatches original\n"); + + if (b==B && w==W && x==X && y==Y && z==Z) printf("other fields match original\n"); + else printf("other fields mismatch originals\n"); + + return 0; +} diff --git a/libs/libtpl-1.5/tests/test108.out b/libs/libtpl-1.5/tests/test108.out new file mode 100644 index 0000000000..ff0ab00b11 --- /dev/null +++ b/libs/libtpl-1.5/tests/test108.out @@ -0,0 +1,2 @@ +structure matches original +other fields match original diff --git a/libs/libtpl-1.5/tests/test109 b/libs/libtpl-1.5/tests/test109 new file mode 100755 index 0000000000000000000000000000000000000000..70813e3c51e04c43a9fa4ff442966b7cd495aa98 GIT binary patch literal 128275 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

M7;3{ZU!d! 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 +#include "tpl.h" +#include + +const char *filename = "/tmp/test109.tpl"; + +typedef struct { + char c; + uint32_t i; + uint16_t j; + char d; +} spad; + +int main() { + tpl_node *tn; + spad s = {'a', 1, 2, 'b'}, t = {'?', 0, 0, '!'};; + + printf("sizeof(s): %d\n", (int)sizeof(s));; + tn = tpl_map("S(cijc)", &s); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,filename); + tpl_free(tn); + + tn = tpl_map("S(cijc)", &t); + tpl_load(tn,TPL_FILE,filename); + tpl_unpack(tn,0); + tpl_free(tn); + + if (s.c==t.c && s.i==t.i && s.j==t.j && s.d==t.d) + printf("structures match\n"); + else + printf("structures mismatch\n"); + + return 0; +} diff --git a/libs/libtpl-1.5/tests/test109.out b/libs/libtpl-1.5/tests/test109.out new file mode 100644 index 0000000000..0515356ccf --- /dev/null +++ b/libs/libtpl-1.5/tests/test109.out @@ -0,0 +1,2 @@ +sizeof(s): 12 +structures match diff --git a/libs/libtpl-1.5/tests/test11 b/libs/libtpl-1.5/tests/test11 new file mode 100755 index 0000000000000000000000000000000000000000..06ad4ff34ede74b249406eef75074a59024da671 GIT binary patch literal 127639 zcmd443w#ts_CMM^Gf6sxqz54o5M?BT1_Vq1F;UbRNT5e28s4lg9z!B1k4PqfiV~O! z(hhOsPuF!_cbC=O6<1f>{ke*d9|`h^y6!IG3!mTvoi?JZ4@6Yve!tb#lL2A(cmJPz z@8^zYs_N9KQ>RXyI_Fe%^{}!kJl>_Mit}+P7bqK+gv`&&^CyxxTqP|6ie2`Gb< zfl4;8vhe5N1!T@i+hsE+)qu;78-E^VT>Qev6~Grht^mFirJwljN}b-BvcIlRKxXZ9 zXro~2~({3W#kPXK@81n{a8z%M=lJa7W|qbGo$aRT_H6Tp9e0(iv<;Mbf0 z-f;r>;uFB1I02l~=fmHzpC$l~H!t^|0RFQRz#lpRe9sBs)S=_`yZHq0G6@gl1(56d zB#|YZy}5xdAad{FkMR0#0ep9TZb6oC-!XJ<1FQ!$zJB>EV=CJ&1{Iy zUJ{)-Q^B%}aGi}-YM0NCDh<&kiy{l_mAdGX#zm3Y(OP9m?d$~$7DrgqP`^l7xNvs8 zvasR$MFO&*7LeM74Yg5a=FHk9OBOAj3EbJy`HL5^;apad+|q_c^-Jb2iq;80{q@R1 zhv;0iQWiEYBH5WU>z0GBs1jMQxS>{ATo3B#HZpICNI(ZA;4fYRR5C6{v2gbMMar@z z^TF-XI@wR%lG<8jLO3*b+{_Wf%SNTMBZi+1LAd_If3zjX$58>NE#e}B82QuKj93av|8SugkxFYQU=c;!GT+4v>$$)z^;6)j5 zBlf9gB(iE3`V^zNJ(`sq2W>QB+qA72NXVwno&=QCpegv)2LzB~c^;9hy(xSKUBog~ z+1e?}V_BvOTkWEJF3VJ1>rqi2!7^3WS})2&Sf;94t)e`TWvZyvB+C6*=5VcgQ9g-f zs-!hbl)JG^m9uI@*~Kzd%?gO};RPsD#jH|M{(|N1Ec-)ZaZhV2GkTm5X}A+-jH|n>njx?aAd66s5Cwoj#yaQ4+vw z>m^7e$)CV6%st6FsuiWVedQkJUkCfpC2v{#dH1&rS|Fr znh4v(l7qkHkQ?}h`K+PlXx7J5u=3p9c|b6;xbmDY`DVlBlN28xfd>Qe(^ zi?DRbY471YjC0eTu z>|QE?Mae6^Po>&U;gmxId}Zya!W*vfDQy@}D*5OSsT9Vu8^|0_)L&wlQ~afd8TOZl zK{60V&WN6)53cmr=!3)lS^D59{(61zz5XV&(FgxdbV$C}i}GV)kh#(wE8s_$3?1z*de-N^)YTmEMx4IN1 zl<@drAoci66e<(-Fq-*I^Ll{+-HWYc)h%DC(_4DLA-=$Ka#2A07@MK_z6AS#_P>08lF@XCjEu>=UBtsS3 z^`E!vkGI26Pu}dE6@U_T80H&a{y}ek7?{CCy(f4u;8wv(X|zOtywYE)KR(4ja&0C4 zFk^(25i$ah5rC9|$lu{v0dX>k;ZE`U$W9{cFG{@>G&{=LL2r3}sAasCX1v-wU|k56s%tH4 zZ<~z)qzZe2lAs>V6_ig#nUZ)K)0;{ac4yI%#HwwEPf^U>mtPsYB6wx+s^CnlO}qc( zjo+qHiSk&=qsRT=E0)T88hk6!7mUOy8?W{$$-{@C;Xd>UYXJRznKNp3(&;@Qrs+N) z*;8;gbF$CQTSFE5^))Yno3QEew|PM`RagfMv<#U$LI8$ANsosquff}i6{d*BIyl*O zeG%%}XW0BC411I)uQcar$q&J{E!^h&!L~I|bcE?QS{C>NRtiNa`zXXAyZ^XOcF%r4 zqx8)Z$loi5RHIqNXw^0eL*+W&1!QY2AZ2fbVq^S@9)AoSwUtKf>N`-)cGfq5f~%*I zK<;-6FctDv=A0QwoSi_i?Hoya8VXh|T5vvRfnus~96*`#c`=(~K8@y7G&@x|hDAy3 zX)L&ubvn5rv#G)}P)T7~uQ)Icpa-DUiBUq#);&&5s_@%d$@vk$4D$*Ex z^`r~6PZ7m18@$OC-=GiRVig<41pN;V zQZJ!|L%?pb5xs@YkKmfx8f_WAY$iMZTGyI5FF7AwBp-9ozncs6@m=VxUFd6oJch`( zILQAXa^EiGhtkN_G{{&VpaiD}r-jTTw2xCK!|4}=6LntNa;>`gLp}aqU|8^5ofzs5 zC9d#mp~UdcQ|pF1>#OZqn`B`OU4fpFSXgQ_?~hI}B2`N4Q1@l;n$M>Eug1G zTP}&IMQ|L=yY$- z+-;~^tq(*EqM86rg<`#ImxI$ortnW8^HofNVg8-7U>J!B-mnSx98T01h28bO=7Z62 z>`0a#|I$UxZQDC5pj4H8m@3R88*t4n<5SHC(ZaX#91)i!*w}=}hJcJN0YUqk*uRL& zKp@@h=D&v$SHgI`)!5zK(V2AS*NC_=i%Uz=^Zd&>ka^;AO!8Ze@1qkRu%GIZkC^S} z#B7Ux5;qn#r*8g7IAY7=qLy%$LSMLgE0_qId&_o(2frtR$2i%7R~w~@W�<@f96etxQ$3-I*Op8VB`)$04CYOW}UmzN?HfLch(7&XPrmz)yd>%3eXqOu5_K>>GdWbY_y}7uk z`FZ^|nll5eS0i8({Qo=zjYufwj#VEiP@sd`G(8@`ked(k1W7kX|RP zph~;aGLdr7S0_kQNt8hXuu?vI8hxC!Vho}flZHa2|1?4d0x}Sg)3`vuW$+mfq-1G= zq^)mQR~MqwL5{x1+SQ8Z^!N(kWy)V)-IM(`D(2T2(%EJGK>vBLs;s>%)p;7%os|EZ zaA8Nce;JsSiK$AkWo#-KJFFt=8{ZMq$0wyk9f@zY9t0+a=CytXBDBwG<2)mrSPA3I ziHrJ+suPQSp~T{%Q0xayUvo3;!c%UrEdoG)-Z=Mc?(I2mJ zZ}?tso&)FxS1^&&nBDZEH)!T0rg{eP_z?W`M?CC{`YA^UbBdHKU{bPEq-3W+vIy&- zu<`C(el1hAi&`p&(J(O<*9`Mz<2?8bJ^mu9EA_`mR>cqM&D{2c5-YJ=crD!0peA=8 zuo>lMCAj57SJ*sY3{F-@J`AgS86vK3XGLN{Io5C~W9lbs*6)N>-Kqw$a{G(r5m17wbPCV<71V@!0QP*FFp;Tn z#V30FeLy?c3A@}9wfWS$_zYJZj9v;J&1a#nBe#4~v=%YB`K(x)pKxiG1rwD8DL_Y5 za0Gv|DnQt7&v9%*1p6cVL(9eB+e<4H2%G;(lwxs0<{ink5CF_jbSZF(LW4gGyRqp& zyn8aD{Us-pA~xokp>!o9{;wf91Q#i53kI_Z`;wIP1al%-`xA2jr7T9PoA8&ie!<+= z%>9%(#3U)JnK{HGDeFe$7=KI+nLh}}_ca|Ky!wEI+kAG_`zn^|s>A%&;|n19*xrG$ zLj(2r{m2`(r-}|leB=h>{pg~G!7DNtNfjQt94-;?#$;V<2==D~Du70@ZJIqQ_&_D) z-(GrkKxq~JB;n=Ozps%vm%hDQs_+p|5H+%CVjTP(6pzOQIQ!@{)B0j08W57-SYmXH z^NC&(i?rke7;9SzimAdWq{L0$IIkXm86Zg!F}`EskQRxi9RZ(66PK4*e#l7Z(d44C z{a8

    d9J`5jY2MhjDgS(4Gj~)cjS2};<%Zy7e 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

    |US6UGUZIe+y)o(QiV*^87XHL*SBEb|WOQfJ| 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 JW{Y#=e*yTDHaGwP literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test11.ans b/libs/libtpl-1.5/tests/test11.ans new file mode 100755 index 0000000000..c54ecf7203 --- /dev/null +++ b/libs/libtpl-1.5/tests/test11.ans @@ -0,0 +1 @@ +test11.tpl: not a valid tpl file diff --git a/libs/libtpl-1.5/tests/test11.c b/libs/libtpl-1.5/tests/test11.c new file mode 100755 index 0000000000..efe5b1878f --- /dev/null +++ b/libs/libtpl-1.5/tests/test11.c @@ -0,0 +1,17 @@ +#include +#include "tpl.h" + +extern tpl_hook_t tpl_hook; + +int main() { + tpl_node *tn; + int i; + + tpl_hook.oops = printf; + + tn = tpl_map("A(i)",&i); + tpl_load(tn,TPL_FILE,"test11.tpl"); + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test11.out b/libs/libtpl-1.5/tests/test11.out new file mode 100644 index 0000000000..c54ecf7203 --- /dev/null +++ b/libs/libtpl-1.5/tests/test11.out @@ -0,0 +1 @@ +test11.tpl: not a valid tpl file diff --git a/libs/libtpl-1.5/tests/test11.tpl b/libs/libtpl-1.5/tests/test11.tpl new file mode 100755 index 0000000000000000000000000000000000000000..d3a3e3de65cc79942e8a4a2f0bef4d8b5771129b GIT binary patch literal 57 ucmXRZ$YHQ#U|?|6sM2KM0y02=5r~<9m>Gy!fS47C*?^cGh&h0m6Nmwej{?mA literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test110 b/libs/libtpl-1.5/tests/test110 new file mode 100755 index 0000000000000000000000000000000000000000..790c293697e2a2d2de1d2a487ebee1ff0bb986bc GIT binary patch literal 135543 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

    mLS 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 loa +#include +#include +#include "tpl.h" + +const char *filename = "/tmp/test113.tpl"; + +#define NUM 10 + +struct st { + int i; + char c[8]; + double f; + uint16_t v[2]; +}; + + +int main() { + struct st s[NUM], t[NUM]; + tpl_node *tn; + int i; + int a=5,d=8, A, D; + char b='6',c='7', B, C; + + memset(s, 0, sizeof(s)); /* clear s */ + memset(t, 0, sizeof(t)); /* clear t */ + + /* fill s with random stuff */ + for(i=0; i < NUM; i++) { + s[i].i = i; s[i].f = 3.14159 * i; s[i].v[0] = NUM*i; s[i].v[1] = NUM+i; + strncpy(s[i].c, "abcdefg",8); + s[i].c[0] += 1; + } + + tn = tpl_map("icS(ic#fv#)#ci", &a, &b, s, 8, 2, NUM, &c, &d); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,filename); + tpl_free(tn); + + tn = tpl_map("icS(ic#fv#)#ci", &A, &B, t, 8, 2, NUM, &C, &D); + tpl_load(tn,TPL_FILE,filename); + tpl_unpack(tn,0); + tpl_free(tn); + + /* see if the result is the same as the s */ + printf("structures %s\n", (!memcmp(t,s,sizeof(d)))? "match" : "mismatch"); + printf("A %s\n", (a==A)? "matches" : "mismatches"); + printf("B %s\n", (b==B)? "matches" : "mismatches"); + printf("C %s\n", (c==C)? "matches" : "mismatches"); + printf("D %s\n", (d==D)? "matches" : "mismatches"); + return 0; +} + diff --git a/libs/libtpl-1.5/tests/test113.out b/libs/libtpl-1.5/tests/test113.out new file mode 100644 index 0000000000..a317aed3ef --- /dev/null +++ b/libs/libtpl-1.5/tests/test113.out @@ -0,0 +1,5 @@ +structures match +A matches +B matches +C matches +D matches diff --git a/libs/libtpl-1.5/tests/test114 b/libs/libtpl-1.5/tests/test114 new file mode 100755 index 0000000000000000000000000000000000000000..dfd7bf6eb22af26ee8510fd30e28b32e3da921e8 GIT binary patch literal 128963 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%0AQ#+(7tWOnvAb)Wu9dLE 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 kcB%V#<9eAMYJN~ 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 C+W%|- literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test114.ans b/libs/libtpl-1.5/tests/test114.ans new file mode 100755 index 0000000000..4ed9d2ac79 --- /dev/null +++ b/libs/libtpl-1.5/tests/test114.ans @@ -0,0 +1 @@ +matrices match diff --git a/libs/libtpl-1.5/tests/test114.c b/libs/libtpl-1.5/tests/test114.c new file mode 100755 index 0000000000..228f0c8c97 --- /dev/null +++ b/libs/libtpl-1.5/tests/test114.c @@ -0,0 +1,45 @@ +#include +#include +#include "tpl.h" + +#define XDIM 10 +#define YDIM 2 + +const char *filename = "/tmp/test114.tpl"; +extern tpl_hook_t tpl_hook; + +int main() { + tpl_node *tn; + int xy[XDIM][YDIM], XY[XDIM][YDIM]; + int i,j; + + tpl_hook.oops = printf; + + for(i=0; ijFMDav5+olfo6nXOHewZtkfSydzOc3MM$@M*A8yB@`3J>9COTlMU87a8MYr*{9?H~tN^ z`Zv@O07N*zM5z$p=~Un01)5*r{FbD%7K#|LMn;^ZZ2% zZ#sX`yfKRwE@@sqW_j88G2_Rb*HnMr1z<$p9{jP3)2^6_Z#i6S$A>?b55ON)#_~~F z&;8W(gWqp0EqJwZ>!5KLUs#i~g=ItWM;@#f6Z-O;L)@A8d%>^n1;4)+{8hc+ujvI}*$e(pz2HCT1^?|{@Hh5?|7|b$ zOMAgD?FIjGFZerp!C%%3en&5Ont>00r+(G}(bM>D>;?bRUhseH1>fBZp8lq%c3;$ok3Zr!pF;mIaQ&1)%KBIhati#a^_es0=Ee0(<}^j- zHb&;mQ7}zwIWNa6^OrA-C{2;ZCAEtil)6Y`^OD-Rk@-qPbEHXWoIiKbqWW4EH#IC# z7B8OLpwvp#;-=e{h=N7)Q80gT)BK1sXU_b_#wGQ0P-SjpVf_-;pT|P7UfQ&zp>g4o zNS#15+@>tHdCx;FWpVQoa-TD&ZaHL(D7A~~o8~L^4d9N}YZo+%1bhI2zP=Hp?1a^$ z#d8-fQI<6>gyc)>taj=e=g(KBg+r64%(>va(s8Nm1?OD|r8xeh|LBc+qEvyUFXJCS z58U@dxFe_XCGx~I4_=tdHeA9#DT+5*1FZB}^l|pb9w)9r^f~sYELtP7Irz5y8WDkL z4HJcUi?x9DXpKmTx0VP2S4V3^N_=W5LVk9%2H%p8?ehuOL~ED`{*=l7EQr>KEcs-v z3k?}~mf4@>(HfB@E@gwrw?u33E%`%1sn6PIjmVR}kI2cd_0bxUAwEy!?V~0t7TYytHitD-pea}|90`B_8Me{lXeM`*q(*#r8Jy4XI`56?R z9w;s_yCIa-$P{l66l2ZjGbnsLP>eHwnL$z91I2}AYX(J04;16g+6;=a9w;s{gBcWo z9w^GpVW4=L>eY=YdWu3f-bpL1y#2Xb14?O!`SMsrDLtwiT_NK+^XO#Mi5IP0>QlCI zs)db@KvF$U$Ee?HL%WQy@ug1<8S1@Nas z=&vpiU3sF}r-Y21=%45i3a+kZhr`ApbL}kl>yWt%3otvhD@b zE$y1(gYDWodtQIp9jlEt$Kb5229GzWoI`O&%{vO_QDG-zN#%n%$I|CWl~Hqe`VY zt%8%IIhB7Y%*kVx$c)eYw#<~6XUR;!ERvaOv#-q5m`<5#FpnQ&^=Dcjgn3ZrDY5xJ z@)<^T1oThQ&BIf|%EQJ!bVYRWi2j%@{lW8vz`txfbuv^|*^}Xp=|cL@vvaMF`4pUY zd^%R|vF*F15^~U1e7aYUH+gK-XOJd7y%;E;je1X@%77}dQGXLC9jJhfdPbmT166IK zHVV`NplWQ?4+LsCPz^R}HBt9-MD_UZTac7?h$3^LDB!@MfU2@k#z8)VQGb#ofx(;3w`&m^k{ zBr6{r!#s!=c;6N z;tSEi05D)xB9fk2jm=!q6}8cK}T^qqbr3Q;a$e8D=)ZHW<;}RgQYWB#yy$yNEN`Y8 z?}FsI(Pa9r`FpRTWK5pe=V*6^m=PK7hHcW_NcO+&W8R4dz;ir!>L;zfujsPnLuQ{V z*}x(5YBUhPpOXjEmW=Fa`(K|y@sQwbr1ASXB|yL#WKa0zBxrkv)71R>2#ILyAmZGx zxlETtoPg$Qf{11eB3ivobe<&Q)G~i3h-jc7qCMM0xsr&J#%vQrG(8Z}Qf;CSPym@Y z9n1xSh(-k>+MrF;E{SO9<`h9ha{&>p%O-kQ648Xsvjhq`;4{`*$_mP<+(`4C>|Hxo6@ zyRZ+vp)>0&pwuHfcwW?_muy)8g2<4R2>oWZ2UbBkV}Ekj4T(EYC9xD=vIF|613K&` z)}b3u_#a}U#smHhB3rbslPVRruW)L6lVZJtX7m z1!Uh63+XjS{}Wp*bx{CZB7R?KN3!VSTYO48`ja%*b4*tq*b8FzC*sH1V}>6~Q`nCk zafKgS;;>(jT%?Vv@KoB{zvK}#tGCVYyKSK}<%IARejmHxH9v;Lr5*aJ=P1{X;5C({$>6Nu%;1cW@!8Dj z&tR(IVaNg9hXj=Z#tQ#vijA{ZSh8@(i9&Y+Pb;7@Uq75ohHFjulVJ3lq!#-XbXnQ@ zi5A;|xgCnT{0J~;u{i)L;tklgQ!3Sidh7F5wb<}S{GLc|sQho*-G2a$9tW() z%aTRE1sSS>uNJGbS+Utr?H;{$xm#Bcna`r_P<*04Sri9#IKIg533a*r=mVs$bca+- zAv09IQ+u#Od$I$8j_F$uVe*8HF5P(j$fH{8vhY=&Dl$Z;Exd50_2w76qHm;n_Q8y2IG=`*h*MivM35pf_o%aaE=3}CZ56RESW4?LD1I3s^@f{q8NLnYYE;MoP)V3+czg1 zgm)^7CS6+054obryk{V{5_v(7pE(Rn%r_3f!dyi{wQ8nVJvW)&p~Xd+}1}Rc4C2O2*a6@YGM8BfNo# zcL_8N@_1dw2*fY^3Sj#Xi+3l0#C+7?c&B6= zG0%StL5EcbHbOb27^knz$3B5k97`HI4QJ#QtVKp=JMF`)wegV^oU$bqac5=e^QFnB zFb|ZcNunD~9y5FZZJ<78F@hfM$O^cg_>Y8N)8mf|4N=Vrgpsj@04HhS~jxy7fHIp$Ri$liy16Z>7m2Y4SB7?n~lnHu0q- z{t_sQ_q{3N#4PAo8>R%W3C;=`C+Ht%G6d!g$Ll=wE9D*3`jnDywaoB zR(bV!wMUO`SM~DUx>4=X*8GDSiZ5`Za`TQfe?)?+j04G{bzolwr`y^DxpjDGINGdb zKw?wjP0#z(x*v{D2*oE^#&sp=!Uo1^hZ}YeATd+)9^-&hrrvgEF^kN@u$ROHsh9Xn zFBXp0m$ZA%0U|9A4%lRx3;VD2DWD2QyHwT=mcO>*{lqt5A@mh@?R4FSK5we@>JRDa zj>JDi33fLDx(X%nvV?=zgbcAhg^WFnM;d?SDB#38%@a1TJcr{A-mtU5*LpM(j-JTU zVn<+qm{iX}?Ukh;B#Z8#7+9LyrY2jDqK0qfMPgqPXJrE`HWZ|%6$I;RVf!K~1qP{V zcl|XKzX8tc&E~#FXSZpOuU_lKC@w8djdLE_)8p4+kl$>6AC34x{d8JCVzf7k(H8B* z@9?%J@A_M~R_f!jws4lhwQ%(g2!WtM=}X~J?{%M1mujzVoEj=Ws;zzm<+P8s(P~)j zC_mo3AA!Q|Ry~erRPE)b+s|JxCH44hccS*>@oJmt3YEXwcugpNr6*pg#B-q|Ps@I{ zTn9bclVN`$R=vWtVLyNhe?MaS1JfUve(0db*m*_Uypb+l-4iN5s6~?)xO9K1-7RP_ zd6J3)Se>UAhq1rFZYZ%eOY}8qYN!fdp~V&;ql0&euI>z}&m|rsPiZ%odt0B^?x8!= zA$k=yY(oAAL$HXrVsx(hP=Ns*ea@}L0_bw<(XC((=luY_yU$u5?Np)N*tMtB*H%x5 zjOf47#m;U!c$?n`61V&==PM%+Uj>v{-3l7p3!6Kvi~l{#;yBdp@-BwSr4xCD{WU% z58CQDc`ETzXaHWyCx_9;K^uWijKH7)sPLan%y3|a19LVf2&4@D$ptMX+=69{dV~HV zlhEi$+y0^*YWbhF*a{S7>R(%3$ab3**vwR(vH$(_t~6xmj2(s5_WR^ zmqA$(pQ!}fCMSc@<0^K2Q@cXiRMXO^t?{jiUx5-`^CW%%CiKrK=R7+cUkT^Tfs6RP zRq=XXC|>UkMZa-tYwm(yc$%AAu>s@(H~3*PiJfWd5|kXRbgEkGH82?M$x7$OueH{j zfZgZ_#&eppTVC`8jhy&Q*GQiCAdV|_XO z+Ge^hYpWPT$Hcw3TQ^?TCt%IcVlSe&LVI#-W$dWd%41I`z7nT}SHo>hs<~yq6qJXR z;Ii!uXh*9 zc@&Cv3VVqiL18eSJ$XV!X%aG(MD}k%G?8b~*%?zd<$r?O)}!q$@Z7pFz;E950VuIW zj}O3xsy|vS?FhD<7@<7?uew7GV&)DN(<7h+S7}sU;>R!(+5yD#ZNWe$!{r}qvG;-P zUMKu=TSUsKrR5BlAB|iI8IA3**Rk6^_O8XA+}JLr=Et0xrNMYbK@!*t%GrazB+9{9 z)@MJq90!=u8QcHkn1Rh7y-*-*{4-vH$qAiznQNf{xS_~Wcpz_R)WNV5hYsv_hhVqg zID{PSQ@XX4#yW{2Xb#b>WMUgS!$%g$#2=Xxo3;OC4ya^;yVWiDOD6t{IfQMJiF=tt z;3%2kbEqwdCnghjAjkd3%#iVoSol5{PvG?Uu(;FMzUqAyQ+3sGervHs(0p{?@aVDO zTI>(++m+UhHDHSc;~T1p^(hsXTwdnmzEA0eaF z-Nbi6Ztc?ld99QsF-XXHhZpA|pb}Sr#C&2OTL{NTJ_eLo2fpp^W3a@TE0}zx`zO}E zB*WjeUF+h8G@eb5=QbRAd@05Wj||6QGSYiXJ9qhM=GZ9JU`u#T_h30MQu~$b&>q(h zYhOC)J%ejBzeJEaM{qBxF2GTFWs27X^J;oyALcPcJ*0ejrlo9XmnVX-4*4xdbNAFPSA5*5l5t{ z^@HXoyDHf)!J_+>)OhIe$#9gD#hD2z(qgx=Ui6@v(x+Rmr6T+ORT!VPX}7LzdQ~5l z*6Le{i-fQ(WRGbPGIm8K!PbhO!h#K5EiY@E`epQ(W7$}}b|CQX@TiW|7+vF4cePch zNi4_5hkfy-wrQLGP)O|v8y)f-uh$-p_x+qrcWGkZ+lqo(m)2DQQDD6#}bsW(_EC7S*;E(3uOuGaW-~+pEK4?=ECyTBD zI)t;bry_n$S!L@>cWHWjWl6GVl8sLmjYIaj8!(DEP8TB|yq-sBtfKy%dPJ;`cfiha zu!KdtaA!P$zfP?gUCE+jGteqlhGfw}k-HU($tPOuzeM@F$)df$V)@mLZp%|)AAyCc z6t3_N52Wc5e%W=1%!dk&j|x8aa%O^&XrQfF)3(t^?Y#mx}n1N+`TUkKY=Ax{^g>*(4;qM9`o)L}rIsVqhvI`dfJ8 z?b41!Df!!rpp;y9X%;{$J?hsF^EuC@r}uJD(%>&PXG=7EdYUtlYz#kS@{VYo{m6lX;m+5>>F z#eluB%!h<&v6YrsX@IHRoFt11$Q7%qSFoOpt;;n9I4B=EnJ=*0uy4?}Uts@M`5q)2cI6HID2;^osr-Y(m zv!|FJ@1>5}HqI8@Q^s4q_*rYJn_}Nv|2;zY4+G2@$ zUtm_?i39Hsu}Qfz5R}q}nkt49u#YfO(WllVawWu68FvMOUD;Hq7CV*=x3j`up=z-# zaHL*!y;hA*6d|e{v``V!uJ{`QS%QiWLUb)Q38V-*6l3u$(`(Pr<5S)GxzKCMHO}&? z+uJ4=M7QT?q3zLq#}MaoqC8|wbz{R;A+FdZi*{67{h10YatQmRfM7i}5G_MMi+4su zJDk967+!=1@%ZSIaNARFg71RHVBs-ev8p0>4Fr8%_D#FVOt&-0J2M6|N?Ix*i; z78RfEF@N+b#-?q#nk>4Qf(W}Z;4R{l;nrruYrLt&G)hGqG?$Q?qpY`8!`R<7FL@0| zl~G`8#|JQ6#SpahFwS<+KBvHfR++NFgEaiftC}sTI|tW%%+wT3-Po-=9+P4l(}29m@acmv3G~AKo`E7NOd_ye@^3cYr;*!WBsE$l9&UHP{l!Y!FLw+9tz z3tK4#S7y`;U{#KqIar{%Hfz&9KiLZ90-bFw&?mG_of&pm0aaIs$43*du)0h$tQ00E z?XR^3dcg(^d&LC^Zo}R=yvuCT)gn#so2&pZ0aNxcV%N1D_ZnT?9op)F)`6N>ykyY?B>|Z7dQ%C zsFa>;t@qPav9r;D+mmPoWcfSWuDxm5b8Tj@lCNQ0wq#V&zv~4(*vYPlF;Fe`2|B?E zou1eYVshKW?ew9^qI<$ZZP=u0u|L5U#4-^!n$e$1VW8si0k?*98XF~3M8;-fQe)$1 zEWqC_*f&aI>nL6>nL<-g&edQeb#v-^30OLEYpqNEAZy~M{Y`HU8ti^UC3zaUQcq+^VWD8W(?EZFI-+m!G2%{C?VX@_CasNdR7lsEE zUalTQi6V>);vLfe#2REh!PIsv-7hfSAuTv|B?vImWu-4sq)~AM<0|}R+5_7W+gl_& zL@V#UR2gQt?dSd$Gz&`cTq_LkJ)4iMmsc4(D~(sHjC~>F-H`E0_k_Cj#;%Za8ogW4 z7#J^Z{p7A-F#2_Fh4GJNH-xZ7n_`UKfXG;dw&`=6GgUOLjL=#qp`l=WAWXWk9RlJ8 zLbW?&T;nE#mF=b2O*71Xu)U!k2VCPH$)ZOu!%h@@!|1MO>7($If~5T+5O6hKgK|;U z{XI*c*a8Z+x-s3Ih#??m>$woEYOD8S)?|{vGjqlyu7Q@sJU9Lv-S-X7o00RPU*<$c zMZa`J{AfH7HQm52^~!u7=KEr}1K93-f@s)!_}~%Hp%&wolbe9q&?NRCpGaMHFSO+l z;}+?M#ibahmkAO7Xf1XLEh@e;fU!^HiACllArr&W^Al|Zjkha}PeZjk!(g&JY<#6} z+vf;l-I~pzoekuoP}>4L1;TX#D7*p#?Xld@r6Dn&@LZbf0nGpJX!+DREao1NKK1}< zv6W_SD6rNjmBuXWXuEZbC1=ym!Hy2U0h34UP;>*Qd0hC=4L#*lW93-#{?+6UVIrI_5c);0|gCp>Xl zzsj9hB#s1fKd0BiNGgn1*;_ohzX}X)!*RgIVo?T5Obs9Vqd12+$e;lk4>VqG#8dlENG znEbFlD2eHkpVjYQRMKFulTD1lB`e5{LzCL6D8HK|4qdUhz*Zn?$18xDg}Nz>Nz6v5gFUEDbfZk>7G`qVPO1Yo2KQnB)8;XQf}X^B+~T5c@~E4O zz{^&oy;Dg1jiw6v3RcpC+=lavgM*D0yPkd^eoe918inJN%i5~Hj2?F^&56r1PpB4m zVge_fXD|n=MXV>s+Daz1ObBPQQ@J>lhWX$C=&COee)z{z>qE0>+DLyp*bqZO$D8S zE262&3q@tP`NUvM3esRBh(WW5C|NYkW}<_@VmuZ&;c^o5p;$aikymeq3bZ(l%M(-L zB}xmf4PdGy-ovykeJSA+D;4bV|BL&8xFhF=0B&|2Y3jCO<}E;Rf6BT8h=|H*@e~=Q ziym0OyMF<3O^Hv&y$cPue{vXDR_x2bsZj1RhKrg)MSrR>@x8JjPx{o2g=xCe%fgfK7!W8BZ@<2 zfovGNDc~4?7HvGY;G_pE!hgZfVy~}Y5?8fFvR#RoSRMjU;S`_5Gy;SD@^mjBo$)Rj ztF&E>Xutw@xNXHArF$60%e(_(aP&#%=G~~1cpdIQ;?WOBBovJ9cZq&Pt__zrz{59q*dre#(pGP>#sA2B z2R8u_zReYb*@9B^3-=SvIyOd)2EW*;fINaJ3aymB$>ld}lq6oGwh`~Kxk694OonZ0 z1;i2i9vot^eu5tkk;d5Wd)hmMz|UYWhii>Rl=}N%f}Xao6Wz2*zPbb@30`3Te{wNfs~@engHo@6iBWZOu#B1JYMMRw9P%xB2|Qgqn7PgI23*RtXiRK%+k z88-s=2#FF0pj&Z4FXix;gPu_i$jLdUJ@? z>Y4pX{Z~-8kAS4sWmrsA&h@20qtYhOio5KMOxusZXDwU_+0=;cHk?Fvb{*VV*d3=__?G5 zUpf#E5yFT04I(GJ7~f?OZM7iPVo^jcj4z|_sc`H8t(CuLBezghDA3~%_(`^fa|^c9 zz!Zl!J$@}7DBtce5~;Xu^gYJaiX&%6kDagG{cIMvZi{x{lJ;)y5cD{r)Y!YM+D~@I zBHXEt<)SG;%(uVWbT{4~jgPw^`sMi`Y|!prjP|1)2s^z%1~BJ9I6fRPThvz=J(0J( z5lw>XLeV6y`0(mO<`tiJ%^SDNn==MVaJ}YMXZ%)Ig^@t}HL}MQ@_tkeZ}HUPCQ0qu z8MuXydp&cBxe1t?fSHS1Up2z};r17M?4uA`>;K?eZ@V0qdd5w_ZAjgC0S_|eyw;w? zoqw(Mb5ih{p3&FOl~l(wU47IW%$D&%>nPNCjSzxUPhISjQxW{dBYQpG7f-o zKHb2h)4qQ5`EA(kwPHH6bOn0Gxn2eto~2Z}dRWIT7>^eHCm_Z{cy;A`J^m+Q5PU2) zT#rBD-+)qcD_DueXgZc2P|$`!4!QjeKQ=t#hvKJ z3>SWNqPzsOT}41Yq;~1$@T=EZr?6)Nx`7C;@IC3a@Y*gf9jw3c17({{E7h9=-_Kol#t`8_XrdvVVXVZ}Y7!_gBZS~M4?v)=ercghiscDg4vVF!=7dJZ0hpm1WN7UO$e z6A^d!Gi|P0uf@)04l(%(ra>*Xkm+RH*<@O$#cpPb2)w`}{(dWAMClhZMU1|l=?E?M zU8JRN!gP3@?OblY)Vy730QC?B%Fj=p1fA`>c%eH>3mM+e)c zCAnWQ4&h2g+l(SrSIza>lWy(FfonCM2iIcoOf_8oT5}?#zQgca5V!j{FJt@RilOKR zDq{69S{vd%%O^JJZH?I0oWu2Fxz_rXD1b7<_M}=p6QTvx(tH8RtWre>?Y0iNwV7;ogyIid=RT(F=*kc$cxPZ1R(GhG(!^W5T zxjf`K`EaisryFhcdn6Gq;)mmf9pe!$c*273hcp#!jZonU>`Sr7F&}?6nVj6|8jID5ph(g#yEjf)W`%87VplZ--Cgd zzZw~3l{X)5SH3Gl(l3woDT0AzU%0o!dxkipkk4K`>TJ&AZWS<#qJK_yzlrkHehD|B zzJf4iajo_F=1XwR4foX}S0NT6S6LpccDV%UCr;{y$Ceee6Q4}c#okhW2v_6n~xKC2}-PQUtm_Ij0)R0>$RxB z1uz-LK5>2MGl+vaI5eDFVboejyhstaV3lh<2nNX_ALvPg+bp`_jTF+w2$*NWE@+bB z&`Yzl){kKIi1&r!vwV1$(BVSd(3f}#$h7|ekH}le~2UM0OnAdKe|!TL#vMEBVBfMO%0j<71nlu4z6>m6*l0#W)A!*Lb=5eA4>T z%0_X%u`+#-U&De@5LH3{As3&nKs(&3wc;H^mp_71DY(5g6*9%X0t4Rc z;(ffz@_O9t;yZEZvAZgMGv?7aZ%BO$*ES=qV#_klZ|43HzG55p4_FU|YOz}|>A0~J z+eDmfzh7c$1p{X76v+mA!3FTWc$H8{X+8ojLP&9Q2c3(tD@uHT^{ike9~E5V4aJus zl>3qy0XfHF6zmr`k9Cd*4Q#e{FE3%?W*|1Mhs+R3)wiX}UF=M4&Pn7r_hXzt<{1~y z+vIQ{_Ba&R6{h;MH3w-G=vv!VV6#iu#G9#c$-K`7Gsk^qunBP)$5l;j)5ZE1?~3u$ zYfHqvHWfF$YRAdP54hJB(l+g~@3wK4>`m07KISJLn~Cd8GtRfPhu6`dJuNm0O5rA%*;D$7S^5%v?B$-g3b#V-!Kt)9h9!leP&}DHkiQG#`@8dmgkm;s#E6O7*a+Q$ zc|^Kuw|UVYz)4<46}aefj}mD{5%!jYF+DJC0 zNB&Q}1AQ30ab#6-BIGUrv({BYy>YUp-h1{$=A+z0Jg({K#)p7-n1$Xw<{w{2M=S@( z`^@6;n7IlIro0Sm|3uNd9~1MgvD3WpHRM)3$8H%Wy)M?W769Vx9J!s2!DF|F*A~&F z)gG>4v%m*ZH0?DfW;ERaq-;7HO^1#5tk$`g!Y@C}O||~VS5Iv{HNT@Dc_Ou^G@ou= z^!9mPAQQcfTqT=(5TSY;MvZs3QbB0yXu|GjxTmJD4{YzZBmm0NPm)E0Mq|7W33Cr9 z*x_;Zq~>$R`n~D^k8RPUgIlNuy-kKO_|AF_H<=5#|HWh5n7;*N3~a1LiqRAye2%8h ziq%?dHkN{D(y7I|Fjmo|8aYR7tscTo1Mh*K>w{bv8#Z?OdWb_R4yqm=R~x-#?gLqn zcPQlgPlGApF|78;s5fx3;1k78^XP9G#m5R5+NHiM4$Lk#{Z-CN7cQFrC3;NJ*5v`S z1#Fba>gZQ)t@TW7Ik4+5iC`V%R$_&}v_WfqOJ*-vq_yrw_9$LxQF$aAS7FS#&J=Cu#|3~AC+?Qyr*8&u~{KSJ8W%H{|@a7=Q z(_$TfqsQ=w?T;*Yp9N)jf%o-M*!n+!2HJfXAuDhuwt@*>PqXB~jH%{$h^Y%F$M7Ux z?&O7c^fge-v4?xZyuvH8>>TcWp}XPQ8j$Ay7;RLkpW!D3_ztt1zbEjbcK5F_B;u?u zZmrG*jXlfn5+&fn(>Bgc^7jPZH5YG&;m7ZU9Zdi=FAwmR3`Z4y7&{sD-O`sr#@^so zCKi6iK~llKR79bz1O=mFOx41ri!;=0fL zJ7#y{r{J1iPjIA>zejN7+t4m0em!Y3WLPFx+=)>a@6a#EU?pG6+QYR`?k9|w z`83y!XXlCjuu5oF26e*Fs-1@Odm|0cCQFBGWxl9a!Wzpvn$ITL@IBKQ^vn)}O^{~OrSj`fNDz?n-QqwwrUB8(1YoL}vqHu-v{@%eOd zLwr334X5qYBGducT7-I8f4C@Su0Lx5WBKs#785q!+)kM;xC2Zb&llpCs>X*meYtb~>7e;~Sj2MMcbCIC?$>OWY_1w*~ZIXw7SGdPJZV@l5d!2%IY9 zVE=rHF;t#B2eUIm0OOtLhj>%|Bm4{jPOtD`$oR|{o_Np)FA}T7aV_>ZGVR~D2JgcW z_TY0kI4&VLTAYx+;Kdj7Zuk*YZuLQ6;~nru3+4rqW9t)OBvknn@9=ghe8rI-=;&m= zqWc+qKI2u|lUKWAxO;ORs7s$u`=hq+sx8MyXcd3M84$5&Pwb`U1A6WA`Zk0@+pc%3 zAp~)Ie4lALMCN|I=ig`WEyvQw-=)AD!~0A<{5}IiabjzE^6xWP5L8!0z_(Sgs4_W)rrG`6jJPr(%7EBCE`fJm*+N6Jf|x8rM0 zoPb;y3!@7+l+jsqVS-cFCclFNZu#!!cN5+y8}_YK7^NCME(!S9uxEKY}g>QgUHr{F9VHKR6D!3a3lH^YM?JbszS5gFZ zKu3=qN5Ec-ZGs6zk9`?g)_#x0Xzwt3{p;yZtoLT8{!$od=sk(sF`3%; zSv@)rBnifep>#RFQoldKgDlpM=z-<-?H4%poltpYT*I}0#7FU_M2GNQ>G0^;(XZ6V zL>ZFoE9{o>$d@zXqtLe$u8L884>oU#erF(0bn-}sK|^`Vn~e`YQGTPR+ItDQ699%2RJsuw6t7o@EVmfIemwQ_BAcJG++suwQzb+=gMLw7W`bJ;hkxM~SsH4a@Y#+AH2b=PSn}5;j@nd4fCooF`&ELn;XyM{x0odcgSu_s+pitm0VD z@$TWGp+4?aL&i4L!`|R4m`G*mo6+Oy(r;C?U5jb;cg!r_=EB;JCvBLWX2T;486p?P z?gOKW1J{&J*B~X_7AbTl_&Yz0V#oVqz0zXEU>J-OAdI+IuYEJ*yaAz?cg-9$MEkSrRKU$1#Dl%g-6vX)-ZeIea9`<5Rke63DMAcko)*U_MB%T94P`!hM9NoqT!zDh-}G!g?Kl6W}K73B5}Kh0)pu_XMS zj=REGCi>}LydmaSru`<~0RgY~`}jajM%%pFlelz-9Y^eWE%rlny7VR1Yim?nzQjJ` zRk_bVDfbyK>D%6SKwTcyo|TDP!O~IMm3HnN&kMcnZ9@G&KvAg2rAu zn42v6@nA8WxSlM+jCkA&NjUal{8*zHN=8p)fZE*nQ}&%8rk*>&-&zp^ojL*B3~pkK zX&Z_CR24R)HQbO^mv(H$^is?th;X$s1TOrM);beyvw+oKgP_hw@5wBUt@#3o%d!CLz-r$2x zkH&Zz9uc$jk%iJ|oe#*O02sMG;*KS+xCt$!`neJ`8H#vO5G?XTuk-x-^tLer&ww7< zM!J#k5&5n#p1PSl1|Fsn9OL7r@TmPk19$k2>f63?;_*2yTW$LZ+JOrl%>Id2{c({z z8B7j%3o(AY;NIPg=lu9p7v2}Z5X?h>0XZKZ$QCoAPy%OIX2%PU;Dj7>cBq7qK| z@ZU9=UfeWl1iu#|8QC=2H?p}8z}gW4aeicR!}*cl3(t!*EK=-W?B~z$pAC8i z$T>I9jVzeo=&PH%aMApE7yCvw^fe|hcv`SY55i{~!);UA8A&aYdz+_!Ma(z%Nkf@Dg4^P+i6z70D3lQ6zIumw}eI90@dIOgP{ zsiJ*fq~6DWyCzkmc}Y`qLqmOIWd1x~U47$XRI6Puw{dQ5WPW2G1^-CR{Kh47Aua!% z8HnIxkDBH;LgGG3221fz)<_vLIo3DuAHVU9tnH)7{A6gb$ba}|;gXx#PDZ^3@G%}(uVo-Z%vny zUSO;qKufk}PZ=(#OAHb8G;jWLu%;BE`rO)EsZ3c)%q{g1(ZZ=JK3$ka^>gQ)ER4YP zBn+)!Ze!!z+bn~EaV>1Zh}JIXqp)lV8lCG)2_brcL6D=~wD9I7b0f`-^D`=CN_?^$ zryEA|k_PlLSaNEQXf(2nmjdu%_vM_pn5Ga}2=fBYw{Y>?o9Fvr?6vdf&2REmUdi`A zE&957_B5J%leE>FZu8A;Xz3kpl^`l1d4=?#@>zkKE z#4rnPic(v@B(m`4=KAI)--y&KgvrmVg+0vkEn2vEVT3IUd%9SRpD-6TB_|1#NNoUs z+*Yp?3~%OKkrgph=F~UcPAjH(jrACTC1{3~s0T8>*mqNNT^&3`q`uyV;aaq4v~LMq z1MTOg+u&ZT7G_k3=S-a)uDoKpZ|;(LK7tj&8Nuqx%FBI=ngJZNIRH=;k^m}Qr4}UxYDpQB(sHOy^wCbGpSUZ}~TLz19E!3tqoS_OE4p z&;9&&a(0aSe^#$Iz741F`+u8%Z|&On-rDdaJ+L;y?Q;SvQspquX!tb-_ z9{M-*r}C+`=#@Ij|B3}Yr*m(X_%AHFAO0KqQ~8{0(JQBX8ZCGsQWyT3t+W;?j?hXI z{@nNr;*X!nGEwS~5+AbCnO1rWQV0H)TImR+{48v)ZK?~+yoLD8PjGs%f7IkusUTN} zI4A4{(O~@j==;eee=DIFhsw_Y5B;BHavtCVNO`w^-G*fHM@)a7Odde`IHH*YAi!wE zG3Ox-ErkbZC8$>toSGJ zNc-Zg#}!BiSe;jIzgkh3d(cc}4U?Yf(GQf7zTrN^r1OxO zT;OSQgbTduoWTO$8rS6o#nG&af)eLVc?HE&3Vgu=FDND#aLo82-|O+W8SU*NVp_p2 zjvIMK@V5Z^-hdSNeX8T3RJ|}z58%&4xiA=Tz1LA$;JwE=xxm-vnp{x4j_t0=4i=O} zbHW8JLFeDqJ_Th{3QB?n#h{sNOA?~ke*ArazlRX(;Y<6t;9I^Oup2&Rll;>C zsAN9`zY6xFqM$`}T-hT-J}{O`R%wmfG$`Kj zTAu>n6ft~oXnLNbArraDFxFP}n+`E2+--0((9gBNZkCcJm)W=iIOQ|-lfnP^Mvcl zh7aJMQ+iGNC*fz)dYuY~=`8D6v0|(^o?*!8!zD=rdF8S-+3T|E3IfrbHrGAQdmWD1 z!ZtadBA{CfI!>EYKP}#XK-E~OUCyE6hf{~2zA{m~eF7qvZ^1vmRl;M*!dQUs7ZGP*#A6!Xe@3AxD5o>fdPgSc2O2>lLMn zQe>ref~hG!zG#g|ZC!{(5*X@EB&FBK5C^;T4|@1zG|f(TIo?M z&CZkkKf_ADWu@b-bgGrkveG&$U23Iktn`Og`lyvYX{DW3`l^+FXr)K3G`p|WzLkE< zN>A;7Z}9uK%KCPB%ODBc|L*-RtDS1Aznf2)N7JTEx!6}c?TVSBeB;i$=)6*8G&o7) za|@pQN6q*Vn?8{{`AgC_^s}dm-9XLNC)3%`B2ZfV)itm-wF%I}w%OTK8L8tS=7wX> zM4+7RoGK=&oBw)-(~;9n$d$vUoND%81v2Y(BraDLBCn{BwHRfhJ?A=+{enbo%!1pc z0J7ZKZvF%;81U8Q9Pak^y1wCSlJ4&V?>bRO79*5gNUpe?>iq(A=iWuoWr3bt6%|}r z7U<38VZfDbfxg_=NStGV#kt=>BQCcEmgG)gX|4s9fRC7xSms{{=HMflL#cHXjzXj!e z08bRsJ4bY=xszCasrnZr&JoxI_i3a+Kg;Pv1+Qx(RpK55NA3ER)Q;lbj}q6frE=Wv z6NG*vb>mU8-HoV_?cM-v9!G@z>ia!ph^2W5?3*^W5ZLzsOca zUAq#N?4AsvvaXY@DDKB{0bNg(I7YbLb3u@GgM>TKs%KKU61q&6mzm&_ZI6j3aYT;(kcs#0lMqd}0)hg;hW-x8Y*vpEr zAqQ&?Vom3WwGOF3{#ut%Yf^DMOICxqPwl79p$NlBYrCMQ1_l7hkNTFTDE%W#6!mQ8 z4glM~sZ>#izYmCp(0{rOH4|#OKv74SD0@tl*$@Y;f74h+^&dppKs4Ncx(!tkg1jRs zLli*abjufBfnCRI5PN_+Q!N{y&QLE_3Tv#gMJVHo>@2%fDO{C-&dN%mAIU%uO`~^a zpvR`sA7!8~OQUo1140>Wa&8)ZZU%aJ8eNrvzBi4o&p zMd|1VJ7Qc$o$0t!sH0RV++r2_P*`$OA#~MY6;d5~s!%EVvxUC|m5O#}0&ipj|HuRm zWCEXO0w*$o98Kz3u=ZpEgED}^Vhf;VK9rKF0c$#3XqC}6zp=_N9d5`#4}cT0X33fi z^toyDrVRAtGXA~jN&cvc#rvEL^xbLn^bGV*(&!Z#=s%>^0I@ig637wylro%riN=}DD`26(vV~BJ5$r_vvB_|caI5ewJjDM<7DH>?u#boeh z0;4j43o?NTnLtG*P?ZVH$^>r81eRm~g?Czj7=I~QYW#m@l~FSutkdXkFPeGAqU6jN zBPr7}W2aTfnQ_@kg(XVSYgQpOQ<$)T?|^ct-5~!xcJV3vI-~dprx$DeB_V4+aeDFa zjN+G1FTOCN_|wyi^^D?vI0y<|q(!?fqqyYs;w2fySDs#ccSiA&(~CD`6t|sTyvZu& z5I!c0oqas2HHmjyrJPaQWhvLRp@mXeM8BR!-<*LyoJRjH1D(@X^qx$<$v~f#M(YF8 zye~|n@6SMo)980H(6wpwsG>BJ+tcVs2Kv4<`gazZrn+6CbDjJby7@^>VrL%(YPp(A zTf0?(bNO9aL9BaXY1?BJaxQ;;QX%H@+g2ehc0j(+1!^jV2P`~?;R1=z7>2?#q%0Kh zMp@d6fJ)(Li;<;Xh2yP4&ZdV>Duffd)GDNGn^T2K;WZYXQ{(S;>uKwq zV-<6)_{gfpE-lZfmR%san(Itgi)Bm5qrk2C6BdV0NIWz@UIuD8LZ6mHL` zxAgRSf6J(MuU&6*wo>>}M!nyhUhhaoy)L_6hg&J^Yi&lUmJd&_=e3HdmZV*8S0AOY zG^5^G+G%>ZB%|I%ve??nt2Rjt!f_!Drf@O+&W(Wun9kFI+KHnZ6tn#JPoV}_z zC93pDLrTFxe4+F#IfsYv zcrm07SQP%2g}2E<&XaWEnaWw}h2*(ZRk-i}H6A^21?I{Cj#aiq@iVU)3xhIJt5miBOWdWg+qcJCiVH_*a zSXL|fIWEG&n6+jqvu~iOth+^a8+OfEYXw0PmXh^7f&D9K;{pqMC2QSuR%7TUtBqMJ zbmMp*d#{V>wDQ2_WL%_?5_&9z8lI+Dv;B!J? z=*d|=i|QH-b>`gu7SK4wx;N(nx}y&Ya8S1o_PJ!U7=L~Cur~NM0myUIq9u3nO5}6z z#TWks1!(TXsmYtGFx2Gcc0N}TJw^*|l-Q8V{Xe4YBhk9sy%cigDiZQ2j$6pTE&?7| z?)~`gOF0~?@YSc}b9~DnR^B&!|3w6`@=kEz(2soBi<0M5i&$ZVJD)+UJeLJ}@)^X+ z%d$XkK7&|!*%s)_e~rXB7Fe9mAXc8+0!#84#LCOHz%mgA$?Ic*fqVwB^7>k!o_{4d z=UZTPzDBUX0%zwlh?VD2Pe6Rfh?@M7V|AOFIs<2c9vGN(j${VKE1MM8KTFoELa-Z4&vzV&#=v@MbliL9D!s z)iI*}7L>!(^Ck-E8N|wG>>}?{mCuMp5UYSetUN1-mA8>95kaiHUrFuAAXeV5rE+8t zEAKZ_Hy)S=f0iW6O`{OT%6?g&Bp4juE>1E0$d^ zq1o=$gl>?~0=J8OxP{$;IVicD!Ten+p#+EGm;}M|$BH?~=T-T)3$N236s{i%uQ3x7 zzu@xAfzZS#U5}jSU2y5AIL=^M_-0W?i&(}o4z1!SM#l=OR;P*{WD#ks^1njJf-8Oo zY=8APcA4V19^w>S`IJC+63vO)Psw=)vXvBE^=%~XP53Ifnpuv@S>RbPeT;zI?lLwz zW2}HYZmvEBGs^|!b+5&!6wI0=AfLNG^ipsQg+&ArCK5nvS#I_&%gugdxhZm%o5DHR ze8FrABx9Kc*S-mih-DUBC&yC8G7GL}AMIFX!3`4f6f%}saHFJ@vCM)wvTYg5ET|zv zJC<26S3)wDX+tuWS#Xmq3qZDN);=^SXRpl$#X5m_y`S+=hfHr=iiEa14) zdpk&1uOQguCL&AdkVW4w73_b;oHzF%d zVmWf@u@yNb=LHaX)jKz#%#Cw^qTVIt#=?Sj)s-xup2oAxf;eHx%)!cP3$r=*qJPC| zv>y_oMOFN)8b+RdQd^}G-Gw*Zq^N5y29aZg$Ne|9U_su(+U7<@z563EED%MmVAU0^QN=!fXkt)%#68AiI`Vq;c4ATFBBC{Fw=MS>QD5jQM{pIC+td}o*T6uEO1o6OmOBL0V&5`%M#b*0ucar#W zjzIrx^6-u%zrt)b>a9fs>VRyjZ(su~s3`kIHUs(2$fja2f&q|cxi1&roYPtEdQ=+x zI8|Kh#!&)`z@T%;v)0Xa&)}3rUg#B!=E)pHoG&(f196O)?-pGyim}?vY^j;8U_|}S z6g{B=tQ`9^Q}k)jT3Lal-sfp*v$E+=2GX;s*9eilS5q>Xr($MH#R#dsBYNt6nG{xj zKt^6@L*j)tt`*uqkEx%cKT}t4Tf_JTg@wZ2cCpWF=N&PO-Xx`Z*Cmu!lmlg|yIf-9 zq59x}SY?-};=Pybc3XsacTG_zIVIsv5~BN)q?OLaY@6g1MnO$Xa*7sd2>~Z9fsF?R zsh1H~b+RCk>Y3uCdZZ~-IE5*Q;jeUx;TL8xRqz%ap60ZNUzf8%Xe8uh|CPauG5YFM zhpJA?mm@XRK?C)EP8Cjbu*=?C*b!ak$5Wb+prMR1=lzt}%Ou4}>Okgcb5@Qn^>PQ> z95S#e0*jdM5ayy3HPVa+S!$}M6j0M3(RVR51`CDYjCeo2z$>cU(fv0F2R#hofuWFt zc0fqviO1k_-!)XNM-As0F1aUsovi1~X(EQZj6su78+p;iH4xhAb&Ww~)VqWAhFkT{ zM36z&8!qde%X-5_y+IeI^IpNjZ}YgDJkGOtEKcz_FN4Q<89c1~&!BeHO3PFt`4!Ek zhWAT$>H}m4?eBNd)l$nJiYiLcFtn-;u$1`%$OZ}X86eDO5TAmg^dofg3=YTuX#{7+ zh+pDXH(PfY?7I$p7fNlxG5svDJS-72oX)r3u(=J2TJPpz%X#0HJAE&ZLxY>N&ii)V zdGTFrq8)IBS)WkFoDx32U(FeS;;VW9-Ob(0)sF~6Pcz-H__OEz#Hn5k0>sVR7aZs8vHW6Ga( zGak}*yG04?@2pzP@NW0jAiNXcC@~=2!o@xbco<$yQ`7_Q*(i72*U`T69B!O|;8ZyT zf^+cJl?^|P(LJXTR`7{v?H>Toy@$gf;YsN2x!Yl$7TioY&gJ8vaD91*rT8Y2{*asg z#C6~1_LZYwf}+L_k$t+(O8+m~-UL3XB8eY=Z#oGt91=k!C`!VhpgIgY%cvz27|pJv`l&4=7J#`N1H5roaKL%Ns|o; zH)X8k_n1blEZ6j@ME4(mim7(FS3H+V*BDZ~8tGOxm$UAZti&2q-16VZS$iexWVh6I z&N?hv6Wvlzan|=Hi>&JZC)0YuOVOX9_5aFQDG^y2y?LZ`EP+rx3B0lT#3t664u94A z<|+_})6vhb{j3o)X<)x@RunSea{8Huos2HB`}V?E(g&We>m|@?5Kmo#N#^x9%6bpU zq_;@OU*l+EKul>GNi)q9)+q@U*>A@=Cs@{~4WQqO){bfccpG5AT;_TkT?6gyVHCxd z0#5ZUL&4+;oc}ZOPlE{X;D$Vya6>+MEoYuI%d!egrk#eOBxRbN-rp_(SNc=TrJd^~ zPH5+PhZAtF-<#s`s)T!v^jHON{Fr$PP)GV_oY10v2DY`wiO=`u>|9jQtGL}|Tk z-w-ny>Xi>d`j{u~&q$w%rODNLqcZReN@3$+lC4M%roT8~x9Jt-p)--KS4wSq12ksmXkTa$voW}kU7v$ z*==Lm*XY$$99{j|Z<|ns=eL>xo8AvPp#fPwy^ysJppFx1uFUe$TxpG_o$50zdG8sf zhIh~u`&@*bF>fF@?nn9#hT?JWgJQ>|euK+9sW5=u4UZ=g=mM}f4WKuGGYr5F&_-Y= zzzYE5|A|ul&pJAYo5PjXP`n!ro?pOYjili;gR{oL*!KCp55O_%CD4=7G4svm%ssGN zdJQM^M7E6+dLrA&2|ba$zzIEJV=42YgbT}`$m&qo?Koc~-@sWk37iD0P;b`rM1a`f zzm4-#IL{emWn9fQX;JQq&B~z@gngX1eXy~>1!#_af%^b<5uiU7a*V+B0E0%s z*tElZhqbCDV^2~&F~^L05Ol529RLAv=I%i5*}IX#!fFT=yY)=dh&%aem#Vo^bTdkf zqN2|Mq=a*hA~8QBhZPVBM@fPC>RysUEJ>NH$=L)*Tm`^@om?R;p>>boTQ8zbb9%9H zlYEeNkvbwe{a%E;4v<@jTwTezqe&0lqGT>PlCSn6HHtcibZG*cw#pv~=%xV-NM}}~ zOOcNT;#68d7>U)KeZ5G$KwT{oe-w$QjA4o600y*nkO+T+L|Xny8~vwo^Y4M6Fn>MF zSu}$8nQY%u1PDxTRyMg3EnfyCa1BRh8T&Os+YuYkt+wCHayyvejFfT6!a@sr+1L2Z zEa%s=+#^|-<>=9Cl=&Deb~bY9sKKwJ^n4@->odLqdeXa((#I3KNgtns-qo|%X?hm3 zi_9E%nw}E#k$WZ%J4~vYQZ$F1u4}p-$$omy8mQ+id+y+CNP&TRMw^^#X0Sn8%e9oM z#?Id)cT$p0O3#R)qcS=r8>|n>&eTemB0YponP2AizsXm7NKA4P{5YIGbT63Mhd*N8 zHRN>}F(u&FqeYFOq14%p{z2_K+fbG9kRQ0*FH+Ztm^)F{lsfh}0;>M#Qa_?pN_c?| zW70QdoMunvt35L2*Ch7fNyyS3yp{lY@SOky`Y>zgXez>%l)MJsV&>D+nCT3@+M{C5 zPKK5=pLRaBU$jgK=i_NrkFKFycAUt_jM)SkdUSnADv_aL$FpvO00!hRYp8Cl6-A&f zLs1N$?tHcLV?H2>B&a|HEdxji=hT(nj~wnjk?;)lUO~*z{;byO-9W~0287$88s&;nqMwXm$|haq;RJ~TaFyY}tK(GhwB z3mQjjpQ$mA_h%XJiVXkR2x+y*)eYN>6svM0m%LY0nHJO8&usg^rd9ch0I71~IcS`) zN=P%Irx_9ltY;|_IjF_S@3H67LM8{YDI}Bo-~_PVN*0f#A~W1v%RhI>I26VtW@z!s zTcu}mEfmFceAf|dDMv8OyEwVMD;AbG+1AfH*gru=pDREIg_hub=nWBI8f1NFArDLo z*ghLgDWWH08pMHu=1+W@@F|)<@t<+Pr)q4SLqRW%qu`Z%^(}Mk;sInaWKM#`Mm-3y zj=*k!e-L;PV8R4UwEF>?2z&_eFoDkj=AMfRC+NqW?Av{I8%usYZ5-&9bq%uZzNedb zd%He^Kl?n(I#-|7-=R<6?U?iQY5ko#)qk))uD?sO+7nF(G^tTY4c5o@cWc&{DXow0 zO?pTkxDjhjY5`J%^CQ2`YNo|upjPzO0q#89p(FVPY ztK$Z3RgiF>?+!5PW!#zINN?s$y^On(6M7l<2q*M1?$4ai%edD#q1V(MmvNu45oy2G zaaznOVnyu(CXbGLE&o=g{>u<)vzHvp@@c`>1s!1A&+Pn>pD{u5X(5PK_WHz!mc`iS z4&?-tFn$=L3B7THBUU485S@3};|${=mU6{-W5@+ChrKcd{jKMhE?1-akR^53MdDnwd)ze(pzMS3$j*gi{3 zdvu!dnX`4(Gp8e$ZvNVwo`JL;M<%@p3$MhUq>D)>(I0QN&(SUQElV7%hoVV-4c0SZ z29qi%h9LTTcAWl}()yOL$#*V5dIU9Uf)@5O(t7?j$=o@}*4{b6Chz<`(t18W*QWXW z)Vavki;DB~eckbt)?4TEbR%!3bOMC~lYW!Z<6_+ODf7^*UDOnlpR}AbooKH?mc z=D`h=&eO71f|rJkNo}DNZbO^YKam=&Z+qw4)R^=D-aF|=#vb8YoNl^&Bn|H$*bny6 z@R)4hHwbHn6ws~Q1Zb5y2Jk7A^~Ve|g*JhKJkptHWxShfXxi1iZHA=2SE20ENTkG7BHAdCCYQy_TGy#(qvTp8%HJXGjED1FzY>eA!H{wEc;2M{AV)jDc}*k zdyhB8Bm9tjrRzA8SqL$9AK$ekn|x(z6#)6l6$HrQ&l4bD>3$KaZKG;w>YRX-w)jE< zWbyX^pvnb2B<>Pb##zbxnMO;EXAK=U*P3v^E2HjxLycG8FE)x<{wDT+dTm>`q5Be( zg$0Z$oxGk|XwpB)u*Kj`A>`i9V_~SF+L>1JfZ?V%DRG`KlM>0(LUKwwJMRm*~EEEVSpao&vzLbs`kIbq+Lv!X!%n!jW(}wNgPo4-x+OaM-44r)z-Kz zrWL>cM`q|Ulufdk87%*5_JC7O7M2>xBeG5D{|gNst;x8fw+1)jwkqsOZUtth!uo=<`z?J%81M_qeWBoMKRUwbCY|xLe=*L#Bb{|`5(~qrK zz3A6j>>d1I(O%TrN8j?>p>O%==NWeBM}hj(lX^Sih$T@!HTQsi(5N@vnt#wdPxNd& zSPX_aKZYgq^g9Ul8%odPY25C%^Njh{!BY0_5ilQ4O5f1!JFpl>9dz#pY3hn!mWVOm zRK}P`n+9tQ-_os`R)gukjH0PY-$dy*Vv*jjNY%qgpQ#@J*sq_^IH?x-cafeZ{Rz@% zQWFm7>hdo}l5YQ-pRP61sFbU0bw8kWmIg%VL=WLTMB)c3|qcfoH z4WR!CHH_K-Fn&2e3jmorcPlmEcBF0wIrRa6t}6hZ1lRzOT*Bh$*6lxyUM9k-&S&{> z(xEy(Y+K1q%tiNbPfpj`(>+{1)w46`PA+ce7VF&y-Oo+l#3lM+Av@ZX(3w=kN`LKK z(+Itfd7l%sj~VtEC&0YS6zh1m7oC#cn_W_uK8+K)^axJiRPYfg9eQULrIWLnhc;BN zxSCn%6GEj<50x4asr6PY%&oh{zl6Ib`6AAx-J0KI^DZAP9dI${Qf(+m(+G6f#@3+| z?zvn>-!SLnC6r9w%{)1<;F>VG=oovrmHby`p{lopu~^9;axPWQyB9r z8<9L|HELMRJT0hUA=l6h`d^t&+FizUbNE7feHv0~i&x4&K%9(e;Pn?U?G;0dSI@}s z@|Sbg=aO}0NA1#UL>~M!eKjX^+pgpU+-?XWq;`A+PjBQo5*P zY5()gvrZV?jg8-758E1%m2m}UX@!z%jmMf{i+7&w2Rb2y{M)>tBVm3-q2c-#!NK00 zEdl=D`uKU`B@*C2k1+v$U(;ZES-}26=g(V(7_0B#nsf;|b?}1}S50~ty1+~bNA)pY z5juD9D>2A7=^ks4e%4FBOKJKEHO>!QinKmk|5BfL??PH1fScrNEy(^Sv77Y$Yk5XE zrcbdqtt08N$TsP5mtl4+C+$qy?1&A1l=MEAA2Qo^^Ndvb!BCg*4y=O zW2g(>qx1{ZS>MJyhxGodkiLxCY0@8UkZp8ptd(#2Z^(0)^E&65M0dX0C&zv`3bVt0 z6xK-epA9Z^j+XDQGtG1BB#y03#`w+ zda;UhL~gH(y#=!L+1G{OOYhH_`s`~IC-m7@>lD)%9a`EsLBlWeW=`mdtHasXS&Iuy zp$&XZ8jU{xgnS@BmYy6<{C5aG=HUW*<~6)9$_y<6edt8`%BHV0e5Hi*rCkUrK4X($ zy^Gx%Cx_I?Sl4Lqfcsd*>k<4gU}M_9UyUaNaeI8>3eyHG0O%>&>`5kBNba;Wb_?VW zZ3aDeD+sB-2l@jH$$j@SGk2P73fZe;_1(44zU&u1oi|hrl`M4kEJrR%+&Y@-YxrSwy1B5;W<3Hc%cotvnvtn=TC@-8t%Udt< z-t^=p``B04VeWelLTKvM_Y1?HHt^riobMa1PD`;+?3>xwNxqztz2)!B9XZ5g#WY*#1FYmfFqKw#=W-5pv6cK1=RA&%U#xSmzt){U z)mdeA#n0#cdXkm=0{0}T)5ewR=O_5iYCUGRzj9C9W%A?N+nVD1SiXJDbSnEYmo;}! z-Pzs$Cmuu}ntan#eS%Ot<^X#@DyK9y%u@fa?IAp)-PV%0n({B<+Sx?>KIb}umSYxJiBn@%6RPi5Tk(-1um39wO<7uUCO`?+1xnv>oP=hX&yNOFR0OYPgPAV0+ z2dPvl?p%k`_+(tgg>`G`@6DM{z8wItKQ%3UhM88)H2JwGZ4W)mwD42iini-b3qRE@ zOxbK&_%GAKd4n(ap@d0&h&+83ZIXj;!0c4(Ap0}D>1;q+@5}zJ_ogK`B3s{EHtDM= zt#62bu3vh22WfMw?+d-HEw~Bk`Bkv)QT@`-c1qK&>M!+cEPelg;?rnbcT6j~5@~Jz z*SU#1$cSIZ^&HFQrxz<}8uLE@vAWd90J#?;N1OkYo7w!A z0MJL@%yrOCJEEzN7d)KuS2LzDe0@i!13tmatPKP3?52NE!_` zEvX(LC7e@BdPYkc+Xi*3pwi%N)GNa~(H+0r>^oXUD~(d5RBtm`Y)VGu_@!C8DPPu zV>~fdJ+H{*UBFknd#7EX=vsdu#mKyUx3Y#~0S3%sR+0^o2tBlyL8P=s(#t-#aczgF zqwP+oj7QfdfIhSYU#VsInhz<-Z!;U6L>&hkIQq?KGZjw;iKgtW|m0xNhEGoXRVqnJibe}d`e z(FMxAnse#Vw-2P0ZW12iqDR}vNd6Jrv>y#eXz-uFS-s#o9b29;JGwz)^(!2Ch-WbN zm9hGaX$`ZkEH6{DLaK2SUQ4w<~F41{BL7y6{6}#NSYf|55~@( zWt2=lg8`ig9(Ojizla`#Paey3nkfcrI?mzNV1+c81hU*w3CZ4#b`sktFRpi~wNVUG_GFr*KxlgE-Ux(Cs z2GgmP$DhNafowpvj^Rvd* zPyJS}vlX~!#cPkWXHS4A?GUr#$-B&ZpR?kJ!qHBoSD9wT)2mD;mfp|Lst8{E%cY1+Mp zZS&1MW0vK&BkxeYjFXkReJ|c2`SY0}o6a5sEf@4TDzS@9*5*6(haw7LiUWS(aIrq{nHNhVsO-}E}~UPN3P z*Qb@328=^&wbwfZ6A`Vi0-b6fbt%B3;2gCS;4^^SHDH^(87b9%s44X}fd1PMnePK= zCh!En3EO!)vV%~$&==k0S5%xQ0Eo3q$bh#2vpxnNQa{kqv`!C6wC?fqEIV%ob z)-mAw@8GOt$r>o5*Z&k}Wk+PCf67^;BfNt~_8Zbdbh~}MvjYx3Dh}iE`1=5U0>cpk zM*+s)4{#XZasmgbEI{s26in@b66_PtSEMpi1AUNWE8rnH#FqLNIsgkp& ziQWLDBUb!NgTrcg-q*jXg1a^>zOpdBi+lSJTBRUN$6FkkzGnP z-Pq$Zrmr%*p(~IW_Mht`vNC#eR!2XDdB5Q}`d2BlncIUN(vLo+PvsWVo3d7~M`GZJ zeR%F!T!65T6TUtUtqkZ1rjrc9v|^BXIsIfkt?1dNua3Ot)qR6$I$}f*?w+E9Y2vdq zJDjQmuem#Du)Yh}&!H!HaC5E@vyuInSvXk%WBpO(=DHW2XHP6N`?tsR(q+vfGCe$| z7d}@#D$~Q`yo_4YtQSI0=&e)mNWO&RNSct|ywE6=gtfT+OKkTk7@o&KKWP_*a}ZPGV8$zvN=*Rxgg{?_QBML4 z1ZX9Y0kDfe4#3!_044(T-wjX%a4~@k0q!L5Gm9TdKVBg90hjZvLe-k9=G5;|@=poig^NqaWe6?pd ziy&_l9k_LV27soc6o8a)PAzvTa}KjoQcp#P1WsSkJW5(1*K8 zoX|_w4u`wR_wy*AHQPO?2nv~3Q}srN-f=|>Xz5@j?_*XP#Cr^@X{*oaZza!Rucen1 zKMBo^skbsuvivJKU!BiJ+$gP1zJasoEbwHLt#6jy7a}r?>H3D65t-bN`;vBGrIN3A zV5@iswh963bhgndsrW9b*guxDZkDV+a~5Km-o0JO437)L<8JU?&slFv)`pO>O{n*E zX82JUW`r?(!VJ9-bF?3fauxfPv(hB1PO>u6xi58zL!u5AyOk8%HgwWU@Nvu}KOXoa zJjXt6hKX$(I#KYQ^sG6X+R$k%{O)z6==AMso#$JYM0Zw9V)LI7rsydQlkD^yqL@Bw zYU@PH>_Vh<3~bke9;R%4mSoaTJWoN6eyU@mJ~Qe47o;g{U(@Mh)cXdK=19e)pLhXj z9m=omG!*&oQCgpLne@0lC{8C=n>tZQf1Z+hiG7_G_Y~LGB52j*7(K%ub81#|U=`SL-6(Uz3Wa)FM8j$o+VjUOWN`*Ic(gk-RQx}YR2?Y-! zN0*t5ls-zl7l1x`O>|eqIGxzXS9@Ql)M*{!V>pM7V}B=M6o-bs?8YK3Z&;;~SHM?0 z-njzubbKrXua1um04d>|TJH78(Q-c`K=F}yS=ZZG=Bpz6gHG>u)HR$#%Zz)4WljU& zxT)jq?F)^r^gEjNbDaiGXFVIir}aDpkV`-6pyjAnSIvLN?yQB6!)JoGK@7S?)z`#+;>I#57nkR{5A$>eJfd39cN|Oiwx3+ch}M8R~t@6 zoYGID4Yj6JVW^)p2!yT_z4VVdqO5+nW{+R1pNa`v+PsQf5+c!noQ3{nT8U_@zyMRA}rm* z{5GdeD;!VD5J_6x)1=sRyEClNy_9RD*S3u+#rEqCI?{R<-=;3QrD^IS3!$nh=%9r0 zCX-$@O3>}qUqeZDvHb(A5^pKgpdWg)Y5nD?3laErY^%p4BZ7|XJ#C@c$taz0g>92C zn-0NsQELW%#s>srYq%_@G4KY~>_FW)c zZL0P%j1%G4)Ayeck*#F;*Q6YZS+{Y??g)-H>OKgm%N@hjv8Qf>5>Z$+z?<0 zfwA2|#jDA5A+An6ZFO9iE>y@y(&^?($fW+@WNcnfO5#U6jC{OaW7~N>sYKUgE3aoN zM0PtJ0Ef*e;usyMNcWz$Cp`g)SgGpx6nkt}QTKSehdnOt`m?%{NIbVCB7A67&)>J$ zXznmw-3gbs*p{zz`&p3P3mN!BIm1xoMB%}v7p2(Y9AIkOdzS>!I5}3gr>~pW#mhS-5j}QlXpSk<&m}>SAtkw_F25UhoF^jLrE{I+174?+ zLHS}tgTgMJR&g<~*y=+pR`X|9y=6Etf4XUBd& zA++CnrNGJ1@4BT)+R;voHGK@vGF?VKqZ86yI?)Ggx+Jlon?#Hea&i|07q5dt#Gm4^ zc5tmzy=uv|`mraVF7ksU_7qMgi&Ihi`iD54-((PZfbihlnCsMj(xKMVxmJugs&$~} ze^l!rPuIMjrrdRAAe`Z~p30pWqAikxL$pP5$SD{JRJ^!LNi3;0G}fY_kfxQ^72?WryPzT*w$O!i9!Cx73;o7xfFN|1 zX)I-)O*Qld?HpH5XO=S|bnJDo__>}&L3a}DGKD)^N9prf4{{*n;n`HJht8YoB}}}V7D^!Y=^eE(aj7VjXh<^* ziH7-bj$SiUED6#kbYU)c3x)*5VvpD%%9VI@DQ_K*3Dal2Nb%183DX7UMOq`^zn$7x zUzfVLYJO^ESy}4x%#neS!-qCjFRHFtRy}laRdwU?p_SE*srnB!rdCy#EpA*;Zs{_d zNS$BRP~U-KrKF_R@5F92ydwyfp;)bDB)wv`OGo>%B>o|>6Km0Q7@-3=MwrbpR;RQ2u_kK0; zz;FDUQ&e!x=*CIAX62MPCF5#Kd?hFRV`k3wtkzjhPGfz}k>EOCN$-D6Y2Py*9~fZ~Vj3#xLfayXnUN z&%mvyea7TWseY}g`+#nQ(|W1X`owSi+wCJ47}|@Rf^LRJI0g4$hkmYK(XpFDI{yEK z`H91$8dR#$;8qDd!%E6S=H$XCI;WJzf?5Ih;2##KQrudAzOuO>g; zk;s1f?*!YI(Ze_H#HR5d`TF;q?If$U7jN+m=;0f6!kV#9I0t5{PrGkP8>2>TQ+dTZ zoe@r}>bgaBZrfW>pOe*U`C{z2lsFaN=3L`69{GJ^7E#&@oDl`H3e@hVl#-IXJp5PB z+AW(mU$2g9(e4oTdS$Rx4RG3Aky>UW)YGtuX$lhL{s*6?6ooYYu7uI%D&ymZfSiM3&{NQ;OA(v4_>?EApMat*U1K zeR(B2)Jo?VuI=grm7SV*X=+wMfx3NF+oUgMk1m*`mbU4zmc2HNV#wJ>E>fE z4n+~QF2?QspD$_2Q3IU{wQ?uPojd8dRJCFo!6^d&2A5l=18-=)g)FBqdvE~XxRSGz#BJ#?w1uPO9ZvQGWD%4sQ3zf<{Y@=lfE z>~GJVIZ1VGfPEUAgKBOYtfPxwv{PTY9a9xBeTI`=qVDd5=GK$$Z!gbRcXcXO2XXC+ zo?e`v6YYS#?&nl>_ENE?A ztLE5&U)|H((w?QxELMZ^4-|l0T&bS3_NZOW`+cYPRL?_B zavT1*`Z3rmMKu(wtDExGFLukC$?C}JY_-`}tUg(tqWi zRqkPRKDzSd)!WpgknqxK46{ce;l7xjUpG{E@ ztZ?#sj~YL0@{9u2ttG4R-n0WHYDHU6ednuKFds$tTr}htAAO=YEyG@l{&5^tNq@zUFuz{VJ%hFsNS*k_>D8) zD!V~9?i^$B&zqqCK6}sG&aPPn&IxL!Z;<^|!O)y6ZKAje;?*4$r+aENr7xwgb@WxD z-fn6Mnvb(lZEoHVMVyLR>ISW@Is$F~(3}mu|8C{yR5}^6XE?(!zVg)p=zBNx)g70w z>a%n8x+x#uCFn%;g4M9G9qR8@pIf@$;+&*7jF!W@)GbXr)!)e`w=|__o4jMUs5_go zTh#$OpC&tBgxY#4qZZkf^rh!dm}ajtMP1jl6Z648AmX|vGO_v?@FtS>k&$M{Rm3^> zZ_mo9npt4Nkkcd1xlhLrU40$=+qaYGxSeq{Ydu*qMm+&NU$yhqgBWZN*~dUy zi>}MxJGpM??7B&+v(tlg^_|v}E(a!GfqRoM%u$T-Wi3XQ9t?2@3Y>)#FVLQ>{$@Fc z)!Jr9_hB4n`0mcmU~t!CRJDrV8Mh}60-P;cla@HAkEZ7xR#SXq?1_`q>rE}rH?8V^ zH1Un5VruPOXk8sx*5qu|#f+Oc_c<$^HGehkZZEGJ+6u4%ve0l)wFyQXaIc=0XEv)Z3XQ=i&S z{^;4d;NP2cx7ZkUMuU|s@y2G3V=r4w>FOL)mo{UV-`u=M9fsR$0k4_Srg|ac?^Nm0 z)fmc8!dY7!#wsZKU6DV(&o>aSI^ zv(+B!@ZLNpxl+9mo3FO7+=*+;dbKip_#&r0FK3b3y3$EGaBu3{&RCV&pf1N6rU0&$ zU7(ilRD%wy*-nqgzRppNm|pui4SB6jZWg*R#mNuu%_?w`-?}a5Y^*h$o|8+Qo=#9* z-wbE|0>-T@m^Ex-L96Ogp=z9#oS~}cmUeYkvC2&;fO{6SQsDxXU)(rLoozmU&mGQz?P~YRohWd`-Ue??f}GkL*Cq?L$5ync87*pXTO~T;e3g-%x#@u^ z=c<)0D!!%iKvv1ePOrVVsppt**b=86U$MuTtzL*TYn*SJw7c1`wGOR1$f&L2H6Ny{qkF;0q!H18L6h&? zs}8K(ukMcZ4X{gr|Z;-#cIJZ^|rMiB6O8Yiq&(rFWpvGtjw=eKgXu1wJVEL_d4b3``EU&AFn>?)V5b$xBRgBcc<(J)RJt~D`jF@rCMvZeWQNF z?4S-|>=#Tm>mw%()%mDSUmktkOJDWZVF8e>*4tRmt%sJa*FK4vNvf$iraPMtE|=|D00{_Gl(Ip%a%LEam8`l)sLNY ze2m)?r!t*wt+VuC!32k8Obf5C?xS|-ku;gmdGzIEDa5}XyRup<5nS~2qW4l?#9+Cg zo`XdbQtr>4NEWfxP0Mv8B%{~|>1zyq#5l#iLD(ms)S8DUkMGNBY=@h|zp_$QpJKHT=6Y&$!FHw=fSOQ@ zjcP^7lVfs-m>P6?W~E+;y;im=ZBYGE)J2EY-(!!dcm%{{*%zwidz{VKj`v3X{KLwh zf_(~hQT_8(AVr{>cSuL4`Ucg?I4(Tm*Yy-=^xeIB%Pc{P^h@I#93S7xiS5vj@sG2GxQ+d)0B+JvrIi)frp%25~qr zJg9DJZc$IIbhg}~mZ#u&vmg-;$7b{bvI58 zKaX*e&Qn8E%x1IzJGvYxm*bLEaX#(&id#s|pDsbo^(`fr>O~}tnh#^J@Mu{9@+M!y z%c}F1BR64}xEI^eoUDbjUsUfeFV-7_U?Wk@US{5TP?^|eOs0wN*?)Bs#jI9dVdwn*uEY7 zt{wk~<@zj=Xsg0vs8*rs@)dT?buC-9u*5UmN5rWU;9Z*obU7# zW|gR79VL#$>BW*S?g;6qgQX5F6rFq&-+by;dnZ=!ht<3G&b*Swi#6?UO?thTNeMb~ z@MU6^!STtoQ(e7uzY4}<;lDB;LGXZjBDPKaWhFf7aZG8Mdz>J~bMktooUM5qQH>qf7N>4qX;#fm+x(0e-q_(bnspdo?Fu%0E z+*({yU74i68msH8Dyz#EB;o8)i>)m!TNIK{h1UtbP+U|v#Mx2U|%9C~WPvbw5V&O{*&E%FC_# zs+Hw*Xlv>AlrAaP>MgD*h0ajPXh1C>^EOs%OHc;Y0izQ%1v5lFm-jHzYLc zlG0jp`vLbH=tc&L4;_{=B9-nwKw;BVsFML9WeckoFM#E6vde}?Z@~`KSGo@ZOB+h( zFD@5b)u&U)Kp9TEO*^b5jn&k65a%ymMCLUR_CmV@^+Z9L zx|*5>tF*RuaaDPJprIy!!}Z28uU`T<%m#O5)dKL&pI^P)^Y1`)`7%o@LxPu3#aKeed*jiLxUJK`_sl~Cpg@Ljd zwFCmCWo6~H4H=qm{tB3H87u^2qz9<_@c~V<%9mH6LG_hZDN$=n14cu1XLVJ>3TmY> zC@RDOKl+F6alr&_(GPX=3YwKzjSfv;VTCWxL zRC{@~9we7qf}jT_D{5tYAnq-wa$};= z492Z3FKY-a)-eiJBX8LO7|>8!mUYXM4vkPtA@J2xiiXY8)5iLG`^~o zT$GIxXeh135Ne=eHK@KCz7WzUW%Fr#!SGe(hjO25q;=KkB%NDUyVP3F8l$;-P?B=m zH{i#Jj5?lMjqq4lk3CvvQ(UxQgaF$S#?fOeP)3Rfrr;tt!>XX0W}v`daZd`;>R0OK zP@NbW^_J-cGwsbLOB^nc+zaT;V zQB@z(C5Z2cm6-Ty=`~v_PvJ~EsSHGILOmo&Z!jkaLjD1qpD35w<^eZ63R-KlP6S{VXDQo z)>;O~1frN_A)=a)K(kqKHhqY@X_x>iIN_6S+bM`s&8TR0UN@e7YBP zX^I0&U`-mF0h)`bv&w3!8>-L(9r&PQU3q=uV$3*Y4K)pzx$!IkY`p-EWG$&*QC&vy zT(`bqX`s3uR>lgftQ>)&(yE1YGcQ$_moKQN1ruURKu;2$!k&>T$j+n_tXNtXVg+p& zvZcwOUe{x)u>xkLmesDH{-=ORE~6(`8uA&mprD#)R#|F1lm?xqRnWYq&CsZQMbA3K zti!zV9Hb}~L5iMdQH^GhxQ^lL&AnR5Dm~eeG8p^Ngs1i)*lsHS?Jc+e-s%=+Y$=5|&o*z=T~W`s?n{ZjCjBJhhR|PjC3FWscxn zkCq^KtVc@}obS<+1W)m3g9PvBZSK6Ijx@m!d9*=-ANFWTf*QbK6!#Dajh{vJ?tj=NcfQlw@7u zvJ?t@tjBNGC0S3oEQJEa!cjC73;*a^x=^6_c9c?L!&UB(Nec?z;?jl%1wZ4`(u0CO zbZHqu!7=Q>K5KYT@aZmXL{RWVmo_pe_#&4!Dk%6$mzEh6{D4av9Tfb9OB)ju{GCfn z3ktTl_kGr|px}6ymL3$`!=+^e1)uEFh6e=?aA_lgf`_`akwL*DUD~Li;IS?(GbnhX zOB)>&{ESN*6BNA1rKJT0zwXk81qHw3($a&1KXPdqLBXH7wBbR)-?+39LBao*OB)#! z+=<7A&l(jJoZ!+jgM$0Gw9!GqGQND)n4sWdmoF_S_)?cPEGYOMmzEwB{Dw=*2nzn$ zr40`XK8=H;&l(XFJjJDr3<_T6(nbXZ-{I0SgMtsbw9!Gq-Ffs=+XVM^X=y>hNiJ;L!INFu$e`evE^Sm$@O+n+85CUY(nbdbA8=`7 zf`b3)($a#0e|BlZf`YqqeDhi9LBai9T1HUt2$wcID0rev8xa&d+og>R3a)l(qk@8e z=h8BRg15S~(LuoyhpFELcj;-uw$Dln3ZCiGh6M%x(WRva1%Kw!GJ=9fogngt2L-pd zv=KqUueh|4LBWX}>1n(PE^}#_LBV&pw9!GqxjfTS+XM$(T3S%>T9-B~DEMxdmL3%R zs!PiV3jWHa4G#)VbeBjYf`W5g+Q^{b`7Ui#Q1I_u8v2d#HkUR!DA-$ujS1@cJjxf| zJJKIoathwZG-WN@hsQXhf7UbEwq^)?$R$k`D57F4{JoqAB_#I%7bGPF*WhVW`ap?8 z_$wYJQOj3iG!*Y!gyk>~6cbqPl8OY1r09xCZe2)yf|q%;1i>pjTB6`fJX(_AW{);V z@EVVnCiqH^mMM5Pp2?+8jJ0gdpDanuV=63?DLCNK(gf2l5YY#Gg9Mj(v?Rgh9xYLD zrAJE;On)ehs<&J!r^V9JIo*vdw3=PQ{_@U1RwSWxi2E-gJ6E=xL0c%t0-!t^sjL;7=}TjzGnt%)B8fsUTW-VHs;( zSw#Xra!Jz#ia-;+By}QJihZlVln_0Nf|8oxF$$d9fl*R*9-}~MgQ?oHk3m~lS5ef) zD_AT;3WD@orM9^(Efn~mONuzppg(^_pN)K_t`vN&M@tZVgGWmge3M5@68r~`Hc0Tz z9xYAqA3a*8;2FF)qBW5viJ44;3d0 z!wBxi3nHzc$@ad*q7QM)Y^zA1SFZi>h?(kk<{!xw!oLM(xuhA{45eu_8#76yM;RDT zvg`@2pt+HyB4YhtB1+ASEEVBVe~KtIT}rKStDi3LGA1djetA$5H+g&lw}$db!fWw# z&;AB2V*V>!Q4!()&z$v&%Q7QeiY(JlcUh+W!qBUG+J7%q7+ES}j=YNnKgw4M_HQ%( zh_9Ia!Yh*oilKZ~y(Kv47Ap!bmcTCDgRkV?f_r(SB#zwglo3I4#NB?5JhnRhXK#3fA? zxW^^Uq#q5Y&qpq4sz5OaG!r<-waqkv&$^_Ue_{BBOPVUM3p)X1oy2gUOPVUsvvWiQ zkF;~K*jbFLup4TYgqYX1iUmp|G@m4-i@_&Qw9tIUI^OpJ?q{h7Ol{3kYG`YYBCaiB zf}Ig5Zfi7gTbq}%QA4!b8X@i|ixa1!crAFS=Pjccio@B~)Fkfz0AHzO8RONiZxo5U zeCd&-ots%fDtRm8r(91c6i;|BgzY27zqo8gk**LiDFwNap8HQ1_m^J9LRr)jdquhD zlfZ(c6G(Hx60Wguk*=0rCN{xhT(AlBj9MtL!ZrOIfii}bwJIjcfSw~Q8txi;jzH-m z+bR**;Bg6*;SVl>GW?;eKra%M2>is8CD8BoPl-U!(sKl^4(VCJ(hGF^ORzW!G!yu+ zTfrQG5=_7)P+SQ53lwhxm%y(*Spp^GfJ>m~77+(RQHJ=AXk&6mv>}e4QVaWJvX{xk zjvc*tluV@{Nq>8KMI50_WG@mIvaM;6y%DkSi!4LW1DO zJ(?r9TX(~!6*SQM7N5L`eFI}y;JYjfLuXC1B#tlD; zBEKk#{Phv?-($IlT=`Sivlm^@SFGUj#5X;XKxrwJ6t!fuVMX#ft0Vmll0a!Yl?-dLmBST{cPlIuSjZ%0 z)iwtuF`tQ@tme#XV}|v0JD@Yy?`DM8Bw{agYnmodg!-)JG-;;ens=H&se;(TrMI$F zF(70Legp5QGV}gsn}@bcVPrDiHXE%QaJ=IJCBiBs}9rtX$Wz1vk3J zEfgqr!U9Ky>rXVP@@rR%LV;2-v4wZ1^hj^luu}z!`JueyhO`GfK7miW9RNN_h}F@< zVpwrKEl*4<&Zmjueqv-zl!TZW5~V?6NzE7DvR~PT;!WsJfzm=cZWYh+6rL9up&~j; zMwl#VaI;ke$sz(IX{1csAW0KN^(c2~#qQU-rk=NzJ5}a-v_%Aoc|Z!cz&5tPPQFrD z75uVG8x|D2&!t7KXCL4^;fXSHjAngB|IXI2V`s2V;sX-kLi5B*(vr};@NgHJ7v9{? zY@|MXr9Fz^{w^&oD0r+(8-}MSjWp3O+Wsb7J{++x7fazQtRgVomEL3t7U?J%u6zQ| z$UXQ&4=Lhm|;&wHd782;WBG+khb>^C|06OYT( z?|n;;OksgEdZsZJ6^JG}JQBhuSd^hfoZuR+lFAAe&4^F1XRXM^km&UPryk)ZB7HsU z7&L_2GA^V|6^vK$73;h3Vu#sOQXErqcx_Qu9uryMG*@uMEkCiHNW+>SA^08hi$OIp zTqXL04D{*m`KTj!fJaLZe7Z+V6g>=pU4`H;wuUY%yvnI0;^oo^cIG9dZfDfOc+UU^iRzPFrHTZ;$|S^QOYlCItx%x!Jh2IuregWOqgfK71u=$y=CfQ8it!a* zEXt6Z8&PVGluC82Fh`(R7Dx5VgOU)XqJ)8?EIpn@`K($;uyh>OM`fISsaxZ;n;A-% zM2k(Ig-MSxqfBKn*SeDDZ4Q$hWm)wH7QCCU5FF_Th2b3_J|=aN%9lsfAMqH+)`-fc zMOHQ~yfU$#^o-A1g}-8GxH9;P@fcoAMxHn*)+qv|8)?W+jhF|dC#7C2)4HXEOXsxk zhKy2y-B>k5=vDu<4!TnkUd1nLEzu*&>RMRD(W00^SVWyDqgs4YJSVil;m#SF7p}0# zsd77Iy1><;#*l=J0cAC=3Q9#GF-o8ejHs5BN=13Hq{xzj(X4whYb3ET%3c0QmWW-6 zut<|&U4ha%oF;}FYB$#{&L5>`h2>M%mJtgNVF?N0;T2gu4aFx{EW`!Jc(eq;aULyE zFn;<>e-Mb11b6jlg9Imdv^2qeJzA#V;U^e*m}j4{Br%GKs3cQxrbkN?JjSC95}fVP zk_6{^v_!$C)dY3dupolV$pM*#;kP9Tb1&ahu zc1hC(Ud$wng5^O;gjP@#5kaK;2fNay3Y_7RW(o|I6&V$$v!!Oc7OQmxU&ORHtWe|P z{LZ_a{*kY^XL%AE6~Bq7KhY*R`oq!m5rr^^3;fTzi8Zcd0hoK~@7i?uJj}Yh%vVz2 zSH|5~sVL)6dQuz^I*sR20ltD%$M6b|B(TjT6$-r5CCwDAKJ-XGF+9yxYNi-XtPo{! zGk}{eHl*eWp6d2>#6&L5lQD<*CC&3Ho8G~YNPNixe{cm)6L`AYkiy~I08dav^>0Q9 znks^lSrCr35~Tfku1Tf}6yd}cuI53O?&(w%DXA!2lCm1?h>;|wl)(r)2^8o1KNy#J zteA*E(U_nlLgcNA80T^Hev3aQLceJ&v4pRh()oQM|?Y9*W78$xxRxrY{$(1rayr(5NNg%>1<*u}FCQb`)$nX^?#c>21xnz@a z!W3;$v5=isc%tkRB3X*U6^&$xxN&g{SLB6~h~>de5iAiEMY2RxB;nEvk#lV*Jw(K}yRxPUlu{&XT10FT z^GMAwYGidY!mAV8NE1%88m((%oTLFx(&-rkR1E*k$o|*HG$vjfb84d#cd^yCe^A(; zW-b4FvE@`u*q`NMaaOHWXPp|9w5NN-%qog{EYsd$DPk9_%EFs>h*>`5E0*Jq;D30u z1i>GBv_!$1PBc4X zXi0*<@o0&Hzw>Abf-U@gdHPVK6a4NVL(>Wx=zWVtr*O*9N}3-fJV@jJ==MNb@J!acl&?7bf3oSVeymcGxoTn`PUMCXzvT9u!WwJN zQ%*OXg)Za8N?U0NO4Fp zx+W&Fn6-t=CWU&G!5xQlZ6iV7ZY zl1>uW1Yb16MzhQ#Y#A{I4GB+EgQDqs7sv8X`HIji@I)`jyx9~b^1K;!y!K@;t>-IV z7ZVubz;8x#;5Q=-K;z~W_A~K2SnAEDXl4-`)HQ>zG*6R%nRj=W|e5|HNw5`OrBz7 zszJ5SG)Y3HR~&Q6oGQA5Brt`Y1zT@{GD(3;=2-E1kOZc215i-l4wp1n;G-_7Sm17# zG*`yW`|f-_SD+W-iUmrjgA((3B9y2HB?O8s!6h@Jm=YwJ7$qQqBv4`#WC;|10hd6D zOW+bH(Ft4vB~XD&poA-M36#hMu1IH`8y?EQWrck{WmEp(nRFkUQtXK81d1Ion8cL1 z?hO*~E$# zEydf#wJ}f*H90&#%c=!?BXRCrHmK$kj}mwKt%X*&BH^PGH{~P8WEq)@g2|=SgFwrN7m;;f@Pw;m#Q4 zfsSit}emQi5YVb!MEOvV;`U&wH9=C3vG7ISU2KFlWiq{odeg z-_sO1I6(|=BOGc^w58XcrpUnw&TxC^;{QwMUBOG3kaf$^XzP}vOru`j)A|{g9LZM%eSy!rBzG~9??#H55-BB2Vmg+9cg$U-&J_5AODYs7 zF)_+K{tk!c@7%dJ;*9$uj$N1V73=*LhF7_yLK(sXcyB~g8pAVOQp8EP$X?#EFy? zxxu=b8~zqw$yxNJQg8_!>%G+I!NJ?{-5tX)-;DtbQt(+n*Y~% zEqwc_3x~I9PNJdA=PSHQpwxqMce%0QOgR>?3I&Gj$M1?5-Y11k09Y-^PFm(UkYveH z>yF7lc$5d1OyqKi0n%PpM~*N+irjKWTe5`PVKD1CjIXeRK#9*-1VpMnFH-e+k*d#& zRDGVPzR$C$K(96PB3m<0f{g@(D2tQu*#=$sW>dH*O$@g~l#+*{l{^&D)8QrQ)^d22 z(QY?~my6zo;d(yG{q&*RUlC6Q2+Kic8E7^9#y!pky2shz#9`wQhuf7>;9V}*3AZaV za9cDe1gW%_b#bSQt&1((H%%Kl$hJ=GsoDOUu0AU>BDOSzEq`Ezt9UTTNgqgmW0IWn zfh2=LPV_($_Yv!Z6nW?p2%oaS6|VTztkfpHVo(T_B?g=?QqOsjdd`c~bDrq=p*I2q zdaBQhRDE8g>hr=?4__T=XAc(@bp%8yd8jE$$;c59rR2V7CHF;)o$!*;dn~+-seGJw zk$bEcao_H2&YH;A)Bp2*{#x2Q(-08;3%T6D|6C5w2XH|tP{sx0Fz9M=t6$Qdt`W;1 z(bZ##7}B4x)b>-2Enp|PZz3xQkYv3t3ssP0hdS9^DMdK@4=npvzQWlBdezN~tZtrE z=XmQvfu08QA~lHc+1t2P&-Qa$C#&7_yopi9em8g21Ri53Qwka^>sOg9Kni!CN4UCO zt}zP*%8>*{w`d^q97vHG%o7cEyGj)b^pu(xsZ@jwF5(5CxAG6jDor$@?qpL>aZMfw zKWPG&Y-Kn8cBil5>aK9torMBD4dz8^FfUSrd7?q7TV0_*ISqmFB9)4;!2)iTggG6i z!cR}4#;zzO4>d(885z5zwQlpD(BRe7PHwq`-Y#Fb=_tVv?l2IwKk*b$TojA@&e=_s4vtJMe<* z`BiJ&fj?wRqJfF}R()6_Mc5+d!B$Y96f=+bgq5?_aDkQ(;eywCv;@JId9*~q>;LcO z&IQb_qRRI>=@>eJXeT_#l$O_gbsgTD7Y7KKr~pmji#qa}D5+daeolH=b(&&pgR`Dba5qL+4B-%^M`Z zvpv@YKHGB*;CFj22hMx09z54`b>M}bs|7!)ABTz^td`OHG%}eA;8e9G_aK1tl(Mr! z@4=I;RS^U};i#p+>rZh~z#AO36u8?_%Yn7(za5m`*~-eG!1)z|^ai{j@P-OOdgLkN zo(pwHYUG`hz=z*SSSx_!#lGQ!-h7vm6+p6O1?fHQ1lxeGI%);*98HwfrT0FUz7;@{ zZ3XGw>;&6@+bb;6`??cc0X!y=zP2(wW(&3nw|A7OGV&aj%q(q10huzw{eOpLXzaYF;o$5WV~JG-!zUHE{+vTbl7EX_yUkw zmJ>$Wqv8kDgDo!W1+q@zOMZcGaXBdf$)K3W^(9^kc(J2W7oQV!a^uZyobl7^!g&v?Ujj;J!o}zVS`ivzRZ>9aZWefwn~Va`&rd6Bk}@%x z;LUE%TDL0nbJhwxLDOS2!9*dK3&1m67F%a4{7OO-%pBK56J9UVVV0%jfOA~Bo62CO zIo74a%FDXJN1%ivmutA|*GB4ctySG-Tah69l)7G9Sy7DdmrLp;-^nUXfl2AqQ(=^l z;lM#T=^Z>@3t!hW7aQ{4&tMdR*^-u)sRN&ieLRD)J93Vaa|V#PvLn!AOZr_dRj@USKQsP*KrFazQEGL_-5LWQFV6%LY716+AN?N<$uaOEtU9&QD; z*SJMm01}fZhM{~>hxvgY4(Nw#PY>5lbjSMPfDMjn$0_eY>Ld~-b6hm>?lGw|r)3#* zzK&qoa1hIek+SZdQeE?G7W}m5>cG!Ho~r|I_gpRbFJ>hitd`N4P4rDs^mTBLW2vSJbV*vzCLy{DBGLEy`dY6nIdu1Ent zsFWR-9(gf>!Gk(0YF5k!2EIt6eN%K*)O<`i%!?5vF~6)7B{Q=$Ge#8Lahi2Ot%kWV zqTL$nx3yJKveTkL8c{HzswiC|H=;r05uyJ$5jvRA&5P&6O#sPY@ZQLQnOY+U{-Msi zk^8-3!Z93}aI!)(a{Ch((`amgiEENf>5OA)Uq7blMEU1JWIBxsn5hj^_GO9#m8=AX zQyr-6OI`w%{YlXmPqjs1;sui`IsGv6_iA+;F)-;7u`m@vg`o;XD90qK7tFMaSm?e` z)e86L3Gcy7u-w0X`6~R!*W|Qbqg5CS(xF_9AehpP1;g5n$-PC!0*nR2KxXJx(64PQ zM28eg0zy}W!jacB455zG-GY)5iVXx0g$jLWPy;iZp#so*(2Ai4+%8-IdfTa|8SF53 zCMF8ZM9I^dy-gF@5HTQb#o3}mibM{WIdSAGRt_^3lcbN3#UhYUV>vq1u&Eg^vo5+} zzB%XmW!4J(if+X5_gv8VraN6P0e;_61>hr&S`7T9v-bYYWjfDzIiR12cGk&1>3Wyv z3cx3nlHXX`T&Ba;C~}+}Ho9wpcHq@YN!E6Zd`vsrz1*D&Sq*YG131$a$B{KnI5g@~!Y zROsVr2NGA-#w42Q7~9h^wuhB%jHQEYr?4qvBNkRMQF78SGT?h$jTH%;!ZKp%vqdqC zQtqMR1S`sDf|&&oVf;gJY5e9=3`@pXOK&*E^oFx}bD7YkdI_d zlLndREhBWO3?m3;ONj+Z$z_!3EtjVnI5T zkr4#@tV)1%_O^hy&Y{ZWMG(#@Kk$hLa?vtY-aH9rI}vVkIFJ8RPYuk8_`hoe`)ocj z$!swxG0AL@nwTUfL>H6cz!cDN>Oed@idjgq{O}8xj2IaAL<~4qm$wlEZ*WU~Ilkkz z5o7jQ4`PjIIO`fQFu{pfIHf`n^4=zt$j2li2m8oZ?px$5_ZIm?A32cAOSz&W8U1=$ zX`%%4tWd;&$()57iiqtkXJkXf!ZP5*#koqV8{k0Fzh#**ghL)wmu z@xTn$DLIMb6qhuI=g(ku97@m>bT}I_@|CbuamFnF=R5< z33<8F<*ca;=Gn8kMGI!<%KBNAA+_-#ZRG|6@UNZu%dZ4uD&zkBR=wo7(cM+Nq89vH z&((qVc&-+FNQ+Iayo6H+uJv3kc#`Mp!pXpoht}wMAFt(SN9(T6dfM^?A zZDo4iR$J)TZE9oG+xjnQElq1J4afSNj=z~5c*W7b2i1#T`l+s&((pC@?1T*-g7zd(VlAnALF?u@bR8&0l)i9>!rMoxF@1> zj*{keL~!17P2jnnYXG0?xg2=D=jy==Jy!=Vc&--wz`GI-R?BF&MkWOeEIXH;e*5sNUJNLk~wq5QvvnklsTYi3kGm z(hAbUQ4s_teNKP>_-ECz**X<+Q(=)p1{VrjJ6%dr&+lI$LT6~{IE6DDRT!s%EOh}@ zT{UFHtYonFvK=pXIpgj3E1Wpn&WzlgoTczSPkmpZ53e0~p@wIM3^Qst((qxIhW2d= zeP-H$B;II-r7~8Xz&|NQjAAk4>hwv?u}|o-SI@Ghk9G-N1|-Kd(Z=+*WiQiQJ>$~1 z{17$u=i0_!P>qq#I{VAhSy+zGgf36S!iXufA3E#uOEPpGQc_O+K;}fAyYAe~kl2sO zaD)*J8 z{66Q?;-W(DX6lrSbuUs#`;^)|?$*q^tswgSqZfsaYaiLf4gy47zNu$pYVD$jP}XN& z!}VPwQ(UH)SS>LbI)`Rr69ckY#9pP1Ww?qlG>xmFVwU?aXoZb;>oQd{6s9l6cNkBE(iYdyKP|RvT_WauP7;l72wMbWT&!3<5sg zbM@evo~r}rJy#39MY%WEoYl3VNNdyTe6 zE*$P@m1ll3wuXyU{bMealt-tk6`VHbCGeekOfEElRH0lg0!ge$0Z(vl%SS&HH#i>( zK&nlQ0ZG0X1LC~#4E(p=7?7$GW5CaNDIhawjD-n(RKvw%u@s7IR*@TgW`Lh_RO_n> zC;0J!EIQe3diCf=F9l@Ph}1oL6vrhop;MzO@}RcyHl_F>&((o{;<Sb-g2@90MB()8}JgP?5;rXgHCWM@b~&=dMilplDTdW;1%;MWd-SN zRaU$K{(FTWz1O@TaPZuuMS6dwtXKq+m+URBQ-i{HSt7Wy-48l^o*fKZ84HOFFHnPK zJ(9W4X_^cN-s!mJGWb><(a3@Ca9$LEc#*Z_dv*AtnwOV+u>rEbA^|;h~Zbd;THq%R!W`)?jFG>DkUae z$2q#VMj^h(a%t~V&qJo`VDE5#6oB}npLuMcPj$->yGCx(oKZ}2-petM&P^leI_fA^ zGaTPFa=Ho;Ks*#33Lgvf$$BhYE#EjV6@Fvjx;%5lbFwH>xPtYJrE#q0Zkj9Q6$OQU zxD{chn@xD^aXP#I5xSpxf4aA~b}LSnsTgoYLyqFIvQN8A!@#nMf>?&LJc67CMgo8EGBV{@MH23_47B{#v~q-AWMes=)iB**5n_Yb6j&7e4^uKltWW* z(qqVET$mi_Za_i1#s2@n$|t71uTDH?Qf1vSuX|aF*!Ii3J#A=Twh#;*@Yx7MY}T^N z0C7?ZZTARnCT41PYL6D>jO}@M*7m%6B;1}wnar^$;*rC$Ea~pK-k*Vhcr4oq{&GGP z3b@B@y9FRoi4?PldqRb72^BhZvpU1MSVVwlyWy6x%U|lL_oX)e<+y&2m%^#MJAp65 zsj{cOtMCy|g?@fn{rtI0o;#`d;i{hW3CZj#X~zpBm^ERuj1)YjKVLQgU`bD~c8GMeSfXjYw%j${m+{#v-7X$qdx z)}#sis^gl=4r^^>y`srQqSeUD?HZ#UgNnY z@H-aR%*%7LU1R7pC@Ib~flu^Y1NbD*<-n(St{!}<=jy;so~s2vvM}Kcou4UboB==P zxd!kPp38xM?zwvKFFaQVe$I2X;18Xja3(BIrtJYusXVI#k_ah(Ao1BJdi1W*42Uie zzeN}Ll)7eh>8*H=^+*JPmpN)F@V56lDc}xAEd`#Wff|PuHaTi3kaUPtwPgHnmy9-G z&c)aYBzzN4TbbTb8m4U5KmxOZ^oCuSt-#|nCM!s_!Z{$fc-2GOqMgwZi$5+nAclU=k#kbL8jzMBw1XEJSa7%8pLk`W6t^@^&E*Qziw;Hi#lE`zDEtS1nEQd`Jm zcz&6hyv~_EJ>^m;vllbN&P-Doe6{16%V0lT`gT=s;F8==2$K|EXvxy5D~A_VF&S!Z z)pOOywKY$ez@PA39r%-;s|VlWxg7XYo@)Sq+H+0d+dS6-e(VD4r96q+Ifl;TN{WLm z;3quS1pc|_8o@FR{|3d9YOdSfTraN@lhkgR0jHM(cm>vMV!D=UIPoUwxR9&oO;0)MBJ z6{L5L=1nXDiNOknVc_78ozE*s5njsmX6T(zp&vqpBMKD`_bDCb@7!>0z;8RMP|&=1 z4^mq$ej_61fGwLtH)Aq%G$un=V={D>m77=3%tZy5e2L;Gi8Gz!24j#_fD!cIpO zfa@G}35j^GOJV_7aFha{pLBUNrOHE|vxLPV6s56S6JwGUmWGI>3!^Dj7$TM~izZhV zOuL8y3Dyh>rUFFF$7j(mH06F0Q&(;oYjJDVTHLxhqpY`X4xNxP+`2h*<62#Vx4T_p zF>seshelV)SGvp3tkmY-UdG*$tG&g*Zl&ZZZA_UCQ&M3hbYioP!!?X}M8%Tawg)B3n-q=tv zZK#+wl)Co#o_g{lZH?F9#~df$$ENsMZRNW5Hwt|)T29_stb36HZXWJdpROUV^|Brs zpV-O4^^R*UgL95cUyuJuZ6T9!`G2*l-{Q=qpGAZ+dolCZ&P-Doe3Rpv%V0lT+Ux5A zmolD3yokxfS#qr6BOTXV1|RFV^l-1JEo3r=`-7_2x=nByuuiErNAj~(C)AAFl#i$K zZSd@CN6A<0v8g8I{KQ+tQ0QfpKOzi~wbqVSw`MtyF9}EbupYWu+ezj=fqYN;`04fI zr;jT`-{&k8fShjQkK@qsTU_c4nNcqce!E&XG2Eq?VPqoM1UR*2h1zsjJ`U|4rrI`) zbK9FN^95~pYWrnvL-{QeEpxlJFKSzVXeep>`zv2N$?CmD+rzc3*ESqw+M6viQ`@t& zJxALEmH%v=weXO(f7JHq$)RQ2f2Z<|+Ro7SbZyVn_AG5fD+j9oN45K^wtv!g(v)x{ z+b=2Kt?g~v?mS5HryXv`Y0-AJw(r(CdB!nzgcaHrwOy|*Ke@#Z?1lauYp!)oH zB0o;JZJLevUTyzT+lRF!FZdPa=V05L@>V;-RBidWKYrs zZNu>oRG;s(|D=w8tG559E#G6$Pl>Exy^`Jq1t+g|t$MSQCc->4Ig|Jxasd0tz- z_U|?Ahw^-j5#RK~xBP_T@XbAZf84;#(30&RY)N5Afaul)$U*kAeZJ5t`r z{{G7Iy&rsxdP|G-_*!jOz03AHwGHDrQ2p?upEeZ9RTiTRx7w>MYBTY8#zx z`#ZE9)i#XxMdk66Pu}vG+5?r}khd0i|2}V+e_7vqzVSSJoHxCP;~l6zZ-3sR@0HxC zE#rpc?XNtq@Q&(Bs=U4MQSCpc?W*_Kk*?IXUSEALXv>Spp+Ea-ze!&lJzd)a9go+$ z!TMQo4TaULEEkab@vUI1_z?XzW(7-U>!J+Q{zKTv!jt!Q2I*fv%fu7;0vAeHZ{tuTn%KtUekz@T` z9m5?_V`*J+&0t4wskp97bm>`*V#nZM$0n-*zN}Nk#Ck_>cc%>9F9zjbV?2trxO!+P zYV7Rq?Jf1m!LHKk4QoZYqi=0Vc-!snThkBjSiO3%bUD4A?!FRO@&)Yam%*&AS_&uV zztsOT(HbLvW6>U)w@3+nvdYm|)^!9-m%l^g5B+Il^U{l=X-eecp8q$_!x%No|D^ue zWAib8w(6e{_x!(5-+W%drTqwZYAVmMBv3co5 z(M=FFaW@(-jmZ=GdQ&6*6uc2Z{H8bMr6>A2V4YD)Jc4fgdgJQ}|96bf$I?5@fbz)4 z|Goc=L%Uv%zn0K{PW7Kt{U+59{Z~5rfB=(I?A0HVj}O(GNs$NoVg88!I+020FI4@7 zsz0iRjs9Ws7v}E<;Y?1{-Kc(IUV4$VaTA60XU0lCu9r?yKd<_E)!!2&yiS#AZw&Og zE8S$AmB(=K;uCuIXcXNnAUXc+>+|uU+s(wtV}fnm|Iq*Ka>VG9|6QuTOZERLxVxMa z+2mt~bdvfv>I)e+Zn9F3Cxr!v<9{{KANW8%))+8_A&+~Q7~6I8r`>3m0CPiImr2xg z^(yH}-CP|vDS77K9*v?01iVH5&~H)wmVMO!spy*c(a)=XejoLp5M2`@`U_Qmq3Vws zM$Xdi|Eq$GE#lv*`dd|>I8k6+`mYNx<2ONQi@x6EcSi|_wpIYx2?@AW z$6u8s1&6XztLTsU3#+)`vPuJ?{`4yP3x8+zzQM$+nNYvEihj*YR$)GO&#UOaOZCJ2 zEt+IUT5zZ;2KxB1u*&#b>#f9;A7$&qwpP*q%(GVi$zTF4i*^*5!_)lV2yaf^-Co`POeAtNh-!Qa#eCuCO=-TAF|{RiMT#U8mp14aNe)vCq$gjEBT2L z=jlrRPETi1TIgV2zv+I1g6xZ;3d+Rq}Na=dDV9a>V(llAq$v zGnM?|5$BIe{)mY4LM4A>#C~7NA0_+usw5TTnrLd2%jD}L_T8jXO>}g`ep<c;?@2-CNvq*k1^hbU$4LHf(({?|+dQt2zcEp| zPPPee>}(0_+!@QK>+QS3XT@u_TVrRZ+8LF;c|0nAvHhd-rW<*!nHnzUogm6TrpnfT4)?JB=3myi27wcn!rlP6gI3Av!`lz+0x@}JWSjGKiw{;$(< z_3}NcRzEvq`N>hk)z(fti2S=Z=F@fcJ>es<7VZy^#q#NW;AxfTdKUYCjOEk&z$A%p zipnB1;pbN2+pF-sRrsr8Uh=%a`tw<{LCWL9RpdWi zg}`0%mGW_aRM*Q@%Gc?-yWWaNAC37a+IgszS30^?dHS?} zkNtv`ze*4665iD9_8_irtNcB|dFlb>x6ZM4%>4!PcqrzhXf*KWS86|87k^NBtL^_! zkhsl0!*$p7`uyO{%5PbgkA*kr^OmEP-=%Tgqj`H9c61+Du0za-c|RWLT;X$c678}o z@_oWjmi_z%ofmVDz&zexMgCeNFZC1V;bX$*V$I5b|0}j5H%E&3_`ocU*StG0t8RD4 zeERzKhr&-zT&Gcok-1;o*clC%hK8G)&k)o(I6O4GVa*zW#o~MBEh(PAsI{$FjJisL zrM2Bdaznc~+*|DI>F<-fyctxn*wtTL+ta_gqo>$4+&?%}?AWj|lDotMJ*DANSL4iC zGiHh9456aAUv2L`7v+xf;HJplukPB=+q+3r61}2vyFzq$pvQzU&{JF^ce{IH)Zafa z6oa)L!|TNFzW%<|a({V!ci-BW?(OXukU@J&R&TIWDs~KS8ffeu8tiC1EheQaVH&eT zrNN$3pFMWEWje%(O;)#exY)U_W6+AOF_zYsN&`h1z-r8l#Uzq}#1LnAa=5?PTk4Jb z#;MCY>>&wdpj294>|d|ui^cg%=3H=I@w^Mql{v8!1g^+QS5!Rrk_+ctuxOr0C5{XY zcMJ|k#RcbIG9E2i=9Io;;E4ImrD8kg7X*6omZUE zIHS?~E25>r!M^^Yq_bmKUYn>Cll%F7oxKB>LzNaTAL<(zl-E?&RMJLcU4Q@j=!(Ja;lSZyDSoM1)y-gLiX&N3LxH>uH#879 zH(2WEsMySA=y!0nDm3cNbZgB<2`wXQ zbHsim8--N5uN;{&*_1Nv$g5Q<*t?-GHMJ&jv2S*-h+*ucC@rPR|^?C6qL&iV(! zdMUo=^5PQR8|U?O3=PSSarv68x>$EbRNB}b#8NEEQeZ)wHNvJ^u|iCp^z?UhMKU$A R^!kG;jF-3^ll2uG`A>IGJIMe5 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test115.ans b/libs/libtpl-1.5/tests/test115.ans new file mode 100755 index 0000000000..0e2897e8ac --- /dev/null +++ b/libs/libtpl-1.5/tests/test115.ans @@ -0,0 +1,40 @@ +hello, world0 +hello, world1 +hello, world2 +hello, world3 +hello, world4 +hello, world5 +hello, world6 +hello, world7 +hello, world8 +hello, world9 +hello, world0, 0 +hello, world1, 1 +hello, world2, 2 +hello, world3, 3 +hello, world4, 4 +hello, world5, 5 +hello, world6, 6 +hello, world7, 7 +hello, world8, 8 +hello, world9, 9 +hello, world0, 0 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +hello, world1, 1 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +hello, world2, 2 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +hello, world3, 3 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +hello, world4, 4 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +hello, world5, 5 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +hello, world6, 6 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +hello, world7, 7 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +hello, world8, 8 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +hello, world9, 9 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/libs/libtpl-1.5/tests/test115.c b/libs/libtpl-1.5/tests/test115.c new file mode 100755 index 0000000000..010d6c09b6 --- /dev/null +++ b/libs/libtpl-1.5/tests/test115.c @@ -0,0 +1,119 @@ +#include +#include +#include + +#include "tpl.h" + +#define COUNT 10 +#define BUF_SIZE 256 +const char *filename = "/tmp/test115.tpl"; + +typedef struct { + char* s; +} s1_t; + + +typedef struct { + char* s; + int i; +} s2_t; + + +typedef struct { + char c[BUF_SIZE]; + char* s; + int i; +} s3_t; + + +const char hw[]="hello, world!"; + +int main () +{ + tpl_node* tn; + s1_t* s1, *S1; + s2_t* s2, *S2; + s3_t* s3, *S3; + int i; + + /* case 1: */ + s1 = (s1_t*)calloc (sizeof (s1_t), COUNT); + for(i=0; i < COUNT; i++) { + s1[i].s = malloc(sizeof(hw)); + memcpy(s1[i].s, hw, sizeof(hw)); + s1[i].s[sizeof(hw)-2]='0'+i; + } + tn = tpl_map ("S(s)#", s1, COUNT); + tpl_pack (tn, 0); + tpl_dump (tn, TPL_FILE, filename); + tpl_free (tn); + for(i=0; i < COUNT; i++) free(s1[i].s); + + S1 = (s1_t*)calloc (sizeof (s1_t), COUNT); + memset(S1, 0xff, sizeof(s1_t)*COUNT); + tn = tpl_map ("S(s)#", S1, COUNT); + tpl_load (tn, TPL_FILE, filename); + tpl_unpack (tn, 0); + tpl_free (tn); + + for(i=0; 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test116.ans b/libs/libtpl-1.5/tests/test116.ans new file mode 100755 index 0000000000..b3a5deb6c6 --- /dev/null +++ b/libs/libtpl-1.5/tests/test116.ans @@ -0,0 +1,4 @@ +1 a +alpha +beta +gamma diff --git a/libs/libtpl-1.5/tests/test116.c b/libs/libtpl-1.5/tests/test116.c new file mode 100755 index 0000000000..35f124bf06 --- /dev/null +++ b/libs/libtpl-1.5/tests/test116.c @@ -0,0 +1,29 @@ +#include +#include "tpl.h" + +#define NUM_STRS 3 + +const char *filename = "/tmp/test116.tpl"; + +int main() { + tpl_node *tn; + int i,d=1,D=-1; + char c='a', C='0'; + char *strs[NUM_STRS] = {"alpha", "beta", "gamma"}; + char *STRS[NUM_STRS] = {"femto", "nano", "centi"}; + + tn = tpl_map("cs#i", &c, strs, NUM_STRS, &d); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,filename); + tpl_free(tn); + + tn = tpl_map("cs#i", &C, STRS, NUM_STRS, &D); + tpl_load(tn,TPL_FILE,filename); + tpl_unpack(tn,0); + tpl_free(tn); + + printf("%d %c\n", D, C); + for(i=0;i4(fLkDhaM}w^6#u5@ifn<^nprS;& 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∨tLsriLSS;-6b`I-|uAQ#5M=)etSbQWD0 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 nie%1n +#include +#include +#include "tpl.h" + +#define NUM_STRS 3 +#define NUM_ELMT 3 +#define STR "apple" +#define SLEN 5 + +const char *filename = "/tmp/test117.tpl"; + +int main() { + tpl_node *tn; + int i,j,d=1,D=-1; + char c='a', C='0'; + char *strs[NUM_STRS]; + char *STRS[NUM_STRS]; + + tn = tpl_map("cA(s#)i", &c, strs, NUM_STRS, &d); + for(i=0; i0) { + for(i=0;imiZ?{8?Em|nGrL(3>hFC&@Bj08 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 +#include +#include "tpl.h" + +#define ILEN 10 +#define KLEN 8 +#define FLEN 5 + +struct st { + char c; + double f[FLEN]; +}; + +const char *filename = "/tmp/test118.tpl"; + +int main() { + tpl_node *tn; + /* some meaningless test data */ + struct st s = {'z', {0.9, 0.8, 0.7, 0.6, 0.5 }}; + int j; + int i[ILEN] = {-1, -2, -3, -4, -5, -6, -7, -8, -9, -10}; + int k[KLEN] = {100, 200, 300, 400, 500, 600, 700, 800}; + char a = '&'; + char b = 'x'; + const char *fmt; + uint32_t num_fxlens, *fxlens; + + tn = tpl_map("cA(i#)S(cf#)A(ci#)", &a, i, ILEN, &s, FLEN, &b, k, KLEN); + tpl_pack(tn,0); + + tpl_pack(tn,1); + for(j=0; j < ILEN; j++) i[j]--; + tpl_pack(tn,1); + for(j=0; j < ILEN; j++) i[j]--; + tpl_pack(tn,1); + + tpl_pack(tn,2); + b++; + for(j=0; j < KLEN; j++) k[j] += 50; + tpl_pack(tn,2); + b++; + for(j=0; j < KLEN; j++) k[j] += 50; + tpl_pack(tn,2); + + tpl_dump(tn,TPL_FILE,filename); + tpl_free(tn); + + /* now peek at the fxlens */ + fmt = tpl_peek(TPL_FILE|TPL_FXLENS, filename, &num_fxlens, &fxlens); + printf("format %s\n", fmt); + printf("num_fxlens %u\n", num_fxlens); + for(j=0; j0) free(fxlens); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test118.out b/libs/libtpl-1.5/tests/test118.out new file mode 100644 index 0000000000..e604dcdc1f --- /dev/null +++ b/libs/libtpl-1.5/tests/test118.out @@ -0,0 +1,5 @@ +format cA(i#)S(cf#)A(ci#) +num_fxlens 3 +fxlens[0] 10 +fxlens[1] 5 +fxlens[2] 8 diff --git a/libs/libtpl-1.5/tests/test119 b/libs/libtpl-1.5/tests/test119 new file mode 100755 index 0000000000000000000000000000000000000000..d5b2d9a94e8b067f7b5945a0cda3613bb5668d8e GIT binary patch literal 127841 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test119.ans b/libs/libtpl-1.5/tests/test119.ans new file mode 100755 index 0000000000..9a477125eb --- /dev/null +++ b/libs/libtpl-1.5/tests/test119.ans @@ -0,0 +1 @@ +size is 1726 diff --git a/libs/libtpl-1.5/tests/test119.c b/libs/libtpl-1.5/tests/test119.c new file mode 100755 index 0000000000..f1e65b7f75 --- /dev/null +++ b/libs/libtpl-1.5/tests/test119.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include "tpl.h" + +const char *filename = "/tmp/test119.tpl"; + +#define NUM 100 + +struct st { + int i; + char c; + double f; + uint16_t v[2]; +}; + + +int main() { + struct st s[NUM], d[NUM]; + tpl_node *tn; + int i; + uint32_t sz=0; + + memset(s, 0, sizeof(s)); /* clear s */ + memset(d, 0, sizeof(d)); /* clear d */ + + /* fill s with random stuff */ + for(i=0; i < NUM; i++) { + s[i].i = i; s[i].c='a'+i; s[i].f = 3.14159 * i; s[i].v[0] = NUM*i; s[i].v[1] = NUM+i; + } + + tn = tpl_map("S(icfv#)#", s, 2, NUM); + tpl_pack(tn,0); + tpl_dump(tn,TPL_GETSIZE,&sz); + tpl_free(tn); + + printf("size is %u\n", sz); + + return 0; +} + diff --git a/libs/libtpl-1.5/tests/test119.out b/libs/libtpl-1.5/tests/test119.out new file mode 100644 index 0000000000..9a477125eb --- /dev/null +++ b/libs/libtpl-1.5/tests/test119.out @@ -0,0 +1 @@ +size is 1726 diff --git a/libs/libtpl-1.5/tests/test12 b/libs/libtpl-1.5/tests/test12 new file mode 100755 index 0000000000000000000000000000000000000000..632091d299993cb7a9d8a4a3073bf25f83d58598 GIT binary patch literal 127639 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%0DW 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 +#include "tpl.h" + +extern tpl_hook_t tpl_hook; + +int main() { + tpl_node *tn; + int i; + + tpl_hook.oops = printf; + + tn = tpl_map("A(i)",&i); + tpl_load(tn,TPL_FILE,"test12.tpl"); + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test12.out b/libs/libtpl-1.5/tests/test12.out new file mode 100644 index 0000000000..c8e233338a --- /dev/null +++ b/libs/libtpl-1.5/tests/test12.out @@ -0,0 +1 @@ +test12.tpl: not a valid tpl file diff --git a/libs/libtpl-1.5/tests/test12.tpl b/libs/libtpl-1.5/tests/test12.tpl new file mode 100755 index 0000000000000000000000000000000000000000..de74a8b2ac248cf9c059776de5301cd644fe0626 GIT binary patch literal 57 WcmXRZ$YHQ#U|?|6$kfav1pojn#T5Dg literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test120 b/libs/libtpl-1.5/tests/test120 new file mode 100755 index 0000000000000000000000000000000000000000..bf27ab7d7d847de87a9287bfae6d5c9a3c491cea GIT binary patch literal 128192 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 VlHrhrR0w97S+H_UR!eZ?e*uswgfIXA literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test120.ans b/libs/libtpl-1.5/tests/test120.ans new file mode 100755 index 0000000000..c527a4660b --- /dev/null +++ b/libs/libtpl-1.5/tests/test120.ans @@ -0,0 +1,12 @@ +testing undersized output buffer... -1 +testing sufficient output buffer... 0 +j is 0 +j is 1 +j is 2 +j is 3 +j is 4 +j is 5 +j is 6 +j is 7 +j is 8 +j is 9 diff --git a/libs/libtpl-1.5/tests/test120.c b/libs/libtpl-1.5/tests/test120.c new file mode 100755 index 0000000000..440f18ab72 --- /dev/null +++ b/libs/libtpl-1.5/tests/test120.c @@ -0,0 +1,24 @@ +#include +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + int i,rc,j; + char toosmall[10]; + char buf[60]; + + tn = tpl_map("A(i)",&i); + for(i=0;i<10;i++) tpl_pack(tn,1); + rc=tpl_dump(tn,TPL_MEM|TPL_PREALLOCD,toosmall,sizeof(toosmall)); + printf("testing undersized output buffer... %d \n", rc); + rc=tpl_dump(tn,TPL_MEM|TPL_PREALLOCD,buf,sizeof(buf)); + printf("testing sufficient output buffer... %d \n", rc); + tpl_free(tn); + + tn = tpl_map("A(i)",&j); + tpl_load(tn,TPL_MEM|TPL_EXCESS_OK,buf,sizeof(buf)); + while (tpl_unpack(tn,1) > 0) printf("j is %d\n", j); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test120.err b/libs/libtpl-1.5/tests/test120.err new file mode 100644 index 0000000000..8d6b3846fd --- /dev/null +++ b/libs/libtpl-1.5/tests/test120.err @@ -0,0 +1 @@ +tpl_dump: buffer too small, need 57 bytes diff --git a/libs/libtpl-1.5/tests/test120.out b/libs/libtpl-1.5/tests/test120.out new file mode 100644 index 0000000000..c527a4660b --- /dev/null +++ b/libs/libtpl-1.5/tests/test120.out @@ -0,0 +1,12 @@ +testing undersized output buffer... -1 +testing sufficient output buffer... 0 +j is 0 +j is 1 +j is 2 +j is 3 +j is 4 +j is 5 +j is 6 +j is 7 +j is 8 +j is 9 diff --git a/libs/libtpl-1.5/tests/test121 b/libs/libtpl-1.5/tests/test121 new file mode 100755 index 0000000000000000000000000000000000000000..52477ccebc9650070ea456e5a4b2e51b24eb503a GIT binary patch literal 128471 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 H6CC*;$&N9L literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test121.ans b/libs/libtpl-1.5/tests/test121.ans new file mode 100755 index 0000000000..6c906999d2 --- /dev/null +++ b/libs/libtpl-1.5/tests/test121.ans @@ -0,0 +1,6 @@ +one +two +three +eins +zwei +drei diff --git a/libs/libtpl-1.5/tests/test121.c b/libs/libtpl-1.5/tests/test121.c new file mode 100755 index 0000000000..f5a9585f91 --- /dev/null +++ b/libs/libtpl-1.5/tests/test121.c @@ -0,0 +1,31 @@ +#include +#include +#include "tpl.h" + +const char *filename = "/tmp/test121.tpl"; +int main() { + char *labels[2][3] = { {"one", "two", "three"}, + {"eins", "zwei", "drei" } }; + char *olabels[2][3] = { {NULL,NULL,NULL }, {NULL,NULL,NULL}}; + int i,j; + + tpl_node *tn; + tn = tpl_map("s##", labels, 2, 3); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,filename); + tpl_free(tn); + + tn = tpl_map("s##", olabels, 2, 3); + tpl_load(tn,TPL_FILE,filename); + tpl_unpack(tn,0); + tpl_free(tn); + + for(i=0;i<2;i++) { + for(j=0;j<3;j++) { + printf("%s\n", olabels[i][j]); + free(olabels[i][j]); + } + } + + return 0; +} diff --git a/libs/libtpl-1.5/tests/test121.out b/libs/libtpl-1.5/tests/test121.out new file mode 100644 index 0000000000..6c906999d2 --- /dev/null +++ b/libs/libtpl-1.5/tests/test121.out @@ -0,0 +1,6 @@ +one +two +three +eins +zwei +drei diff --git a/libs/libtpl-1.5/tests/test122 b/libs/libtpl-1.5/tests/test122 new file mode 100755 index 0000000000000000000000000000000000000000..362df690e6c0c8a64f65aab97b2dc41d56063f06 GIT binary patch literal 127985 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 +#include +#include "tpl.h" +#define LEN 10 + +const char *filename = "/tmp/test124.tpl"; + +typedef struct { + char name[LEN]; +} test_t; +int main() { + test_t t; + char *s; + tpl_node *tn; + + tn = tpl_map("A(S(c#)s)", &t, LEN, &s); + printf("mapped\n"); + + memcpy(t.name,"abcdefghi\0",10); + s="first"; + tpl_pack(tn,1); + + memcpy(t.name,"jklmnopqr\0",10); + s="second"; + tpl_pack(tn,1); + + tpl_dump(tn,TPL_FILE,filename); + tpl_free(tn); + printf("freed\n"); + + tn = tpl_map("A(S(c#)s)", &t, LEN, &s); + tpl_load(tn,TPL_FILE,filename); + while(tpl_unpack(tn,1) > 0) { + printf("%s %s\n", t.name, s); + } + tpl_free(tn); + return 0; +} diff --git a/libs/libtpl-1.5/tests/test124.out b/libs/libtpl-1.5/tests/test124.out new file mode 100644 index 0000000000..121d371ebe --- /dev/null +++ b/libs/libtpl-1.5/tests/test124.out @@ -0,0 +1,4 @@ +mapped +freed +abcdefghi first +jklmnopqr second diff --git a/libs/libtpl-1.5/tests/test13 b/libs/libtpl-1.5/tests/test13 new file mode 100755 index 0000000000000000000000000000000000000000..4657448f1edbc4fc90ce9cc4d768e6a8986ef4b4 GIT binary patch literal 127639 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�u(qArV1P!8LaOO3#KHm4f-4cUo^3 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 +#include "tpl.h" + +extern tpl_hook_t tpl_hook; + +int main() { + tpl_node *tn; + int i; + + tpl_hook.oops = printf; + + tn = tpl_map("A(i)",&i); + tpl_load(tn,TPL_FILE,"test13.tpl"); + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test13.out b/libs/libtpl-1.5/tests/test13.out new file mode 100644 index 0000000000..7ebe6e278b --- /dev/null +++ b/libs/libtpl-1.5/tests/test13.out @@ -0,0 +1 @@ +test13.tpl: not a valid tpl file diff --git a/libs/libtpl-1.5/tests/test13.tpl b/libs/libtpl-1.5/tests/test13.tpl new file mode 100755 index 0000000000000000000000000000000000000000..bf10054303fdaa63bab03d23e666f1582d91897c GIT binary patch literal 57 ucmXRZ$YHQ#U|?|6$kb%u1TsK?5r~<9m>Gy!fS47C*?^cGh&g~5qz(XxL;|}2 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test14 b/libs/libtpl-1.5/tests/test14 new file mode 100755 index 0000000000000000000000000000000000000000..35b04219079fd6e953298ad60c2653f421b5f128 GIT binary patch literal 127639 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
    T@ia%zQWdz@yy<{U|pbAOW`F#Lvgr6ubxEgmpfg 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 W1A>Nw7E<1sWop6FF +#include "tpl.h" + +extern tpl_hook_t tpl_hook; + +int main() { + tpl_node *tn; + int i; + + tpl_hook.oops = printf; + + tn = tpl_map("A(i)",&i); + tpl_load(tn,TPL_FILE,"test14.tpl"); + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test14.out b/libs/libtpl-1.5/tests/test14.out new file mode 100644 index 0000000000..e803c7d9f1 --- /dev/null +++ b/libs/libtpl-1.5/tests/test14.out @@ -0,0 +1 @@ +test14.tpl: not a valid tpl file diff --git a/libs/libtpl-1.5/tests/test14.tpl b/libs/libtpl-1.5/tests/test14.tpl new file mode 100755 index 0000000000000000000000000000000000000000..8dfd4a5148faaf4dea7529835ad5fb0de4b888fd GIT binary patch literal 57 ucmXRZ$YHQ#U|?|6$kb%u1~Nc^5r~<9m>Gy!fS47C*?^cGh&h0m6NmwboC3W7 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test15 b/libs/libtpl-1.5/tests/test15 new file mode 100755 index 0000000000000000000000000000000000000000..40c34881e7404572614c62be0b033c742f55f26c GIT binary patch literal 127639 zcmd4434ByV_CI=WcPDfR$!&x{K$Mm=8Wb=A#6(fMA%WZ48QEdnSeisomPk5)iW2A! za&6+opU#ZqI5W&Djx*x;a}*taB*+qVoDp%u6!L%b^Y+?$UnhM(03ML&K!3X?z>>^fuF40eAcx^WBy!OQ2AMM z0IHAs`5~Yu9j9jC3E<040Dtua@ahx5FF64`cmnu?CxD-E0{G+;z<+-Nc;yM;*PH;} zaRT^~6Tlxm0i4t4$KSD^CIF5%FZY}P{^JwC?>_;2?+M`4q2u+t0vfvd8zZ+nVU1D`G3r^j4K4uo&abc{R zm<7+c62NC>!5y1T{MlLXY`-=?3!ZJ)>$BkG)%mQ*f@gFNl}%ajlO1HF>$2bwT;|i7 z1@E4LYT8{{@cbEy}mDOqH@Hit-wkX>#nKDBr*`m#STc@{~5u z?4VZOj`{bQ9XS>%>59yjSfEF0;F+5CcpmCaYny3xY~ieyx2IN2(6r7zb;iIdO-ll= zt+ybNB7XwMwDzX%sL{0M_EmeCe+BGAmwe^zmv3urZ7u&eY(0OKX}x2{-#ajIYPh5Q zz%2C9v30gcIyS)PrS1T+FIrnSFNeZTGl$Wxn(;%0rnP^$>&k7L!HH1RFRpB3ReGN> zu!*qEEIIgF54nMFT2Go=KfK7)cbV2s^Z6rxh}WU?jRVTc!rQ4%0|8e1iF^fSRqLOa%}>`v4@MvtUo0_~E9z!&cD1TY40U+oR+SURb2 z;E}>gRtjn*RjMP_o_=Iv8~8V5KZpYCKXEC^H_J8W_2* z3V)a}Ldppl0mukI%E4q=P0OgVn#wO5##A?_jddfzVFVo|nlbzuWNz^wW1hb-;58D@ zU~!t(r|F_btOffCl#GE1GKt|%4fx4UG7>0GKOeF>%G*J2MM1b_yf?#mjdj4j2r5
    U0 z|EU|lPN$O<@wCTC1i)83o&PuRt;L=(lc#LD+OMS!ABKke(I>0{^!o+QsMSfQcdwYH z-vCKY!ClO$K09v>SAJ})eIDFIEKi`#2b$@kI$)q>*xDHeFak%$1_QL>`Sn(s}$2ezefn|}+o?fIf3OuyN(Fc7rUC@R^~N!}yunwk8Qu<()O?*bc$zj`~ng=$uT z{<{aMmr%kp!EUM%y+y3|;hNeSr3_!NQk{RTYfYY?T7WK64?F1J%me!PF7(ze^tC`9 zL*!c=E)+)(v;oSKE`4WKkSlfu5OMRAx4R9GhT9tF`!{9?Rddo=gW`nq3!^ zbj)P6&y3a-o5_hjGybG*Rz7c96Me?ocPXLdd@mX|ZtJ2Su|BA=K1vr20Qnji-R1`H zZNfq`I_(A^;)vp|b)WJ3k>vT|wD0FKg( zP1VKbU8cUxepl2WstM9mX!Z-T9GVffgntTKFJTHy>mQs2(@akAMJ%}INV2{-;;#2M zAB;ufM{ zEeh0+mZ5q?Z?8PuxIb)d?`$@cmmUZsscR;ISG)H0O^SV`m7y4Xqh+IW9l!3D?c&f zX-r(#cq!e@=rMhih=Ul%l+p;|3q(WqmK=-)`j;}$6t==h%tyuq?J`r}5!Scc_mig7 zn@ftDpEhozIWxg}4FWd7|4+lvh@@uiT>ZWV1vb8FB1+XU}Co#gPX$cIGqiuN5J{j$> zuHz{kPFz1s>7l+7GBwsv6zI^jUSgl`(B@!#bkA@f~4fd`d~wk@yz-K44;KKKsWYLi?OC&NCy) zRWQz+xLBaLCb`5PPA(}9$G`I$Yj1{Kc-#%PMF5D9DRtey(rHAd&5KcUu-dH~%`>1d z#v|44jo%v0a{=Ax3MIQW<~BX+3t8Qg(>#NDdnz`)>Cs$#&@N%T3 zK~L>DAQ|OmCA9TDSHwDC4oTHS-;3z`7$UA|XGL;C1=esGW9@+`Bd!_H5~PK0rdP$* zAf96md9|~bTu0&fPN6S}&ruml=8iqTsyq#z%3}LBBea5|Zl9U8WYI|KL&(^2ux$e@ zw`uhbq#pPbmF1hvp=gTk|a0X3l>fIa_a zOk_Gz`Js_`2hh&-!Y;SOB%ekXpOMOgu}i_D^(6Fl?%B{}PfzaFMpRVlbPrFG<^vGADwyKQjkV+Ge!68GmW} zXUu)c+>e+;Op>;nnL|91wr@m^@yE2V^__5hU()fxs}D@NttVH%qhqPAKFn_;u@I7v z?;8|9G{{K&7I{;8s@NdJM{Y3QpDt<`ydr~T-M=_e5Qfzj3*rgVVZ%06~0|Cj4E1w6t;JkS}+9pRf zA2bplLhz=w$4mx;@R#)CM)Mw3bh3v?a`5>8rPhLO+YwBb*mH%_FLwS? z#U)wxuH`Zh1JYzJEuPnMnaO3Cr-P<73X74eRjj9^CqOkvpfnrGb7p6Mxh^vCO6L## z*>UMbN5`diK?kJ2IZ<4CzR))(E``3ZKRKnIKw}fM3MU8IJ5RN)fmelaw#qsSrow~J z)l8Pf^0CR|0az|X8PPk#P)U0(q}3Hqgp;EJA|SP1V{PgqPKUM49s?|nw<=kU!1Uv4 z9Hp7|83NeES&vv>rS^T8PPdr4mCqjIU+c?yW4n#+A{I^|4oCEFQnz6iNH!GTp;w*1 zsMu(E5A?Z-s%bvh__q%F4=j{zp3Ya*d?dT#Se${Bw__l&fnuwQ&C1@?1t4ffr)l8I z*yMSMA+LECM+Vbqfpn{*2z?5lL^ zT2EbvJ67MXedjpWLezYIK&XvB%L1N}|zX-Yd!$*kv$-u(9rr8gqfjV+gf@bbMPz}4mlH95~_ zath+n2E?NmV?VPM` zP%>C%R&Hy2$F%;=xcZJReW2Ak#u_(?Nn#wFggVTIiq%SE72g3pdym?gENi?VqVKma zq;4twR(8tzFm)G9Hl!xbx7Ga8j2WB86-T1`Kq9s+g2PzM!c~xO=Oa?@E`i=5(t+wd zy=uHoy&)X?v()^Q)Vms}&W};2e<64s=T(?xQ%{-#_R`4oHRAR z*Z4?BHOD1LbiSCG4>LIyhH|XfGeJZ~;##(gf1+pP={2JiWRHIc74M(w>>48O8dpmMT3B zcYJu@S6>^OwwiZ^_4bI>F8A?f^kA~bm+ZQ8E9Jps#&5BcPR{au-;Zt0@?-BIFO&}x z9vhMwZfJ)a?rmKde#jt zELIG2#vM4XG9Zjd7p((6>(fOyi`=zvCLbG#pNaat>7x07!u^_7r?OOtBjBjYVG3{b zftwD-^-0gCBtAe;94+XK^GSD>0wK{sOEo>3Ub$=KuFn5DTAx$rGek>{gF}RWUIBfl zwWL3D@NV?kmv`C8s^rPl5O|rHyfz4NrHi&r!63ll1p)`%;be9bVRC`lCn>n~W_i0^ zPWp~>T>ZXujzj4jx9>;IvCeUT&~ZA#D?!mNKrz+%9vz{X95w==)J>q#oT`39Nu7|pH7 zS0N<4A!(w>5z zjEuyHR&VD-9Th|;NFCd+b}X%38UIlQ^Z>kh<8Rc2mXNGCLN*e2;V~p+QyT6V?`318 zKBl3L@nSkr_OpysjHx+|Tp1xX*3H3CM=k|wBo5`m?yU?|=|&<46nPYHno&JIMjTOf zLl0G9;|Kr5L6*ScgAmh5Tm)1cI+VhBR+!N~W^%mOJPUHon8xYF`jahV3*%3AGr~{C z_Z`AHmmBqAYrGc$TU8rbP8Us?sKzrMTI3S?Nd`fBd@x>t1FgrqtA4nETQI#i8pPwH zk0ULMV5+BMsj#@TEMnDHIKwlxH0o4`=4n_`RmpjQq18C8Y`$Eqw~R(5XZljlzKywQ zS)r$kp1Bl^2%WZIEs|ql)@H(Lylx~6az!0X{gT+6WwT`>lzngN%6G6;83MA-{t(ku z3Pzg`U~dOG4o&ug(~lo6gUm{e_%fXISi4O3IA8opuhk2#7z2T3RB`bk4TwdEwK~y0 z8FK^s7i>BbH4=Zw!)j_evH(vDWUdi=Mwz?DNSHFW46!?81-!74&@ns6O*0ZF%Us=K zTxv#j1dp`v=kQyF5ktSQOTG{sD;;b5ftr(@Mq)fjR$(Ni_zOb5|5nl9`yE|#rb1|% zRcIt0LQAD(kAh)G%gpH1K#*EqWk!dJz~}s-Lhr)HrT+}!xFuWXUP43a+!k^{&y03K zc;$Gi8yqx!voYbzqqR^v=v?KXj~JVFX6a!SL|r8wA3a;6hD+46 z_4zp5hQ4!pR{$vDrW$KG;?a+5tYsPHvu8s|9r;3P0i1s{@56=|qAsPRUqoI>dYaQM zB<;fBlD+{}#&Sa7H2hr%}*?9c_xRGGK~6#vr($yB2o6SlkYB z8*OO1=v3J?f>a~%1av{TiHOyR@l*>16^{=X8q#QNltghdHVum!fuA)Wf7c*xl*no; z{`4hT!kG**QZ~o>OO&M{SH3c1s8(YLHP%;hMT?c(`NP)u!oX0f@KBuUzJYU0BydGmYrvG$vYr;=UGe@XehFrEyiE8a1mHQVda(p$u7do;Jic5 zQ=(qB6GR=u()kR}JER6DE(HQ+x}tnHSsIeWVO&+9!npHEob4?X7NXe;YgA*UA}zlQ zG@)ByisxDpSnrv9Y`vn!+EH!2Tx0DETYJOSi=F4!wOYHv?g_MRA**k)wE5$kL!tP$ zc~#cC%dZS0L>p%f-GGy^Dr3`^*k|hKS}QS{FG5G5WM8QC(l#)N8weA?{3`j|=bL*-2zVEQ#j17-}-7PjG{pz(>P zynrq%mig|?_rP=q5$=49)38?9;1bBtNHFAN5HJ&xL=5t=lx61vhYvAtv7T@)rP#fk z9}5gM5*JXTlBPxbR_GX2z%{D&g|}-QthHkbd%lC|qHiatkwH<6#7;B|M|%el0$Lp^PysFiS$t3Db~}~- z8V@|?VbfXpg^~CxhbkkH#ydkvpd?Kn`;336%Z6t3fU&8!*x`xY`XsNtP;3cgJZDCs zBvsbS94(&QPXdAKvE2#?jzQrI!R2&vNetL4(+YvpwU9+pVwWET-izdI$*VlK5Pqrg zREZB;4K&FOad2GVrF~F=a|DyGn|_+~s-%fnX+_z%mRNy?SP30hVV!%;t?#?iMK5An zMdw@T?7c=JDOLm|gR3ke8nVnXwo?okd zS@an^-Ak@t--J$}Eb(>^5LcyaH!wj@ohc3j+hRj&4|di^(08;ErYrN>&x$11nWA|}%2$+yr) zwuj_2`?s>a<4nDF1&+G8AMY|Uoe$TwGJat2U=I?OMiYL?TI92@mSxg|f6(kHlAap( zIn`7cM6&j<&jg>?H0e7v?V*drrYn&Y&?-&q+EIPzLY2oz+<>aC^CP(di+_lt)DDk* z73;(}Xx~kK&EAYTg?as#{n6(I{pFtWK$gPA-N81c! z1tA+D4vt`=-HAGxTaZm@GO<2#Ah;KUGIbs+DCDzS@$ibW$){}21uaLAPNZP}ld1~* zDmF4h48ys{!N$f&TtPdKoKY%5qeyaWMa#smnwH`z@`)w@C z^4+#ycq-`Q{}=ZGaYxPz2E^4xq{qDlxcw7wsqO&cMCE(uDe{yq{?UBi{R@gMFGGxp zys|ix2hmA9V~3M}$qi4M92l~`#IcdlT!dl`Jgr}z8yB@^4(Z|{KRgyhc)auC`fLB= zc`2O>5f8(5bPvaYQo7iak{{Sxo8^a8rLVJ`hin|GcJ&2K~- z`&F0&3CB2Gv2ZB9-y_BmyDU;!4_i|2#eLCfiDS;?2jN@aX~NR zExf?zsg>706=O+Rf({roT71?0lfEHFde_^_1Tb`(uFHE&`|O zGAx!V*ZNNYMx(vJ6?fSIYpW0wuB23p#`a`zmN~DszMBGHkb=lfm?S?YjW^xfMfpx~ z&zm>kH?wT54?HE(s=x~C5HG;*LUC|Az9OjGgS125O-D|ehHWE@?l{2*FI^lp3+i>iz81T8KNAkoopXi|Ms? zMv|jO#J@fpi1o%Ti_m|(9mh`3kO0&<7)cJonJwCDJUx-Oym6WY(S_q_T=C)6hwLjp zdsDalL*AURP=o6=*SeF}da5iN{m+&ou9EkoX7d(L6gNqt>!#usKJN9*A!IHfa{-xy zTVJz<^~3Eij@VBojOJhA+ibZ6mwHB>kK2%@^$Z?l%5`l#f;<04^OwZnH9f0GfS%OE zGhK7YYs^;gLF*8-c!eb#PKD3&JC7>-;*q_X?13lwNl1sMuYS|QqthONl>IECy=E+D z)~>|JxYjGc!~c*gQ$Jwh7L3n`{|hCahw$pk*=F(yp%8p5Hpomq9N2)`)LS4WoY54x z9$>T**bhKqJ`f*JKeJBh8NVxypwFa6FvZx*UymfO@!FkO;li$tk(Yp;)N!C6);r8f z*wtM|^M1MxM}YP$EXS_>e^5L>eUGO;Ly6Y%u;7PJyQjnN0p5HFZ1VarRXYNHHy{;v zy&?1j@)!gz0AaicTfUMq$FffseNy3<-oS&)3782Q1Ka=yH6D&vRa+N|^YKsJnAL$z zg3dJYq}9SnAbel^Q@s&Nzc65iJ37ELo{WDf=NbK#lH)tUv9U#uADYtW6Z=oZ+p-+{ zB7Uee_G$dkkl2TuM+6y|#Hr6v$SC2~=9YDMJeqn4kSaV@25)cxV6t+Tv1Tv_Y(1CS z|1<^A)()FuG{206BTnjn&=UI}JTY-W(-PwTT`W)!^`?MJ(NK%O?J|ep`8_Xr7vr8E zjul@L1CAdlGvawromT5J(=BH-zSBFV0TDdb>X~>Dg32*Vjf4+&fl+P8K?A%nBt6n3DXiIaUIg~*P%MR&UO}q zFMW^H+%*T#xoN!yE6RuLUt{c;p4j1aT>1oYb>VrPE_~dPZV-;4w{&4)~SwO+2Zu zVw_ltFiNoCWi&l2%ofCEFtRJ`pJ2b^;6+$*9V#FSdyF_fsN#%u{<*xpYrhbQ${k~s z^^H9e;@S+3v`%|7CRgixCv^%|i@3!WQ^$l8J(P^EJwjB`uGF@~Y zFonHK7foO`V=c;w3}dKu-nyAypfkQ1E<&@f$9mjMr)Doy@n^$~(Uk_29Y{u8aYA(LM|ggt6ul&V(2DjUvOeDwq>{ zlCx#xX~1o$63`hCjdcXO#+`^A(nZtRBr~udp-Ftd-Zo!JpaQjUQNb>Z(ZIk)q3u1i z7U#Q1wfD2jyHw+EMrOq4JqqhH9H_MEbJ_h@z~Q?q8Cz(72@*mz>`!6Av-X3$bC~Rg z=dYui4~h$nv1;!A5LfcqLd+jOqQ}k`$Ksv&w0ltS%9mq9RDI)tw&GgJauj_E0!qJd zZ-@5`c^e0G_TW)xV?Lu*lvx#jD&6@y>ND{YZbE$nW-5|K^V5wN;F=rmtH&ncEJW}z z6nx;`E3`xM(#!D&f*+VO;Y0<`jUTlckOIZ{+z7>!-3GOg`vL1nQWrbhv9O>`&$@6@ z9ltQg0`+MC)Ff{%?d%J_GW**5K?7wRQ{$RWI<`C<#iO_$>K@dd%)S<ke5k*fyaDferLnI~jxeo5!hb{&`P6$e50j6&3l*;HXnYIrMWDmR zA4z$N_ZTX&T(#0~K2G2zDB<6}!m7+D6~Z|6TGXy`s00hOshE7izY^txhL#^BzYWqVUE%K0kj_Hec|MEKi(yDd2nv% zw|4{BWj{b8HkOUWLnv%fU~sDGdf~MzBwt}`0=9aKz?h_MT0nBn(bdB!+23-I#<`7O zELrr0M=^f(8Sa?iCs+1#_ATZ)l$=pa@AGln z<1h1zrz?;SLP3lmYa$UPiPwA)eW*!N?eKja=4&)ej5;Oub#t}Bf98*4wIR$yo? zlR##d(23VG^OAj^4Qh`2%pen{8^={mW7B!&S9`_$nb9(FuT95IujnZG_yPCY!p5du z&fPYyl09}5?Xf=b*i2k!dT+Rr9$rU-^o+z12#vEL;*C#nGcaXs#V+n`(JY9ic~QEk z4UL3?CoAmlBt0SIj0^Y!5QMNf5n@K{1`G-Pnk@~bxc}@c|2S37!7u`*%(2_6Fz^i4 zUx~E?Lquz-+O3~`Vmo=dv_Rg^zXc&A>e|T*XU8??Y4Vx8yprY&I)R?TU+X0ka=c4O~ z^|tDru@rtrU{0p@M_)d+_ssf^f8dKnkLkXvcQM+h_n@^HZETY4?x#4a$7a;pyM+Qm zR|jz&RSq7x72!hC-!)IF&E59S@KC$pZj{P*gQxNVE4T@0b> z%@%o#!FSeYGsv9J_!p0D6M-h6@nB;eQp~0}!sl$7Y&g+K%!Dh5r`<-P19KHm>#;LM zX!Rf>4ZH^qZr}`8Z)a!U_lMY|Vx#Kgc6DhniTi;T;vEX<|EVx#+=fLzAMzS@7JQ<( zGj%$KRlXY@FuY5DL2Q^k?E0H-t30@9{`dGH%~+og$YzkyVr$~xc#Y;$5ON^uFN?ts zGL%>uD6cn~-;mi63ytRIkv)hPT6Av7Mpaq!@J`VX?jHQyJ;=AUj{8m#@%?7B7kIcoHvn^1?gD8Z719!@OZ# z;T2g94)?w=+(>jbPz#2kj~e|8{GODNXKZj@UA2i_7qp|KZ z@>z-9d&v0ljtK8}M**op$G7|(nd-#HVk(S8KK!tSh@Mw=ePBJwH`8IUg)@Th45eS9 z04|3+@)r;4y{XTzWHR&J>;sQ>AM~T#bbtidh7&&@V^i=RfD_jFKt|wS z4<@KqqVm@fxUN$Tk8-)<@rIG$T|M!G5U(JE1-uarQlF#y>;)VabNhQ#$)$X&h$XbP z*|qcw>7s^AO+B}#@@eVK0P>A9dm%X=HjpjRHAowx>{lvj-xCVYd8Xeq*jm+IZ<IOM$TzleYU*)P`amO<>z`T$#Yr>k)gzCpQD zG{pLaq32UD`zkTHO~401wXPZTh=W#~XNq?~U{tw-u&M%ndl-c$_rV;DV8D7S{yyH6 z{{TNjfZZ!>7&87;V!L2Au~2x4!$#sy$h18$S5Drt5=SjK9h{di3@vs@U-9Bg>K51$ zShr?B7`EO5ZS;^DAt^RL3_?PbkMRy~hsIYNX@L%o78$U9mPn%nD6xwoyR}bS5_qgvfy*o(k<4^GW48etP zef(VttTDXLbe!L3;8C0iEsy?v1~p$@uPAME}cwJ+Jr z!i5gZD4*JUW4Jq2jhFfHzv;%g*E&dZBKk62>n6I^;l32d*fPaqy05?)Bxc)wAJ#_l zjbC)&^Wv8PPz0^5tKZhJMEJ^m^IySI^V6})@~55iH8*xZ9?XT+fg8#gEQWBt+cd_$ zg$-`y^NoA$TS+@}{~#&w1u`%%Om|`KM`Qa+Ad7iWeAJ+fcbmkX7B7xthq%?$pW^RH z@Gz45FLh90m&kG$mm^BU_=P85>eo;>dnWt<^%G1_g&yI3S!*X}VCyIN1%OcjYo~b2 z_!GWmjMKnaz$Iqk*b!y(`9C(DTxP%hZ|EVS@JO2I=&SeHJZvUj1-CC|36=gKAN_QTEcR(|=@_Gdt8 z+pa2}8R)Fl4KT{qTWxz)#a}WNx1d5=`I~6BcPSI!nn9=oIDY6b4(yG@Ca6IC(ATl$ zZGTjR<^zxSL10hRd$V;92?dSK<*PyW{RMM)%&S4NHv?q(DD^r;Xkey8o>#U_QDAQd z{1(BtDe%8e^=qBCr0#xD#-YRBMmaSUJ!c(3zhvKl#ng64jc5x{Y@QQC=yH8!et(1; zS@@6mM=PA$FEHvmAoA*@fouObAH|yz?ZS3-9gm(C|3;6Ekw=m}gx>Nz@`bGPQOMgl zAq}B(M8HGQecJBOFtN}}c|IzvbL<72jlzuj8T(#^o?yn~hjQ42{sWQ+Hv%D&TwL1O zPxO~Lr*wn5IHz2M1AvcXSA>uH{h5uhZ{cJOu69m?k-ttHQHp1F*WrlrVcOi}b>2wj zC%pF1)3gp`(%hBN-2J;B-2yT%8NCC3`1=L?S&63+PIzl{yg`cNk!mlF2F2^uVPzJB zh{rQOFY@4H$}GmjG*yFzKD3MSG84=qDEu3<$l7qrbdUHs0AUt4!KPH>)n4%iI^y+J zCH6hS%utxsc#C*Dj;(s&$8&bz=&u$>e>bC6j=c}Yjx8C-ekO;FvB$)Zjg6#55R$+z zj>W{Ujg26voIALK+kG+h45=()eU6Jqlmqr3xOWb6!i&S7LFqFIrzg}b9b}!6Il{x~%yZGVgu8e-*+ztKU7;%poeLd{H5=Sq4 zQ)i$f>Yvl53TE~bJlNa${E_B^H;)YAxUYP7O%xA~_k{2u9Z&9i^k3)c&j;z%>%2S- ztbBRZ{%i{9lF|#zM5 z5O}@c&j)Jqw5`~91eeYbaU`BL5@z!^VYaPMrybAJ4) z3-1eH3g+Q}0XaV($d>X%p$x{b!Z|Pe96#{MXKdo37i7TSRSuOd7^1~$8)D_>43E_> z)E4*`H24S4>#hxM&`_Rr^_12{@NAM+S+*y{zY?E`0<0( zSI6dyMoSuF{v~yO`~vlorPoW$`lYpX3s(3SEM7Ke;R4Vdx1@35yv1h#4?i{SuLD^S zm4q`@{6XrYtHz7|{jnu}{up+qMdRXz#`^jtOJlY3{B=u~E<&^D{5ebKL}Rr}yKDII z>)NG@=YU)Oel=L|b3_fbOTlq>EsLc1DQw9@HpM0N{84TH;AnSEj-UP4&so|)mH~5q zulp$Jh~Mc}5I`S`wKG%l{kC_`n(j)+Pl>+pb|LznB}JgPx#0aObx|AIwxuCDb%(WABV zY8(93m-0PMe28B+&sjoq=1M)Cd%b^7eZ4=5Ut^yuB&#i6vUphik_JruvRXfWQGKcS zF?WA-N#o*}m|{Uq)1pfj#}-`OxTLYcUy@mYQ1^LJ=)yez!Uc;K#MraYrSrtx2~}ZN za)CgAlmrUkO)?4mqs1W`VwKEV(r^PcnCvZG0_iVCH*Calk??u`xs7#ounw^$OZ=Fs zg$sxJ7sD)2cjjIXqoR74Ix#Y9{LD!852pC%ES~3Qu_`n*G_kt+691ycSR)!<&+#m5 zY=8v1RP884Ini<%4MIari2b|uy`1Sp3xoD+QXK{FZJZkddVS>5E^^Ke`;=yG8M@2byr7PQ< zu>@K3F7zGi_j_|kIdC=on{|VK8lWMjw4QoS*}$lC_Wg5f(XdwL7sMKB7uKmcCf#E{ zyLtr$DAoJ;=|%-_Rq6Z_;GL+wrtmixN%{v)koxJuJ??1s$RPWIJ-=@AZjz4~f{;tuo zzP;l3X}yBaR;hUcyc4z8&XsgGR?Bp@dHi(#1PMPdUZxXOdLsN|;d>PQ`f0L#>5Sv2 z8>UNmnMzat0smM!8x;P;%Oss&UUB^NFPBUB1eL!3AMlT*bECr7j`=KAW~s1R_QdAUW1hT-DN5*LCVj9#%M!bc-l3DXMaLdN&`d2 zW@-hxezN=gJwWP@zmI;APV=`9X8#iZ90SUcU*Tv3zeCFVzuQ^Ht0=v5Kp*!v<{`ZT+xhiK2fUe1zrl2GIz1{^)9%3=MG2&D;D_qo zL;9zG0p1Nav_AvCNPDZn>o-i+^c6n+4d^voENs4ioeZ(Z$Jw8KHYU!A?K2x2>xRD ztALz^LX0i+{m4~aSbUp%Y@xr!Gq$jFeNI(j+1lJtVMV-Kq_8REeopURSTU}!EL2zu zoUw()Xfw9Z8_oxv0RFb)FZG*rnlIUF7sowo-IEF*)YrRQ%exnP#}iBT`w`N8zfGra zBA)0Mv~F`(XZj6g`mHLQ=z18v0&=`wAxDrH13EtF10Rb?dR^nF<~RhsDvqP7ut|4a zdR&5LzB|GJj{ja))nI)kNdFG~Jhd^Mev<<3;=4;;*?hO^?jMlc_c^~fUkvGZ{oITO z-xn}N$2kt5-%{u~UjSnNEu63Q?ogqBt*5H6G|u^QUDds?6p)ZJJ5^nBpNDpbaK`oK z(Q-c?|0d-A8!!Wk$H;v`7d@VDufuw~Uh(rImzc*cdP0AM+#`iSck%Jn#}ovq#~!TH z%~-crAn$y5z%>AH4G%j)s-N|)s>0&69CzH~dZ2q@G1f#xX&Ci70(}2}r_=ZI1oPj| z)5V1cboYJ7pC_T$Tu1kSUemU8`cCBKI$D3!I--5i@K9_v?89;U>sm)ug&TDD?~gAC zu|mi{?UWBMZ~UH%^@RM7qdre4+~9I=a2;3A#!;{V{9OTh_0MCyA+J>x`dl-y9;@>UYol-y<@7ChE&HW>nYo^dm zuBWNM+XFlNP{2W>4l<;$xE67CaF1}$a6r+y*7Ats> zN}YsDlOO-`*&=mhu|Z`hCw}0v#iy@Iz1@N$=fL;m%Cf_EnZnCcsnb7>%Efp#D*Uu6 zJ90gs$_rJ!YX1Lv;`}?W$9D9-n%9FW&Fvl(D1B6Vx=Kf@bi7KZtF%s~%T&5nr9V;W zA5{8?N_VRCWtG0K(t|3^%~$=a^mLVuR_S<^PFHE2N|&j0txA8Q(qqSaqVlc+*{}2O zUYerz#*I7AUy6S%c8Gt}@NJn_>YV6BZ4-OJNirFp91}s z_?qfq_T;1SoKinvD*F1B&?Y^Kn(G|3a|4Ce6_5>F3RH1lSWa)ByN%%e0tg{n9+FGUlwy&(q6A`^|dZAQ(~47{R@}q+QRO!1@dI zzaw#%Y}d8!VKVfaZd=fx*t3x$@fuJE&wWxln)glAc>XAbaJlpO))giUzsf z4S?oTK{&1+w<1F*)k8pEcc8rheH(=W;=1}EmvhO#@Ledy3ney)>(g8lSr;h)q)-g* z6xMN6n(H}moKsVpsk(qw6qu@?j%>~kOh9|;Q=K}^#YLEN=_~=}ZqcBQ`m}DVk(A|3 z`UgPX-(%!ClbMAsdrxJHDKChU*UNWubEdv3N48KkmgM155&1j{9cGv z%b7uDT_vR$@%w0*>vf?v*UNF_ddYIGm(01?ea=iW)Q!f$%(-l}2b`Qm8kb8sYu-n0XgSNS@NBc#<6xiv%(4eI>bA@V~aJt8*^M8MGG|DE7-by zVV|waLjDq!2fm^lYEuT8++fnn}-93e%Fac099tIqq9T_EAvC zStk&_giLd870`Q$n-oysYdPzuuo?YKP7AZj&$tdi<#O&M1PkU9_VrtV`6E)@D6%xA zIgg0!1a|NkvpL?AK})$O*P}qmU6cmA+qod<>$YM#YQ0~8iEcN%0Weqhuk%p4u{$cT zrpUlmK+PkWMfmIf5?h0A0}A=BAEGC3=_=&&euOXn2@K#gU?Pk2H2%bfH-r!}PZJ|X z4@c0*DS5niiMkI&?_TeX>`ap-n7i4eUl#+79PfU7_aGmxnfU5n_9ech$Ibtam*<4X z%|F74!#E0hBF%T}MQl*wE#T72_o$+;fF3tLM-__;=yCINRncESkDK336-x`~ar3>Z zSXK~bZJsJt6wu@5cUQ$=0X=Sh4^=b^=yCH4RB>VfJ#K!XD$XpR$IbWYN5H>{DH+&_4!EXaSP~i^9Sln zM0t%~K#!a6*Smu@J#GO#Zhk=TFUsrm0(#v1Vfr%yzf~`w$ITzDb1K{=cj*Q6xcTR* z@&>(t9yh;2l{e}I^tkzzs{Ei{K#!Y$o<2;p->etV@5Jj z9>H~@G{E}`Nc9NaAxeJl8nzoJ84P$&BWAViq0~DVefPLnPF6P(Ay8jvB%}ZFf3PziS>xm6|ywbnunr&rgKaVAxT3$t3_7VwUJ3d^GSqH4%0cMy?ih)QIJ*mVb-j>603T*|Pc@CuI62|Eg}lqFv;h8=}hNlY1b6wZ=;%dn$x zHVHamN8ubTTv-|g8EaD!Gj zpYu-Z?IK>`f{)mwHx$rUxX=Wo*Mdb?YlVxXY1De*qJ&nsSh9>ZL@Zn~5O}Uu&?#Jc z6|zz#Rv_0kw<4!?YX?%Xe$yt@d3%6G{btFxCITyc6)PyGD%PnI7c7an*jR63w%eT; zU#TANi9|?I7r)7Xndg}FW+_B(ueozIeeHQba+UbJyD>7SRNO1txKz_``9REzU+dNv zRDF7qxRRCivKc%ImXY2n$L|Fz?9;{m^>yv!iY@g!3GFrn(kRw{x*qvnb@Md+E=LK* zk@KI)&b;0qvUIoP5q^uU^q)^BfnOjS)PH#hdGDPR!LJ+&+u3FVD=3}|S^72m!N7Xe zEsAOSZzPAM-g@|C{kJt@U}fIRIOyL>Diz@VuVk6s=)e0Zd%O}W-K*bwHX8McYWhau zGnE+clg&JE?4CTd>s_qBvH*zQ9cZNQkps}YDR%fOE6Ca;vi6!YxE$}>V8C?+W%&AN zpcJiT+dQ{Ue4Rf~-vSStd)zRQ^tLoTw|Y+A0A%oY%$ ze5Z+#Pyi~&F-;R=>enJ05Vg3Csy02B_M|T@n?6IZTs(uE$vg!!Qwm0K^+Pez;yuJr z`F>e>Aq@!^(zr}W10$wk~M3dqs);+HfFNM_gi`)`%2N5y+i=>v$!D_q6EtGoEKJ zc$cnED3CKX-bDp1K1>l#aB;}RRUC*Z^ZeNYJuGm@qs$c}gx2(n6-HN{IwzrhX;Lq7 zvCotHHpHM2wJxD9TG4!}aX%%dCFBBP>Ld$PY#w3|BN3WoQh~qA@&+hRWXyv7=QNPi2x`(Rj*z zza*#MNpg_>eh*D8rTo5Vq7@aPSG~6q<}*O+C)B66P@jIn4as~TPDpR51gBV>?8RQ) zIS+LXX8#Cj=uL*EohsbJVzI*C1+eG9IrW;p#LLZ=`}WN@`JW?&dM|O^x9_^?w1*3V zK!ce_G!_PMkUov@K{#RX&Ksmpa(}K*8>CNWTdicLLcUfa=DAOqEn5Sft+ar{P#MU9 zlq)Z-;_Fs45dmjZ8~kgI{TrbT4t{;1By=|T)DHmnbTN=`IRCua(DMwA<6Ak5jW-AI zOb1Nk?Gw?@RLSKe_w5^RMyN29irwiI9XN#RPm&FuVh7`UQBtr5ox(iw5$dT|H?YW> zX)H#u!aKc_QG6K1A!0&0g^B$b<$<^ltLYzkXQJM7dwbieGZ{Dmz@>6JRQgO@^>oVo zNrp3*LJK|?z4eDpIO`4&QDy$~HD~<|>Z!_qVwwN!h5m^!eT>QdA>x1Pr9JW7{$Sgx zp}Vn);)Wd4{VLVZ%nM+1JM1IW4cmvW;m2Z}eF)HZLGWxBOz7F@w5$g*ns(ZwN}!7& z(1{>|$;-X{Pi?F2^k8mtZeQ27Dwo>OUGwALmQej&E$~p=idyZokqUe}NZjUBsfOO0 zG_OD4^`EYlysOZDBYSZz!`m-u1ugL~^ZvHla_>^3r zsy^wWHKI|$9s(O9exeHPD3t$36>vs&`blDld2WA();p@UQda3ftt7Xn?5IY9T-cfp_ zs%B?e6)62aB&#UZl1c^Z)k_VwtN%+?)$s3Cjl5b_K?AZlhN+GKH^<9uLXLL|zQw+I z0f3`;^phT_ofF~0eqKft&Vp;{B?mT{8a@C|Act_D4lFK}hXFiw5uD8PxvZjh^uJ0X zyL0InU{h`$O;7Vn#giW$>96MUV$Zp^0sa~qoVx}YAC`RJ&kE~RObxi#%W1`yAv?*n z91TzVv8w+T^@Blz25Kd~r|M=&GX!iYUaqtN@(M`3g;5^F=9+Msf)8o{jiJFiw>#QV@S=*Cbb}&)bcD+ z6>GaliTUKO5%Z%s!c1~sQOUTtRiPFXNtE%lq9^r%fXATrF8rN00$;g@`TeW2O?>ad z-`P{}HI&w57BX|0S%A!4%<#_psfee}UXM(O8IqaD%>|&+~nQoZMk~bA2 z&p;yt(@#1J;QTqgC2#uMvd(k+W?G1~3jC#nx>i9MHYnI21zT1+hKzGzXcsVS_Nj4} z^^-I&MBjS4FUC6rwdL?Z=U#x!XUy_wdoIM+va;(9# z7b4Td%nD>`u}aQfgUkcW+=k2!uyyv`$n@@m%pZ`sl9`8)xdRzt-;;eLXaB8Iy(!lN z{<7@*u^7U>KTSfk??pgX_I)({MN?l%Zz4pXug|SIiq?fqfQt4NfQ$AocC{D$OfHt~ zZ&0Z|FZa%)Xbe9VL(uziv7+}jGK!y)X+@IOCJ+#lyw92Bk{zn*8K){U{{dZ%fNIIr zyNZgepTia2P>OXbR{Ko%?GLUR!#ToQ)U$6h>&h zhY|H%xTP^9P5--I#A=67K5GMMw0P)$XX2K|S>w1kZWHy7pe)?GEM9mDs>Sv~mhWa+ z>_}yK#HlEYZToGW8nAZ{%kOrPJB;#~2u*$@HY!&QWCz$lB;2>puhc5JQ}ro5 z?ssaC-D*7tqs4e=d zlpxc=%rIn*AQQ6DYS7r=DM9w7%~k0VtdO%SfitQU(9v8@zgJa32wT6@wHFxY{vGfc zz!>q6s(cEP8_}i;!Y6*K3c|g1S7V}kt>~)?!eJvY;lE=pKPB^(3=X4{qy5EcwyL5N z=ntuIHXD>9fNd!GLe&pfb>32K6kocj>qf}cMi^AliR_#kS>Z9xfv z)lfG3Ts8YjrTQHAl}^*=(BfP+{RWxg$6}sKG9!mm{(=FA!T~Zc*L^>!5M>5X1SdBz zLvp`BCeYoH9wt`I2);!SEveP2YQGEAu5s^ocxrcuc+bXgc;7*EauZ5wMAxa7YgMXW z>pqv0Ltg$0G{MUrX2j5t39M154CfgXaUo7(03l_xMOA;`P`u3jBZp#nnW8wA8B$!1 zOyGs1DDr_k=`zlgV=QS@^8O344VuOVj)2B)wH(0pD)u=rahaIx?dzR?KP8U7Bf#N{n zv(6AcOTY50JHdc{hVW>KQPP8z3NHV~(qioVW$|Au@}zW#heu`Sodc%CA=#ON>AO%K z%2Vb6YWx9}>O(!J`JugIYyo~hx5cp!XxXYlOwzY;V3F1nH$ z5?1YMoW9QS+>5rd)n~P^$KoSem5&A!$2K@>O-@!+u5+l3_M|~gXmA{@g$DnP8S2|x z$OINBRH?y^zTG7BZ5jF&{fngyD)o~c!mv9e08r-5$bTDSj;w>N>Wsz}<#&$&&)35!M$iHMpI6ckCqB1A|4canf6 zBxDiDH9!)gkVKNO2?-{kxF-lM?mZLH{Ga}iXk~w_n3Sg6yhKS@QGyPg8{XS{cXlO~w?$XyuFPz16e%Bdn ziDa-Q>T0md&o#M6x%znr_dAktq5s*1(9N z3}@1ork;=5>nz~Bc zdK>qwaOl&Y`$KmUqu$0<5y$9PrBZL>{v-vxjY|+e=xtnoDd=t7u~N``>h9aP>~y2m zZ>f{+%i_d4q{`i6>iBZ6lYT&`|1d;8*-M)#YVd}y_wfinbLLO=V>Y6mH-cp4fR94t zn;x#YLwP2(Fmc#J69&=^js%UI;ivGq(-gy)C04w3vQhbFI=H;YF_+(`=wSWmR4VgT z>nXbGxYKAP?nxxZQ*~?(Ii1S^qczTv#ERw z4X}HfmiEz96EmmluCLCc+WWb+lnbb==aDJjHjU;_66<2hsoU8LXJ|`9OH)SZsc4EL zrjuZDgDJJ2LxS$+a5CkQ=TceU5;o<@g;XBFMxCjJjVa>R76HWu#@NYboc(@v}ed5x-%)6w91@7@N;ULULt%OiGdTMH`N(4VvG@_L*1Tc zI9l+aVWzT>ja%dPI)UaL3oa=o*_$DouVbbkC#;`F$=>}#vN;`Yk_HD@_BHMTmd)wz zMN05G0rn^-@DNcZG2kS*gutXM@`O%@Td1Vd;j0Wd9hO&+%|`Rq6O87K#O*e?&qMQ- z#4_m_7QtRQ>^#!^a$&ufc;J-}eoXUzCmPxOSgyOm9de>*{t`*knkUW@&8IM6%~ueZ z#1F=3&9_oXYyKJo*1T=DulWZey_2QC=eDwR_W5nZGHD-+V9ozcrS#8)wVHUK`5|MC za&gD=juECZi|6F0?wgRkdJf56O++pG6Dp-YAgsTQlKuP-d4+@Uf=nZOC(C}+9XCSs zUQ^+VRIv;W~%68qXR!-CS#>3%rYi>j&WR`V;V;T_i{rpBE1iTW!gUN%bI5^}&?8RxqUjk-=h@g&prlR}#6 zq_+v_RcT2VDAG^NFl+}5ElI7LX9&DyW6}A-(0in~WUDYZ=`TwJ9Am27sZQG3EYtem zWbi4POn3BF(~UnTEp3#oD(P00K4!G3YA}ML?i8gTBSCXTY}Ff5^^4f5zf09Ku~q+( zs<&dR4wdNrGPdeOsXC0ZfA`={KSQccimkd_s?LtBx<#ty##D`YSgN}BLw8sBx#y(G z4&7a$M*9ADl9Q(&hj+)By~I9g+C0uUbR5kO_gmsNdx>#+LGK`$A7Rmttz7Frw$iB|TX6>PlbG&Sd9Y{)^?Ibf<+oMe^3%^VY}Jnf z9l4Cv+nUHMDf+3o2lazS1NqkcL*{v+UnLQX!Q{^O$&-2RZ+MA+P3d)fwb;FHqH*6- z?7pW@He2u4w0(!nqe~s>y>uHMim~(I%w5Vj^FZqet>Nq1s>`cs`RAW0a83D-T;7pD z<=u)^J*tK_3;F?o-TG;bA}Wu#iS;z)V{56NP1vLTaS0ds_P;5<$VGPZUhQVLjvD`r z9ky5TgH_|X{5Jc=)UT%UI1Y!0#n7Fcir-OF(NZ6P)Fvl^+^vUYa+M5A z+BT`>v$b?nEob>;>CoRwE%!zZc^M(E|4Y2XSGea$8-2rEw=7~Gr5z$6kxL$29gs@{ zYwZ?)p)wrS8+GNqD^|H14cMXspo3LN^NWoj{||)xr}dh5C&( z=9tSF<|+@#8NEq(^uRtU1wF98lLC35&@@g`SBVojl2(xxFAGmQ^{_yCXe0WN3C7v1 z-K9b|7hhQS2~x|gHrZC`%|d@jXvCX-v(R2Pv?R56o{VGqBU1G-s_yEp-RR#y9!-_e zFH1q&_9rRO#pshxmH?R<)tbCM`ft&#KaXy$5MC>t3(&f;d+YQ8!m}0({)tU`xm0bA zsT%W^ROyJ#mPBHvExp3;-ovT*BlCt1()`*pj6X&;Qr*)zNbn!&%g=2WA;Ev#!zB2f zts{=+9Q%o`-?*4^tiFS5%AHMAevI>~DKBWIvR)7l=*xIlwov)G9#n72dE}@O{Qt?N z+;1tBKeXlRxva0Pf2yx|AEdIr0B(wj%c=SuW;f-(t&kPrpuURz(#0&Dmm5=Fx{_AM zV%E--%^9)5|DmhT~c-h-d}P+bRF z&F$kaw4r}scKQ`g$2H|Yt|rZB<@!Qjn$KycT74zxOWoPexU5gtzwE(7(7%Jq{FJ== zWsm2n+;3Lf7&dW80upHf^65bt8tHW-pE2KslL59qI zQj_%|0lHGkPd6-<)<1)kV-rSaN8kC)2y*DVz{4-4b%vjoXeNNCCHNL*wWxT2-M2R3 zHj<^UeceEOqZdo1zV>yQ6!f*P*G@CW=+yETDd=loA4x$kT-~mHo%YmZ)9BA~Og)9h z{LdT%`3d~wXv$xs@COzb@H4N$#?)qH3DHMR<*yw6%A&7~AYaz`M5WK=QNx~+QKeCPJlQt6} z^KwG3kt1d72A^t}%jD>;O8Ax# zA+fr)jD91Bgz(a$A1PnX#>T}tWKwNs-K^r&4Rg)>7)-i&3N!GQ=iz?*_xP6+qW}>&TU_kw&w1s zzq+R%CSHHn)EiUN9~0{Lh8le~`bVis$&nS$E=eCs)hVdr|D($vUVE0%GVGmU$|Yb} zFy9d9BwVUmP_;j*?J8<}rZ9AZ;YPo0p;X;zs*DX|>V&FSL3gfnL?=C*OB3{?zj-d5 zl{>C$POUnnLEkeC?@S6TcT280^>Ou!7jF~k7`n>o>XWGxuB7ZwCx9Vc=N67zkwmvL zM9Kl04sMUc4b*=8^+adp@mCRG8Iw|JPG#LgrBivQ?o8vBw@b@Hs-qrss}{7nm%yae zRFlaK{z9cpZa(=cYE7RpZ%13p|E$7%^4;CEF1a5X3zNmNm-0=03$=Dfo@OlkP+RfB z)yBdPwT0E!7z_VlEUX-HU5Hwk(vjEFV#cSsrZ|_1BlI)(|I{a)_i{C#mwlwqO*=cO zTHjkX<==Bz-w^*;zw~lg7qj#G5ufPO+IB9_tt0Oq&@cV$=Q7`_{#3ulQoNp;mnl-_ zpjPxjDr@(riHTduRqp4B{U?k2*%Ix3HgM7bstvk7Q(9*Ap_U&S_kTcQb*p2pqgLlr zjdp(tm9+aGBETPgm-DH!rs%>ma&(9HoWtGojmZy)QQuKKd;_l>0Zx6BavIf$q|n($ zQZG5WMLmBBNsYv&CEdf4f}C2?S6b5KPExmy1dVu*Ltt!AzT=mp3!p7Bk=*wo3>M{biJF zUIEN`N)vT3j$iiqTzcEb1MT)a`cxX)WTKC(ps&n%^mP+SNjpI%317$SK|Cy}DOpn4 zm=~lrpt6&Gk%UpUX_BN4olENSC;btrDn^xmAs~I3L`03La;G@y$ubfvq;I-ZIeKN3 zW$E+9j+=#n3{1OBXzbP}gl-;P;M#YjmLGk42d%V8^bi+6+Qw(f>1)NbZw*Iu^4};` z11NO5TR!IA_zp?XuW;nKUnP*UuS(F@n05;5i_@lP$9OkT-TX6f(s5M+#k#ZQMx1n9 zonTHnI_0X;H3=Na<8PvbpdWiN<@31A`R3XLzV36UuBLp^sip1UB40Ez#eZ^9Uvlb7 z;7d?n{fx?d{cn8&-{Tr|Gj`SwCEQzJluTPLfUgK1ayr{z!jHkHT`P26DMo0z>^b;) z$gNWODs^&Bw@SKhqMzJILkD~{y~by8(ms#suQjT_Ug9Y2G<NkFl&@Ttw>G8epg`kev%`#f%0l8#7s)|n(q2SiyCN0)i;vn**O zMdA_sDpOe!zshvPJbI0(EQw!ZGVhd?CB07^1GPfsy5&Iqrjo%a*Kr>e`hscCWA{$+&6&leDE|#~__#Bjc zwbHyDwMhcs6z6fVX$7s?tF+HPG-WQbsbeBkt&M5b-d#y$bLQQuuN6PUW&Q4!DNoo; z{Oq1K{ifHDTdBw{TCLyoYNg^hp4TnYjR8|Ax4P@Rf~hopuO>S8KK>E{9}(yHB?QuM z<82PHO}~*!s%u|s<{bnoh@5#pfkzoUL7?DvIURA%F|tpPqx);`jkDxTM4yvn1UdBS z!yD9IpQavnhdq7xndr$cZS_0b1i9X9AJXKQ*R8soA>QV}6x6*}@(Bap!OEA;Pcn_7 z_U{)<4T~&}5-9?(96lm!`YiXA=)#|*pszT6AO*_PHyU9{D!bY^z!|-2hCy1$EmF|! z?v?_z+Zod?{bi~B2dd78$ny&3fRZD10d#PDpvulI%`9MnZ`FQl;s}A2~u_X?UY|ASF_DLrm3} zTB+(Dr{vxz{=}p#C4!pD>v#ockdd?s7s6XfRMXU=%&Kk&@>0LLh9wzlNN}7hREuR*8L2 z6SJNV{;5V9e=3!tgj4cKXSCuT;H(s(Yf^@;a0zPX87R7X=uy zg<$~Y932P6zGCM}RTiqQLDiUcsnRXJhB~y_nbPmZtKZ6;pVXs`RBPQ=GJovY5Ws)Y+4_*_TmS z=fEy4=pS6IuO*rCfhRf1@ujHs`kKi(Pf?lE_H{iu2lo0kvFl4JrhI_QI+bteIg;x8 zKTYKlQr9)*rBv2et~U1Ml>RR+>Mi#5THNU0aBq}SZ_uq5Qc+*XdPw}?B$K2&dcIRc zGm5Vx-boDllGL1MD7O_-t-g?@uS?xYBz-CIS!ukP8(-5?H#|s{y5Yp%Qp0^zquZ>Z zlD?MpE&=}NeD?KuQ*cj3B3$`wHX^dQS2q^NOyYi_BwYi>~kVe5<>zK@Kf5mql^TyqtjOs`Kp^ zA}94Qa^CYjhZT#STZm8VIq-S*Jk@GB6R4!+R5IY)&Gj^jyf9re$LO@0Wo_wM&a!x6 zx`ah+Wf8nE{aZIk|BsB?a^li+1=n#gx97;H@b6P<2AkE-7bkF5f5}vbqTc3R75!FZ zr@YO(il+QDG4@^4rbpKYykT7}RNk01C@qaSapD{&Jr5*3@qs^~297B0ZKaDoh zIj4?xQ-g*Rp$}&-{i6=Ks7`jy9i}J}-k-r${@bm6MuM{zoPC|bLpg_hu$U-)%20n9 z>XV#v8!4N(fB!jG`8NyuEahSnwR{kqeVlVYqNL}3_ED2K-5LC|G47wwOr-B5HD%fP+9Sp8Cvl68ZY1q{l#6Gb_w2xgp1uO>gCV{ zuFJo8>~f@N3Hmqj%r76#bdO|LaB_BC-b$D{{uR~a*SWJ&_mv*B8654>cE@px-2#%B ze3QH^!@q6;onEDiP^aj`&qkT9SmR{<150J@5E{S3ZZRhFb5X`n<~YnLbNRRB`kCM6 zba{tkwTzOa#r=j_ka7D-^FynoM}BSFs8a5}$-f~TuUH(JsO%MryozSY;u6hcUGfZR^j$0&6BS+ zUE2y1M2>ryd)y)Yd#gi^I%H*E#e}^6Ti!=Jn?mebSt~{+T4Q z@9_laV)FoZSRYeGzd6d3yv7L(J*c(!l%!8pVY#-Y~d$;Ri0vCsR# z=l#3;{P6y+9q|Df6aX|H+W1r*1V1c{n?zX&lMFOifGQk-| zhm777!~MunnPaKUa57uk&-o7*j#dG3yYa1b%X?iZX-7aj!Gz zr@YYXcn9qvjmF{}_VTFydY0wdM$*}&-qaD@;^zbF zJcSJzO!}Rw0VRmjjImrvk9$)k(a!MY^b$E|`ZJG0#*CDxb(Zxh%RM`)NRsFmiA(?< zM()gu7J`A34)WvGNf!mt<3wjC(GH}m{CbecFXzZ$>kN9X=phk9&y8w5bX}1xm<%){ zn!o{8++7=!l1ie9hBVWVIDE%aLSiSDW;jTlCUNmkF8JBh=CX22yll!LmR@1$Xz#p3 zX(Qx3K;N$W-64JH+a-58^yg-_G%e0tST{GbcHX?qW!dAxx&yPygk4ezl|9NFj4B{U_mW6elAivxzQ2;vdr!qW`woJb!+5O~wN5 zvw3-AbrV5aVX5P~27Q zZ+h^;>%WG6Dw%c&1K32q?G|IA=+jN>rsdt0jxyu_gENd3bP0g1sA@Jg(pfzHgXz)6 zO5YD;DEz?2TbDG~EvhD7nhL~QwYb(eC1-9+-NNRPb^PYAbrCVagPLD=N#fXr_1ryC zjbBNlmijuPLp1ATaLv5>W_CUCE?QJoPlyJFI7zah(toC|mqFqIar#bS9US#hvKt!H zFEr(d)>Ho)8q$B3m!{TSv?(;SUugW{t0zCAY2nffs%6s-O>R!?npRq?GTPPVHgC&ko4uBEPf)$eyCQ1RruCup0p9xs z*A|?o&OKPh>?(EB{oc}CRdP^WkzU>X4kx z>N#hBN2YqP%_~Co}Jo%!vgB>K7|Jr+qT(l!9q$NvGq3-TU<~FhJZ!F7Kcl9h+d+FGR zMtWhsI-EvezuK2nt~M_zr{g9%=69TzXXZeD;;g((7I>gc)ooHMHqm$FHkG!CXUq31 zwtwrbdAgvhK#eI^)Ap;EoSKMwxNY~^Cp$K)vCXQE#_qmD^3{J`l)t86)_oHTYHJHR zI@YK;+du25sNJVBw!i!$`R8SIXWJGpy`w`-+OCSc9JOe_x+D}j!Bu6O)Cu{jG+&*V zp-RhDc7|8L6L8d)FVu93%j3M7f&z-mviytGgoCQwYc5cawB=JszU<_vU$y1z(BKd+ zLp|0fU+rk(swG}OZ;9H{wk1=&?&Pa`+SIRwjd=|4c`t9MqF ztLyqwWPH51T-_GRQLCxhYN~j9RsLt{7evTD_=P$vze5f7a>$11MAdl zTD$6rkf&qHTcV4k#l(r!qTEaCP`_JM-lBGe_Uj-Bd6TFz z#2Ju&phG>l+{+(0{?t*^XBMcw?Gsz>&Dv9;mUl+fSD~7f-ukC2Skh+&gB%q z>Q{^NE4-U1i>xW=Qh8e_rkmBPt($bfd`v@iP1}Ce-WtksDRRy#_tujBPP=-lt-Pg! zLTYk*EeBqxctAy2N5!1t%hX|^vs~4X6B^cEz34Wpg`s;4yul}O=>m$ zUnBzg)V@P~L&DazWpt=7o&1(sZ}i%;r>pgCIqDxyx!TxPUZ)OepV)P8)|2Wjr+E!` z)uP^X^!!aU-zukB8+V5B_{XiJ|4w)N8{U&;1>WJRG&J1(b-~EoiP}YpHO#9ADp8Nr zDO|pUzt-|sg?gj4Jz_rIdUa#lZc@anDN{FTb=7;M?a$kCNbkQm`MI^;m{~KuQ8d5u z)gIFKZqio|T)t|`nWTEBk!H*OC)I7O+tgp! zC%3g`XrH|4wyR&Z=5(k%Zayz|p%}IGQpOg!wfv>mPjbx;?;Le~>o!^s{zf9MZ)F#& z_X*z2(*A0s(SNZ@^d7ixVs2e&fk{JNzeMkToj-K5E6sT0Bkl^7^r^q2v1VVbAm{=`I*K<^av{rR_$R zo(ze53cLkV&(o2t{_J@B)tWX>k6|LM@P~TaB9SK_GzO117gS~5~uJzI;=H6E^kw&?dmT{62QW2L{ zJ}RcW1hq)Yzx!1VMcYN2)S-Gv)s+-4Wd}c3{SR`RL~Rt=bb+^BWirWCwYo-q?dan- z>Z8_!v~4-4UUW#%xKN?1E+nwAjiTYm&^Y4va&)^L4sBMB^h`IqXOU%1l)t7t0!hTe|d)4EM>`Htu);~n3|1lk_;^G;V!wC(?( zLXB?!LQSI#e2kaFTM94h^`;GKR*u^4?B9{+rPZp}67to3E4IKUz&w>taT%hvHTgp`KmPnZ@+7cQzfE^GTmZJWUK;FM=1-+W8U2@_k^>Bi>C6wNO ztGDMq_4JBu)ZjgL3q@0gYH3%!+x7Rs3e}vU`n1!!cKL(F-m=dwc#k%jjoa0sIR)pc z3p3P!PF@(y!sKpCT%%LDEK|BhuL^paf5jc2$zM8cEn_r-zt*Z=v@4iO+tZwKN^)vP zVkb6ik1cOkGuzdO&RQCXbJduf?2QkebCz1su9Dho_e`vK-y5()z2bN#9kwT`$Cq#S zW~mnv%^v5=Rvm6G`C6w|on%y>40Y1(^QO){jfPAW)~G=g5w-d1$eIpsS%*5_EAODm zQ{d%NTHHcue3z3y>MV6%Ta9{+66Aet&6LMGdnoncs%_qrG#_pXmG3Fb-BI>Rq^!QI z;yyJcUp-3+>-k?K1?WA zmoDG0{*~zEPt2{Ir*5DP@SGfvbCN47hR!@J!F`f4I6G}kqQ7JO*K(7jniE@S)mRWp z9~haK8}ZUA)@b<~+xGL()1%;J^NeVwNt5s0tM;tet?o_;4RuwQ+q{GR$Kgk<O{S@N__IY&n9-fM@{y7W(6^1b?Gv%Jh43SKJ{%+ogWi7C8}(1OGlZWEVRJUHl|(n zSNF3WdL~V0bT)r^6BXsZeos#9sHNnhmlu65^+^xfE~w|pqsbW$Oq$9ban;SsbS7k{ zxO@3)0)I_fFzuviJClV;gyGm z(|Pisjy!tC_5O)1T@zRux$D=b6x=7&0-`3D(}`+L#Zwbz`cKR} zpU$;%R8_M&HbY&oU;QQFph}{IxHRW{wQRe0Bb|;9r24u0ReA=Ur_fo{kbD)+P{(bf z#ktEHvaxj3M(^{oh`P7UkNdZs&X$RP%JoLi&c4pejIdW0s@vPj>5R}@>+MnJADrDf zEpJ-ES+mu4w_KmcSE!^d<^=w!`D%WRIyytn;QzkL7kfjf{l+W2VRQ;Vsg%y%JMXW3 zU9F=fiB{)=Xbx6JD@6}VS-gZ*1C8FkU-=PknvnMa-K6S#T9TB=XFgBuYZfjS+Ug2%J zQ!UG&znrk51Xtvx@$i`~RiavvulnUY?H!>GYgc_c*L$B)Y__XY57tE#ov`)F`Gnd` zJfk45LZu(vyt<%k$8|5N+TGrz#Fnp84ywJYb{BXp>Rq=}-O`%>mij|txf(|&A5-ZB zYKWZJ&&pSCUcA4FPA7WoFUuU6OXqWRm0%)Y;W)Qh9SBkI+`TH_d$Hq5)jvPCVB*Mv zf{8R+JIYk`es3s+N#3N=Npu$ARg5W6%Xh108r*dklYg#HASK=k9aMKO+oV43;iaCf zMrN3k(E>W7%SF3fpRCIB`JAu3o#p)YV(Pi6y@GzzLVF}pz1xE}9_`DCyfM`LlIpeT zy_@MQaR;4_=1yEN>qYhUvT}W55a~&)+NRG`Bh?Mqq~4_z^YfmZ$sSg8Qp#t92bS#b z=-5F^^NmTJ@2L;yv`}52l%qael0(Pxv1-A7H7G~T&ryTh7g3fx_$38fewR9BH=V9c zBXvTa-udQjptT@Jz2lVcrG15$p)X3@<*y^`G6bszEj ze!P{o>t!s_RfXlGT8&zqujs6Kard??I zS3Tb5?Wfad&n$gkP%c-Cx2wBoW9MzoTTk7%iJgh+_7!G#t^SkH97>~$q~UNwO-;C& zuMdXn8|bQTIPcu>;_9mT;YNDwXi?R|g$?tZ@Vo_8^!^+3)KoQB(f7Q1C)~84VR19R zsL;5$dWmjFh49>}rfS2vxVl<1Hdi+_k2*Pn#MIQ$e~W6cT~yc4*Q^T~8ZIOq8mksp z(?8)3*DS1}2l-hM7RXFt`Y&(cc?}C&7E!+q3+J=aP1VFoJd3IpUs%1^TyUwOY}c{7)9Lzm57!nycn6tcDkAtC|;7FQ(?pv^Qz=c+`yV zsaN){qsMvNSkX=oupTMaRXYLZENrMUgVIRXhMUbuha0Qrk0KFt7;O$?%weoKoa}^K z>RXzssn(e3_s``w7$rNQe9_BXGS35P!NXaH6ng@}` zZ4o(-`#%*<<$*Q+W3riSr)D|q(Z=fP3&Zm)tf5ZzT?(FvRn2t`^|r3jLXMwBl7r z0T%DiYiuD;*OKvdRTTDcO1QbI)*(gN)CTIlzG`8#@8`{>%7rwK>#8Z^Rn4EjSVx1& zj`X^r?v9<($ic?-I-uxHWj$>u@Tse+EdJujTV*DvzQ?4yxqxO&^|E=@O-*4+5Mo_D z4U(>%*SN%4CK{8udIoZ5ItD0k8(SzjP(F8BC`8G762iJ#)5!^8@gq4$Ppa@dRs@(+ z3Gf)FhHsS-g#wiBM3Jl&7gEdSBvjsx=f|5B1#UpsAr?s;9B16@}Akmb0X(UT0hmVtNarVM+Dk znuQHZ!*uVD{;I3A432oC8>P>AbLsY~^|EA>nq}INY=F+7W{@~w=|1j-6hZ8BisP2W z+_g#DPL1){;`(`%N~yllSxNy(h?A2;sgn{G3FM_P%oE<>+mlT+Ih=VqwQ;4+$Tehs zP2FN@Sk>IHC~9Q!SKUiU)E*3(?8o*$+2JUtP34?ucSh741e zizssZ(QT4RXIACtw9dwb!>l?*4ka4iLDbYyM&h716PgVv4)f$PnZ9Yon9*cK!-brS zxl(d`eM9|RUhSD&qf>l+%R-jPeQ*lk#hB-1nAaU1qugA8XrL0kpI=BZDLSt!xA)vC9X3YaDgbs16vY72|WwMXT(1f3Q=MTBq0Q(&btB{iw!T3R<>x5xj4=V`} zoe)>7E#X*O!m+l5tv&{QDSm?EU8fQdu|cCw|7aCnLpO$csthT5GE|i8*jGL(jMlA{ zfCvZEHmG2SIJrxX>^9)recGr9@V!25bR;MX0|uUWqa-=yN;z`A@i9GR${$)Hw$hJT znSv)rW(2-En$fV?ZpIh2+;9D#$3;0$`%Lbk) zn4LH#!&CC%9(|9!&5~RnO7*C1pGkrmGVq3-J`rpU2 zDvfOw6H&j7X;q9?tNrea0WTGja+;P!P`KIh0d9`wL%~`cv**50_^Mf&XG@DZqcVv}9oZ7eLal2h6`q$RF)N1MN44e41EBi!UII zruYK9M7Yf2ixU5n5&lqHKyt`SaF--R2l^2Sgl#it{z_NEFrzlm%pZ|F~f4Jp5!K?h(C_%Vo4A76R7zuAdEvIjo$OJ>pF0*|2D=@95cp7$VoH0Bp8gfSCTo z1&HZS$^zOg| z#au#}Dp7U;Cp@As0i?{d|K>Tey7xdC(c>*NJ-ol_*9s_s0i>1pBC$kGN}VkoUud%^S`O)5AWiE$68u4@Hk6L0nWCxRNzxA zZ8-1*OUnYDWNF#JSM@cz&>pnYMd4~8@+KMh8cWLp?zFVw!0Rn76?lWCr2t=VY01Ew zEzJYw|I@%9tsn~L36T{9o@HrSz;i5ZIB?j~Qh}>1Ed_X5h*)om!eCq&`{wDO71N;U}cYkm18fDlRY*Ts=v5=Z{J82Nt^x%|`L{GkooI*Fni zaw%#b1D4G@);TS8`{%Pe&`QpT3~b&az;ha6+|%~@C*KsjEVq%5z2Fjt5@own=^Jw^@o2cVbq z?^gtSg4px@o@M|-Xvk^Hf|;K0-Wh=Cg4u%7J47lRNU^uM4GrKfO`I=+5ha?45kz=s zVz7^5880MeI+;XwvwUq!A^#pr`jtRPr-nZy`x1YKl>+`uNXl8FA}C-c60t`F1q2t( zML_z&75$;p4?s*Q+Vw&Gmn;|Ht3slSkZlnZ5Q`)Y5R;y40>lt%-B3Wnr(WTq4Zepe zF&GG0>HzQ)pQ{uQ0j)iPf^}}p&ULMLaJ}!`LO}S5HaIG%Khx0V=e`z&fasXng2Ras z8R$E<2oUZkSfVG}_l7>Q+@NH7tq$GJ-jzi;qe zUAb8X6>B}&0zq&Ok%AuBA|BW#M^3B2FZr}l5#XIZEp|WqpwxjU&dPC$=nMUOIR_)h zh)#$BB)I50cnOw7*9FsEbY0NgUgD%9<;dqKz(agmRs?vmPa72hhJNwRZ-VkE5C@Bh z3^|fl07v`MTOD9Xrw~_fn@`eMqT3Qxx zo23m0UTtZq!0ncn0=&l3l7ZJ*ng@I&{T!y~60BCL9Uh6|1BNoZi34tsF1al*G-Ezs z>#f+$5On&#sYlR7tgrQsK_`hVQ=)9D5xi24w7&~B+b^y{b6S#vy~WviOcjAMe8Dld z{NOuCqdh@#o?^?-+3S~BqQmX-oM+|p8kPq4J%z$aQ-7Vv0G z%Ld*hG&)n;>7cMTiV^q?OUnX&%hHAezinx$!0%XE3h-YnEgAR&OY?xg?`NE*6*SO( z!=sa>A>B#`M7#J;P@rLk->~Q`fiRe+KH$4PS0Uh6KB@Q!(Qv#RsUcvFPbvhg^GU_+ z0)J^qcME*ql0Fd#gGjt}fI(1wny*v|;44C+-0T4F^w|mlG4jj?3{z?QzqJhoXu*uZ z&s>oUp)|jO&EibCIWetfqgAHwh1r1cEM2N!7C`|@#YqDPM0%2l3OS7)Fb0nHNAslm z62He8w+O_L#LG?p3`mc&q7;dk4Zh^c8v~N#Y^#1Qf}fTn3670}!r%ZP#?U9Ld__$E zF^_Rd|Cp%z2kp=Y-zn+N;W*!mx4;u;cMTQ!OeKM=_ut)PKX-(t})Inw9?-r$pF145K}{3J?> zfzlwwZ&(62-6s_TUL+)%1<&gBm$6hI#pVQ45%R0^%$wWRL^9_K4n z3a7yfaW*$Y#dP?P%>yp-$2w*qhk2NDl)qq}?X0+)BdPGI2>iwuJOl7}-;lzwVt^GC z)BUa(K}8UhCW7d)Rx<3*^IcK|2;s~YRCBLLw>p)?N-7CTQcklQGn3#-Oh)n(AcF6I zFfaKBv-txN)U-zgg(!I|W9E4xzu%JHBSt^|ACLU0kR#naa3d(R2r*9BpdI2M&I|wx z^di#%;e4Z&7o*iG>A3TU6#xsSZk!zqST_1nijA@M8_5ZYh;}J6kF(X?5O|}eFCd!J zCD_<48`^;>-lk%K1TA>toF~Mxlyp;%3b8CPH!g0Ij%+H4*&f^+!xGa`EK5vBNS8K6 z&K@AM5OXPxkyrrGDtbJED?xN!&=Zgol^y}V6!Y|0p@0QP?Tw4eokDpY zXvjjtc!U3;X!M;N=tJi5EG8heW{s z8`1K=Z?=q^f&E!&mgvy0m^jBoP`0|qtgKMfvdnl>q`)t;!nb z@N^z1;>2ek!!(I?FW{M0AS2K>S&%>;z{akAw5()nk;UZq!wfLnY)rBUW; z$p15oKj-+ZilO%bO9K4PCzS$L`?8BK5V+Bj0HZVjgfD0ZU{tW*7>GBeJKlbxzvUvF zX%O{D6b)kGDdw}14T3pv74rl&jrVW~bm$w^U$)@W-&FQZe9# zK51r9?~>S7L6*ZsjkF(D2OdJ0(S9*G;>f&!+YB)vJxiEI+ezdBkF~U9;Bl6g0-SAW zslcaL+Hl|rmX-y4hNWc#e{`f#lFqLWxF~!qM7{t3{E4My0e@;~!+}4uv{c|PEG-52 zD@#iTb_N+`IMV^YH9ShefI}U4^c=B_QVyVP*Y!;6549`y+m!(RMf9S11^Bg)I4_k% zP--~JNF_$V$Ax4VQF=PnX9O%t11StRO0H^>IKY`cDGc~a@dj}L{$5C?QKLS~i6GihXInvetr&?b>R9Z3X`IVpNc(4i^iJs=;KYZb~$pI=s(QR zPLdgL#rw9XLQHw-C!s(irBA!3R2IkJz^Q3T5 zG_h3*n5eor;u-T(6OD82_fH(b$6Nmth->oqP#L00a-I>sW8-<|5%CP1 z!BfI&YEV3V?~+{pp&ThS10G?M%&yirnP*qr`8rslv`LQix)@+o0Pl(yz`J4`!1Ly1 zi8I6%EWWt?11y=?HBklDyVj~Vmc$Zv?{?ANR5Ar(+lAYnr;L=13iU9nVu=w-yOUWi)3zuf((02)EzavczDip>CgPMFGnzUFO1?3f+kW zm?6PJr`~{Aq=*Y^ETW!BfLUSyH3Z!1ljZXXU=pY};}FmK-W*XuceHpP_#BGr)+ zb7dh!)*~eV;Y;Ge$_Q5y2@4|<5|IFrn@AQQ;)S>Xk(Y=I5ZQ^i0FkJO3lQmwxB!v4 zh$}W2=LAz3aXEp{hvLd_tV?%_E8$1#4iJ8%$plwU^0z>90GIoua=`8BreC^(z6im28ik&Ut*r^eY zod@Cn&G^#8AHks{($t|w)^Wbkl`s~T{?OP41DB))gE7tnCv7rX*ZHGX2#C>3aN33^ zre~vwRnV8O1AVrPy_Ezi!f97Y-LO@J&k&NNDle24kD@G4PN3pZLHE5$I#!gP+ zjGdfB4EjSi|0#oarEFoM_ALkE?OP7Cej2-@J`iu2JBo z15r-q9f-HFIPjBBqhK?(aU^YTD+<`i(KZq=$~SxC`DU;08|>q>L=>=-BZ+`fo4UR6 ze7HBB5BL5gA5t&K7)Td9ui|)cZ#)m~jq%`MS!+i43laGq1uRH((Ge3Hu^#6-WY)1J zB*)2-l0M+?e3HMJ$oDfvDKaI}BrV4Xg@gVswG{9hpHv8loET>ve^XNPSN_@?bB+4~ z$z2!Ak@oxT0Xie$BK{OneGsH7w0 zDzX*%2g^?!^JBL$mDt80nehn)B<1;Dssyyc&kJUpSV^%bShtAbugj66b)XDAVv1Jp zV1|pg=vRseIF8OLg3^f;l=Qzp_gLK)Tss*iQ#TH}aCVBJ%#|ZW6(IVd zc6a%?;Y3^(a0&sV&d2YHncjl}3jpmFa3+m)j!4+DH2QNg9L(~>g@qg!F^IH7)WIbT zBE_C^#@n(4{V+oG93@Bc10eD@{2>hL`KXN3yZ(5^JQVC&V}?dRK&Jzoi+WzSHRNPRf;_E(?GJh3YMBhU(nq8}3klcxh=j?2D|$pi_`v%_ioNI(4ldcm z6;$e4QEH1_6YiT}2SFt4 z_pwnW63$Sk`#YtWVE;yB|3{7#?0~kr%GmBI(Vb`ag@9Ir%2*9zV)hQP>RErY8pdw- zY`ZXG?)UX)P53c^SW?Jf>|e215Gfcwk4Se<`pzr_#3c!u-OvE*9Fbx*sDuVj`$`o8 zTBRyum5TAf1+oFOJO40tY0!j+Q(S$H@A7c)WR|#aD!cxN2Yt14ccs7YECjR~RK{vh z8LL4hG^p~sD+I*V5OQ9uQZYW5FIFMV=`(HBQUe+=Z4``yMR>gc>1w zW+y0%CP^@?APLQAAYxm^1mjZa7n@eP^cWO;sj%ED$6?O0A6U#H84LGTiUWk?+6*H=SUNphpDuxhOOXQQxW$7ztq)3J;wM0-~9D z#3#_sSuG9Pql5#mv9x61OD!!0c%7xC0$*im!-221v@GB*OUnixH^R4mvx~whLgWV| zfG1d57I2QG4F{fNX{o?dEG-52G)qeco@!|x@V<;F1%Jq+&xvI;6o3Oo7F~k?JY7g; zbWr-^Nk%F$0>15&W&&P5(&qxa#wX1L-0qWR1A3yr=@g|Lp;D)SXLVylsnIe5Uek>c zCHN`MH5bGkTtiPz0=|AC%$frTznBLuP&&(Z$s9m<%P^v}-)AfV{MIMU0h}z3GHp?s z<-2bVAe?O&QTmzBSOU1Yn?#hh`HXV_2SvHBB!Ut~f$rA;!lS0^VCY>fo=fuMtTJP(Jvlh;!RRN0Vm;y8XbqYZ6ogrc0OG4zzHXQlC`#Cz;A={=|&gz-||VF}f7eFt|)wE2p(b1cljtcBllb zi{?Y&YRd=s^JqR4wpc#EC!_gLu->nP_c8TIWq9Atr%JdQ^O?A8w_HUYEW< z_0=i?gcIYwHwT}=C;X6dVz56rVuLSy<^uv@CQZR$D`<)FrJE6eMPdNI6d0>{QBd=E z?+!MK0?;j9+QVc(jL@4*7mX7&gDE$<4k3-y7F~xlhggrU3wj{fKMiHDTOtK}BT}%F zI5B{o=YBhD0AVhzva#LGf$SQ8k`@BOCTbWo<$merW!oK~?XEPoyHZ$pjO`9^xKApD zQdWbQMI`9V9!{@^-I$frP|@jG(u1J}J2BLtrI>f`N?Sgg1>SFI$-sZJv=rbEEG-rI z@0K!OLK1#tK^60oMQ$x7|aFfU~D+=lS%;{F_*XiFBXy!hZ6k4jDZj0EG%B(1O|MrSexLiaz+h` z1pUISaLix3v%)ju#WTzbTs6k1AX0=aZ824H)LcGmZKFCw5^NSr#zt>Ptg9 zdXV>@L0Kozmv175lbZlzXah}t$`A*d#B)$^r~^%YieCav{wFTFKhp#S+Y1a=(ei_l ze_EoO*?{35Vhg&0NI_GH1XBh@MK3Uho!Elv6X}Nn_nj#1fib{z{rc-w&>y-+4{N(b zp=Lw@;mVA_2wlw>j9pFqG0QLkHDl0_(UJ-pj5b0RS76>UK zA%Q?cA_a9AE&@jTf(ikx2E`EclAnbO0j=zq(+p&od!hyk7z0J8H9s~?@CLB~LM`nr z6yPG_1B^Rx@Rx2J^q3~XeK46M0>V_yhXP`lV+I(bPHlt!#+qxVSux-vl8E*1T%ho* zzg*7%{DV&_1l;43iU9xWOS`Bog2LY{AD|tGQp}V8lKD>O3V?45iT=k@TLcB9M&iTb zu*}~JlmcENB=Xu_t=CFnv*o)-AZ7zy%>W$d2W2H-kxvQ(A_i!G9vpij#m* zu{M?lBb$ZA8d-|KMi4VwFp6O%77gYBe#(!rFbqdvF`?zO>D>|Tojy;XuYS|`vjz}6B_;NtEw;oM4DrlVzo2CrM0L8l`=kg|CA zf_qCEt9bFTM>35~F5zIvu(a5O6OK(dZEX=`7mN}0iebXQu(+VRhzKwn8JQqlwT7L#v6w5!1wAAD>A=InPfhF;n4l$+X}5$+r-&Mq1Nl zQrL*mj&oZMixVaiJ+=)9Q)v0xxa>Xt!_mqz#q{u4L8s@uWm&F zk-?0>NGX~TE;&rHfhM8=w{UA<#Jpxi;X%8@1B7!l9|~{~3j{8doS_*}Ko~J2u=Oe# zh{BIeAnbDxWpon+Ys$;k(SX>rgy`W(V5AeGwFSrVdRZDUCZzu}t&or8qlp+T42mXV zG~gOdgim0dCI&l3039m|=+P03iA2*6dO;;-1BQCU1{jj*&1}Fe{*<2$-Jv$KVe~N{ zNE)ocs>^J^Fpk)QLrNr={9^+O%iSo;fvx40Kh5&WAG5rdwHy%JOWM)F84a?nWGjJj zR!D4s(LM_%6k_`^pTQf%77PO{Tv)3px*;3`L!@A<^I`&}7(ww@e@+x5Vv%Bh=tK&Z zMWvLlS0SbR|994e$U%(6IYU}3cCC&I4dC@YZBzvKXFe_VUsx=aI`G7CW3~9|GCB6( zx3eN}13X};!6CRxR?Q7^g5gE} z*BbETH$LAOe zV9Y$WH#pvdWp7pX!+We)meL=RGFhZ>)C76Xis`8+$g)*fo{ka&ywj(RiU9BRX|eO< z5vc=DoOuGjtn_`B6#>TCGhdoS10S$754dNxaV_1#Ne1>T%>(XhY01ICfF7@ld{PzgBO#f45-35~kJ$7l zUseeqTC=Q@2ufB~Nl>rbMaE7m>wnd1W^AjO!M^U5KDNq{;~MxWpEfE2{DQAj(H{g_ zHDkgZ(k)9Nbo$H}R2bALS;nlN9Xk*Ba7#-DKEl#cfKx0j75GR?8xB0k(z1ZlEG-*& z(kVtu{$(!*g~>wX`-s3(EG-N8G)o%}e1@f^0-t4RDZo=LEg87b(mddoa-$UdA&=IH zWfZ`G5ua2H_;QYEZ-O7CKGFfL{(z-IGK?r)WElaWoMHSS?eNRi^uQ?K#iE^=J19X> zVg!Vih7qM*VhJ$syz-XOge}DWJqSyo(3c9F}ClH+z39`2OE{Qq6{{|NN zf@by*INB!__7Fp6`Ud^rtbs>(CIee7OQGd6zVOl)1ooO>MusjyExTNN^*7&rvwMoDxJ3S8K%>TSkPhw+AF?v`cE<_ z>=Gg^{eTz~I(OaLhAtsr6N5dpiYaS+lL`T?mBm+yA=aQ`NN@9pwGa@45@#^}6cg}8 z2>6kr0sTMDWDHQc@4zBJ_?Fp%#w?HkSs_ObqBjJ;FUL4{)G|e>`EsN@5Da7@1v`sv zH8ZwVaj?}G=_6Z?tRnDKpEfE2Jj>UqC@j#b8MEX6dzz#mrr_15>VGB?mgvvRn3zFe+F+dhrL-#ZTg}D<$1I@4fQg3*9w%2kDT0uy=>&LdTg*6s zD=N1GqG8Xs_yhzVtfP^E2T6z+}MKjv$+Ql;ZC^+d2gG~ zRSfuBpHv8lg(ptZ+9}+Blp{ad2K<_(B?IrWv=rdCEG-rIp-ILt{e!V6JR(HuBo+8k zOG^QM+|rVPpRqI#IBRlLCn$^&B6k8j*3wdd$5~o3@Dxk)fNvI>wgiPumN6ALVrePB zw^~{<@LiVX0lz3T-AOPcFhlwg%eNyqa0+Ve2fS7cYZ5B!GGRp;sSwmb;Ni7s7 z#{`wyDJ*}KqfS$Tcm1E{t_3)*>O3Dw#>jvj`2iNeIBN_+B%rK}v6VpJ+Qv2l+pHy- zU}E`dC9R~z`|9q>j|OBzm?ohe#_f=)d9Ep>aT_ui%Cs~?S~oyqI<(QGfDOc8!!(dU zT9a{rkOKYBIsbRg-E;4P9l0~z8SVd_@BXjzpU1s>SG#MuCgA5S*9^Shaxvf+EY|}3 zqUGYihb-3)yvoyA(wZHsL*r^DDZzH&gyrJEotA3>?zUVE_!`SK17B;oCg5JnH3BbP zCe%YEsG)sEMKAL-M_T~k<%a48T+5W+70~*cQCtJ~n?>54Rzz#k*av9+ydSz`G6CRsp_`BT7BszcyJU0Fg!1lFxE@pWV}2KJae4xc-OSAHj1b;*Fu% zJctjP!Ce1KPUTEf4mcoy$+en!Ok^#Bmj{Qf9A0TZOm>8v1fD#*9?=1&U-P8qe)XLng%Bd zuMvsw8J*8c=zt1^1|~i{ppB|4sHUBrT)@?-5I5HrH;JnaVv0 zhBjP}TPeCR9}d@paOhOTi(o8)W1Dbct836Dthb1+!3rCqT#~^1%o6N^ryacR=ro8W zXq|^%V%*6q=Lwc{ru-WF#4bV4FyRtd=_i^MpP0k&d`n%#@QapmC(3e8 z274RLCi;GOj*VOtiAjPXQzTMD_Z7L1^L&$~B9So)q)9g&4m^dWtUqwfaBUUf^9(ny z;<`G4k3lEm!eqR=0VcFr?Eeo|KKk_Ws}q@HP-)#^Tt8+h!na-K*MuD%%@zVj<31a~ z5jJbuWdM;RO|-qENHZ`}dqaCP8Aoi-d!x4Jy`%2-Ovb1j7KMuJPRkVUo*V2L2oM?5 zc7l9yJ|qh8u-SGKfan!zVHA-bQEpm9xk=s0$>3Z}Du9=maMxm&zs^!$4Q>4Ekox0R z3rTtA1b!`&s#xl2hWjk#=J^Qc`HCr?IjPuiHBb8JlH66oi6>BCtO==xG9q2cxk)YK zWKcwUoePK&rJ3-UnS+R-=`*`7KyT9~9{;=t!wt_Aq>mWu&jV7X@CFIcV#IBvN{;C)vF zl0oA|CS@|fFIlby_<-eNz^_=Y8TgRpntptLI9c5h(&*Z>TkZ_g`hS0CyQ`4dCawqcUNJaYL;E zL^(*SRx$q06r&q3X8PC#i0;b{byv_jjk`(PH6S{s711i2Zgv5FhWn%y(P}Y0?E*|! zDWY}2DgsXB{%enDtu|HZ0vxGQM9bDHbb7+XK{e#|f*L$%mPEV){G=&h;#r0t2GoF0 zHswpWg_03alXFa06X<=xQrj5*fTgqq{+U%nITmx@r5bRDDNzE&xWQ7jCeA}-m z!Mv~m(QOXo^^f)eVT0$q+Cq`&Fj+-GCSuvIM-zY604Ahi;o-gwQWKsgI3r z=5atWibO_mrbu@ZM7TRRdSlq#!O;kJ;V)G@n^yw%&tut2v7t;e^SfEC0-RFH2IJ#O1W3 z*y-kuvf_Gz&N>*f*(QZ9z`0D($6Y2=(0JbJ{fgm4lS9`GhA0RHKuu74qR^pT*6?wL zzqQoFP=C5GK6d7WPBiEu!qI#<95r(ekGjs3rdzRHJjs7-PBfk24u$F*wn~JpLT|EQ zmbP##`grYx3L0NE2_yh}jUN4QJsRjgl^IpSY>v2nf{+W?m7J6vj1h*Wmg`BXxt01I zn@!|dA$5Rf8m_GZj9C`-0^$Sq1)Ye@uV}t_k=TmTLs= z<&~)ttX0uRxM%cw1Q0&yKP>^_QeGObsi3uqN0<}=|IAQp0Fef1eR2}rNa8B)5Upgu zn|aUB*XL+G$1EuVA{niS)-xuxF2Mh0N-Lsu8P|3Y-6 zjwm+|qTGl?x#8~SFyA%dx&fauR3gE3u^EK6T;vTEItOgq>ZYkkH&I2psVdS<7Ax1| z%;ZG{FzQ8y|1;`VOp(Y8Nl9y9jH^;a1BpsSV2rC$L}MBcvQz{<)eQV^hQ@-Ss3n z*OlblQTP#GW*jz`8(pXHM8MgA>Vs8?Wk%E|JMzPh{IH|Ywa345CO>5h!+^({_H5w9YSz-8bpS}K?o%wMvutMRMwvB5GYeQ=%pO<^3#oA1D0_r|UTFEWgC^QkKhD zcCd7_^k-`6!F-YBCYJZIjD1#Hw6i?k_V^J^{37K=pVkq2So$nCu*6Sp;Rp8Ie2%xj zdpYj?Eb)_$_?<-jn%}!M>N8$@{CFaMobcXRy2t;-@?Tg!#}aixUT%Gkx4&s;>IgGg z;^+SGOLwSC-MMZix;|*?@;P^jb`8vyA zv3!T+Kkz)lJa?;hy#3)v>Fzp9N7~8qahCYyH~h?-o6mUd*YP+cS>h+w@T+9*@2k1- z$7}!SdD>&|=d{G{XSJNK+xuA_X6eQsuRXrg{tk|RAItw@iSMz;Pl@!k>J0ET`EEYP z+n@UlMfg@7e4~yV|E+nNd7CA^_U}V(yZZPRBYe{jzU9Y_gKzG^_s10$xSn+Tc>BZm zx!{{W4)fQ2;A=nJERI#*{f?AR@_(%Q_}&kEjCxzU&iLyrd%vvP{Vd)7jMv`%X!$3_ zJ68Q|U(y*r#}Xe$?!8#^V=Toby1k3#7)!UmN0>*R_~b1R@kAICqvyYa?rkAHvO#{Vn1nWCTdMf?!WX#x2FuS56fRqBWN+?zo_w9OBkc zZltwuB%K+!AUz;jWotND8WybsTXN)2%W_d4*_bMp()nCf!>41#R3<467!@*Q(VEVs z>A9TROwWVVpkw)gWH~8XQ^WpXF_}&I!vkcCmbUPd#bR=cwgA4qpVY{EGMnzF(0Ou5 zPpvA7_Sjb{iPrvnHk-=P!GToY$PgJPb3-ZObu*nC%mXL;`iiNIXl2s56fo5bFq5ZX z+Lk@J1M~;A&mgNh`m2X^y{8cq{9+YHm9A+Jm`i^r(jV++)qB(uViprI)v`|$EL5nC zo`d$6)O(7*gze8(E&Jr!%g<}P^U+6n#P6;5h!LWf3BEWHxM|p^j@qYH1mz7v*zc(K zs3pV>CdOD!Bu>@|_RUg>9`YXm8|V-A!zXyu5@MJGPLM`{htpK=H+~ezKQqx&+8G&; z9=Nzb{)hv)fpk6$*zaQdU2Gp$UW9P-XIlI*0a;V{+t2p<9ec!g`+tjL-*}=&4An^v zDm`|xV`+a1{kitH5hrWH;l!><9<>BXC4@WwWUj%-x2O@cA7lG5wjXl}&NoQ~{JlY$=I-CE)qc4*&8AQ=CM@2Nva_)RNL1L~^Qra@pQ{YiV&U-Wv^qDQZK77sgj zmt&eX&$|c(?H}bgG9Jxpm7g0;4cz+uy<@*U=PAYQIjw&;21Yl{_;FM0AuxshBQmkNJZ# zAb-q*UpVobH}w)DMDr#kYW5#~-XyhP{xPb`j2d@3x8uria({^9Mz_T0IzO9D+`7djO8K-@G{4cY;TR%?@EIsD%KBQZ= z|H$Kt8u62IVCd2Dl$Lmg9ok(r?Em&jt$ENHK-XR##@vBVDQ|sVYbG57r>Vx%?0o?T z@k3hkG4B7_bZiOzVg5Cuo&t8yHxPh*O zaQ+P*Y@jnY&a2h@WP$T#H9tk*JXp=sPLK0j;6MYNjd9)z&@`@71>&61@_Zw-o2{PM;nB^ z8V^4j#H=t$OoKSH2G4H+I7b`AXB|EZ1ceFZYKiUiPR? zgvaGP;_Jm^;ho|UvX4s%O1|LmtC`>J@I%DciPObq9v7Lnd~Bq@IuV{H_Yg1rk2!w+ zM(Ky=+g{?M`t|SZM@;qz2{ERgh1gG0`DcD7^M{x(Oz||s7ijN+pQiaUxdRhPN_?8Dd?es!mZ#d2 zSU=5tY_{ePP+LAmnHMonwYRYTZOq5d(fs$C)M0T4@iPB!a@>& z_QUGphl&r+tEY(Z;UHpmS!~4>oD?gLP!LvMNwTRmCai`)n z4n99j{8ZZCJYGk*PWeF%{eL6AiS`F~-+Q)({_BblpD%u0L%)tr_Oi}nS9&VV_tiKF zF-h^k%r!ov2LA=-3nytmuv}6@|GFA{PVrRFi?yHcG-^+qYUtlugTJ>1zqBLX1Zx$^)?l>g(4>_OR$AwZ~zLM+p)FEoB$6}>V`_)=c zwa0j#uVlWL*UPuGy690n<#e*vXPQ1x79IB+@PE11zmW~L6EElCHYfjYv;GWcpTC>= zgBNK(x3ixI6fcD5KNBs+dXT^s)Jx zNm3G9v~9NR_YWtFT6Iu*+K@^Wd`HGIkOZ<7Q^IC1bq?#%gb9tZ2nJm*= z2i0nHyFJ&REmV_!NB2tK&Z6#>OXM8tPWDm#2IG0*j5MT%kyBa12(vk;jMg z`3+)IFH=c3bTmDM$pQqscWYKjSB5Dk$&jiAy&+e^iEa2;7$qu%8h;}Z+1&E$x?~7fQ^GuL!a85b~@twG_kQf<&4J`SvB9~ aJjmpe1A>Nw7E<1sWop6FF +#include "tpl.h" + +extern tpl_hook_t tpl_hook; + +int main() { + tpl_node *tn; + int i; + + tpl_hook.oops = printf; + + tn = tpl_map("A(i)",&i); + tpl_load(tn,TPL_FILE,"test15.tpl"); + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test15.out b/libs/libtpl-1.5/tests/test15.out new file mode 100644 index 0000000000..f0c2f49907 --- /dev/null +++ b/libs/libtpl-1.5/tests/test15.out @@ -0,0 +1 @@ +test15.tpl: not a valid tpl file diff --git a/libs/libtpl-1.5/tests/test15.tpl b/libs/libtpl-1.5/tests/test15.tpl new file mode 100755 index 0000000000000000000000000000000000000000..80a83384cc24bc3786bd3aaf847b292b8d4a8a82 GIT binary patch literal 57 ucmXRZC}FTGy!fS47C*?^cGh&h0m6NmwdC<4R) literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test16 b/libs/libtpl-1.5/tests/test16 new file mode 100755 index 0000000000000000000000000000000000000000..180a87528a3563b00cb93bc42e130333dad6d8e1 GIT binary patch literal 127639 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஢pU2B!pTs;VybEo_W7qT%%% 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

    7rZ-o^GVHd`nu) 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test2.ans b/libs/libtpl-1.5/tests/test2.ans new file mode 100755 index 0000000000..858b8f6d24 --- /dev/null +++ b/libs/libtpl-1.5/tests/test2.ans @@ -0,0 +1 @@ +j is 1 diff --git a/libs/libtpl-1.5/tests/test2.c b/libs/libtpl-1.5/tests/test2.c new file mode 100755 index 0000000000..18f9026a2e --- /dev/null +++ b/libs/libtpl-1.5/tests/test2.c @@ -0,0 +1,21 @@ +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + int i,j=-1; + + tn = tpl_map("i",&i); + i=1; + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,"/tmp/test2.tpl"); + tpl_free(tn); + + tn = tpl_map("i",&j); + tpl_load(tn,TPL_FILE,"/tmp/test2.tpl"); + tpl_unpack(tn,0); + printf("j is %d\n", j); + tpl_free(tn); + return(0); + +} diff --git a/libs/libtpl-1.5/tests/test2.out b/libs/libtpl-1.5/tests/test2.out new file mode 100644 index 0000000000..858b8f6d24 --- /dev/null +++ b/libs/libtpl-1.5/tests/test2.out @@ -0,0 +1 @@ +j is 1 diff --git a/libs/libtpl-1.5/tests/test20 b/libs/libtpl-1.5/tests/test20 new file mode 100755 index 0000000000000000000000000000000000000000..b591f64bd7d7742fcd0dbeee425017e0fdd70946 GIT binary patch literal 127335 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

    gOW(X*rVM*f=N*4gg{deX`0| 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 bUCx6{J~<$0IA|f|omr+9EFGiO;vD&3fJ{0v literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test16.ans b/libs/libtpl-1.5/tests/test16.ans new file mode 100755 index 0000000000..db2bed3a3f --- /dev/null +++ b/libs/libtpl-1.5/tests/test16.ans @@ -0,0 +1 @@ +test16.tpl: not a valid tpl file diff --git a/libs/libtpl-1.5/tests/test16.c b/libs/libtpl-1.5/tests/test16.c new file mode 100755 index 0000000000..400d83f862 --- /dev/null +++ b/libs/libtpl-1.5/tests/test16.c @@ -0,0 +1,17 @@ +#include +#include "tpl.h" + +extern tpl_hook_t tpl_hook; + +int main() { + tpl_node *tn; + int i; + + tpl_hook.oops = printf; + + tn = tpl_map("A(i)",&i); + tpl_load(tn,TPL_FILE,"test16.tpl"); + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test16.out b/libs/libtpl-1.5/tests/test16.out new file mode 100644 index 0000000000..db2bed3a3f --- /dev/null +++ b/libs/libtpl-1.5/tests/test16.out @@ -0,0 +1 @@ +test16.tpl: not a valid tpl file diff --git a/libs/libtpl-1.5/tests/test16.tpl b/libs/libtpl-1.5/tests/test16.tpl new file mode 100755 index 0000000000000000000000000000000000000000..4ef0eaad698fe07112a2734cc69bcbcf3242a21c GIT binary patch literal 57 ucmXRZ$YHQzU|?|6$kb%u0y02=5r~<9m>Gy!fS47C*?^cGh&h0m6Nmwbr2@SG literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test17 b/libs/libtpl-1.5/tests/test17 new file mode 100755 index 0000000000000000000000000000000000000000..403f8e5799fcc26d377b27b7dd8f1aff1590c8ed GIT binary patch literal 127639 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 +#include "tpl.h" + +extern tpl_hook_t tpl_hook; + +int main() { + tpl_node *tn; + int i; + + tpl_hook.oops = printf; + + tn = tpl_map("A(c)",&i); + tpl_load(tn,TPL_FILE,"test17.tpl"); + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test17.out b/libs/libtpl-1.5/tests/test17.out new file mode 100644 index 0000000000..7519cbfb43 --- /dev/null +++ b/libs/libtpl-1.5/tests/test17.out @@ -0,0 +1 @@ +test17.tpl: format signature mismatch diff --git a/libs/libtpl-1.5/tests/test17.tpl b/libs/libtpl-1.5/tests/test17.tpl new file mode 100755 index 0000000000000000000000000000000000000000..a811f623c7fedbaa51321b3789b96174f6ca0d44 GIT binary patch literal 57 ucmXRZ$YHQ#U|?|6$kb%u0y02=5r~<9m>Gy!fS47C*?^cGh&h0m6Nmwba00vl literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test18 b/libs/libtpl-1.5/tests/test18 new file mode 100755 index 0000000000000000000000000000000000000000..d7fcd4ae6d06213369ca1838e550aecc5fc9b077 GIT binary patch literal 127335 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�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 +#include "tpl.h" + +extern tpl_hook_t tpl_hook; + +int main() { + tpl_node *tn; + int i=-1; + + tpl_hook.oops = printf; + + tn = tpl_map("A(i",&i); + printf("tpl map %s\n", tn ? "succeeded" : "failed"); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test18.out b/libs/libtpl-1.5/tests/test18.out new file mode 100644 index 0000000000..c12a153fea --- /dev/null +++ b/libs/libtpl-1.5/tests/test18.out @@ -0,0 +1,2 @@ +failed to parse A(i +tpl map failed diff --git a/libs/libtpl-1.5/tests/test19 b/libs/libtpl-1.5/tests/test19 new file mode 100755 index 0000000000000000000000000000000000000000..af939cd63610e1ea34b73c86da6cd32b1b5c8fdb GIT binary patch literal 127335 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 l3Y*hYS3H- +#include "tpl.h" + +extern tpl_hook_t tpl_hook; + +int main() { + tpl_node *tn; + int i=-1; + + tpl_hook.oops = printf; + + tn = tpl_map("A(i))",&i); + printf("tpl map %s\n", tn ? "succeeded" : "failed"); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test19.out b/libs/libtpl-1.5/tests/test19.out new file mode 100644 index 0000000000..3cf2a7d534 --- /dev/null +++ b/libs/libtpl-1.5/tests/test19.out @@ -0,0 +1,2 @@ +failed to parse A(i)) +tpl map failed diff --git a/libs/libtpl-1.5/tests/test2 b/libs/libtpl-1.5/tests/test2 new file mode 100755 index 0000000000000000000000000000000000000000..d515e4a70d7d1a0fdcf89b5c561e6ae40e1dcf31 GIT binary patch literal 127630 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

    clv#5`r++=*E*WXXD@U1=yZM+IRWqa;rM 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test20.ans b/libs/libtpl-1.5/tests/test20.ans new file mode 100755 index 0000000000..56af0c0fb3 --- /dev/null +++ b/libs/libtpl-1.5/tests/test20.ans @@ -0,0 +1,2 @@ +failed to parse iA() +tpl map failed diff --git a/libs/libtpl-1.5/tests/test20.c b/libs/libtpl-1.5/tests/test20.c new file mode 100755 index 0000000000..25b0ab03fe --- /dev/null +++ b/libs/libtpl-1.5/tests/test20.c @@ -0,0 +1,15 @@ +#include +#include "tpl.h" + +extern tpl_hook_t tpl_hook; + +int main() { + tpl_node *tn; + int i; + + tpl_hook.oops = printf; + + tn = tpl_map("iA()",&i); + printf("tpl map %s\n", tn ? "succeeded" : "failed"); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test20.out b/libs/libtpl-1.5/tests/test20.out new file mode 100644 index 0000000000..56af0c0fb3 --- /dev/null +++ b/libs/libtpl-1.5/tests/test20.out @@ -0,0 +1,2 @@ +failed to parse iA() +tpl map failed diff --git a/libs/libtpl-1.5/tests/test21 b/libs/libtpl-1.5/tests/test21 new file mode 100755 index 0000000000000000000000000000000000000000..fa4f6b8611125403b905553d77583b5d7cd00373 GIT binary patch literal 127807 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

    {YrMYc1blouFtZ$A=iZIx7@-D8<(^$ZO}3n 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 +#include "tpl.h" + +int main() { + tpl_node *tn; + int i,j=-1; + + tn = tpl_map("A(ii)",&i,&j); + for(i=0,j=1;i<10;i+=2,j+=2) tpl_pack(tn,1); + tpl_dump(tn,TPL_FILE,"/tmp/test21.tpl"); + tpl_free(tn); + + tn = tpl_map("A(ii)",&i,&j); + tpl_load(tn,TPL_FILE,"/tmp/test21.tpl"); + while (tpl_unpack(tn,1) > 0) printf("i,j are %d,%d\n", i,j); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test21.out b/libs/libtpl-1.5/tests/test21.out new file mode 100644 index 0000000000..c79f83ab55 --- /dev/null +++ b/libs/libtpl-1.5/tests/test21.out @@ -0,0 +1,5 @@ +i,j are 0,1 +i,j are 2,3 +i,j are 4,5 +i,j are 6,7 +i,j are 8,9 diff --git a/libs/libtpl-1.5/tests/test22 b/libs/libtpl-1.5/tests/test22 new file mode 100755 index 0000000000000000000000000000000000000000..9e9ceebe6c214bd3e0179602ea61923c08ae07e0 GIT binary patch literal 127711 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�g|e-zi1} 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test22.ans b/libs/libtpl-1.5/tests/test22.ans new file mode 100755 index 0000000000..903c08cf1f --- /dev/null +++ b/libs/libtpl-1.5/tests/test22.ans @@ -0,0 +1,10 @@ +i is 0 +i is 1 +i is 2 +i is 3 +i is 4 +i is 5 +i is 6 +i is 7 +i is 8 +i is 9 diff --git a/libs/libtpl-1.5/tests/test22.c b/libs/libtpl-1.5/tests/test22.c new file mode 100755 index 0000000000..a69703b794 --- /dev/null +++ b/libs/libtpl-1.5/tests/test22.c @@ -0,0 +1,18 @@ +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + unsigned i; + + tn = tpl_map("A(u)",&i); + for(i=0;i<10;i++) tpl_pack(tn,1); + tpl_dump(tn,TPL_FILE,"/tmp/test22.tpl"); + tpl_free(tn); + + tn = tpl_map("A(u)",&i); + tpl_load(tn,TPL_FILE,"/tmp/test22.tpl"); + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test22.out b/libs/libtpl-1.5/tests/test22.out new file mode 100644 index 0000000000..903c08cf1f --- /dev/null +++ b/libs/libtpl-1.5/tests/test22.out @@ -0,0 +1,10 @@ +i is 0 +i is 1 +i is 2 +i is 3 +i is 4 +i is 5 +i is 6 +i is 7 +i is 8 +i is 9 diff --git a/libs/libtpl-1.5/tests/test23 b/libs/libtpl-1.5/tests/test23 new file mode 100755 index 0000000000000000000000000000000000000000..8dea6043647bf7a6492b237da2edeafc811dbc2b GIT binary patch literal 128255 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

    G0yw5fqqS1!H1QaJGy*4Y&hE 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 RDR?8woSbq@&J6F!{{tiuy#)XO literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test37.ans b/libs/libtpl-1.5/tests/test37.ans new file mode 100755 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test37.c b/libs/libtpl-1.5/tests/test37.c new file mode 100755 index 0000000000..6e619a6a9a --- /dev/null +++ b/libs/libtpl-1.5/tests/test37.c @@ -0,0 +1,20 @@ +#include "tpl.h" + +int main() { + tpl_node *tn; + int i,j; + + tn = tpl_map("A(A(i))",&j); + + for(i=2;i<4;i++) { + + for(j=i; j < 10*i; j *= i) { + tpl_pack(tn,2); + } + tpl_pack(tn,1); + } + + tpl_dump(tn, TPL_FILE, "/tmp/test37.tpl"); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test37.out b/libs/libtpl-1.5/tests/test37.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test38 b/libs/libtpl-1.5/tests/test38 new file mode 100755 index 0000000000000000000000000000000000000000..347f3b3d5f27314b0c731729e106be6d825a19fe GIT binary patch literal 127641 zcmd443wTsTwl=(XcPHr($ZjryfT#^=G*K=IAS8g=4GHYljt04oid>pRP%bg)ASyzn zJIbCWPCPmzUAxmnm^t6` z{NMllt?8;-wQAL>RjbxoRl9bxrXn=ip{k1gaVQrlEG_Kr7a;3fQJ#Oj6UVQVDsIKE z3{eIvnZU}xpN;32IXi8W&Fs_-Tz;JRb1~!K7d{R@zVLDQ@uesO#CK>o+&d6L35AlOcSnWNNn~du;c-Z1=ouXQz84V|Hqfk7MKC zKsmmF4nImP`1yP?WUp~`TXC0Y(7UU zS-fDxl7+*TEMC^Ia@fk!F~i1;9$vqE_(%{UZ4dr9#3`4}z_&GB?8l2g*7w05MaKF+ zUpeU04a;&@&%Qb9vfVEnxp(<*pSgl{XW-A4e@w{Ba~@#>@yAbl?!gOhKk|!J6aJ^H zN7)x~8*Ei}`Mw6_UR_`;o_!j4$!XxXoCf~RY2cTf23~a); zY2d#<4g8|hz?Yu}{?cjSk<-ARISriC?Zsc$PZI#An#bRq27cdZ;G0ha|L`<$+LcrF zyW=$QF%sUG<43OZ^C_~V~nzE;4tng5?LYc_!b@wFnn+#4vhe&!wNl#lQDI z)CfTBP0CW6=t8tomNqOS*|~FTR)V>R5?->rzFJvc3+m`Lyr@njpo0?dm)8N6+{>XX zoxgaQa%0_Mu)Ly1_ES?=U9C(B1t(6LJ92o*=u~#(@Czsn$N%C#TANehsesZ}@sFQ- z?)nAHlvDWvdBPe7EY4;RKd=&?4L8mcDQ#JAk+Z(+`Js$qVjBRdUFK_}0$$BggV0 zR+$Hr_zby^WvaHhN0k4AWvaBzYFKeJYp7qCnfHRp-)l`K;=%_>p8f@P|t=@;coSf(nP#iBfs{R6Wxp z$|G5(%9)BNpT{y)%{+1ffFXlfriz&dMR@?rR4sFlDEDHSDrL5bayOQ#O6F!!cCbtp zGB=9y@g*ozMa&ja{(@zyfY~U@pRmlSH)}=teU>@p<~&jU2g{slvr3frvCJtp{i6H= z%V)4$EXvQaOcP~#QJ&ViaGqZ&X@eek^yY}Kdt%&qit^MF0Ci)BZnSUX)Rwd*?w+DR z0TfZxjdv3}Dix)vZS~03RX|PTfs}T3xuR_2%(MOhtN!nC&}?lHeI(`rtK)6f?#BS3 zWuB6@t9G=Md>S(LL7R80@IxB1z9`}WOqnY15-uS`VI_N$hbt=~YAXXwL@ zAkm}8a&_a-jgC1xwxU;|z+cU2WmWQ^c6K9STUoO4w;yu?UpJoBw|{c6uI|x|UHaY= z4QT%qarLHs5xf2SvVG%)|GeG{_t0|&S|(OQ0p{$=cn2W$%N<+~di25#i+~V0BgI0` z8Le#%;LbRd+%w0#1x?Hq_-YX!{kFq8BpPeejVF8?*r{=kZ=*=p`yN3WGGe~XB3|HPLfc(_mv2KKXr6G{?hmg}FW3{4kUzJuA^3BtVru%BOqF?zM z(MBtJP;^MXH;VETV&q!UGh)1C=pf*_aYBz@7)G~x^K_rvW*TXVPcUEZ^KuyZiR0iH z`h44S@Un$#y>379`wpf-qeFQwp#W z-+q@&hQbNm*cpiakkn$ogDfkWKGkA79EuW*yL>R5T5K)~;u}QJpV0gbCUg_4=&l7(`-@*6< zUo!7fV29#Me4b#t%ZD+5`wDkZ#nMRx%XVt_wrN}1V8EwsTRG1UC2H4=H@6mBtbCVyIM2OG#Vnml!}YZxSd8>XB?g`BIcAiKn4-$z$zWS<>B4VHbX-M$yxgbbIj)dQNz zyk7tVErZ6cAb=rI(qbXXt7s>&LKIP*jgx8B=cAr|hKx@_ut)LIa$}J@@haH1gxmB0 z*ftl5jxhat^AexmOmgX2vX4Ly`zT1cKOV200mc1BZ1tX6JRRjQ_R^j5WnDQ6kB&o+P9-% zR-*;y^B5>5^XdUgpU+#^9P_C+B_o;1yd^A3YENSYC(U!n4Vg{m%|a!GWxi^|IDi14 zmGRL+%;tS|O){@YPzLr1z;xqkAC~SC-x1yTGGr|D9V$1M!hGo~#>k3OsFWqWm_%A?)> z0VNb)bV$;bdM2d`3PTN7Fv-&hr51C(&%^ zf7q)4D-dm0**Z}6`l|QMA3#FLEAHC);8KivQ$@bML05N}ABY-+Gk%&1#eBso2WABg z;h%!WeoTRG{Ef4q>+va`kOB7`ir40coVDJjqmfYbM1~go68eWlRR^(Glzf=X8&5Xi znwuvln~tJ|cgPPcXHKewc9d9@kG@k2d(&Lk$KbQVk ze_q6r)Z??=X87d!YM$W=mc3RtD;U4r6R%L>*^rT^@sQi{gC1>5$k!WQulKr;4~24H zPeOVD(hHED7@)`4d0F$qAue6rA1wP!izYE~o#Ul+x1z`7Nh0>cJ5MVNA-+H~WNyn4 zV@)PBG=;6uVvCT`LAzL2cLvqx%tuMn(wj^3n|5n=(wymFy%GVN;Q!trG$O7TyKehP zfdUgm0j9vYo~!njNfSIV7Gss?_akHLu=oj z@YHPo+znt)LV7X6sBHEXS);ArY@UI3Sl7{n3MZ}}r}R)?2AOJWDGGF`8~fSkNAyY2 zXHz_DYu`ov|E5pSj2=^O{Lc~uZXNdtIi%J}3#ihrG*6`*w6$^4RN^I&0IZbPnno`t ztpI~4z@(v2?i)nNU_b@~GKdQVTn3(TK}x1ukc?4okYD6tbUMV=zi69U_PiEbg{pM< zYioP6-v-6_I!!wJ%pd4Kk5-hll_Wa`aotJz{{t@UIr(#nvF2p%=Z;(c4-_!RRibFR?FC8Hi_29A93N z1W(10Lt7DAK~bNZowj6C_9viiJKE}9h6QZ&@g@HIb6_GwkM}`9)eF6rv;`VZ6lnLr zs_sw&Sh)km^6)Ex+cXN#{4b~p^#JU7w_+lbp|Vf3*!zHXtQU5br1l|P-F#g@`FX6g`C)QAl^L#(SF?-q=;>KdMFJ)i7H4A!9~*C zj=^ljz9eb>g*g$d{SR{hB~3=FTk)4Pf63g}%>9fx#3V_xi8;h0N%I!u7=O$N8b1if z_ca|Ky!zR3r}6A<@2gm&9@2|(l(YJR?=Dl;3 z7oEV<$fog0@OMx=9uweLq{B$*iyp5>NPbJ9-ag4IdWkP{CmzOFTMJQ4=EX>fo4iRL zE%pjPk|JV!+r%Nw7fsv!UXjMHDl~nNk>(5%ay>wa6`nZN?QOyx3&4cos*D=6a7pZvV4D?6;A>-1EPmW9T7y189TsmIpn;n-zU)Y~D zr7mAXBeV)92kARcxvqg%j&QczI3K3Mh0s-x7e{ii$>Z_YQAi`Cb_Ai4<^o8oGoA>> zNBcxTYW#z>iNl-@V~05bSR8M8yaIvgrxi_YYjpEm0c_-~hm3C$dp=1fn|0O5VUN*o z)fIiP-9~pI1E&zjL+W>l)##UG1JRvo`S_*zTJwjX&rMWi)6s^f+vz{BPRmEoI-NY~u)Wb6raHVZ>?PtiVZ{Wya8V!(cv6Vcv-lado)(gSz z{%P2iZL1fZa_uANjV~(1HaX$LSg@~Bjq6=C?aoMT|F&I|97|C1&7SB%$GS;QaOqCG zV^TUhq3&t~M}gQte@3qEMdP3_fNF;xUW8p%ZLz-nkb@hO9H0@Wo*k%fb5B#)ab{{g zr}XB7SyFFAs2jP_3WRTbR|L3?P#bHW_4qWzqxFbKFTs9hJN7d#>&7M6&rA|}bBS9o zdoi+0H=dXB)We>5A0a1gQ&qkm-lwbB2*v%ydfASK_jTh%#?^Os>I1D-7i-)oCW+Q5 z4t1CZ6|1(4Rdgrx>_cj2ytv`Qkb20xh`MFPQ?{KlK1pnV$%fR#`M2Ds(2QxDCgq31 z2SFmTBZR|P%)(`mZ^sr(?=FSjA<}{B?Orq4q}~vY{aIpm!qU4+sLswb#rqsPTA_G9 zBr-sVN(Z;>E-$-2U%Qijg2wE!I8K_HK5W?1Ucqq*5*@Fm=0lH9grS@$_Dm3w7Q3G9 zqMxZLdAjv51=;;?Liw~!dv$HoYkEG)jFkNwzo=!EUZK15z9A0|9flp1fRKf5)hinC{Um5z_Bd9>6zj?+On zfc`bGM{}{K9S#i8fnGO!W@8j4^ZEfC#9rA`9-mcO(X?;1rpMP5C-aiiB|Mq;6|z^& z!7O4soj^WtHMh|4qQ0F8C^_ig0zJ!u3yb8#oN)*K2Bl`SC-b%fpY_SS$3^aXIFnDc z*e^x>yUDx_fWrOiMu)Uih$G;rN?;0a@qn9lVV7N>llVYEu}09D~C$A>KdD6teYIvrthf5)F{#3yyWlI9PMFL7|SRS0*Lueeo5E}7>etBfxY z%4xA}Js_}lKlM6w($MNh0U-wTjW90~riC&smZ_hq6`UmVUcSN$0q{_qq$eVDnT01} zk6@?Q{uB|lrX}dff3)49HQj9GTv}5La>m}0w(X|#=(Dab^+zM!+OtSjkG8vxKI@2N z*RYI|Bl^A?aqh}OC*YgMImKiR!Jd-n1_4=pV{d_&wGHRL6TRBD5}46L7*kUcxne>pjn)1@ zdnN^{#g1jd?5y&Yt6D4r6nPY{>tQuIK^#$Kp@;IIcG=4~$P!q55Ta|bi-C$mhe9~d zQa#*Pk56{%=R>Y3(>OC|_WYm`0!_&4ks8olh z8CX)~@rAyj6*#SIx=O6Klt#s8dlJvQhq-B9sV4J|Uk*luP8+Zm@rf{Nvtc#f)M6UB zq7EkRBsOPRZ?1x}zniFhA6u0okhRYTFkOXUwCM=;c97%HcyBoU=<#C6tWb-tz)6p> zM|V#0M4xpVz2S;65NJj@7avleScF)sRpuF(8`wX8ufSMwy7npP3QBQ5;d{FY$3DMI z&dDwEY=gsi_`42qqlGND;@@5>$3x*<0Wy|sy826$EkiDSWy(<9 zh9OiM-&iYJtmKZLv_zNqhEj!x;#Bu7oT~&HZ%r0zvAxJbcNdX873u=CMJif$oZBgH zpWvNmG3B5k$#S+Bf6>B)U;%}dTMi^M4>N=F4r`ubwN^Vp)HW;~FYvs>(%{(TK)_6w zmh2--MR6R)mHSGyd!EJF-V$LUn%uBPl|~}e{GhK9-2ziQ*9yUU&*o$6m6gWM3gfj( z<6zKuH)y=tF}|k7*b{V4p>+!w{o;j9pRNuBqTgqi8z0;_Cx{Sjk}-56PR7c$OSZ1ym za~7l|*17R~^xzNJZ$^ekzs-siMZa}Kd^A4Mgd5Nm`BuIg^W8DseuO)p;xw!UHn;#X z)M5-d83fFRBoTvrYRR%=vCW5=w@6PomqP4b#z%ZZwb+H!sQ4N`=HAQ^PUa*g&9gh# zC;A8&Z&w&!1j9Q+AhI%Ke5Y?e=m^1Y&F0k325?ERc@drh;W_~XUXF?ONHcUom#V*u z{s8L#cl6wK4U4r0pqC>+S}4=>fC9cosW4_DqJ7jR$<_2A$kE`}V)2LwMK`dU$Au5w z&{IY=RtA^%uNHp@j(lEa*+&ga%`-6oF)zWe%NHMQISdTd6VNu{=o{ZFu;)9P%o}R6 z0Y%YbyU;8c?&CuUXtc{f1-J-g@ja8a8Do(l(_C; zpV3cLtDzn~qHXFUc6eg9KGkh55nBQ)p3}onl5*oUjuubur-Hyu*lzg*$Dr_);PUn< zkUueCuXG~-PH%@S;udzvQQ*Bw-sXZgo13#NeAsHBS=xh+B7Efx9^iU8hq2qF_bGN?zBS$jNMGn~cb~<~v7K@7&0m%;Fk*$C5>xy_fvlJ~j==&}s&ub3ZL zWyEjCi|cVDkRG(rG>C~s$RZ}vurCDP*fgoT6y=W>i%nN7E}-R# z(z&Dh#DOZ87P}c$o##i^1}ypsj#ArQ<~6Jn#jd6uh|ek%p;0J4v9!7B z+vst}imbS`=Lv>!C&qu$egN}Tm%$xt$>ZE8m-3Da5&`^=?O4si_yQ^GKsSK={- zoUOl1!cZOsld}9U%2>x9^S*RJ-9@aCHYAyMn~n7eW`&zBPfCI{s1oaxWAm8Pp~#YS z$Zj+klB0kS$0%msuhPU{BpSoan**>Yh=V{7lV(p*GB3*}q60w^{&J!v{!+6Vg2l5G z>*~#00?d;DxnnZ-ky}u$1yRL(56iM-pXn8z3i|l}#eG2Bk#mCqH;0b&l(zt%`wU#l zJAgP*`O$fbbxIdKyoh)I{9?$T2}^IB4ebbktX;jy5>r#de_a=pFZKka!jZ>8Z78Rx}s{4dXo51jJ6xH;zA2)Xd4 zXK~=@P89<3&?Qrmtvild?AM~NpWycGQ%@kfZK6X6(!;oyyWWRi5hq*XVj>1C?mY#J zwkLsWJ!8fbg+$#xNEnY1gG9RnXaM5KI1aG5Cxv?YB z%SLHdX`gm^9Ne@_r{gTIXSj3ghkxZ8v6Yjwe5l-@2kUBsR zFHg(oqch$`W0U49a2l}49co^+U+Fj-^Og9|y&OiHE2!=YmHnVIlq)52bSEMh`0HfD zTf#ziyd(Ne-Rqfzdp&5=8Mk3Gk~*h8fO|UJR{kHHQy*w}%WM_9&PGUC!PFs2;N1?I zPA_MXvxCPxc&daG*P$1Ctz)8gEw&l+5;7p^6O{CQI8qE5KXmjF{058O!BY-A-O*xy z5beLvjnB#<+UOqe7e3JR=9;&n-z6K~PK*SA7bSBddvRMb@)C|HTQ9;9bJ}u!)8Lgq*O6G)8sY*;*?Yej2eHt~Ktz5M2KUh+w3xK|Op+Iq#+&YKqI{3I=gk}NTUj>N`<@qRxo@R$EM&yQHTNOJ4WaG; z(st`^I&#W|ZTQjw*uWA#%x@GqVa00c7T8xKQY{w6$%XN4^gR`Z-LEzAeOoJpszikz zx6rn7Z9#WxnPT&%$FIZ#<(oZ*nL5{vzQ=R5!pND?V*kDs8eFfr-Wk8%Rc@H*f1Wksa_fH7 zJl^67<0eUX-E`c-$Gx8Uge(AL0U+~n>ua8{ez^U`5qrsm*7R$9>&=(qQqSn|xDBZr zFW^C@wXU@-xbv?yeN7Br(=)pJ=t*@v)76Xq!E7lXv=*Vo>n!1L>ZWmCYbk=hcx11~ zyW>fI9Ma+Gt5-Mh=(M{p@y1Jt_L{JqS-T1&<618T4}T?Bx_U&%Ef|j${U=I158>67 z5qkU?p%8p5Hdv28;oFGX#LFNhoY6G69$>T(m<^yXABYdApJ}J`jNhe3&}UL3m}2ZD zZ-(O6xy=r&aA8*`SeJmFRdJvnRNM73*wsB+(;+P6lmN}SSdN|hf4_Ks`XNt!h7zs$ z3BeDRSYjsp9^g&Kz$UK`Q?*0jcOz19*Be5QA&)`e0uaWFu;m*|=2-U0ytB%@mN#(W zasp<8#sD|KL5+vwe`DaX`~z;{IL4 zR}1x~fD6%3iN5F1i}3uOm%Q_F&kx6n`^A8xCyKRbHdLp@_(FGDGaB9Ho=}en9&7bH zJP1MMggPzeL0=Pa?(SpSP}8Et1~G>-`EsTKEw-5HMBLeATBF6TWr`Dc0mu3K^(^C* zekoI&(JyCOpv7)LTJk1Thu7K8XYi#Surzn=5p=E_|9}$|d4;F2e zWj(5BE2hC#OoOdJq1-o>kShSW0+6X7UDdeCSE@8*!4$AvW%FuR)4odMgcf@g^8^#n zd^rY!kThg`tDnzJo|6yv%CNi9*1ks+VIpRZ5qgYAxS$CQz8l<>H`hUgClHq+#z{Q$ zd@?z4munQ32OiT@s({b2-qf@7Rg4o$5k?6XyqKnErQVF#3`TaP`3vlKY`hRFZa@V@ zVNMXo2j!fxj{hlX>)bDd!q$$l-1yEM1#xW!M@ome6_cxUyr1}C7o9zB@!xX+yyvgM zT-wvzS4;z2sjXOaO2=PX*Fm?rgT4-!!rmqGZe-Rrw`K{EVGNaypKhfW=!kBGi%`s) zupYP4shP`}6Pvke=EOP1Rm_Q9@>J${Kxa-tuFE=qeO;AP-1;pwUf=$Sb?3KA^{-p$ zNEv`v&Ew!e7;7%!RCw{mXfjNzf;lm#+FM4BWgDslbQVNooWQPe_5$1;$h)0QQUm)L znnVw&t%{VuBGke~`8zSj00SF^))iqPs}um7aw41rAhN?-t#k ziweHGlCp*7*B~KO!~7f;JZ(S7JBRTsJbxY2bW~hmj8t&gYuo2B^;fpfbL?u%jRNO6_ak1PzpNOpR+g z$;getFdoHqm-nD%FR}NvIBoG%hNr-?*TE|7!X5r2x>1LFP&rV4J$^IZ^-5x28y~3~ z$Atd~Bl4+rryeGsbQdaE*52?A-itto4L`HwDc)l!O>@;!zxg+>H{Uf$*7SZ=}i+O%G?vS zLy|lWy(mL#`WRY|^S)qwrWfxLI$St6^qTts?6e=C5t+!w;vp2aC@?q`biMG}i_j1F z3K~Nm)K8&*ZyAh;uuH+R<7JcDSjF)`|+oyQRl{u4ri+K*jXXVrT zeA={cO`X_ZNWHXICGM;vJCM!n*RUWIoT^~_#a{7r1=3-t)`WKqUA_ovEynH8RPYr0 z4g`3!i}&#=%9i717vG7)h~1U(Yq5?-=LgldaBVZvBtn+azC_Wpuoc@8KfoUh)MD4c zSTV2^VIp?6SD<$xl{VUJFIO$eAQt3X=6ID*aGCfMsPGYxTio2i;9?w#67M6Q6|CW- zf?4^&_>DNq-Is^~opVtH{RPY;_wm4i&V~>05*BU-B5?gY@e`t|Z(AaFaWLVmlhCp6 z$2@<+JuaTNS<`{D$AP%6Fxji!{u#9bLu;N2GJAwhyqTJp^!sd3bKGYJnIPRbu4-zV z#_8X@E9OrR7mIssDsFm(M_Z2{aIY<>ZQ5hsZR09AV205i>l2U7#C4`VBc$~3IvS*> z#fl&_&W4CLKF7_##7*0=i+fKr^J8gVoXq=txK#LfsriFNPY5~X0$u}x5H=@5%!pZ! zA)#NrxxNthpFJg?CQ5i%6Tj3GS7BBtJs6dyN8wU<6pAMkIOK1~{MLb%y&50EjEU9= zgl@q)B3_j{F{=%ftjnkZ7G3F4A`PfQY&ihS1G7rZ>)laBHG}A(bG^am^RT0-AE4%! zu=>(Yq=u4%?uDZhkYwI>!>qBJYcTK>)*(R6ofsl|!?Wbs`5o(1b-P(NS-4m~?)%}g z-))EYU?Bgu-hn;>+SszH*by=cz^Zi>Q*KcW>bq9FFpk(+54 zJa&J0Z4q6{{%{SO6<(mC>-@xow65C#w7Skj*CFFQ**jw?{KCNeRPTRzt!wY8^&S1# z6A5?ezO#2R+T91xT8uU_)#~nE9MxkpYP`FR0zy|uaUInfXy{a3!B4ifF7N}hz8T>+=|7E@J$P$F?zFBhYxT zu?{I_Qyk%QHgz_v(qgmW3ZhA;7Hh{`MU!geJP}&yH4LpT1vhYpw>`(se(VpiNySFh z!|iHaK8bsQ7T_HU%l}hhin$F7e_8Yo>@4_1aaW=*hE=i;9x%8^eMM}TUF`b1tTirN zG=DLAOwrco0J0Til*roXcW$leOoSYW`imp*gNPiEEveO--m>h<<33 zih1+T@JK%w{xaxnK=b!G%)|xHaP#>^`UpRvlrgY7e~R|yWgpbN#JEIjx)MbZ<(v0n zmJ??@4Qmd>94*#{a`YG;vHgV=4puPq|78(E{|C`Q>mI~{^59H_f+nx0Nq(?msyH8F z>B7kIcoHvn^1?gD>M!Kn!@OZ#;T2g94)?w=+)#KPPA?_(=i2!|dko3B07; z@q0{(*z1d1tAl`JukzKR26VXF#=gn=J%M)&CiSxdcu>fn6*z?I^q&peWaF(%)`!~1i1_Wp4_EAY!RG7WT-$;z=)sfY1DXyo4_=IbJ_%DG z97|mHCjO3PVEzVFJN*f^G}iAC{OMdsmz?tV2*AYCEDK5gfjKEe@yeHZ4M?Qi#eJw2 zKiwiGDVAz>v&dZ#O>3Qce||E6)=N~qK?*#0Yq<7D5I2p7v4X^{n04_EePJ3Y>$R-? z@PbnRj92(H*NtcAW-n+ZBx@b&gdkNJCm%QmEbNaj6|s;TAn)OuR_IDmZP%v?gw_b=e2 z-JC+4LPP@DJ}gkV5^qQ$oCAc0URKXn0b0`5V)g7*N{&)&6Od?`Ifa zPZKx9TQF(ZZKs@28_LoNoyPyrDW?0MbtuDqczBBm@gBpegbU^XOULt#__<51=^hve zz6?M=adZc+fj^2yM|WT&b01Lo^wG;s@raR6RDh%;_8t?5oOk{Q5fC7I#oFCAn7tVv z!z&kKXmD&CfbH0J_>b;#Gz`W!D0hg4SidmzdBPO>I_#i0PHG>{;(2Da+@eT-# zDt8b@xzB43qwuVKFb5+TFy4uNgg50s#?KI7_X-<^j5iT`PB0r=BD}dJWHF?3X@eXLChr~#WV$%~KBt-cn@9?%Oe8rI# z=;%bgqWcwWKF_PPEmyc>xO+1k*d@C=?NRd$YUA+&t^8%|0de;1iS27RtcQ2&+i?`y ze6?E*;t= z5or9#9T}o+fknZop%bTu&UJX77RQJfz;vGj00&%#idBpuI9=v!A=4PA6|$INzeoRu ze2@O)MEf>*tbalGs>s-?g;KqRp4cQ{I5H4?zIlmtU_P9V_lVF9qvnU zjLp+ry7OwBL1MPek6>*qzVV9=d|tdC07=l;e%pHrmIzYT6wsE7@(IuQ{;; za$zovcHB_LU@?U8PFFOY$GQL+>B5E`3vfGp-g@==L0 z-fa?lTD&-p9pZLfeV)H3!NW+-r#vVy3#@Vwmm>;;_=P7=;x|w@b2j`3^%G1_haTa5 zSz{MxVEbqI1%S~$W0!c#_%ps`jMKn~&mm@^>xk0%{HsYPm)dXt3wnqsToz4q^iA{x zHMEo?K48gahq(-tEV&zQGXn+er!kAs54=x0#Nu#ZacHr(F^G0$F!FyGZ0+iP_rjI!}g>kYEvy;Q{=sIaX3t+d;VYOGb>mO`ij zIC|_j4(zqqCa6I4*td}zTPH|D8-U0AAh0L$z1f+66bc$yz*mEQ`3KBlmsf+V-ZYTq zqg1CPba|>no>#UWT43=}ngYK=uvcOa0=VOj#Lb(nICNM~loJEdbJ`K~e)DE5rq&iY zqR-BPka$iEp~o-|1abE7k8mRk{}DaB(!TuyqrMX&uZU~7_K)*XyeZKpY***;=%DC# zYGi_SB-vf)EzcugNjo2fyzLXx8_+o-;GyU~X||(p>ZNr)Dy(zl6`YO2jCvXSUW1-s z#-qnF*hD3EY!kQ<2%-40!jAr;ztlP9C{V|GsDypvJE~U)Px}3t!lg9PmAKkD14jM^ zaYQMe+1-F6$|q=Z<2SfNWuNidLr>i}l9CVaTOvF!4wWSuz6|2mA7K6-6io00F!lr3 zgvJiVneIy4XW`eUc;FX^pM~G+fQ6w&Dx|q9rn&o9Ke`2EUNU+g{P6b+__Gqb5l*-( zRlGrpoOC}A}IU|v&hsgvr;aP0P!w;`4&>mp;hM#6jXt5;h zo{qc1a1%ZCZ~h_HSGxY1?*M_<`@MXiW}UX>Yg=&X3=v0cw-);a23@j`?V9V<#%~d4 zyk^B2sAZh7Pv8E&1LE?i_Np|m2T3U!1g;P^g@GSE3hzmH{>KtS=iw>f;?mSiGzu68 z?8Dq--kbqqI&nQ&95do^FF4`chwx*KVk&uhVjWN?wm!zOvxueVHu+mCVxm(!fOA1j z%rSMtJVa3;Af3m6w5p^{{6uBqOPp{u@d#YlBduu+sF3J9>P3}|N|T9S;btZ6(NS1l zK6a`~=56l}Bbo(t%YID;SG8XAC_Tr+VasAaM3kEaMFf=Wgmc6zlySWHs>OEG@W*St z(CML=FT*3wEWISLS(@rFN#p`z`A6Kb{=PjJ^;|2GQ20Z7-ue$KQ0H$Ce4j7R0@_}q2PZWw_3`_0v!Y_BUwD1|5c<4nT zbouainFED^!o@{J%81C)+7XfJ`pBrU!y~mzl!j%s^TXFKUUsc_@v?>0E4?M-6vgZH zb_I_d=e^FmxZXQtVK-$+y@Hl=ubm%RR9)w-nZI~R^}=!9A@$t|_ExV9S645r_b#2k z(u-fgzBaN*G+N#e@h-3N;%Bdy*WF}c*49JeDlcXbl99%-YXkD`qlCfx8zw>?SI*UdAiZ^Eo{iL-^=ZPa&*s!$LyL96$aTvjqKB>`{xLI4 zmd{^!GBW~lDrTq!^Xuy7-y{_Z%C)#2GaANE5VLL>I-T!LF(F2QNw8+Ue(|--=0_Up zs?!>!b9^!%KUNHDB?OAQj)+QQ)$xje_)q}Wsu)LQh%APJ0p?x2bpEx~UZ{JxdSP|F zx8icX4~h@*YZlrIY5oFBTNm8qonKq)4daL47YO+(%a$)2R=d0&3b3Nuiyw2Z6Tc(x z4KHt477-IIs3}T#`Lf93Ya5m~)O!n3>kvx6Fbs`Y=v}gS>EZ}`78*59%%D&hc4aLS zh>`L@0lcNgb+S;bhFB|em)GA+Jtli~%P|Mb&QhR9c@R@Gf9bV?XEq_Kde{`TlC*#ahr;QTsmFdBM zgMT_YThFrSE8bJ5Er=cXsg-G|Oizd36`qjvk4X9l2U+yGrtZNO{CQcw;WT(%+u3EW z#J{D$qSNL(by_9i8)T}S2Jdw3ZTRM47X22PCeN|TUDMgJ-urLxy0-iOTRCyQH9oIQ z|4;dwS9EIm{GZaX@jYGW{l87$?&oyr>H7P3@YB_wuAkGv=bd}9JZ-vm>K$v(~Xl)jkozU?F%J-+YGDS%2}sQkIb~- zjWR8j>FMyh!jDM$8?UtJe0KGzQ&qz6y~?T|Bh%C2cZI(w=__46b+Wt|sSAG%G7Tfe z7FwytpBsMx{P8o6hL#Edu#qpD}LZ$^s`B~f$uCEEsxQ_7jPheW1uV`Yb zR-mhAIL99V(g6HD_Fu^)e=DK*zwysEpgi!`I7&hJFjBsyxqf3Z$vgh*A511+Li*Tm zfroVH!@vV0p+}R+$B+)ik;+gfZdT*8lh0&$&iM?|UpIdn`mc6x;vxNDsf2OuohRon&%!rlKst8%QyvkKu>yK190e zpMYm6O7}0oFVa48@aoN1DC$a&dPeswcZ-_kA)J@#Mq|9^NgO7p#*%2|2 z>xnup&GkC!b3K!C-E21je|tc059_Do?%}+!&2;>&gFH7P1^l4u*pSP)#rV zuTY4Ixt^anDsuDhbWY6mHoGR~7Ou}I&n><^Gmu*v%?jl<2AqFayXBTn$}JA$76NBt zZa&&f%ykEIK*xu_=kT}n{$!FbH>1wmp0=p2Mz@G+W2uX7v~9EYG+&T*9IHmZ)x zPf1YEafUd+$v^6<0<5nB=?BrzhDVagw<+LGzB}cW&UcIIyo}_2%=slbVo0azXEhr9 zSilq==h%mSkNrNGTEsS!$9M^QqEd(TB&rW%#+!vzV^EeZG z`((MFihmt)zaPwiVi&nj>7>W=@Yz^zH%Wee<`DDPNl)mHkb5ZC@6127`sjin_1J}V zx(@61YUJ$?55xunz6bDt>}S2BJU9P#jyvjdJl-ugA8R5cHH>;40{#)K`$u`=`LE~c zlH4Pz^LMA7C!yC|N52BSsvXJXJ;+<@X#Gj+i1uX<>gT~eoU*^pbyS|aQFZ?I)PfKz zg#6P^9fUplEf?!)`JY66o|3!K;oRsrrJhZqV14+z8ua{ovEGnZ%5y!A*;tR|IkWH` zux8U*moeaN0NyjF8%L*pPsy!yo_T7qS@TKT^D5}MVLy*ceOvEL|8@0RPG zB&H8$M9*>5rkAlyu1YUkibwej1%I0l;0grn?&;+t>=vw{>R5V8@mPFP*H(evLD==N zlHQ%v<7V2y^;}oCXJAQ2GlRKps$+XMu^^y&Df1V|aXt)56i*WCE(K0oC-fU_AHqJT ztq;AXX&X0E9Q#xITU>QaS75uUb*D<%=H;Hx&CNYv+GXh&m4}~LN~dd zrUUO0;Bnb>{djx$Es&i`1Wpw{;$Z>O?xF0Js)65*J-@Yq^ zwfLDQ@f&4o|GS)3UDnBzNt4ET3-Pbj7I{YxA3MB6848M)a=8WVgOWhBYfrLl;m?Li zu<-2;=3Q~>2GfBl>8t#mEcKVbn`W!kDcU%G3Eg+>pMWZ-J8LX@ajNb$Xy9~YZ6VN= zH9-I~Zxg_bW+X0G22M)RAma|KJkg(X{Ze2%9wJgRv!KS+m*LKIlLx1oxempwG59** z`hl-Gy5|7yI#I)R1xj{LmYnL{qUg>JvgndUPd0y*z?C73`Pq4B@5+=#Z}$B}&XUE# zZ2q>s%Pot=*`ryTEsLeu3t8+Yi~j7FS?n&0dNzmS>LH6&*}Tl|%9X|0*-KgUsJ{b} zqhMb4S!~-&-6V>OvI8vkQLPcxX1~v3zAQ$vSFt!ijUaIptjw-u@htTcB+i0HHTzzY zK3knF%4^l^A*}bRe+F%5K~&9ti)Ej>QlZf zvOHFnH>%n1vs^06kEq!u%Vn~>SY5<9cNVm%+264KBK1Yl z|8uI+?R*06&sv8D`L0JO68GPrey-nH(ox)-QRDi(B^oIyiQRw1zUG5 z>2*|EgukNlBe2t3ossQaIL|Ly_g1Gn?pmVs>LCffMq2m-lA|8q)76sR>eOr}|G`D^ z>2;>W{0dmZPR3Mvoi8hUVz?ozGTXT-)%L=)wu?_{J5uR2RaOo|+jVwZ{>zNw)8{H# zJq6VkcbwN7F`zuI@XSZ37OI-}EepT13Vqc}ISUO!L@LMDkGT0tU-d;++$@w)L)3X&KWD_r;=0SWg(y zwV6OX+3Kq4=GJj8I?HGxJ%<;oGUN8i%r;>R8Fz>*W892&0^v^(OvX%VL$8*r$jC%;lbUSzzH{$_;SxKsoi0ozTYm3Ncu!AR=&2U3bwqyo?X}n5ZaX*o>WU;UZomGxo7K?k(S>@JIX4?3%y9Ity#D45rS&MK#u>cXfU1&ewFSnQ)(BdYE3 zK8yLX80kT0l`{ZuSrd6>4?3%yv(!aM=&X9sS>>FqGAMTztW|pqVZB%F2HJF1JviSv zK6QX7uTy(8vOG+E0STQ|4^CXp7?o4uEZCs-c$4L^vb<64L1&dyD$9?kJ?N}*%4B)7 z+Jnw2XPi1rwBM@sptH)EAh@Tq>Op6fbCJrk9%liZRW6-Xj&xQzk5DASS>^oBl8)u9 za(-_K$8uIVk6W_wKt1^SV1}DYA(WNllB$^Drg{iyu?_95Wa(HtE!~G}&{Ow6p@iLw zxv%CD_$^rNe!+i>lH0wRbr(J%N*;GU>n{48DCN8V1j60@>qKdw`{y9lJ#e=udEJ+? z-6V@a{C*iRE36(0-5(J15^L&;-DS{`?w6UOU8$R=pxvuz4IKr3cOe#M_p63sSdIeS z{SfP}wo0?zJV)w2$0{vy?_z(~aX3&1C7Ual?~e;1;9p2D1mitMi8ZKT1yOW?}AEC#c>SFGBSnK1Iw*ko2t5( zRm73?E5T&$W%mQxOMTp~QydjwC-?Fv1$Y<1T&O*jtc~EUICtu~NZet3zrGWQ?gbADPO&H6YAVNWl&dJd@CYGQ`fM9a$<~Tm$+a_%)!QL zBePkHFup=H+7pS8qAGs=05i`qsZEv;-MtqqP}JMU0m)I|akpS(b}7GixS>u_@Az2E zi&x1yh)RzdC$7cHdaD`O#1PdM=^DTa`*g5>bzK{|VoUWNLbLu3)O_{c^~m?GS*WNR zY$Z_1`7f=`-0prX-DmL#zr|MSf6gRVILbEuN-_S*+afL!*-B$xd&!3y$(_M?L3X0{=l&wrgj=1D~p$o&?sP*hJQXFk7$ z-S*7fMdTy}(o4|D|Cs&s&SaWsjjRwpj#jqP8E}TIB!=xE@v){g4vd9a$g3v-M2NtVEz}N3a=ERWm=5S~;GA+q$ z10l+Hh8PJ2Aafkk3^Atu^Q{I%&A*kZHZzmb?MKU|&Jrx=|3JZ5c?xE>B^bfgPsB*` zSCe;{ZzZ7%;Gue9fY@Y@Xp+B@b$cb^HITY`vC~4_Nkk0)VoOWsW3^rE6iPu!TUfl>MzDFmc{@f5M`h`g;wBI)r#o;6Nvr! zyc7^J+5a&xi9F$$T*h4k)dI9|_H|h?;Tt49cWyl)j57MGXpOuWBGuoS?;3{2Xg7lG z2FrG5=GyHBTkSrzYDKT#bmsE~4WCV8JZpwa8cS0&hNsaOF8b~-Xvlme#Ew>-JQZ8? z@&-`Chb(gHJtPO|A9B&uQpz7moqL7$p^p^i3qb2H)TfV7pZ>xPS^2)4kUo|YoH>G% zz09rJJ6HQm^Y@U3+NdeYS;9Rm6D#}!0DGQ2zgAI~yBV`P@7j8+w}BLD-Nbd?wddAB zu3SIRVCHc&5(IFtI)m`RIIM6l9IQ@teyPqFtX{#kN>^UFX)miaHmoFC(Awdx;Z`C_WaXTtPNgtWXL(@=iyraf`pwYhc8 z(0y1%uV~hozLTkXUbYXL+hK=MH|!w3hIhpnaSYH8KyZWuCX^^|G`U>DGVa;{Qmvw9YQ|j~Nw?ruS@{pELAH~x;fqf}v#k28 zlh(+c681;1G4dl>XhWgo3t7N%+c~|&5VM_sOwk(I)1q2tRjGcZV5S6BS|A5DX@gct z7)Mzx;8O`N_=AM6>}>vy1l?_cvYj8MI{QIZJ#JS$AGXIdPHO6IyJ~l;Ri&)@(5^a` zYBfhz9kZ$^)dEApdiR!t?d<>8vTFE`sz&`qRzU;OIEJYX0XM_VZ9;~78otH8c`<;a zdGwP!Te+Yc7xrE&qOcd-+r6!UT|o^Wh=+GYzo+i+6(P_Q0G_oJPG)Z=t9rwBdhaEX zeVKF&uqms@(9?V-dGewo^^Hv4i5Yt*;Qv5_v1^g>V9EP_kXUbEYQVi(LMyfc*{O~j z(QwcqS^quihkyhP)GB;WSBsTFKFQ~RS&DM0RjC%EDXCncjvTE11Xv^INGzdT*UN%X zuA5~6%4Jy1vz=MF{OSLShk|9XUu?>+b% z!JuO(t;t+u7BI6InGMYFTKHMrky(#SfEkim$jpPt+{er&WcD!Ah)foyvS3&ri-8xQ z5rS#{TfX8m{tvQBeb1_M-L;h#;x!5W+JZXPKpBom*kB1;Q8bqKUyCzmKPy!mGhN^> z&AxZV5cYjH3DLgi0a@DjG4vOEB%LaVKwY0%eiE&V8UYpUO92<{U+ru!__;sd;^PIG zstYskIf=&bt{8&e&+{d{_mGkN6#O>NqO}PG#3a|*lU$G|hy8+Gm70IwR5=2wC0Fkn zv3f7y3a>B3Iu)yZw)3vdYbJ1xuoe~N0>jDST3ZKuvgZu6y2m@8iuxq3Fq{P=wBE&t zdIK&v6#bR{cfE+!j-h=1WYTDM(f`gKi1IKljypyD7L>vlB>~PD9s;`k&}G!W{htW8s}${I+t2*Z#S zciCKQa~%euvE0+WiXMh{MHu!GY7|B2`I0j%)(--pZg&mE^mej;kw=w!KHVo-egYXg z4r-OdZvsa%(U4k37cxEDxl;OJI)zcnAcySbVPM{7VP-q|@5S?j2JY30yVU0{JxB2! zkf>5^U3WE#XeyIwfzaF4Xwj*+0s-syH}sj~9U_obUq>H(=_|)O=qr^n?o{VVJzjj4 zpWP}whoHq|Xymw8P@8$2-@i`J``-pcb&dEMNzZd202O9$G&4EKJitspWG+4znF3_m znHh%631k8$S`D7qa;DYUA7#26D`Z3&a7Gt`g)v-CU&|^#gsoogco!IBUj%#>Fh)8g zv(H0vBQ;qNJ~1QWP?s%z(8v@ z>!l-rZ73+0^}}VIyHFW5LiQv`r6MNfLNCT%E9)w~R_}LVIO-v+*s&8(`#}*hQ;->W z9wuNUGH{mo{`H6}@cjvZBjzA;!}-Wui_F8!)FYEI6qz;1gqevWb2~E+AoC0}k0bL1 zGyGBCqG8C~iwsYX$8d*vv*fCl!VWom!{UtnBjAFchmiRNFfZbRtx4NZLSQwN%_f~~ z4PuH+)%ngjcGJJ3#aK4|4w>OyF~^e3sNs~qV8EupCp+o_=cA-TlvzL#oZQR|$^92H zzAI&i457Kc>hUdtXp7pPWwqAj%d4V`I=1C>z!jc zIppQfKoh(iU`7lL8Q(sMYVk7N!G$=L0fZ%^TshHWWvX83{FzO$q*zj%&I~Euh>Wj5 zqNb0I;h#Omf}L`@eh)%j^fe~A;R@bkRXbL|K)}5z6R1iIUwoS-)*)dvXMksTxrvxo zwZQUnRg#6>gZ-#Npas6vyJ0rzs;Zp z)H&y00|wM{g-45xwmev&;PPpfmSN{_75~X1PfCkiJSrP^0hkhpWakN{H=sO}r_4*_ z_#^hL4RsCjLXW$`hwZkU23JE=;x;s?Z$#Mjz{9!F+)S4`3AN2rk& z$fnTd!0cV>8a7z+)vZ*L8^#RzszS!+80=?L#pcV}B(4HP@b!h{=Np@^$*yXfV!ciA z7dFKwkx?#IoKWim=%+X|y%7a#|3o2SywANa!U|pz1K&_Q3R%@#wZdGgh zJ7?y6?>xEp(bxC)U!Kn=x!*Z+=FB-~&YYRMJr5$1n@sm>os93LRimNxQg)ZVJKYH6 zET;3j&R|OK;K45%H4o9mzPnoajX1E%@R6n0kb{UOb34@`Rc3@JXiC z$;6sU*_$pXX#UiT7$2$mQ}0bCe3Zt{>74Yo51vTX@6=b{-5zJ^tM$LsrNKk><@&ocYwiS-0!^u&N<;N!`@1zO-x?UI zFWsB+Tq<*}HKm)lR^LUtN8g%%jmu@^QrDDuBYNt&LyVeN$Z<4n8con{dr#qW>YNsM|MS4|uvj+RQjjXO~adK))g3VItiR|>EW6? zlxI*26Nf!C;V`-Bt+ z%j@~{QmWRQiZfm6)>+17ed>IsHgX4-zu|E(wU$jW<+N(nbh5je zMn-jYwhf)lZm;VRd(k|k-o>7As@}t z`^IBTVLR(^mV19D?HRI&?o3D_A7qas_yx7ixLx?x69XqiZ?ZG;!jYz}4t0B);b_6< zNiW6h$~A89<7wWp;4&JS2^%4suVZGk2-HVjq zbpq^BLEs^xOkluCatVP6IZ2WZH&IEa!&ez_I;^N9n~mnL9B;aAByP9CeGZzhB$f%! zun6|bLFbU>ZwTwX!~?J7{+Q--PB5}ll1cUockl_K`AZ~CYo0t)G@r6H&|llu8-@71rOz$v*hUWN*nfdT(dhkGi9Wir#BzS3M!c z6WO0rDdR<9J(75!_hToS=Ak&`SlJ{U7n2zG@W?ur&9SmJN`M#3XBlv;{F?!LeA2np zZ6|ljOXo@|X^+Pku*U~fJM_u;R;I*VP-UW%zU0`6T&H&@&l)=2Tx+EZyqI-w8)`3g zXSHEZPGgh2v#5^ga$xglu#9>Mn#;mf$4ju?5w035RnLU0&X%gT z!c|eJ`YK$tLaGj;?B6}OGuBDfiQ%d@r0UFY)yGmbCsZ}E$7th??)}i+6@Koy*U1h& zPfCsS{qJ5*fqqop9c}g!InwkwIgY0J;eJcpW-l>XFX$aaG`I4{xVQ&?G{1+CtCv}~ zc*s-IoVPF(2j))rA^fPkdzsSDRk)3`W9COTE;Em8&}HJw4dMk_AYTEvLO*O^o=y_1 zpJuu;?h%%&^dl_#v6ZX+$5uM^V=K-f|DZJQZk7j&wo$K#>sx-C^({aBJi})FDA3_Y zDb2_%srsq82lazShw-iXhs^Ut_x2(dgUOvAkS7b=3byJ`O0VPF#qOLuGXhVs`<_0@ zY`y=a?K@yDUFtZZw{F8jF=`&1xkDLe?rR;YHGExL^|KmU{*U2oYRa#1`BJuNr(#u) zsHM$B@&0~%8Ulba5_NdVKlKUq@Hwy8cK%>yx!V@Kh`j0Z^n9CXF zDi6sS@rm&0flZb;)&qNp6vzX`rg1NI)EuJ;N75?N;z;3Xrydqa4{bzWEOgfH5}}*x zzO4IYajiDkRvFI;{UM(k>~m)h3np>-s#ZyvK6;kg(Lc2{thRBa4ZjU1W> z3+Rdf|Clg;%(SJq-`yro#UGnDbdcs>KizN*YoxlT^N`>_)|a2#EdVUB7-YmvshZz`b4~egD`Z93udiaibRkP;ZB2RUN?IL{W9>}Y zoDm!RPYTDOw{YF(`ZE1@6g)#8PWH=D3d^CdaSAr|?NmOR?;(ECgP;3QUHe+i?c*=C zp?_fZrMyy_@@uO}Gg`U6)R*S-+NoCG2>(iV_H!=l)Ag@<@DL2>pz_anu)gZ?9F_a6 zq4GGk)078ZjMM0jq>U5I_?`G1t$Fw4o5BNfbdN}ScMPo#JE^Xi8f66;viC?$&PN33 z${s)6@T|1{2vUwt8j%}+=Qk_Jp>JGgUP9{(KP}Nr08dNsEzCzmMZQGtUYv9r$hl;ev5(a5|a+c|Y2V<+>} ziF}}E;*$!;kuogXJS7?A&@zi5^JW4P7dp;zd^a@ov_Zz%5@T;0uAWQi`@9C_4sz0$N(G;Ler+o0@c}+xJ?~^= zFh8Pq=y)SsFN8epos4^=`b1OJqs6A|O^AogLF!wQ?jK!xK#qKio$z7eT$r-eLTPJjG`;xTP z-q6qa=+!-=8s0bc#?*|SryGgi8*1Ehiy4EZDm71gAiipxRE7Q>7RVJHKG zQ)3wDBwVUmP_-nkEoJ45^}^5zh8(}`Mya~fR2dsaJ|R@SZ@X5c@w1kkOOy1YzXf#n zhXU9&r&fEU!R#}PQqw80+)erB)W_8?Uc61Dqv$H9t52qmznro^od8C3om)J5MK8zM zD^m8+bZ~nlucP*3t|K}#kGX;X%b1Wxb1LT^DxJbRb!Q5<{9IZVQyul7TeYCoy#yw# zrkZSS@K-8jbMuq0pw{#mIZTw+)^3JtXtlqG)+P5NW8t~NG^l8zZq-7q-C?I13qR6U zyl|zl@FQ(u%~i(2e;5m^hMpLq7N&Ig)wG!Lsjex`q2f^e%>6(0N$0&>&F5tw>vPl2 zPO8@TmQDHhT&8J2Pi5DO3Fuc7Ap z-I)Da(Fdul-G70YxS3q#evv%jWN|-RqTSC1PS{7aLHD;w%bdQ{@+0H^4@sRhVP?k}T~cK<^J_@nP~_C0f=E~LoO&FndwyXPB|9}=U!qj>N-UO57s`tIWtsu4-k zr2ZU8D(U%4NNOZDE$JSX6y(&BzSfdX?j&{VNTs0{a|n#;$#?v+*HigmE}zts2Ywor zwekl}CQkYckfVEg&w)hI%HK~+y2~8|vVxqt%f8of;}J8YHD|kwB~sw9rm*bOwTUi* zNnRUqi&S!M8ri#$Sm>jJ*WcnA#Xb5M+JAAO&f^tOiw+Uytx{EMs@#cA#1D-0<@mnuiR z6lYn+!v#j%O~TMbO79XHyY&g7n@1P8Hd{>MN8jE-D{T@z#Kn)c(PHUjye?ed8jko3 z|GrcmLZQ>$@{!+3Rd+HaS`NDc_mL!W_7zF`8dIA1Zs1wQ0PlLLn|C@+I<82fSa&wv zfRm0Zlgvp+r(9LKDv3poxseire(c4R&*3uXo2!%fy3d`un({@bmbQ(He9_1h|H(yt z$*C)eFF}3%b1L)oziX1}D60;<2|MeDlD-pV)3*uWD}o1{#`c%-WAN$k2%T4op_(px z4!$1pnN+??olNakN!LyElN;&ifUl<4`YcZR=~Ik%xWCr8{>~9P_ji-ePug&Q4N}Sd zJ=d+0p19}!_@UmF9Nogmz5dx}bkZM->-CGcUbn^ddJqkjo(=2+?)A;MUPpDSoCquT z#`QPFXK_aMlo-%q^P4%wWV(<1OmB*bJIy;s?(eC=p?n4KPW{Huq59>ZJ3SsbefjfF zPrpOio5tP!r8k?R<1kvJ?=tUd@~9h_`T?(Ack89!Iph;A%;=>f(w%t*iP8ZvqZdb) zdGB*ZuVEC4hw`gTGkWo>Ooz^;*O+GX;@6nWJ7qI^eLx(CX@x3u%fs}WN(QIu*ODsr z1?yD(N|IpxI?_2>x>0IoFMbr7mg^UKkya~=-D%>R^`*uw4^UXTdkQg6R%rX&TQE;9 zl(*9O9F%;u(!3qDK?2_t=W?-W1+Chvw9h^=WiGO*BV$ypjcL{1T}fqg=H05V6+gsf z{qB}2kK0K6?4CCLrq|$GsmLx`t>5%&rQ&Fw*UyU~6Dha4YrUe$G<~lmI`=;2A_5;1 z=a?k~GH&B-4zZne1C>BC2&C%?4S|4b9)db52%lVe`D>T(8q8wXKP_gTp&40s3Y z=hFF!rcvDf{SQ*ZB1_{$iU2H!NoN}?^jYpv@r4tmpszUPN`dn94MrGU;Hfc9oe?ij zixcv(6m+|9q(JSqhuUQvDe?6WRPiry>QBZ9sY<3H>z>&&CP`H~s$QRiRD@B-4DHOd~VqJ7O4g2Z4PAmND2%;I|BR6X<;>@8+ms zc7JN|6qT}%B2e;60w)mohQVk8*>}<3sRXWKFqJ^+-4a136dS##$xIUCsn&Gkk1K?}((uObKyH_+ z>qAu|ACs!?aZ0XSFVp%pwBg_T<`0dKe)MU?XX0#rQ`R|zzu(I}T-Kh2MU?jGwB&G) zcLw|f(?El0Sux1GoPLB}Ru1FUW{}Rj=GA?Jc{viq5AGhRlWFQAMg1J56R){DXt2Hu zc(lh)@X*GIzwOI?%xs)C%H-KqIg#q)_kJ8!a{N*YGR$b&S6 zc|mHPK9P#_2=f7?(Dz9PPNnI&pXepTFkv+jvy;h6&L8!tKj-yDtSusE2jorn&L?^L zg4-#?t1r0K5XcI0YPoBvM$6s7fG@Z)FFBVl#J)CTB4ekR>~JS|{Ou(6V%vmHqUP{x z$T@t`6?y1o8IY%mSjKiD`-B62(HxF@NN1AyO8`I^iaF-|J=#oaTdpfB#;DFwakJuC%% zarYT1=q+ovi@WJ(mzlnK&vp-WL<*T#Q}u}szvD_4@YcaeZxmLZ#9Ixku{GiicGCYX zwfvIehw-&Nnw;E$PR2lSqB>igI1yH-kCiIE7I=iI)_3ow3Y|rc7rMToW<;j{M#hrQ zz^YNN&%jp785nKOGk!0wUWty&(Q(E*QgsWe_%~PiL%B?^8;&^caWL?2uIf)lrc}Lw zs=TQJvj&V{xz}d zODd+kkIOohuj@IC>IXbcWqqZ~l$TOjU%6V}lT-S?xv00;*J*Jhe#5;{O1)mUUPwiK zAuDo@cs7OnaC^^pN@zy$b;LV~L0^)Z{S4){Vye{_vh;PSJBg$(CH9xb8@cgSJ$1wV zRH++||1CA#Lp8e18Y<~)S??0ykIrY4XHL|GMmf6MduC6I&pTN`4xPtRpOri|k3jrI z{y&PGe?VR@?{bo-^W&w&tMlW%1hRshTJ9^5JMedsADLHlJ$;tZwO)?yJ3Zg(u4|A( z%gkp{oHKt$Ky=ml_Kev^UfMzAyytozS1NjLB0jC>Vb8JWsaDGwME0Bg1%u^M1xSseKF5e>vB%(|2P?)mNz6Tq{*0Zi*E#!MN_y@`zt@}_ z7a4>4-b%%iYaLSjF8-!R*Dd*m3wKLl4aw-OzXQ^Br|~xyxPLh#nf~`u&n!Ea82Kw- z`8z0jU*eieC^2J@V38V{i9(Yr|+FW?IO z?;V$rZkObJM7Y#FfqFS`f$I*YlFPBBCD?DrbEdlov3{JKU6;2Krfv~SdYwBfr&rHu zGdRMf?T+J?y8O*wDL2Z?GW_ip(CG%Mh;)ih{A`rziZxErU$8X8-Adzk&@IMfelE%w z${YtdGhF^|x&G$6IbGi2SS{luX>q@y7G&J#r1^o>(j&jNZB(gne?_C;%lS3O0Q0+i zOVjkl9-^+s&;X^JVk-GnqZDng{>RIZQ{lc#vU@pvUsgZ#=<@!{s!Jk9kS+bE7!iEQ z-fByl^`Lesm%HX!N4^NIo079%W}S?)`7tlkNZX{HUFx1fUOeys`ED_Oj>*`rEuP_C zPI~vRG@bG@MYdC8da1jS)H<+U2Am%XGVQHtW%Py#Mbrnb>+)@LErIO4pW5|u9;g5G z^e_G6JF9UntE7d22v?h~ZH4*zOvgRQJ?4M`ebfO*956lkAbPTmAB&G1>Zk+8^%>u% zU;tf?8shZnGl4khhJZkFMbd#prB{>rz+62CxaxpDeYlZJMX#SPA(zKPib(|nxY!%= z>Gc}dEf~Np`ldSt1F}hEzheo|#b#>a86CLEfm!a!eWBDrZhv=T^7W_o<%TJve8vdr zeo$PI+V%fgyGu6Gmtqs^fXmwH_knwNok|r4qk>L-sfn0-a$kN0`%v52aeWI0_G zc(-5o0Xe`9$bpBrth)BBvG^dixIdG%54(@c!2?`7>W5@e5YU)uZ z2r@RhkSbo+g~N$Ww`4Z*BE%RWNA#hL%0bigwqT5I){o&+Sf# z)0T=u`a1LBbja#Man4^Qojr=mEGLHneUXe&{n}G|GxrE8 zIXofg(JxJu2 zsWR9)i=HidNW{>yqgoGLS7Hk$OHGR>aDbI|*T$r+vUs8)O*bSC-%*s1*ooy?4$`Yh zT>P~Qe#SK<=Bu#8Zi%nb($U`eC#8*u^K1I=y5CVcr*(_m>Cm5>-O{u;dtu$2?D=!& zW-rSf9UVPtSWEr+^$knwhb^qDZ&@~Metk=}{=t;&x_bIC4IrM|O-6&30 zR(2CzhII7rz2{~TqHFBU^XApmW-Z`8o0m7%G!dkAk~*$yAgGAixR3yCUx*d7yg4m( z3!8`4@jJ8p=@r@2XQD=j3~8Jio00ECdbr+TZvY?P_Xc*Ikl0uCM3riE5lo8nx8d5gnpgCxdI});IGw5HJ0(eLW!>CE_H> zhDyKYTrVTW<5AqtjEDL-#f^;YADMV)>nZO=1`n9&rK>d;Y={i$9~pD->XV=FcFj~D z9k?N9oEo!96;y2TPVzcb-wmpF=eDAz{P7(;fXP|Os#m9Xt=IDY&sxSarK`w0sc1%# zdb%~Mva+Cn{?xN>`wcf-uMX(cEjA^qSzd)VxP?nEsFn@eG`TssYfAZimDR2`wt1UA z-{`fReZ1;j(G^n@He3_QIK=y)=<1?#)Y@WRG-dM zO6SKq)DW-J7pX;eCeQCsDI2`8YPr{`uD#I9^D>4m9eQ$)h-zQ5lZ18j-b?uVmOPEK zMpb%87gZLtjLKGvBFDJon)6!dUornvceid(eZ2mvrBL;)*i}@ihVK1Rl@?a2BfQ#z zDPED9Q>e1{=8sor)vD2*Prj~ZcINNOFHnc=SMMk1shgJ<7N|vAy_WnPYIdQ@C{#=L zs>8fys`nPD<%Q9Ui>_CTo7Dk%8`bZey&c)=!8Wf#t*B5bdG{5m`U*8*iyGJd2X$(p zs_#?-cB)?cTU6BBpwf4~pw7)BiDS=F$5d!ls=Tag3i5{)slTfV48{#B+n1=JByw({ zI4}bLkePMgPI?k(AE4HxQ*;Ag&R?9aroa&Lp z?=JKz-X_CuD3}`ax;7SFl081VF8}Hx^}C+Fh+i)&d{WgEo-m-QQSNsP5`np?1@;FOBrVLUk~Wz+SbdSB2WRq=Jqc=vdfsPJx*Ng~>Au zvRUB18LDoBTCsut$8J;U8+f*SzhdjR-kPV2x{B1u3N>Y~ddaDcsfXKkUi@UoMm4Hg z)zR49cR-=~;{}Clie}z7zG(jZqK=L=YWCL8J1XbzQCVAGev$n1vbwWvlb6xap(boq zC0?Fdv{zjei5%~$85`8`g{r(zosgxwmbXoV1H3HtSl>dmt%<9ac>TR4YE#>$Z1uWRsP1WN?;5X8 zs8E@OyNZZhF<(9BY*kOT?Tj2dKs`@#(mUz*`Sz2)vQ%@0y1KPceebrfK1;p7Do@=I zsZbxT%2KyRDBAM~R^-#KDHf`CR#m8L`%z?kvbaLs7Rghqso83(czadh=jsk3WPS_W6E2ii_fpx#7DhKsiz_)Tz>#2xyJ*09*N9F9&OVvS+hiySvV zz34Wpl&xNRtV{i()!V6#+pjv>HmKDuja)}tA+_&N-;l7iZCM@aE2pq!zBl6HGtW}j zwB@OPI2CGrTSc8ZpnZJTy*W>+x18oR+*ONu)6w%c+5A^|&DyxrjmJM}CH=R%Ti@`W zoKfT*tjZ&q?yrl6<&W1cO0H#IJy6Mdq{edjBK~(V|EpAQw6@30$Gb+|(6*Bl@oHzN z8@0OXebV;kwmj1NuTEk9d~f8;>E3XfUxjKH>3cWns|T)7HRVlEz4O$PLi%4xgQ#9` zny=|1^|z@{96fHyURpBEmc37^+gi7%zp_tmYt7O=dDCrIziiFxP`lhhUhEblk~v>yD8L|oU(E><59yosf~XQa_DUL|`E+&4bIuDr;kA+LY3 zcfZaby8FcxA4hGfyzf31oxCNPSFNWi$Ehbs&sW?+^$<J=tx$7alE~1O`E63Fqu~P z1HCP=*prWO*Q(c+GVxEX6>RNY zWMt9&@kI;HS)G54Zf3&7yWd;xrO&u#+&S~rvPg!z>zaZhns0r)ywzPrPwXByWxiK* z&5WX&4|iWY`C>19eExlv<7t#zX&EOe5fyW3<)dPTOHhlX{JU4>QM6sKK^>@vR9#N- zGGqT2YQTPOldO#*o6hsLs%$2?YQC;f|8n&48})JPe%iL|S1&pwXmq65Rp%2}-$v1J zcw{v3dwIIuHitGVhkK@*oir`qbi6`!Y3ok)4Sn_CrLB27@Orf`8{hRrj{3;;3dhdW z4gcDzhsC8?XEazL5`W$%dF&-eD1E*C>Y_H9=C`zMReLGywSZU6Y*U9&#b3G8eXD3H z|AthGPVo@m?qVWk?;{-v5i8TcqKkGB+F&g)I<)XY4! z)!DnPz)PR6{*+Xx?pv{ij_qsJio8+hdtC+j=c|n?ysTaKX20Q`tg@TcWweJWqR`4K zQp>ie%)M%+*Z;9E@>L5huSa{$1s&dm@idHCUSVw8_#!X;_1p7LqrHYV;H*kILx`#C z+bEbnCFjmBnlXHGQHSbNs~Wua{9$UqhAwq#g_@96MB!P~!HtVlVMWUfmA@%ALzQfb z9CrviAaY!)`a=?V|E?AEuBvv)2^-YIN#3SN#(>Soz}IVJy_~3`~1B3X_MKwRUMdDbhbJ_OC8e53xiph+%3s#bSjr+O4sOB zK~M9qx#KhVpH5rL7!Bor7pva1E0|2%)4U2wa%x+0CpK)4EpJ!T+ttv{`7{t`tC4xR z>mQstNv&vCz1rvR8ejQ=cgQyNisPAd*q*E&U%u6wsa{Andz`OYb-20YYn@tkl2LuL z)QLOKnLOuI8ZuQ}s|Hd;%r8`j*LHZzI@GaVMF&luA}^oP;wDPtJDkGdlhl1}wdzll zAn$8yraa!+L#dBeZSkI@`EX;TV%LoPZ8Khp&8VMId7qkCsGg;S@pN0K95>Lha5Y&P zN#-mNN#-4TWElTzq4`!DnRl?d(#`W`?;?_`K1!-kmn`3_{+;XcG{X`f5-Umj=o68F)sSC8* z)dX&EE$`Hu_IihXcbz)4Le1N+-f(u32;JqP3iX^D8R4qSR}{`y|4zzMYgSZbZ}V!@ zzmht)ZKhJY`YI`JR^|M1T1MK{ZOgp=^E@(L*#^Tzbz*pqs- zQDrnq`p~xeCLWUpsd5JOg% zEb}UoE0XV1-}cn`F?mC>%JnvN%+QmC7C73*w9EeLezrr;q_Y^E$^X3Zit=CoC&zcp zr{toS7kw`EX%E^isOQL|DOnFpn9Lq=)lJKECS<3$yZPTZ{x@O4loO|HTe7+3tfB%n zm-55kj4E`-Vs;{9B)^_ciSw#uUK-_@TJ>oUuOgC3=g9**3h1HN`^UF*QJ7MEjn7tx zSEvQ#u3wKWx=*M@L`|un6V=+vr^e+oF+1iB7@vJEoonT(>SlFxmO5{*`fJjD)r%71 z(!6ukvaQ|?bUJ<*)z8_hGP3AAh0dY|7piEMI%W$k&RyQ%_2t9Ydtc0mse9Y}xPRN} zY#IOOd~d|8+-tq;7<*-*`bAp>oe_E$d%M)R`)9RIDVS0;X_ngRR_OEiO4VzVIe~v_ zo|;#yj?9uX_`k36#ao%hdwU9F`hiB{*LDP8JAcki~(DJj-( zP~@SmjZGads=*t!eg1w2ovCE05nHeEKFC)GZBmOjcyE{!`BO@1>X3TP->auuy{)8N zOH9q%x=kHGXHQ<Xz2Rx6~h!E7WK@`It;6P=n>ferBP1^TNGNbUM*v?~LqW z`E))UsAm{ynhp&C2phB(fsiXX1=K2URI$` z3}QWLRon2nYNWbDHmG+g#oXMJGugw6PD=TVaNm->9Ua?fX}+OX=lkkIIxSS!^~zHp zEy<%}#VEC4uNs)A=H;nD?TaW&?*EE{t*}dt-ASiwQ%IeNr+2;u>u4>=Q|~wxyJ=tH zW$B9&H@f~si4R-bFKHS+WnBIe^@^%cZ?7abcHKw(z8`O;?fMLs=&IrhQms}kE>v{Z zytsX%7Iv8yHiHM_>(Uq&d zdJZW%cR@A12^Vcz(6G3fUs7mXT(d;8P$4>}x{3H}>*zP38f?3o`gu-c_2L@(Y3gY0 z!fJX(pG7i1*F@ z6RV;1No%QZs+(V5GcS#Q20Pl=V0vn*UQ#2fEo_*3z9=!miINUUSyv1-*!IU!``cd(;)8tphnRQWh zqq!tb*TMPXI?;v=&pIiauZWX+#=<6N?t;37^T3X!$+F8_6&sGv~&cgHAYX*{I$iQe5QzV||wJd6M7B@6BJJpSi z3+rl{qRkCax(?nl*ZMt5*PW@^{JMG6XwIDaWi}L}^)*W!tp@k7h&8ZdNMf2A>m3fO z#_FbKr=gL&$s<57W^vRmZqlWun#Iuudd7`v_?OF=VSaV<0-`ReS>)8#&0D5vjSVgJ z^P=;ro2%s>MmBL~&7~k*)*R(9iALwuED^J6iEW{Ceoajyg+oIlT|sv!02fj((P;JD zxiyW=Bel>u%W2e?lB>uoBcj~>DN#*xYL?ZJK~3|WYNj?;M~#Lwl=XGZ%h^ifS?Z9k z#nZ^}ofbXMsuyW@x6q?LakezGgBFv9ny8yBt|9HoT8fp06tvpSf*oUR69FYJ>6JSbAEKLg|*bFzQ@3mth%|bq2AUtTF61Rh!PbkS=)&D zLAh#Pou9{yX5{6@nz_x*{HcbnV>6 zCC)O@n9SAFl$F!5K>C(&U&?AfuPmEF`|V`UYlVA8^E_>3^KY=geuYu3JdoDPjGzoW_RIlt+U#r)I`)iaf?Fmu+K z??)4vMS<9`ST|-Nq{tG7v#z1gauL&ZjI}aJIdKt$>{anhzbZm5%QkW9rROV2kH3@O{yL z>ttR_o~W%`Obx4>8y3Zlm%n)Nz;PRP(tNWZ`Ib@!Mx^UrNbh=@fi?5u)Ss)T2k!<* zPs*oJ>T(gqlRwZ+G8N4_>@VcR&BjHetU5&qr61l))Yeg+;;CS!IU77GQPcAJxx5-^Z!|B7);G~$(2i?v z4P}@4P9sS-t6F_c&AcYwPEkUN>LteNZJk!jerKJ?tJRC+oT2^0zBLsb9L!2lPHtw) z8kcjJaF*rB(n~YviIF47$J`UINlQ#1^W4-ly((%qwCIr1YZf!>wZQ}!l{kTs6unAQ zH<|&90nKu|a%&~)^is*nP{JTxct&tmh?+?t>d1ikqeZHc(KQQAj_tN*n7d%HGk0MF z?OV+vsB`_2s5rWM5oeAiwK9LnFT7;v;n2}fI}kjE@K<>pA>u6cfd6S}DZtUb<~BL; zr2)^ev=rdEmPSwZb^rWFmr!?mDI2+t?C4d8j|EDe!ioDQD?+y3L>XvsTEi zGac|(KB)u{qIx*=Ro=0nB-HMb3RVKRfu2U-4=J&SzF^oC_?J)k!;A*m{}7fhJfs+4 zjZZ2AgrvlZp>}axf51yEEd_YFrKJL2XlZG{ZI+e^yxP)ofUmH$T;Q4X%m#mYI7?Um z)AF_h2)G5*iuOCTPtdN}-hmH%_YX$czA zZ(9Z%9wL+K2szS>1uPToU8np-fqC>45PygSSR^FUi+*<#CI03*VFX<3lZpYa^-1NQ z3WS-|gOOnW7mA9reO1c=>wQuM{}MQVj`FpyG6eg7i;ViIeyiCS8yM<3vx5c_38p|< zB3Y>hL8G<4>|$s#*w?5y*eV!S5ho{x@q<}k+$&uX#{0pBp zJO+HPPa6>n%EEwwhbBUh1Ryo z&hEyD(qhX92pde-);|Vq5M80DOHZGQ3^XLt54GaoI_3`zFyKQzDU@{hoB8>3jU0I> zf!A4D3h<4VmI{26rKJJiY-yRmw^&*Z@U51X3p`ymN4zI;P$(B7DVPg9!_snqD=jS( zc&4SL0nfIyRN$zkr2sFmG!M9+Y>2di#((xdJo+oK%yr5DZ9DpnRolX#JA{9YiSX&VJx>yxGf!h{5&4g<=3C8hx)3TRs$R&^RwJxuf>u89I4u_VAP zLQ>8JD`P19-sdZUJ^XXq#-8%K1U}-EN&vU|r1D(?-}6Z&fN%(D1~|+2%{0JgeNy@F z1^&q=l>qjUARt)-1s>;pB&HFhcX8fFUM6Kxm=) zj63cBc{0xEhnPCs67@>Ialy1KQ_t`E}vNv?Brj9N6TLb{tzuWdUs_s094b$^y*r$EOm| zdU_V%s<@E_#wbLbQ88cy3TX!Tu;0NfKqM350z?Rr{(y)k;sX4_$^t~nAud207NHA5 z38whwM00X;qA5<_@(}psN|a$?r!#s)6qZsVVZ5zgp-U)}C5jM2t}`t>8ljC}xK(ku zRcMa!%kccUQH~t*!2DA^{E0ZjW5B=iY2mZ{PN@S=g0pt0r?Gn{zRN5`fYy3NBeBk0inMZ$2{?$X~KW5FDoYoyx6A=j{&dn zX<=u~kUH=r7)wMj|BN+%Xus(JkFvBB;L(O*BD~Q55LSzMj zXIfeg@N7%V1ddu-8gR9xr2@~jv=rb4mgWK9DKxDh3U^z^T;O{wEeCj$rDX!&Z)s`3 zn=LIBn7^f*KjefI;Kwb^1MYXA;nNBlX#XQ7&y(1oISlxg$fBvUx($W*g-CpWRzC4r z$p%6Gd|!SUAViY1B>&GMm%kdEKeS<6D^Ya49Er47;6LR^U3Rv8A%%Zi zJ|n~ahxYW9Ao|0Z78u=dvPV}C#eBdo_(L*02K`f1IysaiNH) z^arGPt-vlzQZn|Q9DgJ$?Gq2O?%xR>;`cWTCho8#Kv>Exp%!Kv?MVJ8>R`Ny1PI%? zWzgn)>F5-{!(zZxKdnKJ^L@t@Axpg~33`QU`#a`dsCJ2x#pQ6s&VY zJJ*ZFgV*@ZEe3?2XoI7I`ZEn(e&K6T42X`IEjXMQk;8n)mH@*2q`c>+vJ;7aC_Z*-0s95XC76^iSh!pg|Ch@=) zIdWPBe#xf|j{$G@Y2p3sgHi{c1S`i_(HHvncJ{w{r09egK!S^}gO^}Qd|fcz#n%PR z?JZ6^T#kH>0zBBK<-~wb_G!aoz|b$z`Atwh1>ztPktIj+3g8G|daDBr>C`f)e2T2d z{pH9f1Hgw_S_*KgrKJK7va~c{{_bS{ki1ObR!hqPZnLyZ;MJCv2Hb9GslaP2Ed_Y3 zrFp=I)7NE+E}>=d$`n&~ha3~cSAmGEmm{U#iv>P!NiPWenJ=gmFi!Rksr}G$nf~p6 zjL1|G$g^jfV5q<}=Be%r2Sp6*@C60W3mXG<_iwp@`LXnjrIg7v9E<64%NhL_cu<{3L0qt!=oolL%Nj?h<1sepg_YczhTKF zfiRe+KH$4PS25t%KB@Fj(Qu3$sUcvVPbvni^GT)c0)J^qcMJT$l0Fp(gGjt}fI(1w zimy}|;44C+-0T2v_t}a8G4jj?3{z?Qzqt(sXu*uZ&m55pp)|jO%@Rzx*`Zdm&??*a z!Yn{|mM+yVi=hCe5~P8BBE6T0ia3oPFb0nHM{}k6BEQFJw+O_LB+5FOY^!b-!B5MP1c&3GI5+@^G4#nQUl!^=^ccs+P-oM^olOgN2Jc~HBF;+s zffd6wQjRnqgUvAW5TLYA0mLx!lr0IZ0~ks4OWU+B(}U8b4Bog|3fNCnqYTYIT-5!8 zcIboelyv8CobSb3;7PE%1`7f$fg8XAbrQ^K#3Ujo-r!(x#@7WEhMYQoP)Y$;#XAE9 z%mL-Jtc;)z4#ZvLqOy6UT9`JcWOQs!aa&m_EmXyDhBi*wcC{CsC z%+a4jiyZ%^9eJ(_t{c2@g$SUvm%nnm+vj1?6JmK+@?H zX%&?tkroTQ+>!u0eNr*tFMU!uw0hT)z7u$iuT(jl1}`Mo+zb)Z;X^hLxWpgp&_WLL zFy|By#%(DvY_5KE||FiWT-q)VG3XB{H55OXPkkyrrGDtInxLokDpYXvjjtM1%j4X!M;N6YMC%ETLfo3rwO( z3kd5H>?l{un5_3RIZ3?=lDVD_SejeZ9u zfG_x@3P1=nXJ#l_@g>0sf%q<8)-*u0Vp-Edxe4w;&*ao_chiI2!8b7B7^lTq*Tekq z>c}DL_C*tQi^1!9w4|=3~o_L6-bLI{)0)tNaQPaEmXfJkDGV`8T!rGu3ZZ3cdGP65w|}sT{DzmtA_E z!1a~{7^eXsd_g+^qk{d9fp}B8R`AeaMJF;7s_L=Trh zhkkMWCruCPT^4Q?WI0&WNdIAV;30$=?H5yG zj?4?V%@709bA)MxokSk+C`(HL9&Kr{EI=|lM zqVS0j`2qm&r$-}KL ziCO&ynZ}%*juz`)l_S#*PBZmGl9(A@)?K6Fp_oR3>KJwj1f3Xj!gSr zF#U#?{xI#Q`sy#@qaNZGZfm62|3A?y+glsO8~4hy6y*5rtqIKC-g;S@5&yItX}1Ch zt99dR#dO32@gbPu3C(w77OTo3FwY@b_ z42~5B#G)37fP~XEF;zT2)&}PG)^ntAK|HZl3Ye(6IpP`fQxomj8T1oJ@bT6^2jZIi zJw%3Rf*h%X$6GN-2uc|<$|XYiExDf-?ex%?wJQfdY~)Fzo7tqC&Ej)e1d zkVI*d9O-p2z_WKuHBL+}Iz|B5sHsGT^ zsRHn6pEMiu=52qyo(*VITm>Lf9VszK7D8k_QUVaZBrdFsa3ztjFd`ul2@tu7WC0>x zhzk&TiMRlfornt%iHf)Yk*yq@FPto zxN?HO1)2@G+$U84Zp|?L(iJ2(hQc>OBx!&c0?ik6t0o4$sEI+RX=2bvnizD6CI)=s zZ(1=AIHMxk5!y6S_OyDkK4aHH=SB$b3F1)AhloNru|R|r;we$u4$e-xDG#0O+>Byw zLN(g6V%A{`MI`K^p72LH3W!NWx_;;EVyyP!egfTqZxpH@XVO!qOia+hE|5 zv|unMc;KW>M(bLC)QSNydPz=OW^zU@ib#&VcrcSQxC*4Wao*aBo#4;?%vlVGX)cm6 z{C0A7ZEeNqVdyA!wzdXs)Wq=QB+l^UBx2AXy7^BTyvt<^6Sr^KmuTOzul2L=j(T6B zWp-a{g3ZUiAKiS!ZDIE%+`_&hdksW6nYS;|#$w-3I*o$O*v65x-K{8KBS+gvz&PLR zPUM^2zHhLP(-Kj@PL3o3#%=0$C-UL$L_Xa8lYB_MAY&k1@VrXk!QF{GxI5&*L9*5i z^%o-YJqlQm=%OPgHex-&b;z8fO-PQGBPD&n=Y5jDnJDx#ML9Ah(j+a%2!;LrF0~x+ z8=q7Rh@6;U9e-0&^Vj~`8@k4Qp5(3z{=xE-!2IwwrV85_Br`stfTRN7OI3hY_&LFh z6P6S{!Ma5Ze_f6ot%u3bBc^Ee4raJSi++`efaB<_A}F0mK}rAj=N_xuf(so@{MBtg zbzKXde(J_S7tTsGlsR&wr~*Vk)b1`nH=KaW0!}et-1+!jq3Jy^umI3*0cX-!=ZJ(Y zOQSz0qrogsTv*6)5ratEL>*khAX500GtrhM=!c=A=Wsca9{`b`X%i4uy(+AFRao_^ zuzp&{JS8Wg38K|dsDxhGM}J)w~fw&YvO!7dZs zZVt9fJcL0#AC+->*B`IYQvqPvEiA`5%|CFDvzhO4Hhal*;*dl`{jv;9xHMx5MOkf$}U{UI-0DU$(L`iS%wA>le7 zkuVu>MUO}bA9$Zg;fpTO;F3*TL8Y!1rPj-lCIuk27!-VAJ*&ccR)zJff}Zc%831Ti zuL`SP6;{0}sCsaBq=P*uD&Y)B&~i^}f|lVKkf7!EL@l?6=1#C>;t>nlm@Sv{&hszp zh3?y(CRLN=cNEfe@kOUnW7 zvb0>_(L;UfH@YZ{6(T<%0X)vqa)9$JEfaWxrKJH+w6s*pAO}ee{yDtXBDAR%w)+o9{G+6C>y%=6c;FEs=5A=Of3nL3UIrS=;~Su@S8$Q=F2$A87aYW4@N&36!wH~ zqcv!DP!MJ%0*J3>0r&Fq!1K}iB@N6t>k(CPx`Nvl<1Oca{ z=`qBCb;VCy!H^xXM$wu9h_Ny~poEn8|I2dqs<;FhmLdq2V(^LdkwiBJf=C$uv;7e* z#dsq(5*Lhrz;eM%J6lUJrmy>1Bb2z)C37C{uc6Zb%Y9PupJghi`x7&?f!!(wV{|E` zVekxTt(?{#F%)L`*`W%sE}jpCD=i=3&GCFFY_fcSPsa11V7*@j?_=tb%J9COPgQU= z<}-2G$T!FnPg#$Zy)J!!=Brf(2qz|dZw@|#Pxv9_Qh`6Tv^3zqTUsXYKP@c>_;X9k1-^E;(UMNLH%3rcCqzEs1YU1xIl$Lj zS|;#~mX-#5lcl8s-(qPgz#A>i1HO1noPs~((a|}khH?eq29ae}PLzHpR9@Ewe%6f< zr9(#e5&_SV32r2!bdyj?BH&x2OSs!aKQQ zB(nm;RAEICmNRR>atEgWDb93Yn9euPVK)qjHwM}>A25cN`G8-Mk!QaBf?*ERfMHG| z)0ppnV;6>zWdXykel(;b273P;m~%Y+^G(EXauZ+-ZJ^0d8R9^bL=FlLb)d;l@k^k| z|Hei4XPcm4dx7C9T7EF{PfK(&8!+5MY(ZBLDQGH@V9LO_=mo~G6I)PyBK=U{z7wZC zFb0^eU;k?r^oOqT!`d!Us2Nc}xH2O!LRT{eV^p;6idh zP!%FUk^hJpL^@is1wx8QNFdOVNI@MkMZgGOP%)s@pcH~$^0RO;pp_ju%|M2^CvKpC zF;H|`^JBvVZx9$B@iCBNn1q#pl%k?zCKlr3#z+FD61n@my+68Sf6#i!U0PR4OW1jp`<~yA$ z0KP3G`i-Tw7z#*@#D~RUnZFk(2fRo~Hq#@DDt~Y{2jUu>m3knJwrJ1RCt6RJgen8bKXRgiaV*O$?5hCI4HXux;Ma&EBp@|RU2J1B+3UEbF-o4Q` zq=n{=UlE)(enoJ`_!aOdoT)oT0b}iR!wDE&%^h@kRQ5GJR$MHH@8ZaiL z|1+(SkL06?7%dEnCSo+;8cl>xV4WrgJ4OHp44EX0hE&LM} zOQjAx3EWsCzPeP7J^1ac7~B947;10`u8>u8og6uOfN%C`!(+gA`m_--;QM{r$QbaW zKJBC!@Y6nRbPV|SK5a}4_!Xa)8w1|y)5gYt|Kiie#eo0j)5gbuv9E|Yd9mANmfRUP zTb>d8f={F0JrE2p@=t5Pli&D!BmI@=SXp!;&Pg%gVLoki40w!B8xsRQ#i!-QfQx+E z*ckA1pEfQA9QA4AW5AesY;SP92g%-Q#t-kY!Yt)KB;{n0!ci0CnH1`&B*?N^Se}j( z1H9d*4UYlu_G#gH@`%)dC&4^{Usn1)%ZUNw?3pjo0wZ%J`dO7Gk#VUU=>h`a<-YhO zD}f;@!S(x2*>bG&uPQF}fd6S}DZu+I%>(Y4Yg|jWa8iIhOY?yHSz1bPFrdflBA-+R z{8&ilo&-t|_9Hg^*_TxYh}JBtEQXSmRTk9i7b0W3mGytsYI?ZU^k852N*|l$$Z-w) zlusKT1Af8RspJm=t(u{5hjhzQ44ppr1r-N%N|7<^Z^zC9KG@PyfDg5_RNz!gO9MXK z(lUVuT3QZpx~1g;PZ(>o;{bqNU{kpK58Dz^7YU8t^1bO9h^6X(_

    Sf4w)+MXG^sE*}%L5R2y`EL|SGJq?R8T_Yb^L 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 Xd@?0yIA|i}ohnnan2ynGagO{iJ7a5N literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test41.ans b/libs/libtpl-1.5/tests/test41.ans new file mode 100755 index 0000000000..52986715ed --- /dev/null +++ b/libs/libtpl-1.5/tests/test41.ans @@ -0,0 +1,2 @@ +a b +1 2 3 diff --git a/libs/libtpl-1.5/tests/test41.c b/libs/libtpl-1.5/tests/test41.c new file mode 100755 index 0000000000..c5093f08ef --- /dev/null +++ b/libs/libtpl-1.5/tests/test41.c @@ -0,0 +1,18 @@ +#include "tpl.h" +#include + +int main() { + char c; + tpl_node *tn; + + tn = tpl_map("A(A(c))", &c); + + tpl_load(tn, TPL_FILE, "/tmp/test40.tpl"); + while (tpl_unpack(tn,1) > 0) { + while (tpl_unpack(tn,2) > 0) printf("%c ",c); + printf("\n"); + } + tpl_free(tn); + return(0); +} + diff --git a/libs/libtpl-1.5/tests/test41.out b/libs/libtpl-1.5/tests/test41.out new file mode 100644 index 0000000000..52986715ed --- /dev/null +++ b/libs/libtpl-1.5/tests/test41.out @@ -0,0 +1,2 @@ +a b +1 2 3 diff --git a/libs/libtpl-1.5/tests/test42 b/libs/libtpl-1.5/tests/test42 new file mode 100755 index 0000000000000000000000000000000000000000..043f4fdfaedc493036f4cd4ddd5d5cebc7642b2e GIT binary patch literal 126779 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

    j(D#vo2}MDP_pH2YE}jc*iS=? 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%0A_Jn|IU;@7j=wh#ocV;{n-5r3t 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,mYou-0UPZH*?1TFWp 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 +#include "tpl.h" + +int main() { + tpl_node *tn; + double x=0.5,y=0.0; + + tn = tpl_map("f",&x); + tpl_pack(tn,0); + printf("x is %f\n", x); + tpl_dump(tn,TPL_FILE,"/tmp/test45.tpl"); + tpl_free(tn); + + tn = tpl_map("f",&y); + tpl_load(tn,TPL_FILE,"/tmp/test45.tpl"); + tpl_unpack(tn,0); + printf("y is %f\n", y); + tpl_free(tn); + return(0); + +} diff --git a/libs/libtpl-1.5/tests/test45.out b/libs/libtpl-1.5/tests/test45.out new file mode 100644 index 0000000000..462cb89ee0 --- /dev/null +++ b/libs/libtpl-1.5/tests/test45.out @@ -0,0 +1,2 @@ +x is 0.500000 +y is 0.500000 diff --git a/libs/libtpl-1.5/tests/test46 b/libs/libtpl-1.5/tests/test46 new file mode 100755 index 0000000000000000000000000000000000000000..4d22b71ff7e01b7d037ca060122b5cc2b42b9466 GIT binary patch literal 127179 zcmdSC4SZC^^*?;??k3p~lDi0jfG8_jY>>AE5E4P%g#_;EMuWWi%1cNDL`8_~ zM!8*LvD#{Fe=V)HVzuh8KdWdh2_i(TwSaH<3R=;<29)}Oh{`_S@66oIg3$h+=kxrZ z&*xdq&dixJXU?2CbIzH$bC=askx4FH*PM?_J5OWj?Yy7>$!|@od94d4sFiD8EvOCB z25Q;B%EF(67gRYXZCA~l)C*jG-1ze_K#mf+{Q1 z?oG1jq?+az0JbBqK2`5)nj_#&8YDyb)Tq>HNA}pRM71kX?VNOnV$4aM@o{YY>#xSw z-xWlOMERt#HFK4#dM(Zd^;4j&0Zr0v5WhdBA7>G+n@#eV$wV|_3DQDm(D_JWP$ z8h`foqUMwn)DAcaeECV>Z=3{PbrSf6CxHh~0)O-*@E@E6e#uGTzdH%M;w12EP6F>Z z34G~E;7^6ZO0KB=9l^uIw9%;*-QT z={%Yn6lLe@R%8g@+b!sTM0y*(dqA^mR?HD)XFX}NXJ5T|>5|!v(Yec_vuA5qUbS3L zW3;*z3!_?NblH;H#SL10bXn7q+PTp>ZCTyiMT?f!vZk?NiMDw0+y-rN=2!gR@&mGB_un0 zcKr(Q71e4NEp4pRmNtMox~*NXOeCO#67ZKU11cF;qgXt5;S%k-WedUW@_N-z{j$0` zZE_?$VdCtO!^=jevm=L}4SBf!!+*3HC&Hnfa0#13yTi|&xBm?0#;qMdp0K8V3v)^T zFe~vnynK#GX_I=0ocwa;g}x%wpcGvj%_A>Faw_HzswAHrv0wTfRk6}Gb;n0);Uzp$$&#Z>Cb`;c(*iE(;711c^U8( z8Sw5I@a7D7eg=GP2D~5xzCHtPWWevvfID-{>J1t2%z50H0nc3Lk7mG6&7i+21Ku+O z-kt%c?{PlQWx#tmK%_e|;Ds6R-5K!S8SuRs@ID#vWCpw_18&Cld(A{v(_+77wzNmH zlB1w?X6#w-)(j+MQ)kZuN@~!2d>aFT$g#YDNcP?oK7%e}nJR1V5aml)rmEWQqI?0% zR8jj;QJ%muRny)e%IC05m9*E3@<^7cigvRopT#m&&~6arfh<$?>^Y*`k7cTyT_eh; zuuN66gQDDxWvZB6D#|XFyR+;UKY6x-`X`A;l!YVBrG{sYUL zQoBKvf6Fqb(w-yA_pnTrvTH>7CoI#n*g=%1wtX-=sFk&2zI|qEG~i91a~3ALqcR{? zuW4CenPF&H{eDG5opDj2_5cw-cC8*&r;Mm9-~Z zNEEH#0prjjUs?O*Ti2Hz2wOX^GOhQ`*art|riDA&+tI}A*itHzjydpw$po1EVtx9v zX(k-nbaNQ(rx`n3U|RdGb6vT06SxzK`o)!PtV-=Q1~e14i6sYr%V9V0P3swR%g5)N z`VQ0DZtgtVg!WGn*KFApb=tqL+BcuO^IAX5dXMR7nOublzH)okW`Ok1w^HBD*tshf z03mv6nuQ+I+x$)7&f1sSaix7Dn%K+nC5K?%yx)W<z{#RCQvpL<*C9cKtof|HRAOSDRvvKebua8;WhP7 zlYd9w;l%hrs&ELfBZ)-;U%0~)z!<=Nl{c(o2_?f7+l;%~jmO(zsHblJ5{oBdb(q#0 zpa0%yc?g)HM1v=EDCpL~N@=vjc)T)DYCJwIFlucj{xD;Nlo2u#kdc6tfyvV9*3qTa z6<;=vuWCsdYe#{@2s(9ZB5$tm)S@Yxm_>hOP)*8M-Po8*5YcpSfV0DQ$#d4B=l zTJ!}oaa!Beel7X&5omZ%^a*PK{eGDai92jUBwzh`>jDV66k5FENw-GBs5nbZoWXt*@)U(fs^>GCDC{bQ%E$}8^ z0ozizE%$U`jRWZLLX?4 zRcu-lz0s90J&9imyJjXH5*9v^xG%7Q_%}bxZlRi$p#RT9)JrJgIdxFNI`kH?K7?y( zTOeilvX$)obN%|nxa6hiBKequo=5aCUFfkc^jm;Dl*qR_$nVYva&8y$uhPi&49M6R zpoM0JW`wPyw2#xLA_ypoBDtgp5| zOOl0mpexWb6N^jDmIKkrW^I)gJKX)ccdchqfmeg|K}p9>LN2y<1=H==w=0C zg&Lo6%Rech!~!oGH*M{rAF)2Fw)UqAhk|@HjBZOK_%>mo8J+e45Ya?Y*Sb&p{YYY5 zIB~vGu1{;BKNjX`s~38Yf<0Y~9`j%(MwzWQm9Q##5c*<|lX6K+FM{J}*=5{z764uR zn2B*DnhX609bkoG9XeZwDqdgtzWp6Y2zezu+dMcLGajibGVeC^t@b}f4WgSMO@(H^ zEX$#pVN3X@u=OgYz_k9(SuoASWM9OBdyXU;iX!d?f6Jk0Bz82*h=1;)=C-{&C#Y4G zeUK_Vm2AK@w@ym696}5K>aij&NwBd6j|~BtT>^skHM4&an1MjL*{Z*X6Ia4`z17s+ z+TNLT=GUxsV-}Z}r04m;d60SHa!m4DP4A-0}jbgS%KZzTQT2iZCiquMZ zT+kZH(&!7UU8&pU)XxK zv&BqIg#KLkef{|xmZX`O<+W>%ov+sEo^Zu$%VvfX7yA-bS|S%R@-^@CN18wsFL8R$XCDS(^;NDmCqXKlNvb^aiaslOVo_{4~%FmYYurF1u;$J8+*4q_Zr zOCpFb5DnRzvoIFuU(!HR*a{=Q02vdsOHF-SSbx@jkTj*BcWRuD!8lDtN^Btqu-$ z%cn)bwJR~Sjx9-F{gzL?0QMl{6h;`;t%1REw2hD2r=lI!bu6jFiR(uwJ=9k~rp6kI z0v(#xtL*bb`lQ%1X`YQWdr<$s=@T?#hxO}zQHH>+^By6G^g3A&sx4fg{H zEl~yuz)Jb$H2OJd#TY~}CJlwkz!`)L1Y{r}XK;al%h1yvNXhmJl2YHWuFglNgB<;f zwd)nn8S$0C%ap&drYHMt(yT8tq_fNZj{fsdRatvks`Cu4J0<@&;lhq>|1vNu6VtU& z>x5J&c0@o3ROiC(=IuhS(KLAV&&1e4RVSAE!-=Iu z;n;Uxc}EMQ8q)0AYVL9z(zps?}oTz;+7y%)4r z4x?dWEbcX}m(6kT8Akj?R9700kE)6vGFrIp2`5%#xA0n|wNXz#cTh6Q%}Qv?2d;>9 z&>WnsuKggQ?`4R%rkxdu$>mtXrHr))pp3Yte`}Byx`kd9TZ34ZIrxpvo^l<9W7~zk z#6L%6D3Lv3TxD4bJe5ZGZ9-@TMSXTw#*$6jpOCTnP+K!Bw`uhXBp?11mO_R$IjBi6qXrC6Mhc}H?B1OPJ>T@IY0@Ze7(ZfrUb@1BZif7z*|i0yf1 zC|${j|4T>?!9~j6g28OUz9eNo!JG)z{>U6aDVx#iCj6!BpELI*b3bMdF-gj9VGi*~ z%Dxdf#vjwe)_213eM!d$uRb8*ww}59eH}~n<|F(z;)@{p*xrG$!vl@@y~vx=Q$+_N zK5~Qcesod8;1wB+qzb)Pz$F6Sl&oJLhW+V)3ZPN!S+5)we4v&JZ1Y_m)Yc1slJIfs z-`7l>L*L#lRk-jD#LdEh;;J^~6Y|2{6g; z_!2T&m?|t(j3%ZQnH?T>sfA+CA|Tm@faH~xJAp1ZZ<&O)iBTg*@iMLJ&j=2CxVTzdYoap?-^fb=&f zi%Z7|eRJYc=nMOkQ|bvcHAAa#a*(<6RO=del?Z1mtsyWK9)zxDqBNR^O&*WI4nZ0b zy)z7zwC6!uUGYRXF*+auQtM6DCiinXtgZHVU~#;ai7Eu92dY}ySDW?^1hAR29b*9oA5$Z;-lY#JcdqjY{7iuHt*-T7DJlcqO^aAW>wqQT= zl4)Il{mew6Hy3!#ioZp-o7Qtmo@T8t(M!n5c%-Jttleem*a#(prDny}ruR+jZ;Y$& z=+XyTt>dh5vzR1Wrv%ht4pgj88mrhg=-CI<&O~X`xe9?{|*2l@aVX`4L zalWnQmuAd(WMWaIb}vXow?=R%i&?k`^6h+F>fMFVJ48BAz2{d?vZ*(OV}F)hkd%5? z4b|C}p?IHSM=KQXyJQv!QR(28y_FT$78$qEPtcfMl)y<-%Lh%5cT{m)f<)&l>G?1d z6JRJOh&>ZTWW=v!yVxgsTAp6BmV)g5ccFa7BRfswk=M+@T~dA99xIq_CV4E2u(cz4 zK6I_*NjPlCYDIbLq_1O#UDu5=Yx@B1jSOy2&(X{xeMf7ho`O3*GT^JPjYqbacZc=% zh}ACl@n-FzME5V*b>|k!gU5{DVke!L?fbqT+X9_%{MZM`3+2OvM+c|J+vU%0N~>b| zbida5p`1sl)(M;r!U6QHhdr8&J#7InKnHr=^ofH}k}CXa8qZh|E>T_}&L$t(1I7Im870`EDOZqbh??#_}d6%86 zOq^N;ftQ+zYl9G1s_^Bh7z8*xSKy#KoXoZnCKs4}ih^73l(pMsr0+P#AATsE<4`)s z$M&J-c<0z(=r|qWVo5UL(l!&hRH28gGQL14XT&$>Ltq_2>UH|0p)H64LJa5|VSXe`OH^8_(jZeAoTLgL zzQhj!@KBtjCm?j0i6>qgvD52#iik$bBJ>nI)ZsE(Zjd>T(Xt*nYiC*e7TbO38PDhD zgVAmsIV5YwIy{G-aYb|MSw_hfdtZ;bx96Y}@Xh0#QnH3%PfPZLfMnm;TOej_$NBFB zzp=S2h`mGnG#8eQ^*SF=H3-tkP!bqYWnd07uu{y|FpqSBN}+pf`FDWC(2)jJRY0Xf znJT-|I_aJ9QWL+_kIiQpWt?Q{iMBOojB#KB8@3VJd!5+l0#Sx(e3L3Etd zvHfbt(s~q2OX_DO&;#)1O}|wWI*Me)5wa1#8;>C&o04$HBrh8y^)U@~OcK+HvY%z7 zVoWV5W5HOY&B zt+I_QrwVIp)OaRAi(EoK$skBi3dYKDp!HNY)ejeNE2bAmgLr&&Akw-Rrg{dJ3X981 zBUVGXGdyE+lTLMLnT{n@nV26KT7}cfmdnL@OKVhOmM{6@dzhQn6?&@h&5OZ^&}j?S zA~6AGZ5FJ?TSnX}I zKX#-PGAl7+%d@Zoc9`yozSuKft0!DB1_I5f%MfI`)r?)SPTL;*&tK5+fv{YL51Q>R- z%&eUj2vW-{&Dxk6HTACpj1YkZ>Ux34H=sTx(1%M)M zsJm!&737tq>zr;OX%_~U==q;S?8p~7 zb&QBRvayOaBlZ?z^kY>_EHtjVRNT3cR=vYvzSWIP-HnJsM<?DE4h`rS;G2t_&kYn`jN) zfRnLG11&(zViR&2DKkB&l#K2YgpZD0^L5Nf<(Yo?b3R=1TQn&vV4CvDBO*x*|K zOchSL0Ffx@Mlf98^54Tw3Y4~uK;WalGf^+MjS<{;8wc|JtbL89;y&7xw zVbvg_OQXOtbH&&*AtkZSt>YN4>51i9&j!t*u9L428J5(bE#2@)j`a? zohO{kF-+P6y4EN92wCq`S)YY#w?#l?Ma25X+_Kjdf!~_NshtJjqHya1JO#pa0tmbk z6YW!G=v`B({&xBUSipav=i}F~SbG5aIRd05D$NWi;A^xhYX&0PghP@B^*)fJ!EeCg z5fO@MVK@N_S+Ze24vfwIKf zJwRNYwB5i2J$0sdF4z_uT6>VQK7zhujWAuA*M3nf`5;^)Y!d@8tEb%u%LglxkI6Lq zbDYV7F3a%#n$73$C?kG5Qrd_kfy|(dra??BLKZQRHc!5VKC(R|r`h+)_Kq|4+T}Rv z=6<}($aFqdzn<{}g9m${ur!+ROV(naeYGr;9{hu5PnGo4xT~tDFo>+$f4vdN=t#)6h3NGDRTU!tl4zmkp25W{fpaj>y5;#bfP zBxaU~&?u6aP~KYeb?k_1c}_y^dBU~06B9gUKZ7+`BhGqqR4AD;9_c_R3DepD`^=?O z32_YtQ^GLXm*FvnnytGgVki%SNmafTWvpYLeNU#Ken_m54kT4L*TMQ2v%*c6FD=1I zs1oaxWAoY5pva2!P^ZyANR9$R9HZI2zsL}Ou4oK1Z}-EZAPxdSOqw%AsltyYDE>?! zD8erTCQOc92f^Z5ioAOBv;gxYK<$|9UE~&28$eXE-@~#j+hzNOr-DBIe{mm>*HpoP zmqSN-!drmPegZDl9YCC@eD6F(p3=qkFW}w3pxE*<#Hitw#aTRvPT(0kocya;?3IZD zA?r&V8yPKyC|1MM`sKNC;rjF;-5nu6JQhTFqVwXKYn}c6NzaRUD-DOpI4^$Ve|cWK z`-JDkt?|GH$b~mOOGAgY=@5{QE}4of?>HLqUyHsj#Vy>Y9z%BX1eXw`k8v+|z4yN? zPPW9wL=0HmdkR_YPXbpyW5yGOl}djNxEJ*q&C4CQ$6eHGmoxKFV z;lc0XDF>eJ81erW?LRZEPbwkWJ9dD-+TAU0t$sW9O{(dg`F5GK8rgoGavn=ZuIB1wCvctx=t~we6@S!+$|6hii?0 z2Acg75Wz^>ej$dbYJR~Q9tR}Lz=U{&xfY=0|6u%5DyBfkLri-N(YiTkbBVStjaHjR zJLVeZ<)nWe2Atga66r(iC2Tkq4NdFaj2nTk3Xbgkkgd3&m-ZG#z~`xz*FGI%Nm_yq z9<}Zr4?1~WbmZ+nFpBB-fXmK@>(?hQSG}J0Ct|+?aN9_5sxHG~sdBB~0x%l=1GwTY zJ78_4V#1Y_n$Xz31e~SMtF7;*!WSeVauX)Wk4fWA_jXafQ{40B4fstgTk8VPiL^4X z!aB?g@HUJaTkayFO)6Q+jmkGe#EaAia29Xn1tbuNUeKjLB;;|f9lCNX$ z=`id;qlNFg$`Gm=6=p)BZQ|O3?ldsP=FLo8h6l$72p~2Xw=PEi zv349gy+8s`=U^l;5NEb%ukrLm-txw25=0k{rEtZES06I3`0Pop`n$Y2W1$AuYp!)C zuJu$}Hu|3dFW+@w89~J{B8jCLRlHKyC6RkP^;lDqIgR))SZupfDeZ52&9R zr}T{9l}6BKQX`mR>}79764!X`PONZYSI5gsK+otn&=2b!W(Dl(4x?osU56t;dp4G1 z*Zw~!o}YfeQ=g$kYkf@cgC&-n0lx=$%VDs|>%&y-2>9KARNVE3(BsHs5V!z@@gi*b zO3EC|K2>2bU8t6Ep_60S;EcPNg_A(|zSyUF z6O?{YzzlbEfN4A#|5DB~`YR#FcYHHa7pyj*x|v^k2#MB zGBAnLUZ9Xs!mZ8C3-EX}`CC9L@mLwW!2y8DiXFz9K^(C4kL14RDS)<3uqj5%Ygjnq zr2eAT=wI=~#05=@i~D!cKm*j90xm&AE%u(v9E|7pyyRVkdww`pd{qoMcC^%pd zGOah_S2M*4yny5U{aTiBO23#X&ghpiEjHpmL|XP1REO8uhA{ZjcT3G(a}b@I)|;@R ze8_HN?3kYDxJv8DmX8Ni>PL1S!PC*9q1MSM#w*sRxKhzNtxz}h&V}u^#5iV## zgYN)0m95Jl!lQ^w5#uDEelC@ou-!8X%L9*Ts&&AxlyBlmeHG)xQiM^01uv!PSz)#! zHiMB}VgC&K9S1MMiXWl^qOiw{(HzZ^Gni zo$n`4!)g(?_@igTd;S{CWjxJ&*|xqx3oJUV^NF^k@RzB=3xFx?U8-;}DZQs%^Fu8uizj&V72VwXIHIUdm2laV`aoxi@e#w~9B zmRqlH`B>iht?zKck*5K_LY08dglMdz z*fl0q0$PO{uM%C89mO22S#hxZJ58wYfD<56c* z9-~#1SrvOO)%h0c)A15+LVW{f$`eM*^G)aCnj7w`N2lN{MDQ^beBj%z5o6xUtdgW8nd*W$FrS6w?9mVFtl(stb8KWJLZa1SaE z>Tf1)z`I^4>}wMvP3y4mAGL^l8ocR;$;aG<3RiSAy^HrE&|%Y$r98!Z4CNWFTIn|* zC-4%K@NZvXRi>2+VVrs`YHt}-h6k^>KJ*3HK^truhE!U$YKs>w1Qq(u(9!AOjt^;YDEBVEeMPGOn<7c1Yj>&#< zWzS&WVxB{ZnML$I2U>QmUMBVzN-v#Ni974a_GdHaH7p1Prz#kKsb4%@fpicGVgzB! z6NsW#GVX+?f~WX5Ai$elypLB^u@pDE_)Z)~?5$2*jde7-D6GGYYn#y)5weU9BrBeQ zt=NM20sf%B5x)k;ih-pF6S1=$iQX|=VG9$+?qOd@2C*RDBFC$Qg3ILpfC?W0dBx2g z3@*;0Xo+6xS;1;PDwtUmPF#nh++E2y&^Z@_p}&Cn)IJ_K(AnDEyo80Dfe2hbO_D=Nhc$@{eF+_Ah0=pjX?YMXg-4-yGJ!+> z4$SW*l0&f?H)6&_YXm|!VjU5$#+#hk4odPes({5-__Syfst{ZD!}7qa67yPbOw;W! zdgxkj@cBIKXz2r}{W+|@vJ>f{bPn@t!qEvxs_-q8Id*$B2A;;+MyzcZB6`EK(X@(u#WesX~)ECb2snbfr0#=dI$O-Xk*K&V@Jp+0ISwhO1W{drr&$^Me9)SBb+bM zSs$Xr%`D{ZOFr=i2BHig?=y?XW67K0Fy&=f=Pms`yc28fv9=}8ejT}+pXIQuB&{xd zSu+Y^?;O2>hQa6bhu0R-rRopYuvy^;D!ML8j?d`29YEQ2HoA^j@2TDyOW`*H=B9gp z;-G!riY(}j;n<*f4bqLo{I!jS zn}1#qm}Li2g-;H_e19s`J*fQ^^N!V%Ue6i+`{w=Jw#8B|hENS=t31ZwJL_{8WG-O* zi^sO{Kr_&Iu(1{?W>XyDb2d#jtTE!V;0j_Xw-N8aT*Xp)^ehotZA7Gj_rSpooZ-#S zva|2|Lu^v9QT1`Vx~z!A{Xh%x4u$mpRG3n3!)iYt{3do5e4@BL*&D+u+XW98-l4xN zHq0J&{Y}nl4=$SjEp}Kl*5v`R31qbBn%Fm9qvbS&9Ekc$qws?aB~}K?8jO~=Wp?Bu zqh%+uhwws+&Mn#KN^3seDH{C0d8df@elu~ld6pk`?ISvmT(jb+vF2@PO4vFN_gzsV zd_yPMGbeGW5u_S4*aewI1Hk11sg?6x1FePzWzm%YgK zY_wd4qKNYCyD-biaesj|2V$NPZ$~+H7?0SVV8uXI;JEIz>jxwBzYiU>m12g}!I=mJ zZC+1P{9wh@a6ZJ+g^}a&Bwp_1g?EfKSi-r7dBeKGE3zCM?tNjnk=i*x%|91?RO?^h zCk6NpvzNao@S<_+A220iuP<(`>cDYU`6^KZI^1nz-z0xeU{CTUFl{Dof*!q9LX*z- zXgjJntFXg}Wb{2{yTaD)&}Ik+?`d`zcRf?qj(20yKP!L-h5T88eW=d-Spo4Lo_Ilw z@8R){G4UQAUJ#S-;qi?z^&TGHpTo2Fj~a35(O7#1`K-Y1J!JfJTZH$!YXPZ7$G83h znX32!F%?EU4}RD}M9(X`ez2b4o9VFF!WqGLhElImfmalSvEC4Dz7Ecf$FT+7du)6_ z(;?=;j}g!(VG4v}!F`70Kd=n!-+*eDKf#tp{vN>{KY(<}DSwXuO#FgnA<5gBQ$iH4 zeA!olMA}{4fNJs6EMk)8r<+|Sa%b0Ov`)W2e93S;${JXz(WA z$C63UcZ&}^+P%?_a?_(pfNePO3t)p4yg%TCbv~RHc&-4|NmTwi0@ro2@d++hJl-(k zysIaE5aM-Yuz)uW!UFy$y3bs|VKKLVMwML3KN7Ko);6n-ej!yDOV>1Tdn%un-UcAw zII|a#^D*;iurEs^P9`FOY(G(;awSelBb*6@rc-3k;{YvdUvHlRSn~15$vnqlM=+p_ z{j2lSCf`oCzMLv{luZIxCZ_p8Xek-jm$kj<bXpShp5G7`EO8ZS;^FDJix*20}uV zPx20LhsIYNX@L$+;48Xcz~=M3%6R+|Zya}Th6B6o`7V3Z`a`|>NU>4*683;Nd-lb5 zHSITRpEtMQD75touO7xB?g`&#`h1|+$Dic)8T^aj`uMvPSYvpf=>)&ez@s=3S|0oR z3~Ii*UQtrN7Zv8VE#Xd_0wd7;p*K3ncpMf5r-p8v8oJlweOeqNVgSB2tt~gdr(uck zmHU=IgQb?|qZMV(JLhX|?0`I&3#$V+lrdNgVVv7ECcKLcZpF@~J@$`CJAMBkA@Bt< zFwaYMVeUg?`$`~-c~E>*ql|Z(#GV!}j$??k#~oFm>XWwX^@0!mWumenr{HBizWsf5i5$aBjcAsBeSFs}csT z{o{NTZ%VWa+tqbEdPeLUJvv?<$eR3%!)* zqry5zU&h%e%&4ES?^WmtW;}K{i%sZ1AbD^j5F&{sC7pdmf9Z3|o}ezyDHr1a;6U_> z@G-wXvljL(oT$dt&gn4nKNLrl;+fqKaYXqTZEoU+-blqKy!Oz;v<{}_!~2#9&r2f} z$)?Z4`1J>vzxxCeJOPY<2R5OxLvg0N!tq)7^(h`Ggc7IY_c~x8a_l5y;3ao8ApRQ%Z3C|U#|3H;(%RQ%f5NP^0^gFE!BFRGp) zl}4=3aq)<9!2SdG&OuIiarkq*d)U3dpRsD#+CoQT#J_=xRF%CIJEAW?v$FLvEUSND zW$`u_d^?`BVRa^(ALfxEauGxym{n}JCT{oi)grCYo^Jars3lLa6Q{sm8SxSj3?**D zuh$s2-4C-;sg3~gE`GRnM_NB{?uLGFjJVsZeJkv~5=Sq4l6}w-_0MTj2{Zc%9_(%3 zd9>xws!<^v_m%CcuEm4n-61?k$CLZ+{nmQ=@j-gkS}#unD_&c@FOvegq_o5OYZUZq z%kBl1#KVD(5W_e8G+WY$r(pL?+!cnK=wW{KrdVH@`fI-n1YYm=^MRT?Z7VV!$E7nw z9P#Ik_|GutvR!P~x=e5W8ga&JGR{CPC8QVd;(r+|w~Q!~&gWbJkib5n)q_7l@-T3f_1BOdpH6V81EKh`LwlBXx~fI7M9 zA zEIqHy-&zq9o!$ZDfSQW00KqC!AAhXH9#S^H)zFD>~wPPkfl1TO56(J}^9 zNOTVMqDDofspKzlvy%4c5G*erJJqBLf72I6GzaL?eoX>b4SxF&J%_he#fL<>K~O|M z$xb*&yh544i?2rfc^dvigC9CQ6!T^I#F?d^Bz*Of#6*%P07Uvn+_B^pHz9@eI0pbH zLl7?tghc_!b$(#4**fg?LdcJKQ5A|LaAPFirTum`HlX?b65EB+tgP_7x)Lw z@1`wniu#w<`|)GcOP5_QF&mcE)h}G(U$|uX+(iq4GI43sqWMdH06hHaw7(u?K~xe> zSMj&0kFA;{`u9hd`uV%q=@v~(8k-s#mM)9d&G*+YUA7p_Y8T91Hn%ofx2&6n-@&e1 zwq!22-zbSjHE4pefz|9l12Wu_QEAsv!9H1nLKd>^P3ho_!lpo4>lms<7*r0 z>aOjoCBA^D5kN|gWRIIJh)YZnv#u%AC6xxigTz7(S^`2!2Amr&%L_N4{filn_t)H zuezA;dn)|;`OZ3;J5MU>yzBjQ8yftz_;vPqLcH3NrAvl2EN#U6FR%0C7uJ`FA9wfH zE^S&874s~pXy^cSa>A#{FzEfiwDf6>Cl3#05=DAYM(0)@V?E4fM_ zMT!Fj@a+r>^P9O?WJ4^K*-IO5pc<3CWlJ#yOVAA)Q4S=0j(=WLeLYM>bm>w*=4;WS zq5dVX4OF0c*Tc@J9;VeqW>1RTugfH$|J!@OqACQBxx% z(4}w3Aj;X6t4Yb@1odehz&wblnY;LE!84nXZ!QQiLjQufjhNy_j9_8y!a7J=8Z+?h zXwUJh!O;fNk$Ny2(>o8p#(ynWuGH)d4o{3nbzU+|Ft?SZ|*1uE~$UBc<@gJG)9%`Q_m?ISa#07e_kCL*2(u2AqfDlI<=-pShUQ1sUpO8V_5Ne}i`{i`&n(v#sI5BDkjA^jztmXoB~X|jHU zs-JTbypy$e;N_=FI?ady_&GlHDfmH!x9LCNAK!j~!f)_P`g6`Wak^H)O_dg%1n*?+ zHz@kw43zYPffJ`YiY2^A)imXZ`v1R_7YtG3 zIP1jY{7>W9Tk`*`-O1>#KaSr2+w@P?uLD0>fBy-7vU-Q^|2ExwoW419opi$(Dev{= zCr*P3UaHcfli;1K{SHNcMU|vqYMwYPpDf|+lVs{w>B;bqhi_E$gVSaE!!u5tHYm8J z(oO#X|9CnL3g3U3q`%~f6Q?&{F5!Jt`uKmqKc3Eo3ST?!vrLs2BK6>}Nu{+&u|?MS z+i70>h49DE1es{{NC^+Cbh=8fLCXE_a+MY%@P<(w>5KT`x(|^4@?U`G zXxh-vz%SBXYVi6EmuUJ5pMGlh9PfHP$47X7{6#R{vlI@K6XQ!<;&1q6Ds>|fLj}H= z>%s!R>)Ha}!~!qdjmO_X(A&ZK$pt$&FKjane;Xms4M+jstGn(l;9T+(!Cw@AC6KdF zhzSM0AG@jwif(gHDDby>CKQyc%c?9Wy(K$TP#(*P6f}q2|IoV?lus-u4Hc9CXF@>{ z+Ds_$hVwutfWK$)xBIuL6kod6E{J(L_EC$-l2fI`0kQdCg1CI_eCW4eaTLeAl3qkC^mGiaE9V+nO;;AesiE+MMS9L2W0VL$iPGy(e=c8Q`XI}3dEB6!e zZ$j?B1v8*{oZKgO(c^jd3aq#56+b_AiFxdzC-g_iJyH;K7oAvrOhJ%(?7=$Sh;@4f z^3I0`Ui|?-2zW^Kv(8mnP;?8&9rL&z?p9EQH4#x7M!k*z-}gVM)Pp?H{P**8LBT=Y z{lJOmN$54#(Jw)-VQVUNC-QO~tvhBN(Y_o+{T$eb6ZY4&jw%Z_=$2(#g0Y-d&u#7>yIiw`ZgM?M1KxAM zMsiiE>aRu?+^>3cmWXUq8grB=zK_*%^@eNy{7Lgg2 z@^jrBkvg(it1^@mKXBRN(?_KTvx6e%z}r>X;k#7f<*L-_A4lh6JnI#HN|hbC9#rLN zs$Mn!Kb|=Mj_dIqJ+9_;yGmbE>4z#kq|)qeLD96gO3zg37?n;^=?s2_OCHU812m414A3MBE8;TyJPI*ONa})s)w4I=LiO-Nz;yWG8x#R@M0JQ^C z(bvz0HsKkbrd{Hw)d||TZh`K*ULB7rw>PH*y|{HR?{m6cIok>J}CPXT8G5r z$-+q~8e~PW@ zb5*fCm)v=}sbVnqT^75mqM3V$ZSz&JCikx_7O3K^+(j(<^as$rt9VZC>1=z7{)i|p z$i0BYUb-AnL+)oR7O7%1_opoO)1ydS#Vc~JXYq8MZQRApdM=-adIspTM0t&#JBamu zo&SoLyEvxj?q@lmZxiLUdM>5v8K$om`0MrD7ubG`e!D2&t>^A!d8{gL&~taQT&~I+ z_1rxySE%x%dhUlTpQD$F_M7zFJQz{Wc)`89xLwaZ!20v_zlr{z)wOQCP3!q>&Tr75 z$g`0m@jeCL<#|9#NAtF$#`6a$9Iy8cmL8U}@oCxKWoVG?-2iAFhr)4n{}D2TQauFp zEeG0D%i#(zvo5QL!g>qPch==fb-XRPC|$vkyNbQuuhAy!N?G#dFKJq=WnCpPi@Yzg zZZ^m0D)xJuNM#NQx{6D@e*yDZb7iU2I|4XPsoXo8rFpV02nNZQiwtGeGFzZ$<6HNz z8)r$sm0@G_a;!@uxOa(JQVIi!M9u?&j#Ra@Y6$|p6lknmB>#IeVXg` z1)A@t3TXw9zLrR?M%H4|e1B7wKSgCR{y@R0?4eJ|b@Sgx6rWRGR+#^j#-hl%4R(7y zw*jZ;L-@+x$cfYSo<~@CKo)x8U!lO5o5Xl@@=?h3+FL^f(yZ%*y6EJgkOM8GKv3Dj z%Ijq%yX~s%t@Y7$(p;|V0;*{*V+pvlkpOz74Lb@(Xu}-i$A7SqpEvO*?3d@&a%7eL za*UHSTv=W|%vF{O$J^ zP_lj`p!X9uA)vt5ver#yGn&J!R%VqsbUg&6$-0w}Y_IEP_I0noJcm>_iYyN*vK|-N z&xr6OvsvC#K}%Ut*Ce21FHQlT!{5sE<*b-NaeVH>Ik8)AEkwzG+f(+nW z%O#n``0Ms6TZ3*R3VALMhT<(*jePEp@x?!Z0i4sZE{bwB{xXF3AlS^+#E8+u18C%w zJl;#dNv`&h=-ulLvNKikX|6oduaAO8mUkb%yOR$W{|%OIrC;J(I)=RO+A(6`81jyC z;xLZ<9!T@tdLbJWd-LfS@;s{O%co<=%TmRnd^(1_Y*qB<(=p`bsA5Sz9Yda16-)E! z81iyeu{@uSA+MV%2J`6{^17>{nNP=%m#>O7`E(3<1*$kJpN=8Vrym9TuHrfQbPRc? z=#;9fctQRJEcVjnh#KiKjGdFSZEMEgy8J{?2ec)>j#Lp~it-g!FDRoumJ35ZKOzqW5|0zN=G_|ygx|cNXL-(u#}At>cLm>vb{{Q}6pw!tSLvfmbeppMllxXa7o+yx!li?%c;j$>+^w-FXj)QjvE92zL*z z6{Y^(H6YbJbcZPUz2n(#qGT}O<&Em@RkDW?FL!I*FOX9QrvdHjevvKOm3z-&spbn& z3VQqIp>+8$49it)dhcM}6|ywT+mEFyWod!;3HEmlhXZxca=C)}F18Q?{+;l?U_5`6 zSc3-u&c8ue9hz0o&xF+&frVdi;f1I(#4KHboR72GLv!uLvMh*PE$Ti3XV(e2 z$G{4zIdnrz{#~phj;gN%lLZ(37SL1lhn+gjH3sYyT>PW}Zzq@wwTG6|idiWwnDPT8 z-Wq%rT*548rGWfR9VSYces();lqmVUS!i4^y+V|VynfcrIA4_f-ffUe!Avp>cMTN@ zqPHwBN0;U0II_HCIm=7tTo~a1+!(}GH@uELxN7=P%u}PWZ>YGWZ+ORPu2y&8zmtEhk{yWa~5MvzJmH* zNF+B`%l@^VjW=io3pnqz-Y()5EZol~_d_VYf<-1EJr^#%S}RyAO{3Nm&+WB>C6Z;d zA!5PO0l;&O1D%3pS0O7^Vg+(tb1QOM&b2@)(r8lfiM~qmt%=Y`U(E{2iJ_5G z;({eH7aQx%%;sDQ9V^jeJ&*_~>f)yaF!LOf-XewQ?Ky9rrr&Z7kX*$+?@bt)Q!46N z+q6v6Z~aKji(kvxj!K`NAg*L(oouFwSWjQCTmx8PpDy;VuWct+Y^mQ#Xb#WciuAkI zA>XrpzNX*pC;@-CM*q3&%ie#3q+u%7jcqniF($zh52QmDRuZ?za$sW*$<-7Be-gZn>|Wp<Di1}e_4|aKtU0=dup<(lrx z{s{DnZeq7RvbPg?Kj-|EY|<#&O?o}E*=f(%u>Z~}ebAj z5vc0Zv!!G9A+UEm95efQS4?Bk z!{lm@M+mR*JvQ0l5xz(F!vL|#4$-7YDCACscrm1|pYN84+lYwapD(p^E>_$5ZlM&E z#QAQ~BQ+uDrY5lSkU%Y>4bdkE1Sy`0Zi+{$LZw@%f|&j)x0rsR7Lx>RG2qE=XZlUK z8iYi`ZjN8;SI9}8_$QuW%T_>)`}s{!I<4e zo?&Q=cKum1P_;X)z-c#7wtHFDieBI8$`=V50f$BjYlbTti_}b`+Q>mm^m`ADZljQU}Nekls{BD*G~J;O9}G@p!F5%(@UsNUmiK2mb%uP z6Vgj6!D;v>B2oM5i2|gUG^9-w?WgFdb!zh-@fT4|2$G? z@DkU3`;ME=i022<7G{11p0)!xP@hitKpYWx=MU7UxIfpY57aMVTdnwK3i(=znCte< zk*$HwR$9Pes1)Qt%9Wc^@%4H%5dmkdHYfs#>)!}%aPWf#lF(G}sUHOHnPMQ{aQ-)N z96#VVzLmq+xGFG4;a7=%rb#ZRxNqOM3ZcSRoPtiT=)fTyJVkb}pB+ra!R)0l=kl z0T9l@%|oaBCCkg81qVcL=V9iDoXKgB<$G9e;%b#;?f{1HVUzxeFn#rqmj4wh#HU`` z6VL6Bwyhqz3#(|VA;)y1O7*jH1K8XS+mE_od+{~=c#IK;0nI^QBU~_{Q;{j{j*O7YuZ_>Q}fY*PfR{TE-?YFWQ*K)kH@ec*dy8UjDY7;e6vTol%y2anA$~R?$TsL27 z7oXyMpUi#IMQdc0g8d0>jI39Mb`;8%sRGWi&OAj7G1uKQP3uppwnA3vL9O^T1*(=H z7dB~Ue5+s_Wu1UeA-uS(hh$}i#AWlV6zC2K%60QKYw;<*NmV`URF%{^RZpp^=bfsv z(yjiksy=Y4W~E!bqpA+eDoV9DSLuAuo@%gN{SQ!8!@pNGYOJb)24rvyQyl?rmY3Uv zEH70@?3)(?IGRU4sR7#AUr}p!%80^Qa98$}16z(3djCSKrMsy6J4FaYcX;|@IGLT< ztQw1j>*xIzeOERe18mBwG4wP`6i>1NDZL@!@u+3!4yy@@BI?wH!Xdz}O@Rt(mS`B4rP_Tgtw!CCK z8Rx>#&SluVS0QM9CG~meTTk`Dcn70)I(*RBbCK!oLxxZ7SM`7dMj?}Zgx|l;%#WBx zIF{asImk?BW)U*?F|z_03#(+r8f11ca~m=?*cx#UGUdII`8_f>GxH~8o)0TQBpuK=>L?_=mMYWhfeH4uTmF1zv=TIV$bD%xKGxM+X4 ztG(c7V3BNpflBrH*>@g8WBBnHg5Hxwie6UVG(W|I3MH*aKtN3L%g!Vh|5R1I;8dmO zKd@6tf@;atyPArupUoBCSb}vbR{JdX?T@Y=&pE;Z(zLUe)84F;TL)*d-#JxwUjml& zC;Pz)!3eGMFrt1Mmk9>{ftGBYh}HVz^1zT$q|xf3|6R#)As5GOqW(>kg?pF9d8eUT zY%gSaGs|K}D$6r)lsiOh+i&w!gS~c^U+f}x`T&qaX!2vRQCTBO*m%g|yC@F1l)SAM z5#_iufGi@V^QR!X;0Er$&% z)qm%?9zx1cy5lj#BwJ`Nl;%}rl+vC5D8}~)8W(*IW3E3bIxd<*QObNEsXCcIQ<|jZ zFh)aP0hhV`AB4spMBQQZF#LFgVIQJK(}bSySB>@ppl|UE#q@Tuf1XcQ zdcGo{Sl*3{69=8IIBEe$GtiJ)Mi(+I*Zt+}AP5pPMIWV|u}1ZBKQM2Wn7MBL+v^f% zns=4vEf09h&(s35PL)ulww~LYMKqPov{>lvDp2jxTY-R0?@#D6$GJoxtG|vudec{q zbJ16772K)rRg~@1WDjQ#LW@bz$a7vsZT1m<|2i`tde@e;+v{KpIH8pDhP*-z=Z$&w)_;A_m|lt=;T;` zamJIXicX*(q{7*3RE_|)q4-%s4CL=A4npz**w^*CQ^$cfk-y=}KgN%FNZs{EeALWCjmKW;HUmGLt~& z56s+)%wA?5MyB^LWcUNQ)y&+5ObnSZ++iM3Ts2VG5qD2moUwlbT=4UIWS#=%d5@xY z;%1bv7KgIg*3;!6I#jC9bzkW;{TwaEvgv@~SZv2*jwP9ys8I|!6b_PsdF}^Eg(x=y zMR4*fW=L)eGJ!W$hYX>`jNn@Y(Q-IvE8+TGpmvRWpTpA!4w0cFFq|6HicWrmk{VG+ zwVa_+{aW`}P7Zl_189PmZD9Bayt}4cwi7!2(-YLeh17Zy;q-Dxq5PH?=(4;BWxw!ZgM=5;r%4|-NVvq`q4q2scF5B6Eb;K{Owp4z z8d@cM)(?cw(yttHH5kx;AUxVe)Y5~M2rl=qv;;eUSu8voMV^!n_VB3eDinu^L$b33 z(@l&8%5)%d?qsXo+mh97!-Jbc*m(rIutxcxzJp=r(3x>24>{c5$i&*4()mbU)C z7BihQ2B=~c^;PXoQ>lKo=YF)6tv>4x*CIZm)pWEPetd&t*5p7%CFD>W<4J*<(BS*g zTIkyzW~gtjvCxJJg_^mVreRA;tyzw~g+HxQNMVQWSkJ^Wz$N`@x6jUUxEy{wo^q>V zq}8hJ9EV1^=ck|{csm!I2;Sx}L*8QK?Mj83$(!PeG9PkAPzYy)O7#modq|NI|Gh(K z7c#?-#}u7*D`#tA0v!tNF3jGAo?!zOU&DbS$W38}d_|E7tWh00e92AXN>CFcU8bt9 zbNHI%sdFgavkD zGrm=;gn`VtpiPrZ^}z{XqjrX)k!&(OU8@z}lpSBlYF_do}C4e3JrAX#dW@`Y1ZS( z_>ub3y(wQpWzMyx^ee8_chT;T@LjYoxO@h=)HUVFq~O#&8Ai>4qV9OwG@7t|USI29 zz}0#iw?Q~IDU$F|Bco)S z6wjJTg2@f0@}5~FXak3nDVLl@WqnK7lxvHrypxSOLkp`Y;nw5>Q@nXLRqN5m-VUhncB#&xXeEy?wWE|8I}Lap=ru1shnEMrkHZt zY}RzTyN*Ui^>lZPoW#<<4~?KbLnhIk{1oy*)h?6l(SkpeUW(b3>)rk*(7a>8D@j`ZCdf{sl$`OouznIJ`<}7iBb(D<gAiflHT&pN?KZ|3M~ za-W0dn}{XOfARc(-i67GZ9cjRK3*FW3uoFe|eI!k5e&Srwd?5qY zd?SH;elSLB{u-6E=3g>k&F`G&YyQNEM)Pi#{+`>;(%I)P5KI0Z7Qvbin@^hmR#@wZ z2b%x+`!wf3X&q@~XLAsJ;=T#lcagOGbwt#%2UnBq4q^Ruob2myO_kdhexhs*&HjINt*Wf-xzSL zq@6>6J$^2M{BG`+m(ER8(jNaU1NQiY8izg^t7S^u3st5#>0bzqw;I1Obh^3LP8WDF z>)tlheyVTH6c$5*HcI^Ss}S0Tqos;AFs60-y~4ta{td%mPxnAm)lip)wobNR>>N?{aAw4Ce z=}yL3CmC&Ck(P9UBIBD;hPKbp=%Q1tA@G)sMIVuA$^%A;OZbP!^(W(YiGZU`l{?)@ zpObAW|CaB3qU!>}baMd?bbueZB-oc%5h{XI!;i@XBIx}3gRH_z)s>ZIDs^0z3-4%ZB zx!+{+eK$4I_rLo&1^S_Pcf8q4Y>}p?k2k|`Hq8(B8{#&5iSc?t|0xm8t^5ft?tve} zkN@ZBW!5boo-56H3qx^W?t~B7#*5+QN>t{LjquM7Q-L7K6#1?~^AB^wadF;$~bdh`$()NUZ>uC8Oz}eK4zuN(YiQpAkcTNJfMTCZ^)L+kiEv(!3$p78Jq)gOG#oH2FrQd{Dsc0g*2lSJ;;!!kw|Lnr-m zspYe^3{x#<`DE$v9;xNts39*Sq{B<%9lpXnU)ty!=5l$7TBiS5c=E`D>jH9VVBB#| z`hH>It~Ul)ob-sq6nFi&)Kd2uLnXXk6dHFnUTCb)M?yCW@twdD9<=oN!V@Kh28}c3 zn9CXFDi86DX%rqkG#5)j56$&bAP*Fq#{E=>IFTc1E%k7_@N`lSi=>ARqVE?vYj?5G z&BYhitG~n#x7ui1Wt=Ybp9zh4GtLv*9}KOZ+EHsF(aE?-sy;#$|K2ZuM7uH9Kpst% zF}F)W+qPK>bPwgElO;f=$F(M}k9j=4^>gv9U$w2zMeEw$tux*eo{PZXpV(xKkO-;F631FFY|^D()^s$jnO5|RQC*BZZQe|U;6U%o#!LLf7Hh$ z_#N#dw{ZghSl2(fjB>2LgKNrS6;<=kwn(}E1+pUS*H^LkQE_A~Yir84 zuA$X2m9;Zvb4F}%3I)r^tGVt|eVP6k3d4~<;nl>HySV&YPQj*p50#JMdx)R);paY7 z&%SnZ`}lKh=*P@X-wf%vru@Y^(u`KF&-JDGb2_P3-w6LgclHdI_38Q-eRv2abWwRV z57rlbo}=>U^;ABd?KI{5i*OpTjQD%@K zYmd}qe@K8%Q~2qIsnYsfNI52HOiuir-^?I~zHvR{Vp?bTX^EQ%;AsiIg?X~5$d}07 zi<0gjS^C=7Q^YrBs#NN0Ulmf&*S_wYYK+mT)O}UD<_*q56Lm@ z6dLo(I0g!n_{q`KtK;ys78mg|uffLDW>gu`M@{E{x%@Ai{$&RFvd-cAq)*RRYw5{Ax;@T6lWRWX`6=3YQ%td#!)bZaMv_0OgXsC2 zh>&#|p)bjiGIswI=HpK_joh_K-%x`I|0Le`FD0;tK>y3gh#;pP!%K8BEE2u!|&N8;H)#6Rsq{GV;>~P|)5_rBivQ?#$qpEz*)7{-YjrtDDj46>hbT zYO=UN(v<|bc`X6{jD1iVYis#87R;wmzxVBaXe`_#Ot%%9`kSe>J8G)2@I!6IKdv$s zeyA}q4-Ka7RdBZoz(g(>A-Ln{rR>YC!kR2-?Fx&Nm=>3oH&`Mm63`rP!-$EP3!`aX(w4-OmQ*@1xqF`~M>?vjc) zbFCcR)B7Gl6s`OpiAgK}6@knkr|vTQ25vlNm$c?=m+^%Z*sm0p19~>oMKH;0V~(0m zRQhmk8hd$xDd^z!^NCTcK^Rxd(LJc|Q^c)%Eu&twhASAbdv75yd_|mW5=p5?GNm(~ zU-o%UdfUST?e;zDR2te8qK~Sge_6Hk@0TPc{cB<4>v(;Lhb6V7NGcn9qfDWI%1*|q zXBb;@Op|^pvcM4NR70vtQRQC<$e1o8U2m$~DNe>7A+0u~2wkciGb7HjjB%pit-{bk zN>>Pt-TI`^&7%uk`>@pVqi=sfD{T@z#Kn)c>E&dOnD&j~h)@1?QZf6Ufy=KYyH_UZYfPJj^_CgNGbi0hbqi0&Nyn8*6zk58n{d)`RgyXB=$5NWS0`~K z&%K!vg1$Xy%I#d{d~;0_U-x-YS5v;|*3$mPMZRcciYd2HQD1WEN#aXTN8UaX7#G1 z>n8fijdXOtSJUf#7AO6=xc=JX`g=33zgvBN(uVu{IIh3vdR5XB_uL;p)VqeGTNt_5 zKlzMK`UDvhw(_&MUJHcIRvt`4rDp^CfO|b#D%r|$y(*``%7wzh{mt-MoUxY(T}M;e z0^@7CkNik~iivy7J4fyd)ZkFQ0(g&pxq5PKH{M4II(ZR2V z-K&`o<54#-RloIfpI-W%A^g2CZbd&Gk?!0xNR$qUihdkj=Dp8~exoQ759L>xD*ExO zOo!IeYfKgW_%$Z;PFY32_le^$tx%3D|T2ht1V4bR8NfNAIM><*^(jul zUH0_hT#>;qZ4Elp1i9X9AJ`(VTlF}@yiG$Xs0Xa!69&A4b;K-V;7O)Y-2S~tYFK1x zoJbLXDLOQoROt&#$@+YxG) zal6$116BO1mim+NGpS0ZA?uy+GhUFYbX1LBfL3oyRc@$iOn-@G){&xvXZEMCkfY;9 zZwm$Zgk+kJOK4;!d`k>d?k2F0z-rj^K@&#Q!bgW-&S zckgzox<5|H3qpGy?EdB|;~S~kgDU%4+`%PAoo`XK&X0$5sXB-T$t(d*Mzhd{8JbIb zmwSbDvL*dqNCnc8>`wnkXzZ67O*j4+DDkt#@W$^zhD+6rp{lVHq^ftEl6!~9wEiR7 z@NZ}Hhek+0`ZVTzaR$FB>kKLHLxFg>tUXJLDDBf}$>ARF4EPDABMhQt#US%?`jL8B z(W}i+oq5fx`v&uJB#5tD9;K6M>e-6=Ia()Pb9c~SeHZW;kDuV7n{&rdukJ6*#wkrE zPes)fs-vCm{Zu!-*qp!pLT_E(dH~DAFZ9OegUwhTo{(+Sx(>Y&dQw*(@(^WgUM);9 z{b9=Q`bzCqy~*0cWqsxKsigO*!(Cg5oi|xeCyk=wagWdx<^}1qvME%grxp$*g}zHV zXckS+{X}mghWvFz%t|IVzE7pB6auIHjKEL=8yFl<;Li-k5;*kd1o8;n!eBaqwT}`g zBk&S~a|lEpBk*q#Kc2t50R8Xd{)c(LnnC^d8%Sqc#F?K)gPJv%N)J#;=KS_KQy4oR z$Efvi`oaZ=D1cc(}}Z&`a?+)aN) zW&!Wn?x&7OA@gdgKGETKT*(67IymY3gq0`pHp6Ocjd;VH^fhJ12!2WNgZSD$El$o6 zPR1=#ug(%D{sdO1KPgpwE$~QFt#6jS94B&;(6w`o$n?oFmV5?QgL-`iwnomtXmg%1 zO?1-C`fqq0R2`eJNV5?yI-p=b(Lbio>5d6glpJ zb4+f#x-Tc+pFUx(O>1n^BqTXWPpv9GQnN#YGx^*`d^@XfX@rRQ_ez>de zUrI24{bB(<7wA2u=(&UVw4RfmW6x8qmQzh7EvJ(K=Wed2QRIcGdcKjhj%97` zTgkF`VY-_|Y+(_+Fb#X28)Up9qsGte>bZjJxR~3cWHk8uDK&%5>e*sEXZ4p%HNAD^ zXZ5x5Z$);?+q`S3&!J-MJEl#ao)37#S}auFn0=#b^aC8}PsY(x%d`@DsW7$Aim}`( zTi0rO#y^B!Xj;%)5V*UMT5a6JEf&PJI7R4dO^dhuvf z-_qfvuNNlH`_CE~#v7dXGqy_YTaeB_)Tuui-$~UMs7k4qs8H^~IkOhiZt92;L>S1~OMj_D9;#EEv$jSk65gN9RsP$p14n_g0h|Xo#lQE6^MhqX z8CZe(OHkj>Ijfms)&2WzT;<;^9Jqpu{U}d70?vWXSvOJAb3c4Rb2>|nK?8q6#gffr zcK>_%n;u=a7x zP=B|e{yIYaeTFIg48K$6_E7V|8T4ICXE4uX)3^^!kNz#vcoA3VfBX$Krd^WvA>mRt zg?c$?k?RhllFN~zCD?DrbLO}a){m33>+)8@)GcL6uXAVR?kckIkTLoxc(>I3CYfq( zmX~Gt+by8eWz&QoJ#jqlHJdFn|;IAv|QeQS#?!C<-^HQX66AfGtshJZkFMbbe; zrB{>rz+8O?yXwFJ1Gte(MehJ#LJp6I6q5=DbFn|<)9W>^TQHbg3`}XuWyR5SPth@1z(b4rU_;F`0>jd;9i~!LA*$A(=FSER`js=}|m1 z$#|GLB2S3Bbs<$8sSAe_o9IK2##=E)$dLmmYKQu6j1zy9W$iVv^wrKf0!TOy>@l`u z&Uk6IYc8f^blJXPal@WrDwsSRJoJq{(&qrSvRALiNv{;n-0ShuD;KGo5mr~UyTOFv z3D$aUcVe8jR2&(nEfr5XiUO3otsGF5#Hx)-az@i3a{z_zAaYdJI4ZN8YzFlBlTrQJ zsr{LI43+3R)VX4;si0dAIz(u#J2|YP%#`um>umZiF7!Hqd*xnoeDU<;YNqHmC0R_H zsM*N+NrvruV{tBfdGugCx$7X!CopezYKTdRd5$`~{ zOs@xt{4z@hTc^OYL=TA=dhk>0q3cR)!6cs9@dOUA(%#ybOjH(6G^9C(#Nj)RQW!h2 zJkvpnWHM)|3csNabi-F^iI+?{(6Dm*DoaOuXD6kNi1RS#JNMfI51{`pxznLPH><5> zS=N%p3$hw&YqM77jE{~VH>$1iyvC*#jiZ(D7j&37` ztOfMTw7n=!W@c6k-LZ1yx6cXDgCVU87uMBhF5*60S2fqQ5Tr$pI$qpFP!Y9x2?5%B z5G!c3)Y4V;s;Ytl`cuDgJ8!z_Ms;AfZm~I8&GRa~VQpOcood^-U6WgrduEh3sLW2asl(g+ z=_ar3tP@oK%AT0Y-?$-?F~obn=$fLl)mi&1m|dl9e8^jor^@!L^XZGfS7$!BT@C0y zwX`ADrG|UmzDO;)JGr4trEK(0QLDUeb?pUSu9q=##mLEhBC2!wP7>DDe=p(h+Hy6{ z99QKXQ&d&ZHZDsojU4NeYtC(>f5rSy-PgWR4e$o3wn8R_#tXJc^pL$)*?atekSD+5tuii_}Rky7wEKp0gd2M;GsriK}qfo8b zs}A#8soq_I72dM>@PpwYpNJt|NbS_sTNn~xI zI;v8AleAZTw5rhC-ldv$K2%V(MXmPs)3HbWMdfA{T$nYfs7T$trhCT6b5ALnp_X^6 z0lBIzcYT24t~K52kp1dc9s6G#MNQO2ef-h?_XVAK>UghSt=`IV=g)X9ORd_>aF$0B zzrDb#e47lvsbE&j>)BLvan_`)#d+5hso(bXMf`GQ;Zv%v@a&1|$Vwj3w{!>`u#FGR z{BIWjtGY;iv&QQzQkSSgHFK*P>+S5xFQ1_XwvvBZz1?blH+e@lJ$I`<9I#*2lk3NN zxmD`EzGQ9->;A^dLUnK7O0}Dg18Jm}6skjL1oo;u{VLU_<&|{YNXNpivkS}|C`_JP zki`P`Rj9=q)#{D(KX!*o-^jD&yVcvi@zy_6)KjF!R;n3$)k{u&Og-AM^P;D^HmPx~ zYB7!7g9jF>|2n^LebL+pClxg`6m@m2SM#@h+EvxCM`dpN!;9pfKd5^;HhUReT`GT@ zD)DmF(!J`!NaO@pRcurz6sqzYDaK^_|tMd1%vuG$^TDw_2P7;2m-Fzfe8YR`{T5s#LG6_0p)dtDcN_I;Onky7>Is&3w$$g{LDXTzH)N7HwItU_OK2=6I1JW03s7F?Lg@;Wzb@a?RMe2agNo@~g@2XO( zx?}3gNc|db!!uPZ>C+wNLwRGX`ojT*>gUS}tGt^ji>xo|Q3abRrd!o3?HhH#d_+Ta zb;n-S*-pQqLXk7A(z}TCcRJP69hGfe6jGBr8#wSHr9-MJx~k@vUZM_;OmkIJZshpE z>P5FzrEK%kV?FB5c5kOTe!uGK*r?XIG;&=Xh19-FeNDnH?a1s>UpR$r4c?fG&YY<> zbmXdkIF;)9j>^UAz|KiM4`e^3-f~*kb60KZO-Ik)Wb3bjPs|T)7wdCfj{<&&-A^oqSK~%qU zS~v8N`rFkBiYK12Oid#Cq#mwK2?e6_ujt-Y6w zENYlkwCL=0c^h;y6DHn6-YPG>V#CC<8`R23hP!J+K@rWj0bcI9o}wprPn^-<6>X>} zs{3H~Mbj_x(kJCTST%`8xt*4Ak`hrdmsUP1X1D~kNXox^RW3!_`5VTnsr8l)gtkh4#{ILIYJre?N=9e&@{ijW1HH`zmLQkzhY*a8bTF+JG85UcYN0;(e`MNcba;#WA6u5YE0+nY6fNCqrF_-Qh3>~w_K;@=BjPZ z-t7fmdV_j3sZc$*dMh0}FIB5^$DQZ(6y%+!Hm&wDcRi5xhBsMdwW`Z$4^u>;m0P4% zZdD`ps=3~vUwoFQ+Gu$_#%nF;^71FqFlKs%vF($Jy!6-a$~%qr8s6ZURo-APrf%$@ zVE&k#+fY<7dU{cp8c?sAyw1E)YVgJ$HMLUZXBJU-7IkssB2`$~R-y7X$0}6G=E(6w z*a4B_Q`PU2$ou!MrdLX}OHSOV9!>H#M=}O)@pe6^o>{$>8ocLjrfAAkZJlaBr~bdc zO0{OHft|FjUG_++xAN0--=j@t^EP!*ZqZrlyi7Hun->PNFu7Zk*XvX+%apFstAd{9 zUvkH1@IRflRx%pN|1MJfX;(0vwx_w3l;qU*;Zbo2!18Z1y-`wCiwl$=5oy>LjBEW~!5R zo;`iRR2ni>T(6Fxh-fHOhu3#`E4$QjUS$_eo+2-g(&A=HcgZ;b@8gb>fgy;;iSBVT6H6Bfam9WoReHx zF?8l(3GP#r!P#l+ll>jzzgL+g)tcN!tHz>8#$mBZc`+}&YQ2_!eaButdU_PR9G(%a zG-(RG2h^_BJJo$jk>RfDaa*^0c{H~xX_`h#TiVBLf)yaBmmHgCupHAv}kDBcD%nD-2>f)7N zWpZWmgX){UIzJ|FOjbGG=B^4oS!jWyZA_=^uO4DM^h}z`=uH0SO;VKq20b;YtAUb> zUS9OM)W>~jyP%#UkEUckoIjmC;;LI$>P*N^ad-2-iTp2r(TtO3Y+t^mZDvt{s-^t! zH=_!jv6!961j(Fsfg$S7l_x;cH(s|S6-tlw_pI=UA@7)hIysj>#C5cw&q8UBv19$KCPbn!jZdBx< zo=q)XFREc1w}1Lx7oDkOsxjL(c<<+_gEy;X8@)HoiTtUhG<8V5*6-BQ?cO$0t}Uh( zZriR7q_Zb4_d#{S#_ch>I4~}zZtdt)zg+EYyhp9fq`%y#q6AmsrStHaEmg8wU8n}- zKI0v#4(?P3bZ_uJrP%CLr|w@IQ*^@CKlfv5GwJlAf-04vMSN1ZHnYT@h@ z;rtd+ce-0?_r6!X&%bE5T&={KC3tbn@4g-&zLvO4>Rx~C*lYQ)Eqx|yL8ghj10|w*Ai3)mj zwC`CVZJt&%+FY}6v=imS7;_kF4&%(>WGC9z*w#|VwbXC{4O&~X@yt>^%0x7d)xuj^ zqqTGu+9>NRZEIvJiMU|NdF(0!$uVSCw1p|8-m<2qR;Q-9dCB6smS}5JlrDO=)mk4% z=^`_6H!NOAybBgIuC#F%ZLC}2=-yfIQtmiPu|ik77dNt)mgYu>L#Mf>rPXO_Cf~8+ z>18Pn(Pb^V)Ka%B+CNi{o;iyHLba+t#M&=VNGj|+?vQD z&dgdG!IiC14vA=VVcl}lQ1?J=OPurS>Y6DEnwsfyxkJ&lgnEfaYieujnp?+ez6Gmj zj8~9{$Qfgz-2JIhO>^p2E+&Io8k`!YHrGUrhBR=Ei(6N*mByjeAzgT<0pS}cdM?#0 z)n0C+$8X|nX=Mj3BMmiCH(6Fk+LN^u8A~WuwVMSy#@gm(O$(hG3U968s+L+}jJ7Ok zYHXlxX+#>^YNN|*qD$!BfR;qApqSDzvY@H4&Z%EX%D0#5HFI5pd0PdC@qofoaOu%0^AHxzho)wC{dYP5Bf2GD|IYbj+VQnJ1ovw;%R!o_~l zGMbT>o9k*@qf2zcArEofMOQ3dNE6TGHFlI9ViMUhT8|LrkY)VCbb8=rRBD^sXapL_ z_{B9GtKyVsYfXbgin6Iq)O{lbMckOwE}+UKoRpss4N`5({VnlW0qz8$2|xiqcnR@TMRdAYMvG$wQP z>}2J1Y*0Wqx3%iz?6gtnlJ_LEbu|Z?Lr#c_AIUj-vPElI5n#?Iz+;_yzNhOzZ=WxHSEbbM%4*tu>36kUce&Rw#|LfJIGB zoNH^AP%7uC;>SWQ6?k+Ox5Nz)4JyAd$qhN5=~%_Y)SlE+l+`zr)oJjlTP-snv>UpmNhdM9;?bK6jHBuxxUeBX|;vt~0Zd=A( zn^f-9vjdUkYF2V=G}h8eO2=kr1%)ahPG=4!TazSsv5RslaQGf$3r!oRRwqO5Sm*J2 za!UQ;Wz?{ywP|VGnEA^U4<5H+e>IpT$hVZTFrr=eLV7pSEUa4?r+%%TBD~6zo|IFg z)a6o&DSxnAXs~D4qpohO_>qaZ5tW>ak`XEwx#Za`<_i z!giJx>?y8>*^M^@V1GPQdBQ9)&T3YdiFc(L|&~~7Uvc1DE6(X;NW0Z3V3oeTh_da z!-O*}N0wfmIaiDwL(b-&cwJg<0-5Khrqz=?T7hXrZ_^>A*DYq&>w^g}Dsd7cDSD-* zZZreZJI!>vdTS*Y>*bP_p`<~&@QmQh5H*uP)RB?%hmBMvqwAKKJli{N7AwfK^R4r8UNDgq+(z1bTENujEt)-;_*I8OBaD%0#0Q1*Q@`pzPxS1Xq;g8YK zVEZ3Fy-RGP@d30A`DY|;6NADH%g_*(xXwJlMWPrFY*`E?^gxXNv-lE-N2@*#|JLOH z+;Db+hV;9X!G=R*QXMHr*C_@p6YX86{6&Ge^k@)&hy++9B+`q1GZUo?EhFHiKB*Y+ zTAx(@u|SwfJ(#ZS|3Xo5zOQOIV53i}jEJg7``TAq5e99QQJ?C!nvb!8p{_GOXdsbb z3X~;MP&PEW)R$chO@{dz6$e`d!z$ur$1r}7=sHo@*2hW$L?^@*wj~<2B^tIR8r13w z@e>^HI@N%P4H|X&5mk5%-5BbrGNkCqP*JjDU;Vf+TDMjMA{Dv0oppBv{6m{w0Q;~s&MEbr~n|(`*0e|L`LP>|eRi8f_J6#0#{gCHgJ`t zjR2l&X=%XoEiDx|YH2CJ{Bs?mpa*<_Y>2dirrQ38M}IDsxlS3NZAZV4YFij|xA2db z4k^9?C;6l~xdLGtuf{@x^aK;*X_0+~FKB+aRVdfL5NcH(ZWW5CUx!+iqSZRT`%=J* zg`}L8l`#}=%D(rC;K$|2$^H$&@5+%@zusLr4h)2&BJ_PSz%joWy@uHP!#_a5pFwiu zc@KP;rKJELZfU8&M_XDN@G+J)0yx9cvVo7cv>af58Ja&dt=73H;N*knJ@87~I2(Ai zrHugQ?+)e>0>5i%DZn3Cng`6^Ip`~Bp#6^_pCOjf;tL3)DZT(N6fU#)qQpNS!XIi22z{t6 z;9gP9v_bqjRIckljZ=zgan}u1Im0QW&gtbv9HzO!OkIDFPp}B*3jg zQqK8nVko@e^OeA!yXYMgV^8_L0w429C4k#}Qu!`{@A{+?Ksban1DxmkW;Wn&d{X%f z0$=q>C4d7Y2uRiu0+07eC4kn?p$s1Ob0z!?=PEiI>OcYRb)8B;7@_%4zz`E3AhghY z#+~;6LK$cDLrmQr33}-6NFc5|w7|{@i`$e)+@_A@;?y|pHig9P6LAPC&ey=BY_v=e zh=6mQk~A5A{$Y0haLZc3YyH?LL%4imNwD)KQIK2SDfpLuBoreO{uIaduHf%{wz6<2 zgchZk7-_@56yc9irHwMwg1-`6I!h5j7zEZF80nfeE*NTzGP420xx@x&omvc7@4J2; zAm*@g*7Qj*q36M(alWJH0b+<;rwXvuasguc6Bi(+KPd}nGeH&L2UZqfhCe=4fY#IV z0N2KiEHFkP;*5&{BTz^)z(@TK<^dv^5Emdqi1Y_UG!YlzXI2&vMd z>oIt@Wm33tOD>RpEf!MjFiM} zfxq$jvSYx9_+dIa1`LmI+raQSLEUJZu};KZD@U>j@J7GK`074IQ6J zeP2IvivjuVd;Ub6<@!y0#>e<i-Y~XH78v(q*($avhv$Ry;8!Rmac$1}h!2BBwzJe&6Eksrjc&?>o1JAd# z5x`MPO9QU4v{c|)OG^P>WN9AoJwnqSMBzTmm;-#jrDX$ewzLtz4_R6o@D@u;1?F!U z=MOm{1^5X|^MDUH$na?e4YdCeljllo&>RMQOJvd1S=WKWdqN~WKr5g4tYm{AzrmMZ z1_+TP|I!5V%M!@HG$j8|BA36`n?JN+yHuj+MmZ8`ufTuGk-F^e_)H4_wtPm0{SWQw z>pb*_Gc7Q>i8!NU=nA5k5BPWfkc^H2f9=zp!8GBETKaiF7i3eHtZv_wc`x?{?$X4CA{bGki5NkIhb9L5D3$R-Vy2TxbT`-6wjA>Bx1^s7 zgmh~7eX=j~XIMGlEkaVxauq`XGm(gWVkjWEXf6WMcd_UXoqhmfO3|(l>c3>U0ACRj zU4-n2p@3KUwXR(4C&M|sCj@54E&3VE*1?{*b&8!0ncn4cuXABY@XgS{iVtrKJL|x3m=COD)X< zKAgVlQgjI|i&v$Xy1V6=AifGjWTPA@^O;S z5`jE>W($T2OoI-O#qj|{8Q#PJH%XV=78sf_AF%aScryf@{=d{C=pxqFddHxX#Fi;> zHq{GWBS+fb1)J>^SD`sA$-&+d>^!E6z}ddw&@Dgs4$^2(kP`b+_~B4Z464N6^U9xL zHby<*;g*&He4M4F0*|n?G~g2~Z3OU%mX-}X#?o?tUlSUgsqJu3*d50R{D!4v1HWZy zBY@wwv^3zqSXwIZUo9;K_ybGxfWI4LoTe2t(Ef)&RsmhXjm zfbc9`s$UsH0ZJuE1N%gJKM@sinmu3)9PN*4rTRj@$Jw_F#E>M)P5%r?Pq3nth?whq z$<;RnBq!Kb-6n#cks}EX$3by$01#v7lU2Sv)PLwPj!mJ?W`{eQ9qbI=!^lLOHT2^s zhHI=GX+8#2& z18*$)1mX-pXY-y>$^nDrnLy0&Ic%Y??08X*AY~Z1m zmIFNQ5F?M)*=HRTCJ2!_$pOx>v~1vsmNo)7*V58}^DQkEc#5T^08h6x4|o-Qi6not zf(FL@7mJRUBaJTLjXr4}AVitRPvWE)C=F8mhGl>=eNrjl`9h*uurh{1d;&55rCxAsnRMcMDhoBqm{ z$e$`X(%l0$hC-VV6NC-gAr2DE0I)zWG93`kH(Gfit=3A%-QTYOSTJ=H>|nrhy)UKI z7;FC{IUy0zF6G}Dwz?MrZ`||+M02_X8{V>^9heerDi%r5f+xXwLYSqjmwHqPvxIJ3 z+#wy=R1(@A+!|sDbrfa^b%b+SHFhU@{$Cou55Up6&>`-okd(bmEHQe2tV0Z8hOgPqQbFS-Sel&ILaMfq& z6y0Ljb$!}Wuj_Mko0ojPGjv!C?7tE%|L0~axf$4hBh8YXW@njmbPQ#yduU~aqLyX$ zn<52%pkl+BF z<$^vePlLFB(DwjoM}r6mk(8YP@3dTicL~W%4wQa#nCXMs0>0>z<^X=;ljZ?_?vv&K zLj43;@_p(2Q(v$0D@DNVzM%3rb2a4O!{W~@zf~#p-e*aG-}A3>0w$9Jq>kf|@3JxCA;J5Z7Oh z;Hh#xK)tl5K$xj`_+Mm5N5PrOo=%%FW@#q z3`oxwrZILBdBEc=Ed_YIrKJMrSXvtJDV8<@c%r3c1D|ebIl%uq+$c%s*ZW))J`y5d z0092j(z1a+v9uAupITZP@aLA63jC#|r2soe7-cxq0lzgOPQidf9e8w>SVk!a(6;M& zw*C9smHO?<0RJj_(YyluN=TfS%3>%r9ciQzBj6K4GK?raljbu5mdGVc+LZu~9_Dia z&hbf6z@LgYs8hffgk(BJ3FaqA4{+K~{1M2GohX{u$dRu8Ki&TNF`|+fpoxb|AwQn@ ziP&?LXskJpI?gojlq08!!N(igNpfV`EWt0!Q8$Jiuld7I3YoU{|Btlf(e{_btOJIc z#+;pw5$j%&BhwB^Gxfve$m#*d8T@Gb3}LAD8Ar!3l8eO|EHLj_BXFJ^nf9IF1AM=X zj{R6){aJj}N8G~lOb_<|kMzop_Ga=wV}16Jy8svA`FN{ zEfN6WX{m^<3fmcse*#C9oQqUz>|XUtDcv}0$`j~u}#+W!=YYx4JS8KQhS zQU_18V~`M<#Fxmii9GX|cm~ekDe+_Uy;pMihjOIU40xzbGOx8K$ULtloUcPAN?YVe zuZsc31@LQ$0{FF%19;y2LE;Q?N1l4EJ&{`wQhqc!b9^Y?A!QOdZ(hK8^!5w<7#CEp zwPQLXxU?$46iAJKjN=nH^sDxNA7h%jY34{Be3i&kU$vJAM|C`BBCjN}*9f=&b7YCZ zQbXN7+l~U3SGvrFH5IxO2{2QFg-*Qzu}BdY)>uS6kpQ#B0BQ)h#V5@NeB38h0zTuD z=40Nx?XTDK0d0z_1VpMMB^Jm+h^$9S0K%8Vg_RMmBoY=zBqSmMA~%sNK*S4i0U|FE z7a+0|aRDMx5f>oR6>$L~a}ifK80QC58F4v*&xhj5udPdWh%4bo>JAWoq{#$V=KEWq z`GBi@QYGLvxx7eMklYvwUkj0>0b&R=U(l_Z81$kh2A!sfK_6*i&?TA}@QJ@^#XR7Q zifBh@(?r?R?#cR$T??HXA-MC!p_&g7g>Yhl2r0x&U}_3@w%t5_(2fn$cao%u5BnvUOC(qfYl#GdF}y^= zY(dH;QZV5XDLh-E;i(Y~&x7dy&G^#8AHks{()8g**0H|P)i4&8e&5&z1DB))gE7Ga zCmk|c*ZQMY42aQ7aymvNXXK!W5wM*$l-+C~D#`DS+_-|Y5% zgMFNqhyr$UBoQ!fQ@1;j4|gZ>;qD*hL+S+?1L=b2RRRz0PUOMeArB6fwPvKh5Rvau zz=A{<9Wk*H>j|zyW*=iha=aWV=>tCRll;v@p`R(rktvZTX*otH?Du!6<$z!Nq+&qi z#02a3o06Kp^w-|dHSTjIcU>Sy+V6J?yvipPV+s$Kb0c2T1fJlNLRZ2ed#Nv|3=rKV zddlEs$!cHw*{%E_Nk_<4WGnIymY)RXhqp1+*v254@d*Va75HAN2DHM@4rZLNr0@yW z?PB=ra^z?|OokpYMXPr(!zEhut3?DHM`sm5=|l=j`oBN-Sl1C;=xE}v>-e$jTJZE! zHx9aRUaFxikRwGEAo`(p_xicvL|hhdiUH%!$L|eI?;`>W0PPlVCXIEDNZ7J8`*SiH z%<{yAg&Y?#h_qeQ!6ghLg-U(@Rj&@KUJccE zSdRi)YpTQ6R3q6SAtczG1Xmjx!q?h^qBJq+hXgJ6Bx<=QG}6JAd}}$_Wun{7!FGv< zFsSF_GEVRK;}v=;04%$O<#?y{d+u?z@;%O0FPTmplIeCO8oVV9`_k>ovB!-a9s>cL z4sp)!d%knNL-$RyM~!fuLkDZN|4G+~lM@T_vU<10f;RI1z%Xt>ad>GVLhv%=R0-=09w_n!>U(@ zRj&@J9^4)2U=NB)I0F*2+|!<*Wq1Z8Xt^U%%N?P)6Kt7y#DX?v$>qFr{mXix`*x>E z)pR)?_rv%3oB7#@)PcxUeIcOLpgOEU zC}!^xtA68eR-@SMo@p0G%>4uWSrh$*KrAU_F!rxlEQk~gpU0%Tr+jA?1LBed&2DIb zb&g134XUBRGrm&AfL5vMuu>r(oGTkZyYr7?mj+FEIK|boe3wUqC$q$bQ`rsQKj`bE zyDR*CXEC7FpgOEUby$OHXi(#KR}6@&A>_QUQXwBK6swTtbealYJxQ3m613dYo}gto zccJA~zDJ7zp+$ms(mH@RgP}0{ALR%LeYTv>f2^ zBYo>PxhR|>M1DX5c%r3c1Ls=W2;h86O9P%_X{o?dEiDCjx}|x*dotq`{63HVRxG2T z06a`&(KQIb(}ZM32c7t ztrsIo&6W}H>RyZ}!A}XUxghS~8hUaP@bwd6)_g$t#XN9<(lp;C^8w*4!-&#epRo+^ z8=o{EaI!ecv_)yI@4oqfaJFGY=@y@{3~*B~i70LL8Rr8Y5$C?L7)lrgx?ckbkD9K7 zp?8&duAd)grD0j63#7A+{xF6fXR8!{#>(mUpBM@lWePdKQ+;=5$AB@+x-ANrd5JFY!BCh&+cl_b=SFC|Rw`;Et&ow8 zLb^rA@Ct??;FL5chB&aU z_>n6ZvLn_gS~CDKR;CA(kP`oYS*~6YmmtGZ1i?}aK9N3@=*B=03FCj3Kcb}=Z{$Ye zg7FVqE|_U&YbnO`bw6u_5_h^}&J+AKbT(kQPb&VCOyzWcVum)b+r(guE`>A-Y_p9N3Og&N=-na9q8m`8CCN3NK z26^Hs>#?%erSDICwaNhD#Dwq7!DsLZKct)-><^B(&KExCVSzA{reLrYw8Z$*%?Q8} zF@RqR3~OEz)I8CFc}ad^d?j4$)aX3<;K?`q>yYLU>+y9#4+Q(C zp$v9Qq+oAE3U-np2C(zoYiA80%%xQ}+}(W0uJNLmX(5$U(uO4m9~OehD=B-?-?Z zEE5!LFECt1%MV8W8HsLY1BQEuE$9j&1x+OqOgSPhdVw+Q#1>SaNZ%K@e~Hr`7z0e# zufJLg{h@38uy#rmYDN?guFMFG(AA8=*ww@zvJ4YYGX@PABdMTCj+zMtxR4wWRE0=T z$B{iCBNn1q#3Mm+RSpzxPSSfV+HB3E;cFwDUV+DE!Ux0os8m$2|EjneTM20Qk0$ z=r@)+VkjUr5+4?amHu9!9PmORk=O2RzeWn1EZ_YCF&pS=2HJX5NJ<4#-~0!uC_5gc{mLY_jBN^mI?F%P$LSRlX=!A!eY=KRWWCPGNm#R9E8 z<$$m&QDUN&VH?ZCHkJn?n}vmqEJt7?h?y-I#jp~K2J-+v?Z;RYh9j_;ExcMpgI3Zt zR49QN#Vvs`3dDwifUZOes``nj^WVN&C4d+s&sk323OzJusJ}@=%-R}IFoyj(nv+c{ z&|t?vT}KO0GRwr+As_Xw4GvxJ+TbYmuEl`vNwfyQ}VI|_&lW&}n`(Ts4(!IBL$5e2w~TLUBJH6sd-*c~1qoTK?rfP+{daIxeJ z&4>cRh#7&cSIIyWerN(=pMxl)n;=+I{$L#qh)qj`9-ah7Iw4v|a2#)tr2%6?`ajza z`A9yRh|$8JXd*@fuF*vJ1lDO{uww+!F`|GT9l@ALH2t6#RAM$@s7Gvo5t-i12HfUP z`FYSCYBL)~AM=5v!5XZ(%mxhOh%GpzM1sjbG@!8Djk6rsT3-F*EU*3{%lli)0kOTL z9UYv}B-={15*TNN#0D7evtU9Ywjc5tyg_WiFu=lvwThw}!Z9#J3br~s6ey(#ig*1v zQHqE~iv7M5DOeVlQodS?l=A=HSrZ}$F_Pd6X_?ryE-o~HH~6&CG2mN#TKFd{R!ALq z61cHWe07N&`|#UYF}ML9Fx21>Tq&#Ob#mnB0lv+rjgA4|<~F!hXP}Kl!rC0MVLdmBmo9vdV&b-6=A5SXuv9t>%PV%?bAPfb_9NjvUv(Py4jd zG2q|%I+grhpj9&z?vQR-ilNh|zM$fuPAM{GgY4LOz=v2`3h<$pmI|C|X=%WRTiOWV zBP=Z&INj26fb&l=TJkr0IVemPBHu>@o?>a)z*8-41n}vWmIge{(o%t^TUrWmv88#y zFXhE4_3quw2;~gp_i2Z3wx$P0 z0WT2k%-lfZ=#Sm*yDWrG!!&(f8 zK}j$ee+mVB2?BnUXh6TmnSuez@EuqJ2;VYW(3nLMAgkrbLG*^;_vM)2j#`!|wNQ?f z2ZDi2q+n;^R&&CwN`tM&N*_6LWEFv@`?S$9;JLm|B~gJ^&Crqy>6WE9tWzj?JSv{| zQ-QO8)M-J*r3~J<3<8Me^i4f0Lvt7Hz?A5n*WmnCG{i9k6K0Dh29-n0xFiOMWTCYR z3rnCXgrOy?8f=(I{ZA#rlKpuZiWvl^4aRw2NUI9J)jUja%mPXbn0T1r33A0#A_%FP zPJp*`gvJ3}ak(834HJ$Z+JPyN18x)(?)Oazh5w~eb&t;y@)209l=9$kV+%6K<{m(V zJLMkay{$f1Dd4YtQZXPFo&-s2hj9NmbMg!4%lAe3j#fUmW} z01;Ir4Db%i1&9%3VL^w!A?8A3k`!d=5SFX0X8<4YNu}Qi>}UH2#H6Eavs7wVS}s7$ z8sd6dYN0qeCaBa7VfmvRb(#|Vnx&-x@3gd3;N6y%2KIssfEyD-CuQnyfv5%Akyj41uL zWdvMydVJR?T`E+P2nfF!^1L@Yp>R*aIj>JrY8$(CSAa3>tv-y=UaY*(0#SveF@;BLZY+4ZSBwrk@A0cih!ZbhaFm8vL znqMgeCUlxi49&DmN?RvDVluSRq!1|JV8}EuA*7;1z@a7Xx%YnGeQ)o33--vJ>CR}+ zx!*f~_uO;uefw7Xo&jCM1-hXDEMqrv@#tfpLzckVxh{?jS;m9kJT|k<>J}IKM)x3R zEGF6aQXEGYrWSM!1WKz3f$tk#1|fF9xMG8aPYY}_>qfX%z8Sn!_+4J;^2w2rGm9d{ zP-s12YMg=GEpny2B?C5ex5dwtT$qo$+d_BjRKkZ~PJyE=Nf&Lf5Fp1yN5) z@-Mh4*g;EsFz;j=N-?lWLOt!^1aYF(8YCLuNpR#_k*N1;qIlr~w%<6J$X@95|i} zs`F1i<*>Ff^5;2h>6mZoI2@x)!imXLR|6Kbo9zD&W=l!Gp@+`{C94CeG z?3ZN@tLN5m2O`UeWjSHI+z$mJJL#6)3|aO{q&SKUPar=mf&8HEK``8lMTG37&fWD~ zMmN-3ER=gBlB=XTZJ?LVlc&AdLv8{LY6C2PB_Op$k`U55T z&Jb%Pe_e<*k-ss-QslRUSTp&)5NjoW?iDuk^4V-(9UIL6C74$7=Y?1^`A>ydiu{Ek z)~5uda&( ze5*Abf4Woye-HX;!udy|7Uk$v!L zCq?!V2W=wzDRfi^47Sxlo5(U9B2_CHf9sObNjByB*g=-v*B$B{W9t-jQ@S=(wFfQr9Chw=eVwB*!$rS+6DIepjwms&q6V#V>SA& z#mKk26lIu}{bG*|6KO%O)Hl_DeSPiP7yC2L@w6Mnq!<^ot;^oBtLhVHpa%!L%Cmr zo$g}jI0-BhA`X}n=3XFn=#fzI39!Elq3N;ybZ~sa%86|>>>}MsJxnH5&g7_X%t-nf zdjv)PBe&6PjCUxO=eSlTt`+-|g;m-NU-I+XX=7}B(FKqp+vVis!S!sg|B_~AiPfBN z`GhW)!;~({cJOo~rR7`FVt%H654Gv23N1r^p~Kq7$g|3lK0tg3Ta-zN{3e*Z!fWGE#>{WjOsy{H1 z|H}|-B!72^HIctJ#8Tw%3$bSM_lH<3`3FO6CHa@v+bHEj)ZRKaUI8cpt|WgT#9GO} z8e+}lUkkAm`Co=u6Z!uLu}1R03b7gFyD&3NfVDFE7 z86zx$WdF=To5(T@k^1-`IvK>(=#b20vbST+u;=G&Jr7g_$ubx#$kwwiv<|ZW3CIev z^#$ZjERtm(tf1cw2Ka9-<}FMSqm=VaKRSW@I0W)N3go-H4{pBY+;x(D+CiBN@)AZ6 zTXGpUMPv`ywbKvNfPSC`^g}hEA1r5X8jwW%^?Yq4R&1Xl4pe&Cw>why~ZL>f$H610{rWsa*p|( zYpvLiLABT_jM_R^=CM!W&9KlGu})8+^&2+A>Sj>c4;G{TFK|;ML-q;>ZTus!Jr2r{ z9dOVMOvKeLi5apP2Z0Im6EBa}Sb4~27QZ+IVrlG0Vsx_n(h#wDVYJ2yL&V}`(dx>A z!!BZE*;(zBJS#xN!v0zAHKaTo#Mqfz!d%>)G#7X8OepK!JN+P}40rGJ!}tp3;6rYe z*g$q4pjqlxxuv^2W@Sd|lVc1w=W1^Q*+D>ZmR2{$28X1|h#$mGcnX)Qjr2o(Ip^}V zxGiuvrGMi){|eQ|%p33sH23bjKd!kqmM;3_&_uQ(u3UCM@T=3J>u<_6^t=oEJ& zhRqmd-(`TzoI%cB~xEn}*I14$=1p0VG zLEKOfHxxVf_z5EUDX5N`{L2oL`>}z4160my-vS$U2IUk6OY5OXhG8ynvk!A9)H;Mi z(<3W6`6h?8jge0|EPg)zA#715;q?DDsNd_%#6Ly&G9O{)Po0_8G4gvH);2~ybQh2M z4lksHPZ96ZWMr4D2Y<4|+Q!JA;jp;7-@_JV65Ra`>NDITcs-of3FS`_x=5O9ry{HsF5(+}Pv5|ydqC&t>jZM2^yy2Q zrZ1T`M)*l*Aw!nit@$|)8{rZc+aVL`h0Y&>b=`+Y!PAWl1Q!8rZAo42nw2(Pdl}U4 z=L5%CLk59T|Uh2;EBeCtN>hrOAhvC2O3~Tp1&l?`eNG{C^Ylx1hX_Js%~~ z-C`r)ZSwtijuG2)$mc$XjF5AWQ=`^OD0 z_bu7>v9`zix$w>(lepanZ~Ng#akTROJyJf-{?W?wz90M<^{$mR;;(>qea^OfK>hwq zRp0+<`N#P?TKQd{wGlrL%AX^5U1ISGP<5$oKLR=d>i73u;Ea>Myyb6drz$^^wifvR z`}~LbL-^nG?U&o*{HJ%{-&FPa@6WsNzmj`F>DTvnwDSChcLHCj^4|;p9ql(kyRNdH zZUJq=x9=HHeu?bIbENiL@#W|;(5d?4_uc+i)3xF|Qu*7_|8Ii+4D>gklc0w{eScHc z_rD?bzZ~}c@e(C3vo)@_61>KC3fiZE@|r9!LHu9a^DldTTzq~!Q`P6?B3`jN0hd{L zX~_3?wDNbt9xni`+-NQGnvHM&XysK)c}KpI?G{=oSvo*&uu#dBhE+?USjn}lTHStO zCEJfye_^Dhdt`8^_rk$m)uLMi+46vD>D^HfdzMy8_Q}=!wF0=| zp^9o5EDXwfCAVGP`=lYqioMxNR<+~?g1%BVp9=<+6z{-z!g6YJUh zV2`*iia~j6Fj3g3Kv{bP;y4j(Ske^-545T&{REHf>oc*SrA+9cNq zqpuE9e@}f{T1xE!@Hpsn!E~Oek1HDHC-4n|Q$KTDT3SkF;BcB&ioCq0`LgkFB>v9n zX(QdK9m)%5A})UVA>Ar6e~9SshW>8ow;C%-`SAl*e=Lm7Dedip{ytCN&ma4Lho?UY z{YmJ54TiP;Z29x^cc)-FClFWLXQrj4gc_p!`qQySUtgC-RDT@$7tNVZ>Obvrykq)2ov@HRFF1@p29a)2!rA#*RCPVxcq5-=Kmn{4?_P@@6vKg zWTUS~q!HD>3*TbgmA6u_M1_U-^Y?e2{%|2}G=>X?sQWlDw&}(XO|?&$x$>vyfPOWO zbb%TYljr!`qe?w1%!%?x{U+!)jU1W&iz24`PyH11Q%9(OKy-B%soxC!X6R37U$zemqy4uM0Hr>z@Vld0R=-GR2t(c;vF};Guv_im{+;Oj4`p}+a(RP`gTMhjRCf=-5KHC51pzr5z=YLtf#aM@E zh5kvetl@wBL#vU0nwpkUk7!2?{W(us$%Ebi`uh4XYlk*9efv2pne`OBrWsGJeNp}0 zuUg4*^#5!*xJLe1e@zh9>uZw#*0-$wz1+AU@B0UwNE&o>_37BL23f6no)bOTAd&F= zr5c|m=OgJTWcUWz)%PUg)8+gjN&a}n^Mk0d2FVKd{c3!s;(lI@pP;x;SL3tX{#%XD zR@_&s@i~h7Wi>umaUZP4PgLCBs_{m}eXAOur??+g-jTHy`z`?s+XRZNw{7gl5pLlIu#$6^8~L~b5!H( zv~c0;^TKL8?cp1M@AB||!Ryqi>UxZej$6OEb+_O;{sH(s!NRIm{e0KR&r>sa4HNSJXz+Ml zJtMeM^JDA7OGZAv4*U}GJfDSm^`4QBuLHBCfAeKr_62Dpitd`v!Se;#JJaIkpuDv} zKC|57UD&5q7@Sfe-Bbg=N$^xC=D0sGczj*@b7No$gYyMe%)hm%SYcI6?~qo zZz;?po~L}jhWx(>-YDyXzwSL(L;eke$M=i3YslBhX0P)+epT9p`GFZHrDhsD8oA|9 ztAT&I2EMiiext!9ZQbT@H@RW(T z`t7jb^Xi+_42&<2&X#pT*RB6LQ}B5*Pq~j{IZ-V}Ue=`>(ne(h^?Wh#R?Lg9!(h9? zl{$EWl?SZ00B4)DO#7Ev`CD<|7QuDBb$RjM2KiTJS$W#|8t}arS^O>>*lloWc=8X! zzF*IeQl5rEpN4&&7kwG{Pk@iFOB-YapDUgReh~e70(tud@XT3OezVb1>bC|*BT7Us z6>Wn*N${j`Jii8hso=UE{Qh29!+y81Ge@O5(#GQo^lNJk`?nc9exCVN!RN_-O~064 zO6iNXEj_A|D_52+7pA9FDOX1N`h*RFtJZ7`*0pzZ27&6$m2&-qWx1#vRPsU3P_ZCa zS`(lk=q(2QL&fgwP|#Z`mdZhPWV@0pwZlWXO0KtM`HH10#BzdApsyL*E5LzV)h+E% z_L_0;NIt(qR3fcFM_naa86MKT7#<4xv#nP%L!IHQud*g?I+U||rCct^R(1@x43s z*IXuJVh4zPRZeUU#`R zH#FGY6ZDiv%uq=BbGdZ-igoR)*91#jmbQfPifFD>Dii}rXSO2W4^)fEHT6PIez+P8 z+B??=VHI_*U!!ZNGutis*Vps|8=4tHajdqL3&SP(7Nf7)j6Ob4EN)ddmj)|dctOs5 zIgl^!DD+fo*$zouGKSShw7r|;3kF>b)kj3SXP{J#^;JqE1?jTqSjMiLt5l0>!+P+P z%$2eyFQ&`#$*U^2rCheR8o_v&yhtexdJ5t+p5!2sO5K6jCB7Hwp^C!zO65*@N(M+y^aKd6fviwu5K=eRkf|_V5pewRWckhX^LJ& NnaL@~WM+6r{ujW1?9KoH literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test46.ans b/libs/libtpl-1.5/tests/test46.ans new file mode 100755 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test46.c b/libs/libtpl-1.5/tests/test46.c new file mode 100755 index 0000000000..e49775410f --- /dev/null +++ b/libs/libtpl-1.5/tests/test46.c @@ -0,0 +1,14 @@ +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + double x; + + tn = tpl_map("A(f)",&x); + for(x=0.0;x<1.0;x+=0.2) tpl_pack(tn,1); + tpl_dump(tn,TPL_FILE,"/tmp/test46.tpl"); + tpl_free(tn); + + return(0); +} diff --git a/libs/libtpl-1.5/tests/test46.out b/libs/libtpl-1.5/tests/test46.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test47 b/libs/libtpl-1.5/tests/test47 new file mode 100755 index 0000000000000000000000000000000000000000..eb682ed4fa639e96d98fac00b190312a39e59216 GIT binary patch literal 126395 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test47.ans b/libs/libtpl-1.5/tests/test47.ans new file mode 100755 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test47.c b/libs/libtpl-1.5/tests/test47.c new file mode 100755 index 0000000000..62cc619a2c --- /dev/null +++ b/libs/libtpl-1.5/tests/test47.c @@ -0,0 +1,14 @@ +#include "tpl.h" + +int main() { + tpl_node *tn; + int i; + + tn = tpl_map( "A(i)", &i ); + for( i=0; i<10; i++ ) { + tpl_pack( tn, 1 ); + } + tpl_dump( tn, TPL_FILE, "/tmp/test47.tpl" ); + tpl_free( tn ); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test47.out b/libs/libtpl-1.5/tests/test47.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test48 b/libs/libtpl-1.5/tests/test48 new file mode 100755 index 0000000000000000000000000000000000000000..1fb859d3905b8185b8335faedacd6c3cad4064db GIT binary patch literal 127327 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%0APhNlaYVcq!d2=rMVMhy(D>(+b0gFAxn` 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 a*TG0W-LGUgWFqCgDl-#Sj>&BCj{Fa@OB8qj literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test48.ans b/libs/libtpl-1.5/tests/test48.ans new file mode 100755 index 0000000000..a4a2f8e799 --- /dev/null +++ b/libs/libtpl-1.5/tests/test48.ans @@ -0,0 +1 @@ +0 1 2 3 4 5 6 7 8 9 \ No newline at end of file diff --git a/libs/libtpl-1.5/tests/test48.c b/libs/libtpl-1.5/tests/test48.c new file mode 100755 index 0000000000..3cf52f7721 --- /dev/null +++ b/libs/libtpl-1.5/tests/test48.c @@ -0,0 +1,15 @@ +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + int i; + + tn = tpl_map( "A(i)", &i ); + tpl_load( tn, TPL_FILE, "/tmp/test47.tpl" ); + while (tpl_unpack( tn, 1 ) > 0) { + printf("%d ", i); + } + tpl_free( tn ); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test48.out b/libs/libtpl-1.5/tests/test48.out new file mode 100644 index 0000000000..a4a2f8e799 --- /dev/null +++ b/libs/libtpl-1.5/tests/test48.out @@ -0,0 +1 @@ +0 1 2 3 4 5 6 7 8 9 \ No newline at end of file diff --git a/libs/libtpl-1.5/tests/test49 b/libs/libtpl-1.5/tests/test49 new file mode 100755 index 0000000000000000000000000000000000000000..3c03a5978510f990c5bdd9e058e814572ca38078 GIT binary patch literal 126395 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�B2ZQF7TxBMoa!?F9(ImLgf31z*8(O2lymQ8wPxe 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 La!gi>cjSKoPxRht literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test5.ans b/libs/libtpl-1.5/tests/test5.ans new file mode 100755 index 0000000000..54164a9348 --- /dev/null +++ b/libs/libtpl-1.5/tests/test5.ans @@ -0,0 +1,100 @@ +j is 0 +j is 1 +j is 2 +j is 3 +j is 4 +j is 5 +j is 6 +j is 7 +j is 8 +j is 9 +j is 1 +j is 2 +j is 3 +j is 4 +j is 5 +j is 6 +j is 7 +j is 8 +j is 9 +j is 10 +j is 2 +j is 3 +j is 4 +j is 5 +j is 6 +j is 7 +j is 8 +j is 9 +j is 10 +j is 11 +j is 3 +j is 4 +j is 5 +j is 6 +j is 7 +j is 8 +j is 9 +j is 10 +j is 11 +j is 12 +j is 4 +j is 5 +j is 6 +j is 7 +j is 8 +j is 9 +j is 10 +j is 11 +j is 12 +j is 13 +j is 5 +j is 6 +j is 7 +j is 8 +j is 9 +j is 10 +j is 11 +j is 12 +j is 13 +j is 14 +j is 6 +j is 7 +j is 8 +j is 9 +j is 10 +j is 11 +j is 12 +j is 13 +j is 14 +j is 15 +j is 7 +j is 8 +j is 9 +j is 10 +j is 11 +j is 12 +j is 13 +j is 14 +j is 15 +j is 16 +j is 8 +j is 9 +j is 10 +j is 11 +j is 12 +j is 13 +j is 14 +j is 15 +j is 16 +j is 17 +j is 9 +j is 10 +j is 11 +j is 12 +j is 13 +j is 14 +j is 15 +j is 16 +j is 17 +j is 18 diff --git a/libs/libtpl-1.5/tests/test5.c b/libs/libtpl-1.5/tests/test5.c new file mode 100755 index 0000000000..1594fb70fb --- /dev/null +++ b/libs/libtpl-1.5/tests/test5.c @@ -0,0 +1,27 @@ +#include +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + int o,i,j=-1; + void *addr; + int sz; + + tn = tpl_map("A(A(i))",&i); + for(o=0;o<10;o++) { + for(i=o; i < o+10; i++) tpl_pack(tn,2); + tpl_pack(tn,1); + } + tpl_dump(tn,TPL_MEM,&addr,&sz); + tpl_free(tn); + + tn = tpl_map("A(A(i))",&j); + tpl_load(tn,TPL_MEM,addr,sz); + while (tpl_unpack(tn,1) > 0) { + while (tpl_unpack(tn,2) > 0) printf("j is %d\n", j); + } + tpl_free(tn); + free(addr); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test5.out b/libs/libtpl-1.5/tests/test5.out new file mode 100644 index 0000000000..54164a9348 --- /dev/null +++ b/libs/libtpl-1.5/tests/test5.out @@ -0,0 +1,100 @@ +j is 0 +j is 1 +j is 2 +j is 3 +j is 4 +j is 5 +j is 6 +j is 7 +j is 8 +j is 9 +j is 1 +j is 2 +j is 3 +j is 4 +j is 5 +j is 6 +j is 7 +j is 8 +j is 9 +j is 10 +j is 2 +j is 3 +j is 4 +j is 5 +j is 6 +j is 7 +j is 8 +j is 9 +j is 10 +j is 11 +j is 3 +j is 4 +j is 5 +j is 6 +j is 7 +j is 8 +j is 9 +j is 10 +j is 11 +j is 12 +j is 4 +j is 5 +j is 6 +j is 7 +j is 8 +j is 9 +j is 10 +j is 11 +j is 12 +j is 13 +j is 5 +j is 6 +j is 7 +j is 8 +j is 9 +j is 10 +j is 11 +j is 12 +j is 13 +j is 14 +j is 6 +j is 7 +j is 8 +j is 9 +j is 10 +j is 11 +j is 12 +j is 13 +j is 14 +j is 15 +j is 7 +j is 8 +j is 9 +j is 10 +j is 11 +j is 12 +j is 13 +j is 14 +j is 15 +j is 16 +j is 8 +j is 9 +j is 10 +j is 11 +j is 12 +j is 13 +j is 14 +j is 15 +j is 16 +j is 17 +j is 9 +j is 10 +j is 11 +j is 12 +j is 13 +j is 14 +j is 15 +j is 16 +j is 17 +j is 18 diff --git a/libs/libtpl-1.5/tests/test50 b/libs/libtpl-1.5/tests/test50 new file mode 100755 index 0000000000000000000000000000000000000000..aee87af5f523fd2d7134cee74c95767d9140df2a GIT binary patch literal 127429 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 kZ6t$Q8=P9Ew$w(A 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test50.ans b/libs/libtpl-1.5/tests/test50.ans new file mode 100755 index 0000000000..556f45ce66 --- /dev/null +++ b/libs/libtpl-1.5/tests/test50.ans @@ -0,0 +1,2 @@ +bob +betty diff --git a/libs/libtpl-1.5/tests/test50.c b/libs/libtpl-1.5/tests/test50.c new file mode 100755 index 0000000000..d7f9d68dbc --- /dev/null +++ b/libs/libtpl-1.5/tests/test50.c @@ -0,0 +1,19 @@ + #include + #include + #include "tpl.h" + + int main() { + tpl_node *tn; + char *s; + + tn = tpl_map( "A(s)", &s ); + tpl_load( tn, TPL_FILE, "/tmp/test49.tpl" ); + + while (tpl_unpack( tn, 1 ) > 0) { + printf("%s\n", s); + free(s); /* important! */ + } + + tpl_free(tn); + return(0); + } diff --git a/libs/libtpl-1.5/tests/test50.out b/libs/libtpl-1.5/tests/test50.out new file mode 100644 index 0000000000..556f45ce66 --- /dev/null +++ b/libs/libtpl-1.5/tests/test50.out @@ -0,0 +1,2 @@ +bob +betty diff --git a/libs/libtpl-1.5/tests/test51 b/libs/libtpl-1.5/tests/test51 new file mode 100755 index 0000000000000000000000000000000000000000..3a06d153abe55a2ba28472c1775b27f09e14b1bc GIT binary patch literal 130394 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 iiI%JgT^F6XOq-JFk)@Uks?IEF)yEM?@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "tpl.h" + +#define DEBUG 0 +#define FILE_BUFLEN 500 + +int num_tpls = 0, sum_tpls = 0; + +int tpl_cb(void *tpl, size_t tpllen, void*data) { + int i; + tpl_node *tn; + + if (DEBUG) printf("obtained tpl of length %d\n", (int)tpllen); + tn = tpl_map("A(i)", &i); + tpl_load(tn, TPL_MEM, tpl, tpllen); + num_tpls++; + while (tpl_unpack(tn,1) > 0) sum_tpls += i; + tpl_free(tn); + return 0; + +} + +int main(int argc, char *argv[]) { + char *files[] = {"test51_0.tpl", "test51_1.tpl", "test51_2.tpl", "test51_3.tpl","test51_4.tpl", NULL}; + char **f; + char buf[FILE_BUFLEN]; + int rc,fd; + tpl_gather_t *gs=NULL; + + for (f = files; *f; f++) { + if (DEBUG) printf("file is %s\n", *f); + if ( ( fd = open(*f, O_RDONLY) ) == -1) { + printf("error - can't open %s: %s\n", *f, strerror(errno)); + exit(-1); + } + rc = read(fd,&buf,FILE_BUFLEN); /* read whole file (no points for style) */ + if (rc == -1) { + printf("error - can't read %s: %s\n", *f, strerror(errno)); + exit(-1); + } + if (tpl_gather(TPL_GATHER_MEM,buf, rc, &gs, tpl_cb, NULL) <= 0) { + printf("tpl_gather_mem returned <= 0, exiting\n"); + exit(-1); + } + close(fd); + } + printf("num_tpls: %d, sum: %d\n", num_tpls, sum_tpls); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test51.out b/libs/libtpl-1.5/tests/test51.out new file mode 100644 index 0000000000..bb58756b59 --- /dev/null +++ b/libs/libtpl-1.5/tests/test51.out @@ -0,0 +1 @@ +num_tpls: 4, sum: 180 diff --git a/libs/libtpl-1.5/tests/test51_0.tpl b/libs/libtpl-1.5/tests/test51_0.tpl new file mode 100755 index 0000000000000000000000000000000000000000..a811f623c7fedbaa51321b3789b96174f6ca0d44 GIT binary patch literal 57 ucmXRZ$YHQ#U|?|6$kb%u0y02=5r~<9m>Gy!fS47C*?^cGh&h0m6Nmwba00vl literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test51_1.tpl b/libs/libtpl-1.5/tests/test51_1.tpl new file mode 100755 index 0000000000000000000000000000000000000000..b056e6b04d65a73da77c6e3306d6f87644ff05cc GIT binary patch literal 114 ycmXRZ$YHQ#U|?|6$kb%u0y02=5r~<9m>Gy!fS47C*?^cGh&h0m6NpR5)d&Erk_C4F literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test51_2.tpl b/libs/libtpl-1.5/tests/test51_2.tpl new file mode 100755 index 0000000000000000000000000000000000000000..328940bfea42dfee025e721362a85c607705155e GIT binary patch literal 30 ecmXRZ$YHQ#U|?|6$kb%u0y02=5r~<9m>B>--2#;W literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test51_3.tpl b/libs/libtpl-1.5/tests/test51_3.tpl new file mode 100755 index 0000000000000000000000000000000000000000..bb7446337b54794f192af444ef07396cd7d9a07a GIT binary patch literal 20 WcmZQzU|?ZjU|Tc@#kU2#V>qZ0es=(3gAmo28!>l)ajim`|J7yWY$hU zZnTR|swh4IU_0`9Sk@nItP*f14Ui#xDrM@lBYSM8tz<3JsuR*Zk})TB#>cVoZ?GKS zU{?SomIF+bGV$G&3RwVFc`&kw`N(n`A+kImGEVx24OX1gX*UDy$mf6harhjwbjiXo zOBan=x@39d>QSppCXAXeessf%(PKe~w7vM_5T{=<8{hVHu^%7)Sl<_a6dCK!>-Sc_ z@Q=&)hl+bGYWvljv(L$%|2NhR!k;7mn2?wEY{CZPkDrd*1Lxmz_@`?o|4(VJ($C@! z*skpMeKpFxyTMo-ate6yDd0Dr0{+%1;1`_&UU>?5`6=LkIR*TKQ^3zU1$^!);D0;? z{DM=!SDXU=+$rFZQ^21%1)S6E!(aDLGXN)>$NxSB{O6~DKXeNC`=@}@uAHpjou`0L zknpCQ0CHWQL&%bjw@080h}=f}5nj~||0jT*rVLPuuCGE4c0_#RYySLemaSMmzag@q zJ~Ds4g5_Av^*2GOS-m8pG(_r`S1+qmY9sZH%c~beYLvRhNP|*evta4c71gY6s9UZq zTehH1S=MmvxGjk2N+)X{DA;(C#Q4objZQ4dsdFNd;h!II_5 zs`@2hd1bBar?$SPMwuQCO_@4>?C9e0sqEO%=TaQ5|KLAbo0H+GfYMg+kDoj5_$kbk zTloxm!WsuI$z~7Vu@ayCtExmwTh>S9>@R12=wr@EgCCXnS%95jpjKB2EW(9p6D7=V z8r*Sltn#M8Q?3T^{4}^@(~0j(gQxqw!ZbL?;CzbG;N;2ql%&B^x`)a@8XN*jeT+1C zj}#RCDGi>J2A`J(@0kX#N`v=GgD*~l=cd8y(%^a;e03V!nPXNrrNK{2!{3kwPhan? zY4G%Uzbg$+pXPivrNK{kfJir|!SmAK52e8erNOtR!TY7b+tc9v)8J2~!SmDLd(z+o z(%}2k;7;tsY9sowX2dfNE%PZxb9*EsaWS;ih(4*&;Ng=z_gz#ahrf?+eMkT~mKU?i zI*`O?_-iavwXHp(yq9IFwAC)k&#+8YwjL7Y9V}CYtxcl*ILlOBt5uZ$%raHhY7*r? zvP@OA>O}b-mZ_pvl_>w5WvZrCDat=)nJQ@oMEN$Bsft#SD6eO^C(AxjzJX<`p5+zg zdX}kjmLkg6vP@O84j%_#_(GPcV%7mszMN&MmbFKeFJqZ1Wwnd)MJ!X5tcOH-3d>X> zYm+FS$1+vKY8B!nCQ&|{Wlp_SC(6TE=9F7iqCAjgPPJ7j%Dq|U6k7pN?!odP zmWxE$#WGEl;5Awz{+@|Ho~59-ZheYDp z3PovdUpuz#4G>QJ&v(hBKBO$g;oFJ(?fU2A;Jxib;DE?i!0LRH-M$GyLYuwC?N{t< zEj|=7U%1*Z-!-D|AFiAg>S%um_(sQepGZ0mz$YgLK`39eraoII!XeK#M$zsY(WAMB zd2p5Ms-0UgUa?@lxT=j+$piY3Cc?I|IS}H?l880bfKZ{G0fe@3&$JL{&C_O z&3hwG`*&sgrt`O7=Yu;sZ8lma)hWcsZD)b$SPxdGC1_3)9 zU+VXUIy`=i0o<2sAr(s~5h~rK|Eyhqq#X`p=C=J+0Vq+2VZQqL@Ac*ffEkR}d4fj* zZWXK)MGEyt%KSz8BeVSDHk9EHGe$@;A!7j<3rI1TEUIW3UsO^0Wy9q1=A^!195@W4 zqgXSBUxCc69%PJ3OZ}Q2dj^ZtFh5P^HDWDTPoSg^iIGVRcb4BrcH&`we)5H&*-_jM zdaHYdTBd0!#w*Oj)`d{1+ScOswvq*KYk7S@Nl=eu3(A8~rX>CfrAsFBda~$9;^rp} zpQ4!iued6BW$>!t)xr5#n|A++&ZEg>yd;|R=rKR|iY9aZ3ci)dGe-RME!X&z#0|%w z;a@>$um;fY7dfM5C!Oyf#5COlBzp?(Vovtid0VLTkbcVx;3jN({B2&)Oy<=B11&@5 z?ht@sP|{;z%4@_fVudN9DGpAiU7wG7_8B%m3d0`7OUlf}T4K@Hkf;!D^Sxl(S}Z!k z^cyWp{Q)bnlLP)nAc7?sp0>74kOboEeCp8%MD%SJIw?f>nbSVm?7J znKu=n^!dD)%`u-wb25^d%$v-jr1n>=;G}gXxgoR3yt7bAVOcLZFb?1}Kr72$uh52&WkH^ljo|=tuNu(%fabBiF(g znY-Jl9|^YukF4R6Eh>w<%Zr~bPCkZppgc|#!))*-zCD6I&>pMUFsEvfH84H#UkbZs z#2*kAJ{|poC|G-Nct)QI9@=YibMIGJMfYbpEBbH9jd} z0W;xu(7#y(^xa+P*L0!Z0^}!%{MDC|_CJVxcNg;d6tXo3GS-JE!MVXXA@exx2N9ZCN_-!%c7ju9{S8r2o~M!eE%M0co0=?jKg>D6y}j}nS6*3h_d zXBYjj`C*0maWZc($XCGVHaCE80~VT5au$GyCi1)1eai2LEUFi#5rXOMG@d97pqB{r0l~=;FtSPa@H5=s)NHD;Vui z**aMI%9?kr??6JxEAH9#{xXbtOL@L=m!a;o-V-&5ZUQtFiuIyh4$cjk!as$~eV78n z{5xmCFyhm_VH55-9Iwj{yX$<-MaLLbq;)@O+In+we)H4%?KEcwSg%09CiwqZ2pSPr%-uJCpg@6+JgMoi z0EXOrWE+UXc;AWd&NEu0yH!Xxc6qn<`udsR5#u*IIN0r<<_9*c!O%LkC%m=WKh*#{ zjga1qFe+O7Bka*OJY)?*JFM$yLWL7ok5PK4FNI9?^%Mm}m9I(h4w$0!$hT zW&WXr3(x>#;8dRmrUtiyc{WdD* zmub@3Ykf!md8E9!y*Sx9l$27t2ZwMbh9fM&uYwUdd?d(v*NQo!+FdJeg-2R z_C@@ZBZN6iN)|9F*;!JuvmjZ7bx_zC_oNuGc2P^&C>kcl;+kQ;XiS37&|}Y`x=ep$ zTzTw>-pp-JD83H6g_pxE4QgVZWR#ng;P&@jVe_ytB2iKOepo%g5OIAwE8^2ju!f5m zYY#ygan0bC04;Pgy(+c_(F|k6tDSx9brg#37WxwV9F@U%=9Ecg#Yyl~6gjvRp%oPM z$$4o@Hf4W;`nDr&Rm-t}&A$G`=ud%(5Ix=(0ab7GTHGFNI$ogP39GtO4PxaE7Rw`` z1aH9KbK?c6Bra!bVKQ}5z4TzVvODR?w@Kwrmg|0sV0 zVsdkbSehSkX%+|LWw}W}$Ch#g&swD*Y`5n)wjzT4p8cWaV({&y6$*sSf5wZjI3e?n z#0CfeW+<`}IQgLwpM>4mbRgaxglNBh5Gi7No*qiWPofHvLnM*3wqr0`u`fwlk1{8M zwf|ubprplUbu0do*4@k@5=mM=Vh({x(rRW7kyX;V5jn;mvqR>0!ts4c#|N)IBCF$RF7+$JX_>;JoTmJz@{5<;h9?851K|$2WrtzupcThYY z6X1NL(@g1$5pO_9eq*80G1Vt}i7(d@f52GV3Qj-M(DFk@LXT$V7aziUVkFWCn9c9xLNc0{%*&9B#%Jam9UgY61fx$PAlZe0 z4?v5z2l!`yGg0|EF;`fN*ZLvQWt4vN<+jkQ0fNsP^RXWS$hrh5iAA04Asin*37|wK z=(g>{WQjdjF!@sFuVq}4X75@q_b?!hXVT(nrpt)0#5^4_%<))^wBBMp#XWwiIRd3B zD9_oQ1MPK@idQ;+;7gB7FFY|WowqpfZ{pHPLf@RY6#Byc>?!s58=Ih2I5|k)dCGMS zyfTEdW#&0B6&{4HM!YDJgH0Zf!ES*x!fIy-Drqf*w7TMnP<*^!1f=F`tWA8(=`eR% zlYzzYmc`2vm>w!`ZeM3uX9-{vXFY6wm8kkCnQSpsGlxA!zgAcF#daIrg-x7791E-8 zBy!O&$p)jl)Urv-^7WSYL7$tbismDYf9;_Ez(U#S>3mhrM_L?ISs$p6XhPny>am54bi=b%RSSv7A`gd0{va90g(n{Rz1` z3tWYS0aQDU>c!Y))fE}r54yN9$pIR1+~iz+lY5%N&eK!tIi)xMJ6GzB2z4W?>_B+c z+akbihuYZlY{X|G9&JE8dJ*9djDhWV6~r%~;V_Z4!| zw^ZgE)q4#U8=-ih$SB>}_^x3-%eeX{UHU+))y*0=iAiD{9EUnoLB(opV-?*6J$s+p z882!)Kdc_KE}(AN@swky%#RXx!DK^f;=EnXFU^>~Womx7`T$5oc7|~%i&=Op0l)Q# zt#=ng?-1!g^`2fg&7$5Aj{R98@u97E6;PdBX^QtLcC+<#6 z=_hE+E{Wr$srmiJM>@(mEF@hLErQ^cMLBGO~mv0d~NH6>5YsHPx${#_`a zzU2i&-}16CqD!i8SQ7=aO(c(H5i<8gE`+WXJ_d&kS*a1-8S-dd5n4$kC|9=luAzn#om3@F^M zVRlMOg*XC^su-s5MlZPOU|b*fd`jYj1;q)1&Q!1M&JrLbI%p}UM^j7ptl87~;}i8c zF^M5sd@39w{PSw)JFO-CnS*zu*Sez1PL{<7l|$e~M*O+}#Ffn3ITM2bhvy3%bcd7K zEri(%%<3)S=9|UsRx#;2&Qblqc8(+I9Lo-(rn_?-EOeZX@G4NWdZC!O;(axD2c^zCb9a$F||Q87waK zI(5>}7C-?Z2K0?E9}=d8GA)v6fTqL;k!^YSQN(ASC zZLWnjq+USQ;E97qdkT7XWF$s(^OKyY6N2a%sbl-qj-}O#rDf}98PNUk=8gBr2`wO5 zafGbL?&^sJv<->X@dnF;XwnV8=8uohbWQMk>bCoJ6jOkP35cAlQ*ff$FiNnJ_zR z{AH>h%K$~n)iA2n=wxw3m4zP4Li#2Dz(JP4;)4)Fk6j2<96A)jd6pQ}{fziD%{T{g zO_|0y`Rb0ADY?-dS$b$k^uSS^bGcC;GN)+>*vi_-ax!mbr5w*RXpu|kCm96kX@O`7 z4zwQcA^YJ1Zo%~8Xb_K&4uxBm!Bo$|Qem;aC~Vf1IK$JoHL6sH=Gjxn8 zY`#LQx0FW3=Xn$1cQ7|CtJP%QGnax9p;soXMSKd(+B{f|*Y%iAuBd~FGl zW|VR9A@z$zh_za24Z_^O{so$jSL?CgXJa)r9bbZ{1$M3xdqz8VtsXP%+)BjmkQMMk zdQ8RaAU9i&4YG5!k8!E#lvVi7Ys1`euFlmnUkW?VvNIgFdcr*`20`We|0lczpC+g&Z=~ zuw1B|t$)o;kP8AZuc0o+;WqT0)4Li#5jRzss}PSKsxVikl+UVyk~;E*)ciRAXg+`q zF+^QRNxy`=l=N(;TS(f4!NvRhI}tnbg-)Fy;*LzLVnvU>ju`z!6%z}Mt1g-MK{#!c z&u|tx(5P#%HUEUBii3>?G_Tc+k`w1kz0U9A{ceXCc>fm4<#0wJ{ku`nf}LoJcm}G+ z4q*^n&|M3=PAqN*xs5h7nRkZWHG)(<_5^f6xQVdYi1CyQ1r?7E7#h-OY_^HwWNbDT zH3C0#G5)Sa+-M`qt@zUyrwQjWkg;Xc-Cv??8*=F@Q-3*LDaQwAE6EN6@H7cE>E z7EoBZ6+p7`Ff%ysu;(dOXSWkX9mCT349`1k4USz31k7|v@m{htB96njGJlDF=MJ3h zEfp4`S%WpIFcaaH-};--EilD%tuUZY#m9B3C zgSdfEsfEnB8VRgxD@HWUWA;zlsup2`YrdDvn{W{#QP2%zxZah&hn*BCZ5x0{ zqOS8cXCDxsD##kh%SW!%ghyH&4rZ2Iyaw+9{3LX&B*BJ z*IAJf(XU+*KaEc`p#i!w-_G}7z9*(TfNvRl2%uA@+42KCEx)D|UEd zw?0F&mWnNb9nTrnP?9q9WsVk4?q`6&_1JFt1;?Q9h2U}yxg-Ycm0V+o$_^ZXx_q;~6$SY&FnqZis{90*&@T2F_tjzH0br(#zroVx`qZQ(Gdv6vRsC zxD4xDGq!)=O6I+UX%(Gsr?c1eSX`_KNCsC~L^Na?Mf&Z{FfwIkVtc~X(zluO4}TUL z3|?{d#jW4c8@W*RKT{SX8E*0XsrU%iXKhel;Tew*^7Ej+&V#Uhx3~1@Dl4eI5G>uN z$3}r}MfE!uwRrwp?#rs5!PC9?#*Izr1j-U^_W*HS!g2!>^yHc1D6lOywAOHEeFVHG z8ezIJ&3aBO`2buaY!d@8vyasu%LglxkI5A4bDYV7F3a%#iuImdM*McHr~yX;=|LM! zgP2%^EMg)po_q^^WP33q1hmGJ|E2WyzHG>Y&`<}$B! zja?=^_y@(}eSofUpIc6aK_qL9`b@yFX;OD9%AYS3o32<~K+6=RYe)5w3soLHb_1%q z&X4R3So9+trFM9%t63+;LHlm-t7ek3F%Y2IU z8KjYd+(yV8v`s-)6S5iN;0P+MPSn}CCFztdBi6?b1ovW4rp{vp1-(}5Kkd28p=>6C zmLo_fQn3C(RRw+-8yP`{;oRe3W248eq#cOQEfk?qI6kGMrSj|OG1tnhxV`5IRpU-f z;Dr4Q)?lSL>&cR#WK!SKflv~rwGQ@~OQ{Uv8i@%LhS9nlk1?c{-Z~XSxgSi*@+y?E zj=k2;(*?DFSYsVXGH-^1^$});n=Wrkf)h|B)+xv4wPrz)CF#LVqhXL7l?QQ*V)gqX zP5fU^VPlwiYakW{aS#Y%(wr$u=Dh+8!Jh#HNq8qqhKJDmJJH#}*4NYMNe$3}W{9*Pz4v_AXXIIlHzNEZ$I z;ISaWlbshAEp_($r#vs_tu!1WAylED9dkr9wbnx@0P{ zeaBIc{YLcl1Kh%W{9$CbO>v3csh4ptcfAu|6enBaVj>1C?mY#~_Q!y0KV!xdg@kJ_ zB#g(1A)?(1GyrjAJP2TM$6=EIeTE}>o)LR+0Q|UZY49-OQ*&qHo);wIz35#$qWCoN zpwsvfz(DL1;NS#&@d*!Dg#D7ob6CU`Es;!*6%+0u01;00*^qib5HHWn=c6;;MPrke z%WxX7SPQqT*{5_4!F(mo5nZ%30T0xe_8rcOim-zfLy3AuMF)TcY38^N^{y z*Ml})aT_)xsdMW6xTnKy<^PRy>ivyxSZ!k0*#s#om^wrWyxT$3>EkSNcJP=7PnB@u z`t1ci`KPVtP z!dwkdVk+ckOJ$@$$3skO0?}@8&}I;Aa0+dD3hjhzm=}}&1sHH5C>lcS`E2+ehHRK` zrQHbJCpfY`hHS+Jy_C1mfX`Da%{l{PNqqfx$>*NQp!16^I_np3TwoN_eH`T#S%WuZxT6S#p>u0*;f-%Jr>P^CHXq~jtavb(3|;wuN^{Fpu&jTXj{3qpgVO; zv3WD%m*au*4PMhqo$E&5;kjC2e?UAxeV?a3BZ=1Xu;7PJyXU~+ zavqO@O~#xDXAM z=sPZB1fJjXl6OAt`Qcb`pBQlTc#$5>hU&DMpBZj@Mx(p6$qk6$u~yH9{_J@&#eJRKbw zY?+>9ykdTeD-|uX@>D}jwCay&`Xl`}=-dx(z~m*=aOo?JR!Dt|$8SO0?&G?Q9fT={ zpzA1z^+%~~*buCq++eiSBdj@_{$sV?{Eeu9FvHHGT0a}C1>^m|4;F2uZ9OV!D`vu0 z%!I8#q0B#nkjntM43HThUD>q8U!pW-!4$AvMax=G^WF;cxE{M7^8^#naw!IakTh(5 zZJfhRo|_N%O0m1q*S|v)VIt0)AoLiIa6uCq{1b3f)>01<9!Fe?7$*^aDw&+J+cOT! z1CMDcRKTyY-wd?%Rg4o$5k?6Xyojb}wb6pu3`Taf^;7J39K0|qeuxT)!kR3O56U=W zo&QtZ-nCx{SKB+rGV>d29K^L194VdFR!pwa`EH_RH+?O<=c04rJ;#8#w5Pc*T6}eA zD;Ay7`Doiy&~2Vwo(D`}?~-}bnN3-XVj{yBDxJ4&r5EUoZiS0btn0BJx6-LuE0`0T zxfw^9vkSnWy~fS0Ue;6NB_ zF5y&oao>0{Osj%9v1T}1MvmonR0-%@h{imQUE{A7;_g7+95zV}>_=!4J*c(?qy$P( z3l|mW!k7RIY!ur5iq_(M_k{L7c3CGIe={y6KJ5go&v2m9wqJDr6>#|OO3D^mUxI{C z4eL`_@U;CP?;OUn@ceZ`^O3C(TQXA4-5=sgK3jnM1n=1uuO$GD6lj z9&S4<`Km^rf`HU7+}q(jL*B*#o&9*!*_gv<6=haMpGtPVj`~!*gqu*`fSHoG-u!gq z`MBnW`|6PyI13Scj07LJ_X_Q>dFkW$1Hli>nQ)?l=f;oQK9FL3eyrrlYEx+Wq2GAd zBd&^_?G#whrsrHZsg7QdVS@T>04m~Z3p@LRuhhQwe$YS}$JDr{lZ>niRpU`yPk9gO zuGGF3r!C%!>gllT^{`62afkn~VbX1wQQ<$T5&6_(8BUL+4x=zl)}fn?r8z$XrFvlwQ6qz_GuD05HP0ZH;W^nwh%`9o+u z&ig{~IX=8g=AXRuR7j>u7v_NPPp>HY3d{={329_dB#LjjYddF;q zOiUQNhkYR##DaXQ9j_7!E)!FCz+`|wP2AkU;9?w#67MUY6|CcLPKk zO~p;G>hbpD2i$85>092`=h1w@H!f#r^iM>Xq*iZZ+wcI zfr)I4&w58R3t(wpn9OTKBcb5&66-sgo)B`%1^gZeLfD)LF(Xz3hJ=2NmWD#yfA$t1 zN)+=zD1NawuEMNPdN3-@_rs;|s1Z*laLC_*`JG~OC|2WU%$R76KOlvHY$!T4;188@hiLS%uJF<7iQuvjC1*zU2eYtz@sr4QG&>N}l)_qs+Vzf`=DVjan z$PBx?pW&z;n^F8&0tJMwj);519BBAtUBOSbd8z}zEIyRXyYC##_oqVL1Iphp?^r#l z^_=FvZ~mCuwrJAD5US2-v5ztM&UzJt%*Bj<@z^%zZvq+*HZ~x|Y>Fd%&ZfbJm3nL* zTtPJH)?*!*t7uYg9H|KA*&WKnwB?h3)^T zFh$&kRewI>HS8?-L~(cG_fPN?A09BYM}1Ljm_6+Jo2+#nTr__+dQ{Oj<^Zx4WR%GI z=r@|)d^$o7MEyk(_(4Pt$QIY>&2QM*u}k&l7mz)I7g|(q$;OwNi||g-i2vlBBI5gu z__-x#`(W2Tr1Qu&N{{R7-+-os%nNYeb%f9M5#@>=YeGM?NkzQ*XL_ZdtNuLXZbb8U zIn2bazjE{WS^5Y+qLeYP+iyerveNhJpW}Mgn=eOEMETawFw2SiABQyuVvZhbM>%>F zkJuh%#gAFR(0>V-NsNaC+q|^_EKBhgxd;Ul|sUhd?DcZ@Yq z$hn7k!@9yNvK$=lePOua>MEf28ihV8)GzRp0(^&AqmN3aDwaAJHw(;?=;hY`>xVG4v}i5tGe^H|;1e}ih5 zKf#u!WC7P*^ejl1obvYwz(ky7A<3JWlR^})d|6k6M9N)Ui)!&xF=CQtrJ7wNa_7!W zYn^(3z8`@0OH_S83OrOnvyyqqGf(6pOA_Ou7v7;i%4&xZv`bq1=o{^L!hDfWb2U6W zw|YY>AzAxSCk&~|IC(SM(@m5^Gx!q%O^{L86gxaBrCF)j3u7(FrnRfH+u@|gX&R}= z-k%s1BX;8`KABhHpxD2P5DAi=cxGY$;z6C3sK=5?&3CgGJX-zGk95<15?~un{9=qv z!g~TvSm%Q&fqy-mpc)&MzmC9lop|pNE>}F>&||!-Cw>s(6=bl0H={wK0o|uB;E?D-Sats7Pq%ry#Y&{DVXOttS|d8T*=1V)uR2(!%Zvqn*P_CA<{5e%4b zML)os@*m=72(WvF4MWD4h&?HojV%>k;+P(L0GYOCIe9A!9JSzda9%<%wAdki#fvYA zTVY3F-I{%1*nA7L(L-XaO|ki55E7z%jCXiD6u#m}3v^@(U(x*nHlOEJ`XiTVG2Fcw z4ea8lyX;ZR57nk)1$x;(um{B1vp2T4@nfUfcyAbirVq5paQzWj6r38m zacbz^fcI%}jEDiu^1A?V!DXme#TbIyW6cvXjd5Bbi`mY5^smbI=s!$!Y?H_O#|2a6 z-gqAq7dkMbd}^;naCfR4FZ1Jn!;N#V4UlFf`Z8P_DqS0JUy5UFndvdySK#*yRu|M-+ze3s2s}e?#G{dGG_&PcS_TdW837&E1@V?VsQm0LJ^x z-Qq3dPxzKGP6H!;mzag_BTDD06I%Mg5GD{fW_3dM~-M4P%NGkL+CLsFPuNh z-yh*d7XBmp@oMMx3yk_Mh`c1|->8wv_K{>yp|?Dbd@=2O z6!LaXNQ3Ac5%5TKpR_vAH}%p!9~IU)@*>VgVMcw7eXmAOFyqmq8Em2wJGKSf2!wEa zd12=O(O>GE(hch3oN^fs01id244v@%GmBy0Lh%Y*?VJrG|3h&^DW2K=5J!{`)8@v1 zsD(>E;kAd;4D)bGKD=*<@VqEonrQqygkOJv`TMP4f+v8n@4zNBb|lVpS35onzdpqS zg<$*){9Xqv3@uV2&0P`A-M{+LEgzhA(gm3SKAgjS*A4N@GBlxsK|6t7o@ zq*)9g9#8$e$U~1wvltQ6R1OyU(JtDTnP3({;a`|V)`nWE+u_fc!&*rc(_K5hgv2nBr zLK67Jv55G!v9Sada|d_iNpD0xLn;cJpX1^Y<$(PM?wy02@Z#|2c=zzzK|Xs2xE<{f z8+-#5DKCCKdQ4q;W?9SSSXR$tW$`u_d^?`BVRa_F5Aw(mxiF#+%qliqQ+Im?DB+e! zAGdWj)RL#z@!s%PdaMuxgYld2>oxlAe}GvjlShDf7e7?JC#4@acSAooM%-^yzaDa5 zg`=0Z6My(0kb?d>ZOUL~Kf!~&-7g$(KC*UP5XXJRdn>B(;CO!!57P1EzUROVo`HOj zUcN!&X<+Hg>kg(a1o`JiyO~l86u9@(|YWu7a zE{MykI;+yU4kV>$5V%6v6b63usCrLg(*w2`x(-hP7ni2ypi$7=?;PeP^F|F6(`lI7 z#W5ou_kt77eHcI1D5jF9C-wn#!T?Z-2dGcBf(-b(&%wfA;gS&} zlrfQIbz>qm4Uu!lj*iqVRYs*g$X?*P*0-d=H+)eKWq5;v>iO3!h%BzD_th>~vb1K= zdA{KdJqY&Itgf!9S=8WLwqUgnKc#(5WU*+pqA}uIQR~BRXRoNg-o~t}uc=+K+P7r+ z$^}c8fbP^4jY}6TKMQ#Hk!)Wr$bzU%I90`;(mt_jn&{sbS>fZ)c&A!4E^lb8t6NbY zsafQ!T~WUb&8inKs9#VWsj2Uw;AgvQ>X$D7xBTU8u;Al}8fxmnaStVpr1%kUn}>9Y zE9&@j;J)G2JrsNV?7wb7eFIqr%=x+T6Qm=4VO&CdXkEJqlCf#qKNf!SI-5oQ6!?Joo^@Evi`! z(&R!kUr>D=g=yCka_x$U=%Krazt7Cl6$=)f$c%uTj2UXdg8KRe*Gq+haxH1Vj8@}! zj9IrFoi6aDm=L4DB-pdwu;iNM3nGp6HEE5~IX;n(?<+>*@;Zz%Sk!$)R2sXE&;2=e zdqJE>J%}uUZUN?7vTVUMH9ly1bBw5AAStJUi=QduX;t}@`#vYK}}JrS1gY#xu$VNV}q|CwFIH> zi>jdvi+oF$EL##`&qA5b6O$)&gr2i{Au&T<(JI#Em*$D z$6{G9LG5)ALqXt$DR@Y&)S`eZc{gU|8LVjRlg4WRQ>%s z_^Ik0y8mgqr<=Yxbe*(yqAl;H(vzn}67G|!b_%>xwQra77f-Y4`$8vA3k@6o&~!WX z%JfwD-Qjmh`bBf>_KCSCPpc&Su*BQ^Z}7X*sgn5KD{T5#Uv={IhgaJ0ESdiP-{5zr zGfCnr-9GiQyaXwZyOc(mRwKohSZTnYhQA>G_?coSN-a{tLo%H$(`%99I7wM4(*mUY zENQH6s141&mhkjXaAu)@#FSL6KvxI3C+!E)K>RKJRWixnKA87w{Id)whkt{k5tIjS zN+$W%%0edBk)Lwe;OfCom_+@DN7fb>e7#f)@=9!@X$j3xZ%Wbz55 z&pn(>_Qb$P{ssLYUGr!%Ig4dnt^F<1=a4?hGG0aLn*sW`zp)7EmDtX2L^}A*WbzHB zZzq%EGZp2Rc%vwW^bP#--TO!%_$T05xS{*Iy&570bG=d5#koG$>$%>kxf#7{AuL0@bqMxTWCzEedz+HTI$t#`j zR@Hq8$$g*mi*m$}PS(#_H2A)NDLT%vAN>|W&-nrn`)}cVZFC27eYbeZatouJFW1#Q zati?oI0R`AzP$nK?Rv@2k6dCNyXXo1 z5poab2Hg24S06(Vq#k>)PPby+UWvT(8Hvnbz!f}y2+Dpoy2^6%Z{fJ39@m3Ca`Uk! z!cxPi*J0rM{x_MtpC_3AdY&%IJ*>L#JNY~bz2-XlCFnKnOeXI{-d;x=PgqB^FA5%t zRlz=-w7;%(RF=C*b^q?&M@f zpjY<-)*JFlS+3VL59_fkXD+^j_H5egG6uY-fcM0y#?htU({t=}buBxocx*nYYimHy3%fp1(z~5{+(J9Jk?ZP~3@piLW+=B^b#3n<76eo;W&VOW z?ms{hMN`GPOM%nY3H`?5_hFw?a_zED!p?Tdbs7w&yX5486?4V;90@+_aH-KmUb*O& z%#9hfxq)a_i|2Otk6f;KLN~ddW&v+M@VIQce_DG51gK7?PCciJA947Pw5KRR-q`_> z!%v!t&%;##kq)qn`1e$+L~f8QJAQ_~ou8w!p6iJpr~b?1$rUVDxdQm^`ZryhGVC&^ zgrB=y0VWEz;^M=Xu=sKGH{UKQc`|hpE=_(8tf~^JBMb4O4Iq>gKXBRN(_f~ASpkuA z;72pN#dw~Q_(@rI(Zh zlj$6p*2;9HOmC6tPi6XhnLZ-Z-78y}viLJ*ZZ(rvaNMp8{(6JQlYx^`G{|Um`g3nw z25c8^=($^%1+_saWN4Y%-7Kn^KSwc(|NPi~&v$%nQR5Qu9Is`&0ww!2mfY%3L{ZD; z06iXA^k(lsJ5Poz=4YRU_MS{x^kqLxaxYn|%-%y%xw1GfdmW2j^*$iE3aYZtVB6m67ExTBeG!X&ReMBr*PoBJS7i7ancv-!;0Q!2|3so5?N z_ME2{i}qX9?13<%p2>oHcR{fI|4CKpaXty$lXWi|37jd(= z7>ta|e+b>xhJcNXE2I`_cV?q>C57NB&@}#FO2$=o$(y^pahZ~FwT+ptB|t4>K8Ncn z@M#-JrHTYy1%=ux7)QneyHuo&0gh8D(H66`(5?%Bs}DfOMTRn}nbp-{_*Oma##!CZ z_6(q8f7B~L+Z$P~s2R*r8&11cQ8NWwcP#CFL|TL!QTYMb>7&lhcJp6l47gv#PR>WpkR z|20SP=^d7s{3W+_DNLpJRT56_xnVvj_YsNo9+3W#YE16Cchf8})l8Vk6ET(EKarJZ zpt1)@iN4-QvG}{RwrAPZT{3!1R-T8p)10;+I&J&zl+_%bEk0`HDojV-gAhRGW-7I+ z=JBnB%=_#@KlLi=P@|Y&l{3?ywk%)irv{N`tP)E}rEL3i=KFKTQF%KnueU4NUsq+m zGC<`&`;oCyRVgb`gBIMGW!zx5pk&fp^i#*OcC}qg(R9@+1J!TQS(cIs6dQr#@6Sc1 z48mwIm}^zLLI4r2ya;>bQX0`fvmMGn2!Rg8@kBl;wBw*5oQY>&39{0eIG)1xA{p9+ zqDr_8c#k-G@8)h!@H4I=be7RfdM+Q#QN}IPn7tkRX51>WYe6AngFxWFu9I<_fIdRp zxPSs*$=EoP&FGslT9}o-$@L_bZN{C1WNNNov9Egt<{VPpEV5PX>k*O7We1Njo1xLQ zNtfnY2$alaNx-xEf}l5R^&E=J4RL1O@CLx}Zra_jOIbJeKn3g)8JGmrY?4`qzaIP8 z8gv^_$Z>JiYK8PQ*+0S;{{#kb&VwH0XDj?!4y_Nu&TK`D7(MW|oKx~>*NVCiMemw6 zkDV!Y$*Z`|BK_J3Xk=&y@!gYrxWf4AQS>FgZ7-ek9WUGoFP(Fo6Nhp1It^)#Tg_vG z0<9OlbdE74V_QKJ1;wHLi~&Sb$oy>u^n>6{BxYLL4CUOJavI!AixoXr%8@X|T= z+0wDSbj}}b;n-d}=RsRGUZ@A(gUryV6hc`!E~$zc8r4HUiyUYlC5y3YYtPX-^i(?r zCG1(m0|hRD-+|Sh=l)uhG>tzP-Sd2^gsZ@-<+JXB`$Q>U<55Y^zy?toto<6KdIoxag7P5imhT0_ZJ6`*Q?f(1+=X^s0K8SQ4dy_}t!6f>8DsM1*7ikWb90T| zztX4S1|@ef=bhHuMZDZ4AG66$2*sPb)BvQU)JD<~%hr%s6rmc(3a ztTr*5^+SxWP>r63L`YE;zvFa8D& zdGRS(7An1JoVYeC8|`L_h_=;M=^DTa`*g8?bwfM3VoUW-LbLWm8u{waHX`4rc9Ejq z_${_le=&yy7GZ@2)L(N2X>}CAZyXA7w%NoAiYJ4m|7JfJ zSfAQu5kFeuPgzg_7WPY`|SZJ+5vX>Dl5oZK3RLs8C-_;4jQ`ngB9xQ z6M&NUUu>K0R*A3jNA3Gz(~#|EvELHr*lB<49eRjdz8H9pnrvF)hUm)Hc8 zSS%VVd9QL*6Wl6?u6`#gCy2@cLJSk!tWxp{$>JK1FkGr1{Pai1H+iO^u0Le3)%gt;@HvgxvT{2H9xuW{{^D8QR6-n`=5l zTY*Lct0>}XO;!8D2@Lp>G^;iC+mA~Yc_CL2T4d+IVvPv+`mbV63^}isLz|sxOJ*Ag zQNFXqNGJfARNUDT-0%g*5EEkjCXg8W=IP`f2H%zoYy)0qDZxq90pgqL@i zP4;+1;Gz0pfY@Y@Xp+C0buUQ7t08suLbr{$i-;Khg|?P1z-qhDEtG+nq$UL1 z)C6`O6sY<9MSOLNK(NI#)lKo(s!-+@svxGn+%2YGsKqovTMT%*+nIjDUJXJbAvedb z3@qU!Pjjj2^j`K%O>;j1J)e|`fYj4}rFKx^d15UKv|e9tH}M!OQW z8z$SGp6j$5X1656iOa1YDH3g?r9(}palQ`8k2H(TyIw%+7hOA2)waou<9 zxoK!5H-NS<^K)?Z0l;DEY{G}(ltx=LOr7EWT%A2ky^L*@f?Fi=bv9zQ`->{OHPG2g z@jDC^fgDJ=vXe5tZbcIja8@hB7enIeH$ody__|GKHuzKz1NTfZkZ(Bu_i!9%aU9>; z!`Qsmf2PDQ7yZn#xt!s?WAj>s3OW_LQxhE&NyMT)b_buZgK2#zDOiI}VIHSICTCpJ zz#?mIWU(46yi>aj#n(_AAtt0#nAkqh*de$ptEeAq^HA@(qrGk2*$kWj;8F<#;cQ$3 zb;@6{Tn{ZcBzg;A=Fef5viwVyTcDn@yq9Hz>hXy%eUz5(Fb(CW8tsYaj)&UTjogb> zG}UX5={lLJXJ`AdxgGT}>P8*F*XZsTV~zrvjlRaXU_xgjQ`8d~MH#wE%4sDXm7jQ)m_amk)WU0plmmP5nOx6zLu~)edJ)f`q%r|-HrZU)wr`{6*M4?W0>kNa5FS+6Ed`!_!j%- zB>;}+(NA)Sa&8|k>=*2a!dY+?eeIqY$*Y6$)N;iCx&;=O%4-0gu?$Y;g-lkJ!gl&L zk;vXmItJL3wG-%Ru9iIc(2@FTCNBd`yd7|y2q_cSBg1IZzf5Aiim3tjYB8W6~_4b&QZ&r*w&p?Av4fpZn*V!Ki;LQ_(?OdUH+{QJHq_3wEB2n!d>XhnPXgMcTab{qcA8;h^ZWBmTj z7z5u&@Hd7*$7L`gW9B2Xfte-9Fi0H3`|xFmr^akV<{D=1LgqGRev3>yGh2{3!b}q~ zqcD{PzmkkR1C0<&^B*M^pGiX{Z|XaCo#&3Nv=GxI_)8n=S_fsQlCWVCwz6%J2evZs}knot_BNJuj&&WK6jIi$)_qRD~ zkg3{~=>dOf_PslXur|}vdG0$NS~r<PX!0YmQHhBXHXe5I0E*`{lDAe7QJy~( z$Rbi|6&s)}EF;peYt3O$-*;(F?b>s4pakk2B2fJRb?1l;on4+%AeC0MzZCk(k~t_Al_l?+BJ} z@Jp6oL&k}N#>kGF!OAUz3k-=z`WVU%y#o1zUK!Gw6%&> z;@3*fRQ!h2HmSCrJDNl^mC3X~=K{`Rpzq#cC2`580xhJRO-cIq~i z5Lk_5v;Q3;2O(2+f%___>6d6Rkxhq=#$xM^Igw<3fEvlbqmsg5GO*BnKdBJqCZGsT zHZenTJCX4}BheW`bA2`7TLjVeaE43a`dpxPt^1(E(+3Wb(PJ>2O4N!@?nOzCs93g~ zCR6n~_e4$(d3haZf|ujWh@lmMmnjm}=4F$?b%Tyid8R~-`cZZL9+IAXT4WCQgCKq@a=lKEf#cFY%$EDOGW&M96 zW;%NUSQe`&duRYzJT{Z5damaWJ}iIH>a)9HkHtr{nu}JWyEiytP4<>liXCbbJV{U! z8hjsG3w?Ws8S0y7BD7(IL``2!v#=$l)~rO|!k?ZikxCu96FpOhf=l|-9-lqxa5=g= zo^-2Xr02`Fl@5&(&wqi2;O#umEtB z|BJUbfv>W-`p2K=P7>ODShciOK&=&RtkzaVT-)C-~d$qp5|8hT{+~+%I z&YU^t%$YOuY&T9JF}X7n9%o@}WDYTCt=17JXr@|i*k@D{Rqh#H$k^FAypRu$J1e0t z^`hCvOc61q4A{690wchRlx9*7r?e3_4=<#H;~;ae#p(Y{D`c9(8<~8P%_*6~hpqs& zIO&K;ZZg}ibuyNwn^w(+maOb9ecEtS#aT?}cb&nOO9pG9u7Dt&ES={HYHo5k5|1=S)s| zg&BoZO>Z~IF|@*St7ywN=`O0gTl zz&T4l+2r0Ca<_=&w@xVJj+}#3?GB^86zAJJ^)>h{`Sg^QzE*#izWVMaoTIPS|4f&L zkJgv#w`$g!0+RwwX%m%3>&y0cYu1y<_|f{(y(#~Y%A9LW=~rB<@1otKZ_R(f<#KYV zYs#mSf>Za5pl|y8TaFWH`kSzQR$uF1$kloq*C_^VQ6%C1&|So+w{brpj&avXrQXKf zDh0ibdsYg18}}zE=xyAaQqX(q-rKk@#EHM6PI@nkxeG;6cb}=_%e_v(pX$fYM!nv4&=&jF5LuSsnmd$dQ414?37T*e-QY;n$Qd=3796+G zFdh^sw@hSDInJ->;I7W3@z(2Fp^oZ7Q>n~XtqXNk2^B|QoJ5SL>)4!j29{9Q`XMTfUdOGaTta0% zk4$;jbecc>l7`f$UC3TIQ(GEZkvdvWMN^zPg9MWsOlj-6B79I{Dexma?hN<-QItJ0iS87n zkPot^5FA=Trx`~I-wnjT3DKM8jQ_`Y(^iMNJ%Y&0)8*+_3DZnw$(4K%-lSPGtI5$u&o=ac3|!g??9z$;t7 zOY=WUgOntaz1kgqG6`bM50Nyj`6+VubJs zw9&kqrN860vvl_PE@CM-z#>@l5%Wm%hlI6`c%b=9-=;YS%ED8O>}(FAkKNZG`!14J zz!O!=9$Z7Rn}qdOQL@*6m+X_XjqE)v`%!lyom6VQ?;&XgDW1qaI!v;s2`28eJd;C2H?D63j5MYllAyClG-SX0T2bHwPpJl)v zpIqzEC*wky5?i54p_BeMq48GZ8AGR=YxI0<24>wGhMKJYQCrAjNYJ$s|NLHxwjngX zkSnNAZd#|`EG)d}4>fEFbf=KyJ~GPijxkg>$4Q@Xk|D7Y=YW}&NS_~7Q`@ViMQV7* zb*ZV*C$*wLMxMmW4N|w9^d2tbyw%XC>x}n>v{OjaoQ%`P7;SzpE$IS9#`~FucF@q0 z75~?F{_vKKMfc4z<$iP$uU&G5FgO|4NCX^bs@!Q#`dMQQ_y3T=lQo&{=&hq0e@^;a zQB~!=sxm$qXIeF(4?l%v{6(Vm%GjzONj%*dTXnZoJsn&1OR0K2w(9p%^?7X7`%-m8 zrg*_>m>@BKN^Dh;RGkxBHBYMM$5f4PjX#MJJ$~*vnf72#H#O4tzmuIJ{gk~s(d;F* zNYe?Ej6>(r{BXY_ZnKw|s2B9RiD+)+PjYb&{CIu=BS$Z@Zs~|qq&aV4C=Se>@WDO2 z7+$ILa}{ng?U?zIjVsL~8+4L=l|j5f3*;*RSL=rj%+pDN_0vq(L_NZCt$u_>Kelq6 z|JX{mer&}V{3+-D?ebvJZtC^uhm@x99$r7suw6e2bo59=W|ma_)ZBymL8GJi*8I=S z^F;S1Q%i&CX4Sjo$s+x_f%_+=*YQHJdrO{i-`ngyz7W7$?>}k#CM=*!9mn(~`k%Cd z=P!gaUslGM2ir$$4PVh#Jy1u>e-E7ld#j2iOPn!k(0Ki`TgvJUgkKVv~ zn(|qTsGd#Or@Q+Z7y0(TDIVk^yLrEM^T-BjT$@CV_ba|z9YUq#iwL9xrcfl4m;7%%iMdYjp2{bejc#^SGea%8-2rEE-z8b^p}JupFFrOAeRQlo#3RuEiByi<^YS6en@J$>qn)QSF!#Q zUe61SJ3CQmtk8!-Hwy8cz?nQ~=`(~UObQL0V9YU>Gt5;U;u%*XJbGxBOF<9KWl|sy zl$yrLYQg+M@&-%d>uOH=HNw+bWni#tZfc%Ub4yIs_*vt}r9INl(n)0J9 zRNlmS)s(MorLtZS4(iKz54KVH$^@!6bscTl>1*IE5adt75fksM|ZHcrhMBPS{<`lJ5x4i#0C!}4~@Qy>psz! z>C-6;NB@FX6H~s7%YWn)Y|2}yd_3Pn{4{}|`%oJWwwv3>pJ_usX7&}lQkwD?>qs+N zxjxgE=I3`(?RmU3eXcuun#=lh{qqDKg2`P}-pGUXdBSg~Jbpcu&tN-Ex$rWaMt3Eq zoMy)Fl;6;rH?+VMj+di*Oyb*1$uVAii=pm~x_znZ{pv{FO~#nL)nn3y4ae)6&R$7yCWVi0V z%+m%LzZA|l3|F7!^h0LDa)vqS?@9%qd;ZH*(&GbszWSPkB|oA!B-aSn3n5Q?Cu67# z5w|ekrdTX5i^!p$G8S13(laXX~ zx}{V7`~_BUO`8b=&+x){6&#cR(4tgrOV^g|ax&Nw`$C zp=#&+LT;+tuBEn#vO;x(q1kVnB2{;pDr3X=lZ2{Q!Ts|KSr~m1JBQB^^xHYo`XEgQ zHz8>gwV!k&(V2PD)dW~ZL0Ufw+Iy&UI`7n->D+RGv@E4M>Or@<1+D(Tt=3UZ7B}c~ zH34p3M}R-$Z4e<(jfH!J>FN?we+#vC$4oUAzOSwL;2LA$``W^* zt~D0^!&q1|x*$X?OzE`iXffkcT~oY*ilg;2_y5!(~pPN3~P1X9|vMK+Q z%ld}+hx(6+|Ew?G-=Rj;(oS7yPpj#I7qcY_kScUv-@j@Y4;y?y|g-$K*0r6qusxnO4|MV z3GheX=4p)RbGqdTh4Jno)vOdht00N+uZLLf89sqa26qZ*O)j7WGMl4kb#86@2Z zNqbmQkW))K_6C-8S~scNP)L5dmNzsL`ta3)*;F<9ST3L1hX;Nom9_F6(}@$=oTKSiWNh|*qfy^MM?sD9X+<4q`(wehf#^0pCGn>M)--c~;5lr&hxB*2(r4Q$( z@vDnXK?kp&PmE%f!g!$^-NXCrByQbn1@)>mT*ZLhdn4DDV>S@vd_cP z+W{VEx6iROLkd!eKBk(!vKG+SFG))J--V5@<0TLeOKM4xR5tzxGKB&vI~iloHn!xL zCduk=^9{ktXp^ckRQVSIGIC_3>rItg=w$2>(rW3OE>(`pi?S?ZgeZ86Ftm`;=Ln76 z`h?KUqYGRcky?KA?M<}OCecG&{AinAPR@8I0>wg;)8dsr)^4a&E6mx^AMM z+(<_Ud^Nq^XK~UWj_R*Hs=w!>`n$#FCvCXDH>3LdO|MFN;-35ChkDm=bPFT*`e&cf zNgpX=!d8A7)$3%Tvz15CQ0dvgKHy%9rIM|j(5tc#R+bA3_cz^VamKF@x{fCP7q{j! z`02hB6L*<+j@;i;gCTqc@Gkwv&k+4`&|MynoWA^dm&Ze%+LylEpLz2rI*y`6daGtW zibvhRRQ=Y^-FoSF2LFqfvdUx~k?x$cNR$qU%4B_2Rli|bnLLKn8N#nJRVMSROhXpX zYfP2N{2G&ar>rvhUE(-OD^#Uh9;M$@GB{PgmQ<}TSf}b&k_7A5kba*4c^#^<2qt2Mg1aI*xyDgKa) zEvsqOUaNhU647NYvZ>Wv)W)=H@7_UWbLQQyuNCj-vVM2VlrPvq{Oq0%{ifHn+o{Md zTBqOi`Y9DB^1MFv+(Hsg^NMn-dxcjrjk5JMMCaZoT}oik9R!vWC?Zg>j@V}0OeMA9 zKzr6t33L!S>wW@%X7B`oi+>`gBTtL$zsu46h4<>&awekBNiu^R`t;#H)Lx(Bl>F45 zKAbNy_@%9Z=a?YZo9)9|9P_%>24}dpWf%o@zcqZqfOoL^o@Wd^#WafAzvoH~i!6&0 zDFUz@wh5a)%e^+baH|yb6{oFIpgeuE5tgh{>P_FyxcoAMw2*mH(Cr$eK<)O#w9B|g zYX5<%9Ei-gL#mQ!$a*LIj7Oy^9aa2~MD-`*MXAb*sT%i{RI!c}9XzxD3JV8Nbll`^ zrvRUnMDwwcMrP92#4z$2$Xlf@!Ehw5%9pUQRzo zFDrVr8KyI@d3E1lUXBFub<1OQGEH5ssGs9>;x%^%4c2!7kN5Zq9=bXAhD%J3nT=CQ zxfzFZ&Ns&s@1eSBrRMzYF}-zp<6bNekLiui``fTQJTBX)bsc&m^n|V+azABkUM);9 z;{nR=`bzB%y~%o;%lgXe&ct^~omaOLJ8!a{OdLbSQ4i7-<^`!|woxeUFjDB7#KX^} z>3N9gD~O?B9TBsV$c=xeQdSCqvwlus7=cX;MiMx{U_61;hX~{oxRt>)0v!(%C@1g| zg9`{GJVM~#B7P$Ocmeu9$o&uZemR}`Pwr1=Tf|wAMuVC)h)VZSN#^_$6-ME|$kCnX z9X_MioDXv7IsXOs%ojJ$eAJ)wI)|KGY2=+LM|ZY&5y{gR+!hh9zTkEhfy^MMmU}{7DBE%1KQOV5ICqGt1J$l0uyTv*G<7rUM!W<4MLQ;qaw zQITJs`P@{~j*xe9`n@lHJbo5sApQQ#!FKcB*K#^ZJGR=Wp~dY%t|uM&;_huyxrcQ; zkl4Wi!0)FV`xu=S-XoRz;_hQo&=+@yNFeJKYlIZ^#ocTv=q+oni@WK+EH{eqp6wp$ zh!irfrs@+Ne#ez8;H`s`en41x67Mps#@3KG+(};|QOhqWz877a(Bk9_buzA$dUc*S z@iJJQez#QdwZLOcHD~hlr=mpW3SB$bh)mCtvE(zbTGZ<^ur+c9Mw|1DiQ=O*==c_N zoN=C1-G-`1rHTenuN%$6@HiN@`pNrdsd^PvmqxYab?7Z&_zDdCe_;8;!kOUVfMuhq4prl)N|lKms6(4w{#`=%+CF*8Lbr72TfxP!8ozSh*;hqu}HQCa7}4O-9< zJE>YO)>pbr z`8F!+D_1x4;gml7msHeS>>IVXDlT(My-By;NJV`iYnk}NNg+S{w9lI}X-4sN#21J` zU&!iunsQqy)#?jb`nuE$MADZMJEid!ZhUPY-7xi6(y*35!2zn#ZSJ9xzLuqbo0as} z`RwsIg#;-t%hBD_Cu>%({21iWd92_W$zxX%h`z{w`dlM#jvU=&?<$g~^W%NQtMlU@ z2xJC1wcJl3xA51JADLHleOP4v1+w4l^LlSxgB)7s0v5$N^8o_5QN{W8k$Fbfv?IuQ zzv(lwO!WLC@o7Etf5V=qS}o@SDrq_E8F23AdKyJun9i*+viN0ZcUzw-mc#X0Ta3O^oNP{(`C2SNSEYuZ?~yvRmHf zT}yrT7h~TxZ4x%T#~ao{q4LIzpAwe&pMG}~J+)jbp_dAs9n!apvD_+K*P5*Hy3mVF z3wjFzcQ?GSaSykcAJyU{p|3S9qBel(Go*^IHQZsE@UIEbZkaoPkk2b&Ba2(|+{WRJb=iCO` zO${AIg#Mhp^p85^qdLVoZ*Pbq;oVtW<-gt9e+)PmfpdUU`d5!Q-&;nM{*|cz0qT>T z^ExP2-M`<;RsPMw{wuhcOnKr#aQ1i3dzg}*`~Gh==YgfhjQ+P%apwIFDZVu!f$Hg; z)}_MTQdmzi`s&|+blq9}iv{jq&Pt;1WaX^7fLhV%tUIR<@m%hjODNeihWfV!_0JLN z-!n|%XZW3Rmv2!H%Ans`I*WNuGmQt)^yu3njTdu;{^DP#G3^q)_X(G|!mW#9+-6MX=c0_E%yEQM>GE&O4K%;a>GBT8Y8fR- zi~A)jR_1;}njc;(J@RYYMwKe}AsYQ;=NB9U%^YFO)Gc#XDA1~>$)!AHrEo!-p9zCWan2r!E)GTd}lSvW!3I`Jnq+-u5E?+`AqtC zIroIa2K7^i9dp?1q$B9bwiF8Y&=5x*Hl<%~zoJ2OIckK{uU`Ri&?$&Oaz*0dM5R}g z`M_L#2D$36e*L(SOGR&hFCmA=LyCz-gSgli^6B*&*DV^vE&8WBMT4?PEvqY5k$p5%kVfVbV=g`*XvT2|iG!mWbi|Ggjwr_Y;jAWP!CXWCQJ<=n6_G3Tw>h(nF zm1YF@I#PP&B6Ty$>WX$Znh-w8TF>oHj?$KjqocH?;wi^cG;_CA{i+jLwK0j#SUP0( zqp;#%Nza-OkYl4k#kmb$e585wa&IaWx3}>6-g5PDv=4mBgmaa z(LykA(m`>&I_aV$dYtGCCE9^>rC$#c`Q=<0Y@J2V6Fnqi=-E-NhpwAx3noj=iYBm& z%X({L@=|#;(U4{v5{K^u%6IIR&^@Ksr2uPj$>>1gkKMQJ1C{DSkH z`!%I=TDQoZ4*j`VZ7s{PmNd-ITC`w6*2;3s1s zT_IotYg>)^bdpd1n|hpafbSym0bIm>vEFKJSXxKCG)suLcG)81uij3A_lOD3)%?0k z636w8+&xi^%SofQ#s;E8H0xw={es3;9u?wUy0o^D5RDmel4L`re`?(*1sZ{HmC{^6Umr>IHWR8iFq?^Lf# z_1~=ecJD4}$TgEb+MPGR%hO~TlMQcy=+mWOO5cleUVypchaIR zm9p8JtX6s5>iSE(JTGJPiqWSfgjDD9y(FxwZx7*b+VV8coKWo@Us7GvHX%zb4V~bU zYc6b~uTuU}ceig={k(yytyuN1+E-GoM)!QC%8IMiFkM))!rdGZcuNkysV;2vvNyH)SYX(r++kOa>;bHyj%6lQ*C+c0~|kH)2)s?q<-0P z==m|!L|vBPkN&?e>C9Iny?V8J2g{u|{Wn=^)i#FbdL;4dOT4N#$ncws&W(5*wv=3+ zm7CR&e_e_Cbst~EFIE=sRCUGYPf^EI@rb^zLtwxzJ~Z>!x%^dqnfhvt*IA-|po-Ou z9csL{cSAwNbk)C={L|{~SM$2bJG$wGJM>||AyrSVAMfQ=tGoM5dXIX+sgJ0KJN90-vulf*(5f0}?Cv|PSpDJR;`JqS?#nG% zw5X)3YrUGc>yxhPMF&*ot{0yt|GcQ~>e%LGbaknMU1}!%rvB0%b!jMclB+5=tCNaV zMX@?LQ&m){oJ_BTC*as^pQ#xXmnV4jB_$M>mBkmUDTh>**IJ?;=_sa7Pm# zt2ftHsp|(&WPG@+O5G94Q|qYNI;wbMZSg1SP9o$S`b?c&+@*$jd1S*3@^L7Mvq&gu z3xB`DUoAJN>O57@qt2tDd|~Z2^(aaB-CCMvkCKGv*Vbog(07~qW8Y$Re_Qc=s;Nr- zeyx{AtzGp*$kQ?9E!V|o*KXsZUZvENArmgYUfapU4g8f$EvmfqF7@o%sy6j4> zLs@p{6aFgUuZ1r}_Wf<~n8+CQ^N#wyr|ipYzDo$5Yf8hJ={ zb!=AaTpGEqj$&%xrM@I#S9D}{sn4C_wng5!%g&jhHg@Exe>hd@hK{NRby#QahI_Mj zs@I*?_1smPdd<=EH_3dfyjE@8na1NEwv+yQ++DAFJ1a}PBUMFcl>3X4G5NXLMM?F{ zs|PAckJMx?U&>#X@mIBawY@W9KHf%kbH`p%#H+7VKho-|cSze?JMu{Hx18eqMc(*1 zv%Rr2zlzm9()VuCR}WmVYRM~5ee=}vV*0M8K~&EGhLbv)emY-Ppc^)`P#1 zh#TA4#p+#xx3ILo8fo;8zmmKM?#s<@s3De4K*^Ch=f{hTJ-L+&9Wt*4 z4$>T7(P?Dq$&j?K#9KV=d>zT^FOJuv)^~V%43lVuKiu09iR^rgyH?3Nl6EDL0B^I_ zq%+AoTGNYq)VZN4?zHLZ5AB`aXI<(6GVxFCRc!56GO}b*Zpq^F*X3{2%}khh_j{|n z^vaD>&R?WfhBDlJ8;eS4zV-9+)@>+xV*ixsi@cJJl_hoW?Z0f=WnOx2{(aTCG|KI? zjFXg*inz4$Q8B|Ms6|r#?NNCYZ5MA=hwC9#S5drF9{N-bI>c>~v{7W!h2Ace#UxiP z(lzP}M<2gbAG9B$ZOb9`yhDN}hDu#^5rG>zC>o9qO(cFVPq*9c&}QXm&vdhwrsZpn zSFC=}zE^!oKScP0_B9hQcYHS_()MVe zcZPbRqvyS9HLmkBHJvi>ab6y8DZK1gS~jUUd1{x_v%APkU!?w&Sgh__y@QUOSE$u_ z6E5;L6y;x}wygFt_uZTIs&|^oYE@U#9;SpsE3ZVY+@VJGs5#!i$3D$hZM3`|@3j_n zc?G#NjG10>WOr_fm;TC6^Ut8YhBs(NHJu?u)J+`}%pZ|+7nM|womSGN`qir@uQPv) z8nk(Xnp&j_GD|2tOS-smi7KvYt5o^hB9&_9w$RAI?10e7RQ0<=^8VJ<^yaE|$;q45 z!-?LuP{yF`-oE?PQ>%ASgLm9*6iu0`tyA^u)Zd4yRcof|-%0D*4<9V^R(^8fJG9Ac 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test52.ans b/libs/libtpl-1.5/tests/test52.ans new file mode 100755 index 0000000000..cc175825c3 --- /dev/null +++ b/libs/libtpl-1.5/tests/test52.ans @@ -0,0 +1,2 @@ +---------- +--> j is 1 diff --git a/libs/libtpl-1.5/tests/test52.c b/libs/libtpl-1.5/tests/test52.c new file mode 100755 index 0000000000..364ac3a6e9 --- /dev/null +++ b/libs/libtpl-1.5/tests/test52.c @@ -0,0 +1,30 @@ +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + int j; + + tn = tpl_map("A(A(i))",&j); + + j=1; + tpl_pack(tn,2); + tpl_pack(tn,1); + j=2; + tpl_pack(tn,2); + /* omit packing parent */ + + tpl_dump(tn, TPL_FILE, "/tmp/test52.tpl"); + tpl_free(tn); + + tn = tpl_map("A(A(i))",&j); + tpl_load(tn, TPL_FILE, "/tmp/test52.tpl"); + while(tpl_unpack(tn,1) > 0) { + printf("----------\n"); + while(tpl_unpack(tn,2) > 0) { + printf("--> j is %d\n", j); + } + } + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test52.out b/libs/libtpl-1.5/tests/test52.out new file mode 100644 index 0000000000..cc175825c3 --- /dev/null +++ b/libs/libtpl-1.5/tests/test52.out @@ -0,0 +1,2 @@ +---------- +--> j is 1 diff --git a/libs/libtpl-1.5/tests/test53 b/libs/libtpl-1.5/tests/test53 new file mode 100755 index 0000000000000000000000000000000000000000..042b51215be6c524041c1e6105991da844c3db4e GIT binary patch literal 128009 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 SG_~^1C{t6Ij?w&aj{Gm+zKpv7 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test53.ans b/libs/libtpl-1.5/tests/test53.ans new file mode 100755 index 0000000000..eb90ac5a69 --- /dev/null +++ b/libs/libtpl-1.5/tests/test53.ans @@ -0,0 +1,3 @@ +---------- +--> j is 1 +---------- diff --git a/libs/libtpl-1.5/tests/test53.c b/libs/libtpl-1.5/tests/test53.c new file mode 100755 index 0000000000..311556fb58 --- /dev/null +++ b/libs/libtpl-1.5/tests/test53.c @@ -0,0 +1,30 @@ +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + int j; + + tn = tpl_map("A(A(i))",&j); + + j=1; + tpl_pack(tn,2); + tpl_pack(tn,1); + /* j=2; */ + /* tpl_pack(tn,2); */ + tpl_pack(tn,1); /* pack zero-length nested array */ + + tpl_dump(tn, TPL_FILE, "/tmp/test53.tpl"); + tpl_free(tn); + + tn = tpl_map("A(A(i))",&j); + tpl_load(tn, TPL_FILE, "/tmp/test53.tpl"); + while(tpl_unpack(tn,1) > 0) { + printf("----------\n"); + while(tpl_unpack(tn,2) > 0) { + printf("--> j is %d\n", j); + } + } + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test53.out b/libs/libtpl-1.5/tests/test53.out new file mode 100644 index 0000000000..eb90ac5a69 --- /dev/null +++ b/libs/libtpl-1.5/tests/test53.out @@ -0,0 +1,3 @@ +---------- +--> j is 1 +---------- diff --git a/libs/libtpl-1.5/tests/test54 b/libs/libtpl-1.5/tests/test54 new file mode 100755 index 0000000000000000000000000000000000000000..94b05f49e07a4727a360299dc604fb87de3b5541 GIT binary patch literal 130738 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 iv}8u8anYH}v +#include +#include +#include +#include +#include +#include +#include +#include +#include "tpl.h" + +#define DEBUG 0 +#define FILE_BUFLEN 500 + +extern tpl_hook_t tpl_hook; +int num_tpls = 0, sum_tpls = 0; + +int tpl_cb(void *tpl, size_t tpllen, void*data) { + int i; + tpl_node *tn; + + tpl_hook.oops = printf; + + if (DEBUG) printf("obtained tpl of length %d\n", (int)tpllen); + tn = tpl_map("A(i)", &i); + tpl_load(tn, TPL_MEM, tpl, tpllen); + num_tpls++; + while (tpl_unpack(tn,1) > 0) sum_tpls += i; + tpl_free(tn); + /* this next line is a hack to test the callback's ability + * to abort further tpl processing by returning < 0 */ + if (num_tpls == 3) return -1; + return 0; + +} + +int main(int argc, char *argv[]) { + char *files[] = {"test54_0.tpl", "test54_1.tpl", "test54_2.tpl", "test54_3.tpl","test54_4.tpl", NULL}; + char **f; + char buf[FILE_BUFLEN]; + int rc,fd; + tpl_gather_t *gs=NULL; + + for (f = files; *f; f++) { + if (DEBUG) printf("file is %s\n", *f); + if ( ( fd = open(*f, O_RDONLY) ) == -1) { + printf("error - can't open %s: %s\n", *f, strerror(errno)); + exit(-1); + } + rc = read(fd,&buf,FILE_BUFLEN); /* read whole file (no points for style) */ + if (rc == -1) { + printf("error - can't read %s: %s\n", *f, strerror(errno)); + exit(-1); + } + if (tpl_gather(TPL_GATHER_MEM,buf, rc, &gs, tpl_cb, NULL) <= 0) { + printf("tpl_gather_mem returned <= 0, exiting\n"); + exit(-1); + } + close(fd); + } + printf("num_tpls: %d, sum: %d\n", num_tpls, sum_tpls); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test54.out b/libs/libtpl-1.5/tests/test54.out new file mode 100644 index 0000000000..5125c4fb0a --- /dev/null +++ b/libs/libtpl-1.5/tests/test54.out @@ -0,0 +1,2 @@ +tpl_mem_gather aborted by app callback +tpl_gather_mem returned <= 0, exiting diff --git a/libs/libtpl-1.5/tests/test54_0.tpl b/libs/libtpl-1.5/tests/test54_0.tpl new file mode 100755 index 0000000000000000000000000000000000000000..a811f623c7fedbaa51321b3789b96174f6ca0d44 GIT binary patch literal 57 ucmXRZ$YHQ#U|?|6$kb%u0y02=5r~<9m>Gy!fS47C*?^cGh&h0m6Nmwba00vl literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test54_1.tpl b/libs/libtpl-1.5/tests/test54_1.tpl new file mode 100755 index 0000000000000000000000000000000000000000..b056e6b04d65a73da77c6e3306d6f87644ff05cc GIT binary patch literal 114 ycmXRZ$YHQ#U|?|6$kb%u0y02=5r~<9m>Gy!fS47C*?^cGh&h0m6NpR5)d&Erk_C4F literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test54_2.tpl b/libs/libtpl-1.5/tests/test54_2.tpl new file mode 100755 index 0000000000000000000000000000000000000000..328940bfea42dfee025e721362a85c607705155e GIT binary patch literal 30 ecmXRZ$YHQ#U|?|6$kb%u0y02=5r~<9m>B>--2#;W literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test54_3.tpl b/libs/libtpl-1.5/tests/test54_3.tpl new file mode 100755 index 0000000000000000000000000000000000000000..bb7446337b54794f192af444ef07396cd7d9a07a GIT binary patch literal 20 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 Im1qBd0bRT?l>h($ literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test55.ans b/libs/libtpl-1.5/tests/test55.ans new file mode 100755 index 0000000000..f840753b39 --- /dev/null +++ b/libs/libtpl-1.5/tests/test55.ans @@ -0,0 +1,3 @@ +tpl_fd_gather aborted by app callback +2 tpls gathered. +499545 is their sum. diff --git a/libs/libtpl-1.5/tests/test55.c b/libs/libtpl-1.5/tests/test55.c new file mode 100755 index 0000000000..94bdde7feb --- /dev/null +++ b/libs/libtpl-1.5/tests/test55.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include +#include "tpl.h" + +#define DEBUG 0 + +extern tpl_hook_t tpl_hook; +int num_tpls = 0, sum_tpls = 0; + +int tpl_cb(void *tpl, size_t tpllen, void*data) { + int i; + tpl_node *tn; + + tpl_hook.oops = printf; + + if (DEBUG) printf("obtained tpl of length %d\n", (int)tpllen); + tn = tpl_map("A(i)", &i); + tpl_load(tn, TPL_MEM, tpl, tpllen); + num_tpls++; + while (tpl_unpack(tn,1) > 0) sum_tpls += i; + tpl_free(tn); + /* this next line is a hack to test the callback's ability + * to abort further tpl processing by returning < 0 */ + if (num_tpls == 1) return -1; + return 0; + +} + +int main() { + FILE *f1,*f2; + int fdflags,fd,fd1,fd2; + int selrc, maxfd; + tpl_gather_t *gs1=NULL,*gs2=NULL,**gs; + struct timeval tv; + fd_set rset; + + + f1 = popen("cat test26_0.tpl;sleep 1; cat test26_1.tpl", "r"); + fd1 = fileno(f1); + fdflags = fcntl(fd1, F_GETFL, 0); + fcntl( fd1, F_SETFL, fdflags | O_NONBLOCK); + + f2 = popen("cat test26_2.tpl;sleep 1; cat test26_3.tpl", "r"); + fd2 = fileno(f2); + fdflags = fcntl(fd2, F_GETFL, 0); + fcntl( fd2, F_SETFL, fdflags | O_NONBLOCK); + + while (1) { + FD_ZERO( &rset ); + if (fd1 >= 0) FD_SET( fd1, &rset ); + if (fd2 >= 0) FD_SET( fd2, &rset ); + + if (fd1 == -1 && fd2 == -1) { + printf("%d tpls gathered.\n",num_tpls); + printf("%d is their sum.\n",sum_tpls); + return(0); + } + + maxfd=0; + if (fd1>maxfd) maxfd = fd1; + if (fd2>maxfd) maxfd = fd2; + + tv.tv_sec = 5; + tv.tv_usec = 0; + + selrc = select(maxfd+1, &rset, NULL, NULL, &tv ); + if (selrc == -1) { + perror("select()"); + } else if (selrc) { + for(fd=0;fd0\n"); + } + } + } + } else { + if (DEBUG) printf("timeout\n"); + } + } + return(0); +} diff --git a/libs/libtpl-1.5/tests/test55.out b/libs/libtpl-1.5/tests/test55.out new file mode 100644 index 0000000000..f840753b39 --- /dev/null +++ b/libs/libtpl-1.5/tests/test55.out @@ -0,0 +1,3 @@ +tpl_fd_gather aborted by app callback +2 tpls gathered. +499545 is their sum. diff --git a/libs/libtpl-1.5/tests/test55_0.tpl b/libs/libtpl-1.5/tests/test55_0.tpl new file mode 100755 index 0000000000000000000000000000000000000000..a811f623c7fedbaa51321b3789b96174f6ca0d44 GIT binary patch literal 57 ucmXRZ$YHQ#U|?|6$kb%u0y02=5r~<9m>Gy!fS47C*?^cGh&h0m6Nmwba00vl literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test55_1.tpl b/libs/libtpl-1.5/tests/test55_1.tpl new file mode 100755 index 0000000000000000000000000000000000000000..85ae076aa787b733208636b51b59a603f8bb37bb GIT binary patch literal 4017 zcmW;OQ_vWQ4hGP_wr$(CZQHhO+qP}nwrzX2-L1L3r#F-H&EzGoN!N~T12#nn2q=`Y zRjPoOK?43?fn;F*j6n%Ta6%B0P=qE7VF^cg>lxi$tXrMhOvxeJQJA6 zBqlS3sZ3)!GnmONW;2Jm%ws+aSjZw4vxKEAV>v5W$tqT}hPA9?Jsa4_CN{H$t!!gE zJJ`uCcC&}Q>|;L%ILILmbA+QD<2WZc$tg~AhO?aGJQujgB`$M?t6bwcH@L|yZgYpb z+~YnEc*r9j^Mt27<2f&Q$tzy-hQIimx4h#Y{^dO%_{b+d^M$W`<2yh2$uIunHvxe( zfeAuTf)Sh$gd`N92}4-I5uOM{BodK{LR6v=ofyO<7O{y#T;dU*1SBL8iAh3Il98Mg zq$CxoNkdxFk)8}>Bomp*LRPYoogCyO7rDtpUhrl%y1;DMMMx zQJxA^q!N{>LRG3!of_1n7PYBEUFuPv1~jA*jcGztn$esVw4@cSX+vAu(Vh-;q!XR# zLRY%cogVb07rp62U;5FX0SsgigBik5hB2HGjARs}8N*n{F`fxbWD=8^!c?X)of*tz z7PFbdT;?&K1uSF{i&?@_ma&`_tYj6dS;Jb^v7QZVWD}d&!dAAiogM6C7rWWRUiPt{ z103WKhdIJgj&Yn5oa7XzIm21bah?lYUG8z82R!5vk9opV zp7ER)yyO+HdBb1)&0F5_5C8I>4}9bkpZUU9zVV$O{Nxw^@tZ$~KM;WlLQsMcoDhU0 z6rl-2Si%vW2t*_jk%>Z7q7j`K#3UB6i9=lC5uXGkBoT>8LQ;~EoD`%a6{$%>TGEl8 z3}hq|naM&{vXPw}F`or2 zWD$#5!cvy8oE5BO6{}gpTGp|i4Qyl+o7uuvwy~WZ>|__a*~4D;v7ZARh2uUbH6Na#aBRmm^ zNF*W?g{VX$Ix&bzEMgOfxWpqq2}npH5|f0aBqKQ~NJ%PElZLdUBRv_&NG39qg{)*F zJ2}WnE^?EHyyPQ41t>@%3R8rl6r(sLC`l}a>$Rs8+g{e$qIy0EbEM_x@xy)le3s}e^7PEw-V?7(#$R;+kg{^F3J3H9PE_Snrz3gK@2RO(f4s(Q~9OF1AILRqabB42= p<2)C*$R#dwg{xfSIybn;fX**A`zJ=L?s&j1Y!`ASi~j{afwHK5|EHYBqj+-Nk(!~ zkdjoSCJkvxM|v_4Ohz)1nJi=_8`;T0PI8f(Jme)G`6)m_3Q?FM6r~u&DM3j}QJON8 zr5xp{Kt(E1nJQGJ8r7*mO=?k_I@F~e^=Uvu8qt_0G^H8MX+cX`(V8~2r5)|*Ku0>! znJ#pt8{O$aPkPatKJ=v@{TaYO1~Hf+3}qO@8NoeG#AU83dBtnq@RoPH=K~-4#Am+nmGAhTANY}<_?ch$mEZWCKlqcs_?v(DMj%KC zMQFkhmT-h80uhNsWTFt2XhbIlF^NTN;t-d3#3um>Nkn3jkd$O3Cj}`P^DMC?-QJfN#q!gtoLs`mEo(fc?5|yb! zRjN^)8q}l~wW&j0>QSEtG^7!YX+l$)(VP~vq!q1cLtEO>o(^=R6P@WoSGv)i9`vLa zz3D?=`q7^O3}g_48NyJ8F`N;MWE7(r!&t^Ko(W835|f$2RHiYV8O&rBvzfzO<}sfI zEMyUjS;A75v78mGWEHDf!&=s{o(*hd6Pww>R<^O75O%PWUF>ELd)dc+4seh|9Oei| zImU5LaFSD;<_u>!$9XPrkxN|W3Rk(tb#8EzTioUjce%%X9`KMyJmv{cdB$^I@RC=& V<_&Lo$9q2TkxzW)3txi*{{l=6^ltzF literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test55_3.tpl b/libs/libtpl-1.5/tests/test55_3.tpl new file mode 100755 index 0000000000000000000000000000000000000000..bb209fcd20380c224dfc2e9e2faa5d0d7bb5c287 GIT binary patch literal 2017 zcmWO5LjoKK006M5ZQHhO+qP}nwr$(CZQJd7Yb%F5A%WLH0)aQYy8VCd-D8UF$2tpEy(1al@;RsIzA`*$nL?J5Ch)xV*5{uZxAujQVPXZE> zh{PlzDalAq3R04a)TALT=}1ooGLnhRWFafr$W9J&l8fBrAusvJPXP*2h{6=1D8(pF z2})9m(v+brs7?)PQj6Nup)U2PPXij#h{iObDa~k33tG~O*0iB5 z?PyO2I?{>GbfGKV=uQuM(u>~op)dXD&j1E8h`|hDD8m@e2u3oB(Trg%;~38bCNhc1 zOkpb1n9dAlGK<;FVJ`ES&jJ>*h{Y^nDa%;S3Rbd;)vRGH>sZeQHnNG$Y+)*>T;VF$xXul3a*NyC;V$>M z&jTLvh{rtPDbIM$3tsYyKlqcs_?v(Dm;d;m*Sz5^?|9D#KJtmreBmqK_|6Z0@{2$) z{|QPkf)j#}gd#Ly2unD^6M=|CA~I2kN;IMqgP6o3HgSkcJmQmpgd`#{Nk~dEl9Pgz zq#`wGNJ~1>lYxw6A~RXYN;a~SgPi0dH+jfQKJrt5f)t`KMJP%!ic^A;l%h0cC`&oY zQ-O+9qB2#eN;RregPPQ$Hg%{=J?hhdhBTrvO=wCpn$v=ow4ya_XiGcV(}9k3qBC9S zN;kUGgP!!FH+|?!Kl(F(fed0WLm0|1hBJbZjAArn7|S@uGl7XrVlq>h$~2}kgPF`? zHglNEJm#~2g)Cw*OIXS>ma~GDtYS55Sj#%rvw@9lVl!LV$~LyMgPrVRH+$I2KK65f zgB;>8M>xtcj&p*OoZ>WRILkTCbAgLo;xbpb$~CTYgPYvqHg~woJ?`^>hdkmjPk72R Kp7Vm2yy7>;S^RAP literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test56 b/libs/libtpl-1.5/tests/test56 new file mode 100755 index 0000000000000000000000000000000000000000..20e3e3227291fafa9976bbb8334c9a608706c2c2 GIT binary patch literal 128583 zcmd444SZC^^*?;??k2e*kh>593!Rb@pxa$3p12jc;4eN2-hUGOBPYSXeG>ecC&6EK68x`Ef-gS_ z{<@RkyH0{{I0^nQC&6=Az4$x+(+b3i^ncGu@IN^T{-KlL_nrh#`#Mp(TTX&6m3V)i zAGw}S0$K9em+S9AB6lnPi1!{xe;aUpl|f454ReuG;3ws0&YWu(H`LE*j?8O{%$cKL z+J!mKCMY$_7DbfiNK<`yaidZjX=KeiP1n7B8OHs4Q;2p zYJjO(+*}h;=FF*SYN~IT1KN3!MGf_=xPXOZx1_ngv1w6#q*fprZ%`Jem@YsqWpPVA z+0L0$y9{zglyF@`bB)r_2<~V$ys$|m-~$Ns4NV}W;IbEs=PjyNmNqSdv`cDbJGD(U zHOjP5aPpKnV@H>cPiM!DJ_m|${Kx<3O-@9m0!v@SKYs4K|8keRT#tGp^0fz-RjPxfyuMn))ovz^82vg^d|_C@B3|mVxh;#wto{20kwXza|6U zI|IKi1K%eDe|H8xKLfu$1FvV`H)P;bW6a`5GVpyf=r?EJGsm|x17DCq|5OG(Gr;W3 zz%!PmK6^6o^d+g!z6^X}3W+q4fgg~8KbV0Zn1Mf>f%jzK73nuPwu3V8M)ZJY#It7A zdljRtGm@2<0&6s)PiosTh>%U5GZ`ew;T8DShx(BtypTlJz9c@w&m&Azwss15EMc0k z)hXb!2-9?}M+7{KFiqB4FW|w1X{y#b0rw+J6SZ0e+>0>9w;BcPAWW0A<_h@8V!$*- zt6IRH5~c}SegS_-n5Jiy2>2bsy$O2-{2F1Jn&lSoZo)J%OA+uhgmuCPj{-6L3Boif zYoCB0Crneab_)29glR%nr+|M;n5JVrBH()o(=@F00{%H+4!yNbz&|3)A-7ru{6oSV zYO7Jes|a(5t+@iekuZnWsupk)VVaob7w~n2Pa#|aI50D?naY2h8t!;!`zm59?JvP z(+u;SEgW;h+*{h2IP+|gGup5Aotd~1vfFJM=BtMJac0YjYrxHjlR><{FK9jqzJd>! z{Bar^3Yi}y5><-Av;>@t_#|Iq>9@(GVSbYMC(@3m(Fbz}D*Q`eKkj%#bSm+V0QV+- zOQJ-I=sAIXtK(~%=TT=Rm3|a7cYPn-F{1AstezR{>Rb;>qid^M zBwgzfpA#RT*5~WQXY*1_uvx|^#sMRGINvb$FLhkAZ8LNsCf4WIbg(G7PaoP!+-5>4 z`mKkZpf}7XjIAGDXsA04bBD3(Xbb8;PFkaFcO+H+9a+Ei{JwQwgr~lom+q zeRs1_^G@G-k*@V^KpHY*zDGp5)<>2Rzdj=7>qJf;vDUX!q<8xEiS!=dL6P3?k^aqBg4Ae_`KptRcFe`j+lC86my-Ot0lX&=R zjAqU}Ke$AE-qOxw;WO8Hl@9bLnNT>Gw;b35V)iHED>lrTz7oR>`N~3I=?@`iM9$Sm zRQRg(5h34PeZ)*(qdwvuUn}b9BkmUsQttHvepK{aAMrQQUkbDjc*8tu#LthSS)+ZX zPfH1nG%Y8Dukd-<4Nv0AZ<5Kwd~oP` zYz}~mcq1lOpPh@mN~QX-(e`vz7!xYub4PN6<wNBDm&=DfK>A88sABpgg5}%wyE^qvod_&5 zwp@(C3ejD>`q^*vwueC(h&Q?dhx|?zqLf66^-UGN5`EK5-?%ju_``@1Q%cNOV8#Md z3L#6X+Q*kvm4DGZsj@ApuNemkLue@0hVEA(bE^v(V`808(__!T)4@R`3%6q~Sbqbg z4~)UbtqWmNwd+bdJ1#{Bl7(S#65J!X zg7fu&sfoYB=#t68s|ltwam$m2S5eG8^eKUB0^bkJ!Q8alPds}#nT(f3lP*2xgIv*M z-d`cN5_!gmpPIbZt0XQu0t@ejHsK9m-!E`P&29$i2gERa3L<+563odqyMGug|43iG z3(|y4m#@POp2@;Zpg_%_xg!W<2%Pj-i253_om3&J=tn7q}rE)nAc7@9zmT4e~YSQX>#Q z=XHP`r%T?y0btdj2FJ4+9Fv7V1}bwrf5GY)Popgv$xaroB`CT56*D+#ok3|RY_f1E z3aKpX#T1SmmnG1Y}5lnA6umQ>` z#W;PFI0g0*J)AVRo6g8}h(qR%4%$cJg)b#OvYb=4q$2LDEPc8(`55Mb@;FHhv)P?^ z?hx8QeavFRoT5dR!}Y}P5q`~xKP)_aD1N_hJ?U?GlFh<2E5LsoD#puTgg4f}2)CoP zkoi7BQ%Bg=;R|M>`_HxO;u8~(fimGrkzY*mpZ1Wi=pkPX;Vp-w|#cSR4%hJWPPeTYavSi_TuomABvuoio_U{+ z`=R*6VEjU9Tw_2NGBHluG}t`=YnJFe#=(e>Gum%1W>MlG?8TaB>m@$RgTT?YTfglr zAbR96;uFa<7xo|aDxeBPyHwT=l)tk49qU`L5c-O{w!7-l=Z%#f<8DLUX1yy)u(I*f zRVdaAHXOJjXo~n0G+)9H80J5?I5dp-G6p|>OPdyKH5jBA+@voNXvdK zSG(Jc_!QXB#ox7`XVD=eK3lWG$BtL~ELX7n<)$lw@k`zDN+q5P9l2ZgYjzxT>zhKp z0z|!nH6b4Wti*}w2TVU;`l5qwbNeOj3x>N4^`&6>$9go0f$QlnwYwQDCXZ3EAJKV6 zaR}=RtcI*DS)#AWgpR846?$wTG6r~;80z+*`lR&`dD?b!v8U~6{WiKY1EN=9u`lGm zD+r5-W8ryH8se-JwFeu`7?OudkW`8PR{Ui=Ey2 ziO0WYIl9)hHQ}z^`iTZ)Ut;=kg;CY+8)5gh`4Q_B)Wf`vCR7A*^$4|x@^a`@Uqw}* zLBo8BZNAT#6n!Esv%YFC%Kw`-!83YTUHXesEZn+(F7%L|C+onKex-dn^`Nhclcy3d zg$CfIy!J49IcP=bL=grJK!xvgVuk@T44Bh7K_F$|Z!T!b(ge#G^#=V#E<~flQ}!3_ zRLh^zW6M#LsegS{0o!d+%r7#uv)lTX@$*n+X=iD&`*hAbssGmy!j7%~0w^ouvy?#l zn7N;qc@T*T+8iZ^(J@di&Y z`mLs~UID-GxD#TF1t528TMs6aSedrfqvTMfQ`Ot9fWhdSDxDj?(c9(&yTK8N=d@(E zKIaaYIq_Mp;XLkyJVUS^_C|cvBa}H)Y8E)D*_l$aGoe{5>tL|4-kg5zv$TuaD@M_; za4n8q>I=q1#0)+59EvOSP2(zKhx9gXdxG(m*e$#qYHwB(#ZpjiRsvh!bA-%;#)w2! z_`Q(2k4wZ=oh*n?E5jTv;aYnrV61C~wEO9y+Za``HHc;zBVO$;u;)=Qx@ySw z;@OiYR+J_oQ%Pk1W-P6^37wrWWz+sApl>(L_pPI%RAY5+5Lh?pLJC2)&QUU`=j5A*SYsoSLP9ctw5^*s!Dh>t@~Y&x*sJq4@%rc=n#-kztI(uk8N zg66Q2NLpLbna$XjB(1+NCl+hJV-BdK#ntL&{3WfQF^82%(z=~FEKHJC8*^B3C9Ru~ zmqo#qp_yrW{O-g1QBdaMqbkM0{5Jv>a0-G{tkN2t|XU;?NVeNwYW95GNy`nJ0l`jvGep2XeU`VTVV z=P|bTN){fy%8N!2X=K&-6vR6i9*+rd4%2O>?Zt>UV@ZBfvC%cfD_V)yYl#QY*N$R< z$-?`|iJQDBZaww_P?96o_$e2M)FY~P`Mn~IUsY`Rpd(>NGd!gqVLovs(gK_<@1$Z1 zT9_=HB?XPo@EBb#HmL-nPhvr`9Sf2dm+u0(ki2aw>c+>l9nxbTLh**V$B6s=h?k7x zdfO)8;$>~g7R!2;#qnmZfykZs_<(IG{`gJqL@5AtQ_5<0*ZKj-rh44hjdTb{pY^*kv`A7+d!{xG~8C8EIZ% zRrO8oX^Oi~P0#1F-8g4UyAey>$WnVDymYTv;O>Lj*yC)(XJ9?rjP>Y6*w1Xme&%_@ zya@XlalRkFNHfZxjqEVYr=&iOushyg=tf;4HX-qxWB|G-`4VuVLr=s^^be( zfnMu4Z`>*diQXv=bC?SgtFfI`bUWA>`!UOCmG-4M@n;>{n}c2@<{ z*`8r|pI}ET4DZ`S4H(hr5SF!y^6NeNZHyCiW|zcq($w}|%cibM_Ditnela~BMtm|H zLxi^o=hYBYL#@hIOtGww3HLErRCG$c3=A z;>QrMp{r$O?Nh&s9(F7pXM_g=uZ2c*rpM?CkGiwHLQNtZ9~t`PSNg`S#@#`+Gh}w! z`*6I`rt9+H`qzX=eWNc$F^p~vGGeJ_@g=4(_R7!@PS>oe4L^vP8OaEbP#)GcSZb)vdXsID|92ivLsnJ zG=)zV_DA-rYcPt~PHV^quI3gRQPj8HSR~@(O|Y{Zgs_MQ?u# z5jM_1_&ad4`T$H!e2;<9h>uzYRN^0~))NSmFLnQ^R(#UuD;e?7{0s+In}u?h`${?t zEamjr7Ccvj$E97TPZ~P>0Iy%Fa{!n9bXB{KChwHGJJ!jCWWLIFG! zC+o>rx?F)LbQ`eK>w27odRrY@@*nDQ=xsOJIhWqH4mopIY3EkUdFTn(XU0R3UR^n4 zYec(Thn{dma%%|#azx)zBhDQ;XasWeIH!c7VX>zqu6vg{X4}|XV9nZz^WVu{eM_ky zdxzMm*tP`CSB$O-U!!1+3^jo+RruyI124sVHS zQ(F?b5@M>%75+e1HWjMJ4rjyfE%#NZdMpbZsaL}YtI;Q>Z`s%D%Gy{28` zL6MV%_f^aOOobIWgnd##u%7CVmf=9_@m{hWPT+P7FOCNB_~@fh`(n82%Q005HkE|T z#QSsUC#E`c!HtoyQWZ_^6BJ9eXf=*3_ zTbm89@wy((Iq(PF?SlyDemYKnpuEQjE=xEDmeL&`otu}T&=cF!Pvn6`CE^M_1JH6F`HVC zF2d6SJJ*6eqn*1>j~RAu3D)k=73hL`OvUIRH%pJ5V&`ff<5bftLwKZxzm&Wc=rQaI zyW|TXv9vM$QaL6&^w?CetUynS@#lwr|E-}R_NQzuH59_q%zQoeN7R&7_7@18vN9t) z)90s^R~X@uV&OA!q_Df7e(Cc89JgfJ+)JoPo7+Mu7@1MekEk3?d~|Vor@RzCl#mk3!6Gd z#a-E$#flz%9c%PsO-xKQ&bnmbgj93v!B7Y;8ZLt72!Pe$8#Q0ZOg&rCob^ zWVb>+vVQ~PN=Zf~{ij~ggB|ONcm}G+K0+rrp?fBFqnO+&;tu-IWMRGCG#06P>~F9I z5hg-r3;I(j3{*Tm;L?yzV}s2UCu6fPsj=`g7vk?atQ&1&xfLIj>JOE38Q9pmIX+$j zwjH^Qm1#$H3%XEcereBWF_XK$w=P=e8%Yx$iBsJ-aIO+)y*XK|$95qL+g(WURG16M z7OJS(eP)loeL{Ag#Z-WYWXsXw`imYe1P>^@Tmy)#LW~T~JM3|aHQMzA)0AWBeun2A zwgty71p!97taLX;8WG1~T!pVpzw-&4?bQhn(Wb#0RhfxU`~ALFGz&`cTq^|cJ)4iM zmsOeDE6tay%zZ&~Z_s?Pdt&W6b7#;wjovL_4vZJKeY7GFh<=k>VZOWcnjn^FQ_PX; zaWYn+Z~OxLOchNlMS9zXXebaL2$OE=fPfmjs}?k`(8yqAM=4g*JZAs6W7z_1aLsp< zg{v>ZN)&uU=&pOoZ{Q~dNymB+@X=o_%0*fC4^#Vq_!Pm`FlT613|T_TLyTLbFM>-kb}thnzL9$Dd|Fg|r5|H& z<%uA3jF8sQp81J30_K~Q=BL5%_7IpX3z=UVTlYCah+DHcw6lS%3$`!BQy^R?fWj*< z&~E95P79`{GUEZv|DS02_&F@*9*|!40BNyIGZz$yHAYv)BRvahu?_F zBUUJeiQPOdd>E#YcB-**guH(@`9lcgbF0eVZ&_@eiVlcz35H$1_;@>DpsVhHz7a>? z_+ElN-=Sn-C?y6AMUU-3wP3ivPh6Oi3l-2}F^TWXx!q1&^(qfM7GTp^{<$9eGrMZ9 zL|X0)#6c1_+-x)Yp=wt&!Uy$@{lyMX?AE7iR-M=q#Hb#{2*XG!%$M0)Jh`6^1~*{4 z!u+fa z=nby%SVDdl&{w*!Y~SH7KfKfmsJjB?FX=JfW2p+ieNnsXS8`t#eg;qX;%nEoq7fKN zw9^H`l?lrUO7N3siZ{a=#fH`zo|+$i_pwfxp-i)$6I0%g&gImD$H{a*TDy+x2QD70VZzfWA}*PW-PW}>On!(DiZ#RLC;Q!2NrS;k)*AJxkQ073))IBaL~Dn9ET&jd_Zg4NwPrP;GUi%+4*! za5G4!GOffM) zAQ=|`CtQwI1I6N5ihcFwo5@6r-MGDDvUXEiaBT!r#d;glvUIoQ6_E<|`2WRyK-`hj zAb`fMBR%0Qz$f|SPTm2;iOP4*Q|wc^=z)d2`{x&1UM?}Jd1Y}n52E9E#*QHW5+-{^ zd}zS@0>?&rTOq(IL|U(XZd|x7eMt90z>A0lU7hH>xVkR2-#_VjF>j^e5EQ~)$%V%}U=jXH9?xMCSG7m7T~$@%2u2qtg{scZABnHMo>3 zBXM*)RxpUy$(A>ShwOe!w41)yGX?j0P^V|zmU&LS2lsTit^B`nPQ9n)4XZ=!I$NP7 z1w)5b0`GRvb$U69934F7!BZuixP~tD+Q&p)dh8L5OUQ(#k5bb=f1g*$zU}TWqCMmxM&t0q9m-&`U>)*`VjCm1doWz9e4# zhm_MxKG*l~v2XuDPz?V9G}it5+I5MC1U2p{dQCyRur9Y#xbr~c}pI4jT&Oj_kC<bEXN z`_WDuJ3T`NFlT=#J`88JsITz!#J=T?((pbdKqN+JEbzz zg9dKFxb^720P#G8S69Xu@xKX!;A632M*LCVdXy$cgOvzIGZ1<}v5v?^&(c>=h+Ced zeP*1}bNwzYf-#d8!4!QjeLWPvPP4i(!-Zd+WM2Y$LdAi8Q0+3x;a7L+ZTlHIQVO)@ zU^@2f|NY|m>3cl&8A-DCM}<6m+I=|!F7R!KAttX6)3ig7cRf;Z*BeTYA&*Yr0ucI( zWy_bg&N1zig%^~2?P%b_D0cMMNtVug8R>xV-t)FZo&;OXedK>M^L*DK~HxKhzRvrskE#5#SGrf(X!M(2KT z4F)fvhRR=Qv4ZMbJbnw{b|2?uY(HEv6x~QgtU63wJSQLSm1B3KuX>v#!bL2ZAnX{AaOofP z*pDGiMSBxecogeWtZ@=Uo=PSs?{JO7^uS}9Di!!^>^BE(dlmh}RD@H42QQ)PS!T3j zZ3ZX1%=#(zJ1M#l3x0qCsKS~gjt?q0V%@(h?d;hvgu?cYvBLb?8V7Z4hD1uYwHbq} zbib2Wyo0e8(eu%B5IvKaI~h-NU$9JUr8Z;IDcyhR*azF@4*G|n6#gz*co(y2Z&6BO zI76lThnpD%x}%#BA{6Te%*V|PYE}btVl!96oH)n0iaD`Mp3WQ(=&WhT9XHQkSySy4 zw|>jaSGIm=-}$Xp{cDyv(hlH7>j)$e&YDv=y}bBpJO!p#!I)UnQ(H#%=jUr zc@(?GN9W`2K;ds#CEc;xQ6;)x?U*e!um+_FQT`r^38276p<_2{i}T%M>U-Jb8d>>b z7BO5T3uhlg^(hWiIzAE2PeTFUT}k^w>kF_DreS>o51z3f95U=~H6N_M}F^7MKMH=(|UFlBMQ?dg{Dam@|))g#k!79!*r2{~}@71m+P zQjm%VLLRs?5k!T|EeATjm1-QClF8~&==ovac-JGYik}UhZpgOpR+g$;i@R7?0w5%X?6p)B9SSwz#Xp)8N^g;FWgZ4*x;J zY{EULJea=`zY*_xC9$uKk2TE0B7TIi@@dr450j6%3l%KyYIzIqMWDf!+iiV{_ZZ4D zLbbGSK2G2zC=uVj#H>sk6_#=GwJ0yTAoc*bKJ+=nK^<%w&aN=Sa*G!!1Q*8NkHH{W zsDPd{xXogio=5>*jDWc(?1CnF9C|^P-u3~k9_M|*_~l-_OXzUn+|X<72C~P0fJbC9 zD~pFv*rLGUR5J7;YOg63as|z4*y=5YU^Z{V1X1c7T|SJm+gl3OI9KwDDT}u7D8|b+ zgI&|Sl*+oCZHsXZ#INu$`h3*3du5Z@Ur4)5%}U%^M|KFSrC!5=QgEt*{zEQ4U4eGE zN@~M9hAv+OrMBRyrKyl9_B9yrW*6_{RhBp4W*6UyLyxtp__dfv<2^z34P4udw239l zcwfTY3SY4m>j%VxA$sgOOgb(s#WE2)+olq!l}`F>FJ~>;U@geE-tj7-kTOy51Y8D% z6gPL!xfr{m#QTc_TU;;aqk=0u!T3@f0q-{*u?AU zaml>T1~bQfX0Qn|jN_`NzVSTc%e`X!jBts#*QVm8S9rYr_yPCYg8Igtsk?2QC3~ze z>SKQ5v6;BeG=7ZK9$rU-_Vm~YD2<~b)*GMTW?BoU8B9Z826vur5`0qad>0IFLuXOxD{#-PNnT3gcKfy z;>iRK`MWT_KLW4RY}|km6Sc7rx(V}$bk$noFCE}yUq%(U=rXqwX+aUzmV+@pFsh`y zUW+QK6+{a?^9?bdhaGJLfwew^*Oz`G-IcS^ya;pxlPo+1F#B$;M90%qS)|&IE}}I& zOP=lNUYjnnMxl)Nsp-eWYjd|8*olt(pLz%SAb4ZTs$xgTRRCtKtAu*vWKF;K?2go+ z+)X@RqBGwI#LX=9?oRyWRdj?8f8YRlpIJN}OWcBhXE7SW_^57)3+-~}m~_9P}{G~EfL-E=mZ4w-Mu z*148K>+{mB|K;W5TTjpL=m+jd__*eKS{J>28c)&e-bSX|&E18gdTd6`y<4atG<_Cu$0Dvg4GnAC#pZB@4eg8{_?nFn7Q5cZ@q`PkKIQ#P3@UaN8D5I=F;tG}`TB z48F5Imy67WT>s*+ZOqpSG9GNKL5k57NBA5~gB7dw*ldJ?Xws?2x-eGJq#8L(EUnhp za%puvq(Lye7> z<0(EOU~s4Ug4i&-*!0&qD_yu~{%rKHqOZ*ZW;56*kyX*JHNEXrEIF|1FNq)yV&#Br zX`|luhMgT-r?>4w_7GlZQMn}>Utuo5J4GY@n|F#x?=|A*tU1dIzxDxxN3KzRRA2Q5 zEG1}Ofcvf}!4L-#k@Q$A+M!P>;mtqOE#qAHv!JsD)!$(^6F>PYH=mzo_V7b$86CUr zhp1ms{%+HAoX>jOl>o&m-?|H}h zajhTIQoKbjmVy?qr%8D*W2!kGV(P-l@puw1ck;qJ`sy#{*u%YHUf~s4b`JNx(A`jY zE=c>_j5ey&&+(H2e1}=%?+HAo-}+k&iP-ClTdM)kq-OaFQ35{PZDZeL|DM3!#G4S> zh~Er5ItA3cJiuEr998&XtYp-^rMrXXp1>9;2k&Wi>32O*+KG2#(myMJ2Zj7uf&D1X z{8<6<9-eqXjPK#`jWO{a9$pZ$-^1e@WAZ&byg!F$?;kYd(xblSbjn$d-Fra)$@UQM zcZY$gLc_QI0-4I#M`9@SSRUfAi4{Gs?9MI5u7hu;!()qJgxDEKzC;6FmLJ4?!(#Il zNUm?f7IfdS>jSzDF%DkzfH4U}AOcI=@FxC=*=_v_TzldPwltT{l_*~Mvc3-%>2UElip5XKh(WqPUG3*0cg}qowbSp<*8*w3L{$J*kYO1t zD_M9cX)|QFLa?|Qqb}Z|H!@h+uVuZ&*l4dO%oq4HSHrV&s~@ZqnzavgLeQ#QCm%io z>=`C1VHx}hfmY}!WQrXgjnb^v?1`}gY%}V0+V#ZG$=FpRP1yUBqH4qr9K|OK|0hLa z|0+TxKz`zxh5d^Mjap(drc8Rg+uV@R8i00Wn2wME>u}%~!Us$I)xZR%* zThwjol17wBX`Tm?Z=6|ml)N;|LHl`{a2g4TWc{chhPXTKd^7-vn%F=Q^t& zaEWXoJo{mV(4ma|YwD*>zL{lyF+IswZdbdvbPpqLqd)&NHMaPt-u z7T#P=C0uX^m^$t+#m{N#ZFj;!@MQqTi9_3P4g4WgIhSIpfl!`Pbn0itpVx`x2U4x|FxHvgd=j+SBg2Ip>35%U+0o=?H7 z?~B201w9zbdCf(SIB3Orrg#SgPL(?dv%=@KMp1e8KA4>m0+??_-^ZKsAK+&QuzQ6M zL&lqkJt>5Z)rlx^M2|g;OvgQP@OBiX%!0$gaS6iFVu$o4FTNyhg&%=;Yx6>2^DXd3 z3yHBd$F@hoNT~8L-r?<1_=+Pv(4onEMfY>~e4bb7n=aF0xO+1i)TK}N_@nk8sI5ne z^or-P2gKR4JGQ&!fDwM$*ovdj_Nz5Dh(p{HzRxrcB6Gcd;@@ZRE=K6%`2gk^-e)?& z?=$cyPAn~t{e1>GUOlfUZA6^{on*z-`66;^-b_7I5l+Q)X=#G@6+NK5gnN6 za{%E$$WSqh(FLc=nk{r1*2pEX*$4P)29bg^5l>pZpd!xaGTA_F6wA z@AUnHxS$urpu8a2L%AQ7t!qFm#zD$a1sLx(i9Ib|9LElEtD!!{-;>~BB*#-86j((z z9K_{_;vjzE$({HW49=R3_(A)G&@*92cwg4s!4cT{F@6DHywBVr-ZK7}ZyDn>FyeEF zQ8>OwnR5Q!VvtMkxBm@4tSDSIPc-yp^e8Q~j6L3C>t>r(4^Fn;P0h*zfc-Q^G5W6e zF^8BO4onU`_9i;fr3^#<55ugT0DAP<@qwI@GrS11yp>=2wDl=SI{qjN2BW}s;p^d) z&9^%KAq&)W!L2B;Np7a!?yR+4^uD2~nzcYj4r*^X2*gjr?{&b#&?6Po z-IdVY{ktFC0x>Tcy#smp`vv@2iKnrg(5h6tL5ky%N)1PY;`QpFbc=qh$J0MA^2lS- zEk?vJRYHUT^o#aoCb&g#_&08mrNQ>gUE=2egj?JQpHhied&L{*eC4>vx<|MfDzg%A z5kHAztKRtWob5RJtHIIV3Y6M?AAr7NOUAyR#creT5%FVVEe%c(Au)*U`2^E5-$I+*i80DvSrmdjfcnjwkoM2d{Ar=7aRgH5yL?%U@o(Ka&HR zq_%_V%T)AA)9MeA#KVEE0GDt0X|{wOOTzCNxGRh>(bxF$H8H<3?bmt>1iaqwXE@<% z;}N*!lp-JyiB(^v-FaMcCF1KN*4LR*zpl} zEP2IEXd&ItIiSf<#B+k6&Ii3N@a;3&N97EF9@>W=E(957z|Ih!x+S;`JV+xr%*Rck z5&Hus?(iKlwtnlx<8xfLn*Jc#feRhX{)t!pagjV3NcMjNXZ(1E6KV-pX(sD$G_{9Wj9QMgE1*gST0bEy}vX!b6i zw@h*n{2N*#-iBH)ervm->4sipz&~$eQ%&unW!^>gOXk%rf*4a8TIv?mp9xz0u(r1r ztRa!jJYB?}-#)fzs*u4OY4Gx=ztc5Z>YG~{8ylJ;H4D784NZ$tExd3Ze*863)6`4B zPkq-k)z5>({Iza~;AO9xYnq^zUP=Z_@x$M?44E7o8u=6A-r?b1imd~--#D+SnIZ$1 z`gQVSG$ekNTw=VaUAq9w|Fn$i1W%X!uo;NLo=miGB9`)u$*VfOA zv^3RZRLYe2SUJ9H7%laU=w+bf_#V+{>@r>tph3%7aUKmJvIxcnoOjXUdDqs^)WbCk zYMQ;3m-0PONng7lHIe4cw=H%44c>W;jovVReSW^sty14mKdP~z8H2y1#*1H&ZxTOV z?+rJ!)JMc13vP-MZm5qey0)dErP*7Qo`*2_1z}jj0&m@-#fu_rSyngF>ROti zfgWQ!hR_~rdn(y%l@pYw4FKaHhGyR4YlY0LLb*8`L=U|S=QU$|o6&n2xqwKS~H!-`K(dBOM&)e>9Zi=eqRJ zXNyGB$?88M`7az`^Iw0Gbmu_XzD&I`JsJJ+_=A#f-l;a9nv$=#S@PNc!s2ZT|jYCr%eie6dUq{|EZx z`Ls&<*Nbfa-r*-sAMx4v!!n&K)05Gk4DTLo^Eo)mPUoC?;&ihtZ~YH+C#(Pe7rZgj z?qBQKC+_EelCyKf|Fe20@bM zZY)1>>Xmr6Ob?fxnC@itACdfLPqpj0gC|ZshK*l8%}y1Wo{au@{2IyMd%0bI&lM+5 zt0jJ)q`Uh+&>zpITGA_5+59iL=EUi|t8M(3lJ2Mff&O?tXG?nJxKERW7a_&*n9?HC zFj8!xm1g{D_zU2VpUHNj)FLH5DAQRoy$&gkpOhssEkerAqLy%TZE)6g#Akj2Gm3p9 zCZ|gUxq6Co;vNtU#$WIMNhbMQ2_yd(|AYhJA-_x}X97Nelt1gZc6~Crmg)V;(8roaDsKY8<96M>^z>$>eiL?|C$tUWx|gy_q`n(sue*^o@WNd=2`gxo#)%9MMZ z>b!*PzAO1fd7?`vYG(y1d{@C#-6S+Q9_=Q6n@sWrBDUYo@mfo}SPi=@u9=;mKmD4M^`!Dop*>H_U+-|Pcbw49rckk*mv!J*vJ3MKd8H!X?U;@E zSdn)Hz617X+Vk>G(5(U8-%i$#9{Zk_-{?H`#A>t0b0(U45Bv_puO5;1w$=fwlzwa) z6z_PYSB57u@*ItsFs8{>nXqkm)XyZyw|)<RgdK zMZ&2#!&uKxu`K6&;wM%9#nEH~;kgb!zI*-+*o9d(%pu|DZikv4ehEJ*`}NqM zQYh0@f~hG!?qzdDn$pF3nW3KeK?oP0fil%{{34ga@5#2|l-wnfE?1_h_Kzm*{%nx+ zcz7iGm(uG&3D?PTS^fWblKOXTk8kLGIj)Cfn%&DUNCwFC44F=l=~S6sF4J0>E|KYK znf_F!zme%CneLG3%QAgmriWyjohRFu=@~MeAk(Qby9m)iV95OpovHe+#$f z+j6A-9Znv-yJo4oBACn5f$C1(efGN>|RsNV2pW@twVr7&ZGZD9_QdG=kzcHw?#>gMiDO z#EMs4M5-bs_ugEjSFaY3mTRDO$2B(O?p5EiSaE#cru5{V!m>GKg3_D&YjT-OhK{1* z++Nv8=h;w6?ikWYs4O=|Xue(Mhmf}cc2bLuu*f2(xYm{u`x4l>+L=Y?%K&IK_}Y{8 zZ9lY~8wWn?s1!V}FCnM8hQvi$-co`t3A*$4qFz>(1U-3IVl1+NM+AFG(4Xfdac>D4d46*4Bf;vtk64;7!P$BD5Ok|^sk)-Md8d(8 zKebkX3-joDvihrbj~ep^lGr1`NZy}VI#@jmSVz&ay#FP5np%s*S=6fL?I86~b-I98 zsd>X$?p5o++gTJ<^ZK&fr*hZjELx-H{e|VD)N_D#7OhkBoD_V5%CUA9-L2;JB7Cld z*P}k+G6`=`^E`yhCH#n*Hj2u5wSg+i&4n3dJ!or7$=#2Vtl!$o(sGXy`n|0yH->8jDr9NX zz(jCnKLuxE*^I#cD1|M6MPo|^jt2zt#^)LvrN6e+!$OBFSbSVxiC zt9h)V_NMJQigIj*@1_`LDY`lfJXBqDIpsgL^!9_h{ZTJOcih#2h;nbopL>h|S;7wW zjnpfuyAsg3=t#eX&5GK0J=?p(4*;!8sJh>x#n&ooztyPYyyKCT{hDu7)B>UVJ2tN@ z*e|_T4H(_)!ctwGmFwicTFFm;b*AHvK!0_*I-$RMnd6RW{ngp(c%|S|S!o3-b=Z|0 z&7@XKl!9E@k6)nBI;L`IR1LXfda!E9OBjl!B^3L)j(jJ9u17b=B|Bwm9TF8F~2P6cqUB*J+}!Agmr z0Q^=PpX=m5lPNw0w`CN+pDKPML#O2N(+u86C2ySF6x^Rt`BX?Q1|*TX9n#iEG+ z&L%$`E1vyiY4mGZ+E7@WzRLEh-I2$ayaW{h((GVb1zj+hrlK(a)lq(WQxHZ_*Gpn<91}sEsVI3ND4jCg+D^e~hf}9Rgj1&- zYMnCFhQTkZjr<&E_Cj{`RA#q2kiAu8{{V$#tq}yDV5(&OP+c*Bo?L}LaiW!B@NyN=W3<3u!bm|b?RHW2foNURY9UvyVnc4l z!54P4+6Z`LY5Vcrn{qf7;j3547x>N*p+E22PN+m<=+8UKfkQv~F!Uo17qUW;)`y`# z&m}>3ABO(CED3u0F!bkTOVHbgp+7H2g2jCp`tvjimh@rh&&!oySs#Y}yj~LY_hIPI z>n%Z}4?}-m9|>0XVd&4xm*DI^4E=d-^(e%56wU3!(4W^&b)naeqJ@1J`t$m$c8?nS zF!bknBpB)QCzcLYJCGps_hIPIJ561PgrUC=Lx0{-l{}n9tJFTjS?*PPfj2{cABO%s zpE_8;Yt%jr{duF*X9WE^wGTso-UO9H!O-7_p+E0j39m)(t~F-zm+~XcWR&*)M5|SsKklU`tZi0wpH~=IeTo)?ugGP?%ls z5+1H_3Oo!^d!Ivv!g92?V4%Ive^fwjZ79nwcu+tdjla6m+rLIYL$qCB)jRNG0eQ6> zSZ|6gpigt6<=&Nc3&q+{wB7q6d+16u{`+3NFR?_uGR-7Z{keer+89jE-dBx6w;V-= z#_OZKuePDt8h@sw_cb=OQ2U(iUB~Xg9F$znVE(9pP=Z5ojDg^N#)&z|!-qaM3a{e; zh3lunYlJZI^Dn*_2wjZQ)yTOyPx>m3Y?g(t6=k%Dr7YvnDh>}imS43hU33?VNF&Q1 zg^>A|FsAlXf1fH-93hC4f9Ycay@O~@)V@m2^N_71fBKn7v|r*Y|1xGdD&r}`j8Ov8 zH2z3T{>*U#a%+qq`LoIe1D*2al`Q#|_Y7UHT{uLA!n-G|YAFX9+>|K_|eq?DB zIZLB(4mO`Zn*!yanquT%`8qHfw?p|?*<-0_+z#bm%|6mTxE;#B#)jMl+z#b`-=_3v z+z#c>vD@})zb2QtWC%$#Zin*c*-(kb?NACT(_)0?+hu;pR?RvTC_l_>&Tn&|vHaTp zNNj1YwcA$;u;$BO$Z@Clc91TA(E(OD1X0}ibp|j6Tqou)wq2uAfQu$de!VR+>X0zM zVJPSvKLnrrrtc$bo5V8Ydd61dl$^&wo`?n+KRxVqIiX>C!~+SL>>Wa>H@8XyYWbg+GOO(&&dP4!Mg{)uw-^0jjYpH@?rZ{Y2o%JlBdddj> zitV6d1+|MKih8dtVX?LZ2B+RvB|283&19$Vv$>Q(`ae@-HlyBu7hB{#Cry1|3@R0b z6?KD%nNp1p+SObL>@LJ{rN2jgWf2Iq*HKB`V|PH&K4ycjvVfw|C#bKbI+vxr4FMb% zz)aNFCxE2z9@fous-#!>4+IRrh9%cYaKIww*yzCPuz?aekLY-wlRZ}oFQ%?b?Le)* z$SN4bQc+nc?9G-ZI8}CC{Zg!xpN%HfKG~|uf0=?(_Q|G{gT~u3*vzbmS8)U&5`#! z$7cIx?;!C+jzGU`^6(UrUqLn-^<0St)c)C2-@ry#P+|6SYzFcT$fja2f_{)^X%~xc z&gm?z0hI>-m?{oySkNN~3>r+HVU6t$;FLvP=oO3>*g1$;BNluEmog{1To_@sS=qK` zwtx}!J4^J03XnPWX_n~Ipk;Oil6tuCS1-?|KN(2Rrd}aL_LNgHJ5R;TwiP3!`kv^i zhd*Yg%KX<;77BaQ#Xhs0x5O}dKA}{5T|#+< zM_Fa3ODsH8FB}l7>=aczt68>767t@idZE)M+)hGt|3ceJ=V7*8=oCglO{Ez%PF zPFeyR4+v7vT&icXAh6Xl#Yy$prcmJ&rXYsD(kX^tn8j4VTXcAuGd28%JsX5Zf=>2d z8GH>!U!Ceu)oFd~k(%nDfqLGcI;T00-^J7zEEIx0Ta;elMb%!>{Q`u8 zehA@#p^$_A1R;?p9)rtu*AR6MYB&eD>^0%5WIbn2GcjCc3>t&l$crxC456JK*C*{OGu9kjpSMORBLzb~pNg*sYQ`%7g$1F}KFeEJLX8N`(XN>$u+|^bcTVN3$>ctHI6v)0q=QS#7gT~Dk4qR^b{(&4CHPSlo z*m?8m3-bL`rJ`MqQ)eKDsk4Y5hLZ$s!7z2Y^D}kUFmYIef7D@#B);Az%ys6>vulH# zwG>}Upc1eHD@SfpuCLdjidb-lmEpf&-@g{tkfQhMHlqvZ5DtR&4AGIVIsS3r`ku*t zd}DWG!wTO3Nna`2nQ2Qo-Fe4`6<8{qO2h8fL<1?t-U7RUSJ=SR0%{80pj)`dvtfg$ zU5mrBZjB`i2!=7kyS2*zZUZ<%3`na0HyuUZBGP}N(Vw{P zc%)~7+$@Hu{){}41o3ijVyF#w>QfYNc z(MPiA;~rjPhxfI$@<)gqoM*+%8i6O3@~Xs7DL*m%W8iAiqd{N(icC*WRs$U>cKekc1PX4;O_!M0ui+-Of@-9df{ahA3ohmv# zUF&zU=)F`?b-LEyWzk`~h*~YOB(9)9cDASeq%0c!ouY9A3v5YX0T~j*Rfj;ErE!~( zrOm*%*f%c%ay*ZIl0%hqrowd9UG|D1HQ~U>a7VoF6jYoV+kiZ6F@nsl zY!(f}#Px0`lik@24Dcx{CNR=mB4zTTA@$X4UW_{THsCE(ICm8?+ zN-wqqS)Mp!=qhFTHz*$t7IaX{@y#Ra(_^x5@D+-3v0bQ^pengsrj8w^eh*Y*|1PP7 zaXl*mVO+0C0LEq7)pMO;IdYU^Ijr#mNpmsU7<(X-)sakAxl(0d^?8dCw^q%nz7Zgv+u+ z6r2-7IiJhsPD!wDkj=dcZL7(F=H^|g6^G9UvMMn7d zi34rP!ZKA`vt205@bAY{2>-r^jOgF_TVT?^Phh+#@!0&Tp#pVncEvHgE@%Z-)SrfG zqW-%*^@ThRsj0JMsxHXB^B5kZkEam)?#DF}!S5h4Ql6r$0k$j~!9Wc1^Ql2DYLP|H zq>9qx@B4$)1kIAOcO?y3J%=;Axft_Q%=X!Q#5IXy1glq+bGAF#U3=@08tlIhv70Zz z^8xiSe4Pd-wARHH^#i!YGU6-7-?d_`mUAlNF`q-K?JmaOYY9)}65}>ez8$a#?>1O< z8j8jC!iFCtEOw+e92g2%Y};>hRYAOm2-A;AcDY`#!_wq-u~AtpAZ$Er@M(Z&Z=h`J z#ESBaVIUSOrFCKhbT?tFH0;u*BJ2rr;Hd%A+n(JIMxfpy7OMY5+1X-4XTxXvq|seH z*st)@DpU2>t{X6J8Af+Jg&5=r>We|{L`Dwsg^z&GMpX7prpS+phCS=4N;~g+N;b0K z3fmM&}+x*}G_A^zj6v-baa|2s?l76hHIIKK!X$T_Z8P zJ>p;Bh9-o_;o(x`ZOEk7K|^JOZII}4RHT(Lgv`u!UOdkahD1$Q$0?`Jm#sVi%3Ey8 zTxV;2ie{#^0*^O*TG<(juS{B-G+WmltztEm&9q3^?Fw-1v0FiaP47QBb`u?9A*;TE zHU= z3Nv}g{E?Y~$Xrs4Oc63KGeaNVX9Vt(Tc|Z`^1)N>#`?)d8%_aDIcTPUMw!6rG)oro zVZC~(V=pMqeHQpyP>h`~3!j4K#x_Vm1hR)EAOhLr5)gr`O9CQbBPQ_Qk+(lZ9x2Wd zG;(abIQ?g`h(TcR5PLM6WgviWD7s&kkCtUxu`=#<*^*$DUNI@>^8{h1Ec>0;Zhbwv zqwdEHKX(#JKRpYXX~>*?HU?lUG6nN-8aM#lHJY>-Q6&M&S_#3I`6PN7t;*8y(VIrpbz`e%yCz!G$a7b8R? zYXQj~oi1xmkg0mT^IQ%NWqA^0LY5Dh5nU^VEMq09Ez3*?C*pK2AZ#7g%i_CI9ItfV zp5o|7eZeuz3^}eQ$LKK}?cQ6KzBFcR|7Ez9mD*%50 zl4;{m%A)J8bAt zLOeV>L$uTlaHxn`XNst#UUT+Z2%w%RBHEA7u_IWqkn$Nq_1O8_pfUjskYAfzj%8S_^OJeZTy_uNjPj8K_nn*LQqj82>~HM5+f>- z1TY~X3rnsc8&ODN7B(Tl1e9@2P~1kjjN>jU&bWdy&WsDF<1jM{sN;x=qvJa&;xewU zUsZQK=iHoo_4WP!%l-Y5^K^A}byanBb)W6tn7gR0X?1uLf(l1{`l65g0X0Si@&iF`bff)GQ-mdObZ+m`;J*Nik<7 zk(Ruk_B;GrXqn>YlVw%si?Px+2Qo5ZHjxai+vp6@EuR7F)<9rXmavBFCR%X@>OV4v z6r_7dBXjsb*C1owVu|eW9te7hK#HGJclrg@$ml`B(>!|lF=I!HUc)AfxJ(ADSCGJ{ zMI&>#sRg~vN#bgvXiMje%pqu5r6Y6rKr3oY4J39#;vJB90s^DJYK%kb;gmLN!^j*uc$tGOPWpRd4$~~&$YhahPRSfTbOo@* zNxfPi-hvO~yQ+lGAkwg8+Q<{;4eYQ^(~9W{v>MO_17=79P9?d$4x)`G`-J5bVl{wd%(!E@(@1ors;JavVb9oWD z)HdZ)&!mO>=}|rK;TYd)Z4fw;z;k1O1+J{ zQVMz-_lOkqHtvs7(A&5_OF{3cdvD`D5GVegI_bSEPNg5~V|^`qpQ+=^y;kxTq5hX4 z^2uIOtjOmLU;mR3e&)=d>c^jhdcE!7Ep~v!#@OZ#tt|~KPZ*=8qA5<9O@he{rqpvD33`yj$&@n-sH|@ZoAT^J zDxb(kouh?Ko5QWi2d22Lh^lpTo?~-#{+Y^pJ)ds#dR|>j)p}ELuD-8(8JG2`^SRo{ zce!kFIxywobE(YN38h>`<%HYV6jPtb_e$vpbk@?ysGjbQF&A<J);C(q?kZNrrC|F>pe3W?19j7;k7g)VeS@hAGr<`h}HxakpXg>qZuOOD}r&$DhC2>A!K3Q1rBOZ9=#-Gys z57Hn$j%2U0N1iI0zd_Qp=0g^U=I1eB&3{24n;(qPn*WYUTJv`pu;y1UbTz+mjM2QC zrN3vlvvl_PL&TDOfJLz811m`LUkhsu@j&yPKc+bcO7Uq%b{YrKr}pcReGN&=UQ0wR z`@dOsP*{H-CcE{gWDid>viGp;N9~DpnyK}^Hb}DL9g!V4pJbmZtj7@#^d2fXEFum$ zRtB7IWEYSadsyH)md&wp14+{!{|f_-mHw3k*yD2vWOsA7ymVecCGGJC7_i4jF0$y8 zJWr;?-B2aRO4=(l-fH~8(COwHJ(!$~S@)))_EmvJIV^?*wM+c-J2~2hVT*FOf(pf^ zbaeFtX(i_1e#N}p*S#i!iNl1B*!BE0I*j-p>aNy$AnlCQ^6h_9e2t6j=Kb2u@fT3z>)2uY6+c)toy)&tznJ=Ks63Iwp;`>xL#fq% zOEu9Yok;^oo41G|JDz$^J%&n$FC>si;N~R+#t?Xy!9-?UN`Nog(RR*ColW382J;B4 zXHY}nT>{BhNl$syg-##t{g?D}CL1qvavZ;DiYaKGuc}Rf{5z2YEi1#63)n9Q)#UM{ z?oCAR(@5ZI0+%u9B*5;@-ogglL8W(zoca)fIZXtfB=8D>q;e6*w{HJs^fDP%^_v!; zD;=ue!?u;wE?j&M_tSEXt9tf$zLQJ0bIbJE2j9<4+9WMbpv})@(?VBr6D$4C zQ;iY&JmyU)=)1lDmI5&^H_dwA?QNmfLnS12>l3A*Tc0ikx+?exT8H16rPfKA!ow$2 ze{wam($5K(S`;od2&pYrEV)|`%h*N60xRhPspYe^WK%6?`R#OJ;3BEz-l!ojBc#Jt z@eW_%UMOw!4Rg7?L@kqc3Qrb!aIH@+4Gg_1mh@L);jTCPSgfRXq?WsWRBCw@`%Yr* z1)*_g$4JPrLLUp=D8zRH3wh9zvVT0=do5uVO6%UUcwbP)ZoLTBwR6}q|Z%X)nn)@rlYDtQ!wOlZWLoG-LL z8CqY(zgw+8$u&~-F{-ZbtzCK}p7mhx)?6nu$KubHh^p~dNR?J-bdBLN)0Vyh!TuGe;*ZQ5I!N=U zpJTW(FQU4gnMm*->C4YoHzUD+9Agsvp7t?AImdpY>u+zN9INl(nsTU>%C~V|HRa`P zRMrc^A$=L|W^&A!r(&qyl*^V=`8QrUX$6(}`!J;b4le6!>!0c?-u6mLx_klL6o;&$ z>eravl)t!GR)oX)D)t+zSvoH_rhF-dT*6$|&Xmm=vBBR`u#9<_>ps($>HDpv@;hv) zDK~KW0H!mzl&=1 zjqopZXZLVfpRRuy!$UA~9hD#B!TK_WFPV*4&-HAlDW7sFPNTbGtut~g{+#vj zP2os6+Q-JeGl^D*y;K*ZMk#)V)B{qJ_8|e1!cRAhl-7BWazbo+M);lI6hDW)3q0vE zT4(rai7olQeXR;Bn5r#tLrRdj7}{*QsC*A zajO*c!qw~A*R&-$rqR`MOq@((zMo?tFP5JiO?Wd5zvJP2e&*HRnA(gjCi>VJ{4bOL zrP03>KVRDUM5WIeiR8VD+#Y9z^(a{PXz-{9M8zA*bOwp(`DzV48A!Ls`S+g9XCgmE zn|Y=w7H~K%i``7}$951sdkYa#e?jOSa-@viOTye|nrUROiT#EeO!_zR{`D6G4iNZ) zK#HGJk72^)GKQH9_=!g571`&D%nfq1t7G$~kTNXWJSFMp&@zLNc^?6Z3ms?4XXlV; zx{NAEds^(xz2*5iw7i!gZ}=6iyrh7{>UvuHo*^N;^zz-%h^Gyb9~90v4OgFK^d)a2 zGDcWQ`=o-;J^y1W>G1(RUwuKsk{{9ITLmm!FN8ept>k_(kf)idm<}s_l$CUgP28lprtRD3({h-s@5;O+ZM8S_b3S@?PyW43qIXQaF*UhP#^QTJ4SQ}e zxl^hVGPMW7t8SL6$*6jGQ4aUd1He0=U8H>aUAT6}MeOZNCtP zZZK?c+gj%s);mp=v0?l$q3Tue6OqQxT5>L>ce!cS=h8DmG@ER5YLz1mo|0oV1(v-v z%bfby`o)WX6X|%m%4zG9sf;Tr`_lGqUm7A#9c@2CtXi;W}b8< z0hW=S*q?&-UMii*J9TR&w=9yD1yn~p=vM2{YCD1KwN#VJ4GvK$m7CALidxfW{8iFe zTgyKdVm^8L)pPqpW8u@nv^w9^ucOxX*lEVX549D0uQnEbs4Z;0##s1Y#=?p*7X_$= zDUI&tQy)6jHN}glI7UBn|8ITLxt*)|yzC==ZW`*LYJG3nlwaktz9Igxe(5D~BeV1S z5ufPO+8!=1sweLr(l7md#$~=${i%M9Wzn_NT)!K0SS$K8m9_i-A|`HQCw?9`m`+f& zBiRz|el{@sP!#vSB`wniP|FXE`~O2?b*r)0QLFQ*M!Ua?O4|LuC%_+lmvhOvIl9m! zM|*Uih1@;gnEVeh>N|?bn|S5$aq7E|^QlH8{YL7yLsDU%yCA89*tDc4SdyPpONzUm zC7sbt>elCwpKjp|&4fOD$1j_z#!Tb#>3w+ME2*rNZ=6A#^l6c!eRiMWMA6DWMNGQO zcL}8UIdzxE-oTC1ACuOc?UMIOfhR77W&fV7bP-JQTKe}=$$4%31$o3mA052z7S||t zZmy}DCrA6pK0An_dp(1C)fz5hz&C8y6Bt!0tSp;EQtFXRX-(vpeQuZD4)8$ReU3Ym z+!9apvE}qHwTk}TO;VCx6E?n%7ehQOsU==g+4$u$g?uVo$w||Vz8R)TU-kVWL$H!- zq^by2?uCHl(K6DtrpnH-lAjjRD(RapRi>X7W?AylqTnxuftG@#NkU`OpAfovbb)KH zky?KA?Jcy@CecG&{AinAPEHrozA+r(8U7rp8bYDd+w$@AqdO#4zp{~Qe;P~9zA{!{ zV_GY$t7aL`484)+s?Wwr$Ca@Z>(-8&aME#AtU2lEma9rv$8sc3znKz(zCCEl^<3tB zb4@H?_jyEDQ@-fd()M$aFB+NRw_MbhoO)vU5>(tRROah{8)Nx?`6*O1H>iFSJAbB8 zGU*fnd{gs?v)KOPz;bfx8A9ikVvMHCo`bK46iOvOYc;!9C0#esPi`ck1HPJG>#|r$ zw}OAO@{=~)-=D+!d!|<8*pL)e&jWKZiu=fGF+D(PiHIEbTj%BJmi0m8rDv^uYwH=ryL&zWf@Kd8e$j z@B73tR4Y`bTMpH4DjA%hUrQ?27pxQXD@lU&>qzsobfeV#zPulylk-<8{Onc6?zQ5Z zFN%y?c2Zc{2l6maR%!d=&0K6*MXUB2?X#~B9%qUZ18;xWhYr$P*d-($=7JO_1x& z_7N?XdEKhV8tH5qK|$SrHJ>ox9jtGp;c2E(*#3RYdB$`WSrjHx1YkL=5jK66+a6xH zQVRNt(~VM~Jbj}P)>n z#@tEZ5P{1W93-%Z!F~e6?xJ`(L=961QHvL;lzKdY^Y12bDgoyn0uu@F7m1`!BXBE& z*#u6$S0d>0f*h^(Z{%oq^gTAW*9onkLr2gSYOf>c-vs1@Hu*@AF^&XKa-{cZ_{?#< zPteglv%u_k{d^)HJ+KhpW#OzOYy02=y7ssBV8)YQRLx}Hih=kF;o3coBzd!lpXtX^~8&!Ol1+ay8H z`LU0=b6#J>8eVGTO^~BK*SV17=?iWJ#H%m3wGv42b85LaP>q)RE(5;c#=PWQz7U&U zW@HzT9d@?E-%jFPY|HK@Y8tVjk%z{LT|0?c&jG}ZcPdU@}Q zACI3y8A!iBbEw_C_qB{p(gv0rHMF?*k?ToEzPNjpRPJFN55#tG0Py=MagUS!H%q0y zxOn^uI_UN89a2mxi)o; zt_v(r-@DHlem!?c{)(*;I`dU+WAKqqPPi370d$gc$xLRLJGUXqhg!UE z5J_K3Y?j7bxbf9}bVK_O(lC!e_5rHVZLXz~zLxbV0siQGcK7@oUDzW>drzO#IpKLH z#m}Mh*vWsCJk~-W{38Fj1x8-J9PPf&6(mpR$Lon#=f~{?Qv94+?wgQ%$}^H5nOAhZ zU1Yut*>ClEqqnYp4lQ#gi{hMlBLUG>=i56L8eJ2QBIiBR=j0;Ma|iKhJx_X;Jx{e- zPA-+SoTUsncXK_BA}>tY6-L%tmbJA{8O!2@shdS?V-dVC4SbFpBtIylwvxE?T)}l* z%$3Zo|!YbEqjVQROCvD_+6*J^t5i$c#cE$A%>+}-#pti__R7Q=$ZZEH-6 zunk~RmQ?YzhTBXN{x$*nu97VsI`41mu#&2UiSz!`MuzbQ=l$fHrS=U-SJkFF`fd!V z`Vv)6om7pt&o@Xr-rYx=Z*4f9@|1oWZLBrBo_15iM-yQHXD|Jw4q2#XB5+a5_Jn`28$@V*_-nrkPpew>_bo3|3C zZYfK8l{+i3caeohr|YNS?IL>`NsPZqUY6l+w}4L1QAMCzbmC{DOjoRNy#9ivQagsm z@2Fdi$^2ZDF_bxuvP$g?^7J6{-JCY>a6B!;Bx!NKW5tT>Z%FeaE2T$%ZQH0)X8)c> zzpwQo#{l!&d`r{x#U7%r&Y=N{Khsq5t48tKUj2`kA*;;(7s>8xea61wYg#t%zdUtG z#PR@XJJX2ZOZJ|&q}d*l5l>$V%))HG2(Fuwv)^EyjI;SMFVjfdq@7)4HFHnk$9Go4Tvl!mB+cWmFS6l{`gq8mjG#h)C9K|F4EIm=rlmR4E{x@O-7H?Jso{HeS>qLU(YnE7(x{m zSJ0U+cxb;xt;PN`2Jq|I3B47`)EW$n)lL|mKm%}WID@Gk;gVucCLyfzap9!g!G?Ie zpUC6s4GgMd8SUwcV87l3`zfCF-0svcZK*gWOj|0Rb{xes8(Y@D zJeE}(8*6cZr}U?=8bpptoj_%llg5C)-O8wb?X-T(olYg065~w;-RaOFLJ9x$NEKy1 zPUK$a&{uz<*Gb$f_mbg?rw3(IM7NwcF>Q)wBkQLcwoS(3O!o4)!FrNrd5xsA?Ecgd z-S_1K>zu=ej3E8a)PS7Gwn?zv$_l0@HN zWTNUQa%XP15Dc7jkQc2^y2uY7Cpw!6cOcyr(1S#NnJt5@6YqJVheQlLXR7tkb%kER zWUV>j1P-vG-rAV_Qyfk-q`8K~;X6T6S4oN$o{Bjsmbwjfpqr*;9`UlABUpl=mwR+W zq?F;1^8(iMobT*!j~Gb*ZK7E8XQ!m3w$Sy()V7x9)Ft(cQtPU!QdeY53{IRdwyoj9 zhQ{R$W0%x7w5=Fh*U*-#e^@8AzJY#RySm1-kwWSs`T^%&6uR70)6#nS#FQ%PiGP)v z9=WFuTUx8DYibG8irTuesiuV>?S821`bL7Zr6P_nNEIMA)9+#%OiN#2OaB}eOv7TU zzA0+Clel!=-1k)9PPMYEyfmwvHrd4soE_I>y%*}*=#;d`X%xLQ|gnhyH^M2A7 zu&ZTdZ?nP-{eR#t;}E*Gz~)xAl2zmmx;#J@rc;3&;`)g^66PmB_Fnzc8seonL%fyE z;+o7wZS_l9$JRGwvvc4}VuFV?zwXlXLccs@q_{)W)=*FFAX>am&1$O}T6q)+E?rvL zKu9ZHZH9=b^poKYJcuNiM`+u?90r#9DBcc?9~8(rrv1!!10x5|caqe)i#7*F4GK&; zdhHocIQ!Z@fVr(XCr-jZ+JpGG}BPm!4N`n|Et+Yh2IF zk~)>rskU@DTR+?4w4HZ~>Q~kiQrVj~29k$3@8@5WKTn-^xRlvd;^qgOv$0pIKBF>QbYeZdarh-5pogrQ$a`lhsP6TU~pxlj$UnSw7~Bn1JeBwwHu; z^*c!T`?gGtQzn!p)zGa5?^S&dx2d4BStad#UY(yw5+~16CzfedDx8#!xmjcL)xT632II!n zoy*i15?Pg}jw@5!>1ugr6Hcd5p`59F3_Q>&cAbnH=Ysm#>eOH!xi=c_wbchCG} z{^b0bYFW4HpQ+k1*ZDYZU)`;aKCFJ%arlL?)I_b1aYz5Vi#xN_$xf|WwVmZIocT*xi3bp8Cs0dF%4$-#<0Kt}ef;Yn@uS>$9%%x&ta@*PmV>|NKea*|F70 z?&?z6yHuf*sg@p8mjnW**s651Iwen)4Ig_=cid7@LBpHFdF znseMndI&WV-k<04TGuAG(qhoL2q`~T0l9SX;KlXT-{FS0w%hWaPdFp$+bL}kk z-kMBxW1viZuqH+QDnQYmNw6%7ews5+y|t!HT|1B>&sk3pG8jOO0?c$%a|v<3Jo|kwDxQ{{JffYuTjAGgbCMbsi1nOKY~OM@hnqYiOE1 zN)ldJQ=6(mzpd)8{qocUZF%>r#xnKiHBKV6w$&2>N5_=2Oc$SBvz3ooy6|Mcgv%e- zbaJ_e|4pS9WlmC;dUj1&n|dX1PzOQ4$)?HxXF&Sq5B1PWCvWJaGsn%Eo393TPHnp{ zZC|-s*&R~<3DmB3HtsBENuTADM|Z2?EIaTS|I6op)h~ti{d4iy&{*}Gj@tD*9#q43 zsiSIN;1)aipDNk)Sw79rh2-iJC~s_6e;Syle%qW^?%YIKWLJ;v!3*~I@OaMWo=y)QfGA5ao`1thLo3fl`ky1OdS=NZmY)3 zz{!Kv3wEoD-{mBQdepDmoxSSh!>X%evs!D@$aQt(QTs0SH3{3$khQ z&QcpYGSz=sWolDLS-m=G>OH{;N#-p*=G0Y~%5d+e!aD z_O92Q9i{os(W)dc+I}j3Y}QomqPSY-)dLl$M`|*cFX4ad`Cqwut-Uj3KF&sUW5-@n z#HlS+H)(a%d!+3x9hs!}+g4syoil#^TxT53uROJn^u34l)dQEOS~9a$zf83(kN%g_ zAgbrB){Q-+{%-ZLrN=GKNsOb}a&U*bt$n+Cn|*Rydy4kS>+}n3ceQ7BseN`HFLr?l zwe?cQ7TI#GgUul5H$z{PNd&$iwW$Tbp_pCBgY(~IljEp$kLM`ZePB$c*Z;($?6}Lb5O18 zaP%0)(F%X0vpp2r@fdfl`fiWg6-NS`&03SrIA@rq=N?qE15@l7Gu2<(JDo4O)PrQ= z-`dOA+Plff{JN?6i|4J)+NhhEFmWDmRys+g8>h^xQ!D6q;`VLK&8PX+-^pCtlmEp2 zDKqPw{EemgH6QF>KV!XMKhhzg8c$AEs@~VfBJVf+hwEY;_@l zO&t^s!vYhD-^tYNc3ZSr8RnR7_R_R`-E#8OW$k;_*Yp*Jm$hf=!0X$&VrtJ5Y3f7U z$(uZ1H+;KY4~tE+&S7Z$TYsW5ikiuS5|7>QP8bTFs zbEk*a&{X~%y>`2=eY@WB9n)3HJHAb^v^^T+oTZ-VIQT)iO7Hwa&7=%`ypzdW3McK= zmh05~Ots58xI5QLs#AZ9%~SWU+D^yL4Qf^9gbSUX+^h@LmQ_y5zWY*NbIwqyt?F{x z!{k$FW#+3D+tuiUYQ8h*vCp$q8!fLVIIX!|PWDt9#uO(nw0mm4ll1ECS!dB+!x=oQ z+!^eI)D0aJ%%6~R>+(y-&B*Uk{cBaD)0s6^4c^?Nrj@Delza-${4Q>suky;;N>$d@ zP^l{18aR0fJ0Ng!f_gEQynpv9dgoQUs0+a_5Z`=sx?Io=%jV+7Y`LVD?Yn`&RkT}E_GyP{(0)c6g8xq7Y4I1+1umR=~OPu zl&;aMf}ZC8;f~MYe>!cgU^IsRtyleMS1^ONr+1Q_J6XhU``^)9)*>oVd<7_4vwN&V2QJoY~`i*{;LQCSU8+ zs*{WwkfKi8J8#CKX*6W2pjHj1h^Wg`!)m*n6u)6Prj2yX>lv1@mH+8ansfP z9kuFjlpyc#Xr(;f9i!BTYqmQ(Xg=H&DBD+>wY&7?P-#PH`TZ&m##dhzKe76re@VusT*hm zyfD+@oMg+2p)(Iluy;@fXQ!=;b9ap2tu#rhHLi_Tjm3fFp`oc+At$MPotD3;;~*a$ zJqk_+&xlrYmuZC|mW|t-GBpn%iYGO#_9t_QZE_d8t!tXq%X&USF9v zU0tNzuClqowY*brIp_@i_Ih*@(4AEiF%)4f|=zv7_!s88lYYH6k# zk}@N$POY=Mzfj-M>YxtL+|MsG`y(ffx(jfhfn5G~AOCB)o;CoPYJ*MtxecUc*L6?Q z%5lNDSu?vH{MFPf_3`o)bsdGkN6YinwNBo$E#%FSPHXwh67}rzynOYflSj#zH>T@D zJM?O!ifNMcr)~8aJ)f5o_g|OO41CbZTc<9dO-FuizP36}Z>{2Xy!YAEuJ@?PLC35h zhO91K;grRd#oe#I>7#R3+~zoy;cV?H)sux5INHW^%KqvBwnNXPS&Yu*f6i1z`ESsU zsahrTChf zs)m)R#pJH1Cgy&& z$!b+ytBy;NGx&e4amC&c=)CcA=VUsC&n}^}_wEPkUR4`tNut#`e`b&Rz&^P9GfIjL zn-zJeXG=@h3u@%%-JiYJMQ180Dt*^R=lv{o)K=BJ*?G;J$e&q6Q-{=R{a!uU?(8Dv z+Cr*&*KTzLojp03_p4Jj?+($$fe9h?%Z^U<)GBB5ooYo2{bdFfCAdN-iHFZ@sp8bC zJT)kDr*n)ts#6W@-spTrvDvB4JX{}Abi&pz^Al<__3ZrIa+Q2|%i8>&-PgXL>h?O9 z5?h{1IIQ-s*_-dQsdwydb!&Ux8|uZlGBuG-K4#Df)JQq8pP#2*zxZGaole9YEKMDo zMdx#Lm0&7g;W)2V9STtJ+_NUnd7*2E8l0DvKXq(={#2T+U8Sn#pfifXBsaSxo6Z89 z^6~j<GJ<&8IWEEVRpV$*L@m&-u#e zqS{{d`-`dPmd^4^^d^#L%{wu)@#tJhP$7Fb17xX!(URc<@Kn^d+Bs-CJj))(L3MV>u4>=RBu^j`)Oa{ zr09zhH`(q*i4WR4FKrn&b4u1S^|C5cZ>}ac_S{eWt{;Cz+x1eGXsd!UQms}s=P5dC zZtmQog+3k_j0>D}bZNON(^=xZIK5d4#J$Hl>SU=? z3umVQ=eL0RwY{Bo?+4Wz_V(QJwu?0FAMJX-m%#PdyRat)5#&5%oANX&Jkm5Y6ksQ?nk>8BQG;IN4T@cQ^;>G}X{s@t*2k2YV>-kX{ffEDw}I`-I7XrGk_If>0A?}pN$JvH7;pe+Mp#?w=He5 zf{jb6S?iV>l1I!-E1NH@Y1UUm8|Z&C|I`)Jmp9k9))+HdSa)qiVlOR&O^v3*mda%{ z#-8AkM$$T1%ethq(8e~h1{b^8tlH+98mpy#RSjRR4eN;&=K8hU5Q!FVGWh?6{QEQ@KA<%vjc9RV}VxQcXUxT;*w8$YLH9 z?d{;Q*2+aoYFw`{m^eXt)}yJ%iuKTzLe(XWmE>d^sOoX%kZum+&0&H$oNkd#Z7ns` z=@wmyUS=(>Yzdmn*)m!*&TUP`eZ){@E!9Ee4uS5wr8QVZ7qyKo*3z~Hww;KJmR!ib zG?3gyB7-eVA?=$R8(Xc)rluwJH7&u`M((t&%ET5ALXfUm6L(#GHSsQ5)Ud(}<6uM0 za!UsQ3tq|{2PvxP;(2`oi)m?UusFz?DqC8u#wK#D9@(X&Bzd+)ms)C?gN^i@9o2A1 zF+*Kt>tdoVtyyZ-)>p64w5G> zomI)yrplnvkjAy4zI7#AX&g!&(sg_q6~1+&XIk z2&uYoQDZ}mRl9`Q*&Xk%7eAkslGqK zGp@3=zOlipYw{q+)>2Axq-1RqCJW`c>UuW^8qLVdO*K`m!6iC1k%u_$g3IfxXvf>f%g=gB(S)F`D%1EM&+E!`EnMGS z(&z%3Ry8ZCYFb)?jTgeY1{x$?Th+A8S|J*fxq5bTXF4`0pqtuSbsD$YD0Int656_& z1I;2Q1jUc!96i~B^bPGE<}3sHc&nCgk`aXhm+nE4w3b!c9PX3mNQ-4gfs9^OvxNBS z8ycC3eYa>)Yi0csvY?U@38i>$vbeF4b8h7lT8wydc=1979*_E#upy!JPKlE;RujJ& z%I)1C#f;Q0)N_;dHnY^KbK{2$q0nn=){R*RDYDGsq-!XgsPu&Ah^eJWYM_Cqb%V2R znzgK@p^0w7wQ>a0TNRDVYMN`8G%gQP9;LsUN-cxK-RMS(an&NaqwBd?QcUd%?L{^~ zr&cpU9IbSN_d*IENuF)Z+_g#PRxLXZIjwR9M?ymtt*~@#vX)a|65`}#QED|QL8o1w z`1%HA3r!NMN~b>VSZD28@Eei4^GMT<* z)p#>KmU_vKQuBqJnweMJ)6m$kh*xta8&0cMC;o=ECEOGD%K5KEQHlxbMZ?qE^HnXon{^^*RyKz@L;HtaYAQH<$*pWs z(@GwHPM91rdX?oVKR%tD%U$sDvdly%PdZJj;9- zW<K@|%N^iHJX$>PqaG~*c)LeS z1b%FQ+*P-h@3BzWE=1}i5qO73O8|b#qs0U7^l0?tVeb!&_>CxHTXO-?EXJZQ`VRGO zX1Ufs<2Eb?3~yK*(eNW_@TuFd0PrYL)V7KMhq$D~VAMkRI77x7Aqa^@e?9mc|J3QKG;I$qt z4fslrmH|9pKXAf7nzMZE?=6%ngi0RC01kSzG~h~)HX69fqa^~@c(erII*%3)%)b!9 zA07$dCVD!CKSo1?z5np(?P42^51`kOf9TU|Vo+qmVl;#$6ySi1MKK=O;t)#cA<9gM z6kiDOXcc4euYvy0dd-Q_kbXJT-*AXbs$=D7TLpl{qP=aEydW@>o{i!UkpT0BM0(M$ znxb@x#|XH=B^3Z(>yk=75ePG>2h)}JKTlL#=&D)**x-`N0;1~iuJ#q42!poEs84fS zEyUQsP}^GQH;_m$1raC0pv)DLTR7jin4a0?4=oYf z=&Qs`!I2{~0$&x*XxO~}=;1o)f$|dIw=QV`Apcecf6Tgp5;};MUPQ(^S5`6LyDq5+ z5CTp1Lg^Ukl=cLGDPejPhfq4lV+35-ixH(}j}Z_yn68bL-v7;_D-^Zqd0ml#hD7rC z4MMA}uB8Ql{Jo<5iIQ~qcMtfpQI0&6!2AW({2^LA@J${q0r;05EfM$@k2V_kR*#kj z{40-^0X$bWN4zJpP$&^1DU$(Q>e14G%RSm?;Q1ac5qP0TO8^dfw0Pjf9?bzBC>tWJ zpz)FSA0GX!SY}(rfL=TL1zWF$L3arMMCp*?8*r*inwu#QrtxYlBuI}kF`g9J=eU9v zMz)H`_0L7LDv4|rv5fsbqE!)E@tb)3p}7TksgRV_vLb}SFFiiME#Z79cor8K!QTH1 zh5rgyR7Cp!qg4ILWubQsdw;M^Kgng8!@mf_AFpqEi?{bDvQ>Gv;^SeJz660 z2_9`UaI!~B13uZKWdQT(SzY`Dd1-4+ofkqn1BfK@?sWA}a{|hDS>Se$%6k27b$Ni!XExH zb7N1*-2xwRNriyBTvEwCf$zGcLO?i#Gy`1V`eqK`A6!z&a{~Y7k_rL)OAwH(;Q~)~ zNrix(pCdAOq@T;+XE;~U*-!@xaIbBZ0m2B)hXRI}_yD1W<}>c}{#VO5qaR}G?ugPu zcSjU)-4P2cf15gg!o+QfCT>f|GI45{c3UFE9TIT}D$duyW4&mZBoF~-TZM@-{y{l% z%PPTZ+}J2axP0o7VCRjZAh-Or;HTV3C_p6qJ&f&L!QZ=V#gU;9u_%SaNH6@05dIid zTFjvq{6!?=YVUu%2*Mz+=D>pm!bTPtqY$tr zgn$t!q#5ADZU+khkxYmS5FteR10tG;3-EJK79dg%aRGW^5piiW$`s!gZBA~BHpS^X zG<=^7i83tgbViSe!cs~kjJKy(#3hs&5=96h+nN(O8W9`6$W{fBts>^w719@f6S~-$MfH$~3F0+82a@pnrLP1(SHg2 zL*P%qTBg4nf$<40+gw2Cuf;J>_-BsrpYO^_3jsH~v~eNeRW2>k8KqJOo+x992<9IN z=MV4VfhTyhc;Ja1Ede;gqa^}Q_GqJlr+Bn9;B1eU0es~^qYG`4yKNM%5+ZMsfv@&x zX~5kcZ8Y#kkCq60okvRmzTTt718?zY4lw^p27k1ID9jTgD+oN_qon~a^k}1jgB~pr zxYDB~09Sdmc;Lkz%>lksXj(xO?(rBifbaEaX~0`O+GyYhJX#{~HjkD7%-;deA96xG z@Z%oM0Umgy;nNBl=>11bULdhSa~SXqkwsHyZ3hbP36b~!J^94vNj3=b>sE{(x%|cJ{Gkoo28p5@ax4zb18i1@fjK3e`rtN=%GKH z?19luz#11qR}jT~z|XrwGA;!CwM$D20mF?f&(px51nK`|SJi?%5mD|ANWlhyJswHP z*gJCkiL7);Jjl9#D|nRK-vXHUibn#3rQ8x~VYbnZ(y8H( z$-cy$VI_b!3rShaR0svkL?Xt7P(X0eTm+=AuhAbm{Q$(2qFo=#&z1%T+7+5E$a5gF<_wh$2RC*>VCr9I^F0shV%0OCUdUZ)X; zV-b2<9$bsy(?o&u`fe;zL9ejVB;19+a z#)W|QxU|Uq>_buqo+vBFWYHJ;_p=WF`2^7kF@OXYUI#D1lJGizx(l!Ko7+#EG)#_s zjsiT=rKN>{&v0quLcq{3+WC!NJ_X_k5s@NC@(N(OE4|$UhIDG_S3X`=k>rtS_oMv1Rn5!oO|O1{q1r1CPt}@BPP!%oc$> zd*%p+3QU6zkA(37LmA%00XIsQ+!h#`F(0t!t;o#~bo&2N55J38U(Y)RohG*AgxORp zc(oj9f9G#@P+W!Pv?Tj`i?Z{WAp+;Pf+KGE!FP~GdxH4Te}o?n)kMEa{7t<48R^BS z13b#3#RH$@(Gq}1d$dI0Q#{&e;8Q(X8gRNt%K&~wXmqBw$3kI$7$fj&9xV;{4UaY& z_)U+N2>g~uO8|b`qs0S%;L#l5?*|#DX$1}R{==hZNJF}n4v2QqpP)d)6t`jFbb&CK zras_1E>{8Ie_T@0F{0rlIZ{KwOqWyuSnraGItAY4k?s-rzDN2*APge$o&yYm>N8!X ziUD6166IzKc#q3g0Em%iHei@a+y8AHC_oEl^nVtKTnMH4s@plIAVPpcs@0_K3S+E$0q zQCN-w#Kef|NpuS3*^`ikhS9uxk!Xb6809X1Bum6u30Pnfc^44Y(bYu1qjpN)2>vJ| z3ziREUq);^z!H|i{T*3@4JCjhZN!0NJX$<(oJUIlrY{W9A4031U zqZKqT?7vuavK(o20dH_g3jiU?Jbn@;#XxD0;5IAmmzip+{d;;H$r$C@1A3xpO&JJh(iWakYje4E4Kp|Sg0e@OIc;iYDKx;35p?R;*!=lSea%2U55Ij(niZTx|k_bT3=}c)Alp~Rv z1zzEi0J~jM0pMLOsRUZR5Cc3x5#7HMA*c|7l0*<)){2MyxvonJ0U?~({A%tO z>7Gu-k&=r2l9bhIN36wgB_<>J2@t{eznGW&E#>@y2x=M=LLp4v>WFzB$M3f!$3*DI zzp%-layio713QF5n-HUf4cZ|NqRarWKrb>K5Y9JRIT2c|k&e56Tmi6P>PFeYfMt^_ zrN|iT{YP>_BBEW&`jfosUI@Hl(-#oU=@M+@mJRK|6m3(nSb`QjQO*-0S&Dn9M}

    ;O#=9T+%0m!i!;<%|4y|0pPQ}VW?=t=G>fyEtY+)@5XzqJ5i2Vc z^;qV-E>hqZ+LiguJ0L9Y$dR_=4)8xcT0HRk9xVZQ(=kRWpDzGk@6i%~Z}VvJz;}Bz z2RMm;7=%77PlK?3(08D;qd^3ONXkxtzxKEQZx@o894P%^sOf{+0>0pq<^q1|k`@4d z;gaS8Lj5RN@_p(2Ggq&YD@DMquAq`Ib2a2&EaT5?w^b4JKID-Azja9^fHkh{q6-9W z@<@PT8UVrggFuS<8l{X~B&ML5$S>X9%S#KKd|=SemQ=D=0Vs(S1;Ds(}u3zus$X0%qqeYFRA6Ew+LYUEhF+OC; zynx#b(I-7kn9{vTTp6t;^15fd2X~1WDv<%>nh8ZR4{Q8iM z!pB173jn~Mc(gR&Pd(ab;Lki-BJdX;EdlsH9xWc&8g7)~Ob7hN=r9F+4z=LX*J=tc7i@GBv4UMdcu)Of6sN{oPy3&}8|v@_9V1T0JfDF`@j zBuGVob6rvp@GkKNbqe^LkW8m2!Tc!c0Z#jsI|6B;Q$_PiInvetC)-~=K~zdKM@<|i zh3s(Rr((}>qOs;YPB#6Wa^y5I_+%sMG&wSDw&0iLs2jtMSKQ$zg-l!T|If7K;r5rr ztbrp;W6n+|h;?|9fN4i3n)*?4Wc7f<41TzMrZ7~vjN?KW$$D`H3(Pvv2wWgXrhPAX zpzD`$p`Yuke~6D_#4Rk(^x*yfnO@n`-Xz|*?>N(#9KWYMin)8*FHbZaJLO2b6+l?6 z8(%A?BOZtk!3*uC;mqYwijA^+M~tb zWMM!oYLN&?I9(GH#PgHAz}(Y5PYM@>6WgVLiK?3;o-sc)(Ky%p|1(GM@%F#_;+p(D zN`@#~j?}^9?HDA4ChC0k~l-$k*8j1kLDJHlp9UfTo;OWNSSEPTi|mZ zz5N0|h6U9t?U>F8F0G0`1ybXmfXGY41&HiKT!2Va#07|SMO=W$T*MU_j0^p#jJPb{=RJAWo zq{#$VX1iOUg@7wvQW@Ybxg$(hkn9i&Ukj0>0b&R=pWm&T==Y)~`kkhUejjO~-zA#p z^NG7@#XR7QifBh@(?mJY?#TL#T??HXA-J=}p_&g7g>Yhl2r0x%99kx(J!Y=9wccg=Wm_(%O2W}$908>-IdEVyngLZ6~zLz9TeAq9+Tq40@ zSW6@rjNv5`W(!g-k^BjlNRhK87&$e9k@Fz1-H@P~gWi8N!Bk#(YLbOnrsr9U>d z{=g+^{$Pyqz)6RU*0t`a6#!!NVy%wRamg7dB02Wu!Hi4hDv-j)c~?7jf;YRFvj7m& zTqI-oy~)|Ls~w|GcmJg{HWDKMWo>x&kxIdZ)_eXee zgse4V+=YmIj{+7Xy6A|BjaZLz9Ww0%6Ot3}t>x#3h?7O)Bc!_LR=j+oxVeG35X7H}qw zb&g2bvNXAKGU(6p#D#?%7cq#mThzfN3?fCIaz@*-`28?O^c*Kg@&h39Gi?GQRj-It zy&_Weib&Nfp!y!qqkx_@6_M6dAlV=xMA@A9R~s6_SK9reG|}&eC@l{}Yk44Ir2Q@V z*0R6LXt$gF?V=B%U(ZKnoZfNAE8?jDuldaYtxyRYc_c&XfI685NquZ5e@P;(( zL$@o(pEQ0{2n2LG#JZ@@MbZB ze8-ysfS&3Vk*Zfjs$St&-M>51!R{9obp}Lfd7wQ?%g7lJrRAPzE%!vs9e>N{Bj&d; zRW9dU;9k~?xNmosRLzj%Nk4s`zlqPCc?y94d}(*`Pq(Az1Ee7uR7t})nsiNcs~=@g z*NANpboE#wrt}9QwdZ)_3-S~0n_ve)B<%OGQ6&=2P-nS2rHEkvT4etqM+$a8ue*xK z?kdooJMh3Q zrx+vX5rG3X3avuax9WXHLfD1EL#Kj(Xl5Sq@wKzoN`uZY;lS%WT0HQj9xVZQgGWmQ zzS5(O2ENLpr2+SNv<%>hV_fUE*eFaEB0nGjJjJ7>0cU!&(ZJarEfF}!qa^@O^JwwF zGd!9Dd>|!E!5{PJAH^~n3c#Tvi>^Tco+TtRIw<}1G$WN50pD~EC$@tOCn0!UB-og z!^7NH96|}BK=*3^;Zf7IKlH8=&-HcVtSC}e(IV+=vpb9tkF(W^cP@0j6a;+8C6$~a zhQL)(F5?7+1x})8V-Q79Bg*44AB!F7t{n^KNVjEf_XU6$Wm+&IH43g04c59|FM!t( z_~c)}BVC^q0K$VL9;(mrxByFCQpD!7uk<|B)u8w};oj}F0^B1cy1Et*{JPNM_%cph za=d@s{n1YbMS8-u(KBeFUl3*`0*J3>0S|NsqX5twpCZgjgbB9+7*^1B0q}I!i$zleJ`&av7-OugzCVOez$jD50iNl)J1qo^Vb*O?z|4zwfe(hl z6xyyqU2kqgY}blJZKM@4vO!3{kR#0~^zTiVh+Do#2{!_aLMH(ch7e*JurHkC3Z54W z+hyfKLjLI$3_-vtX>JH{;JM;wu3*THSfgmo0K{0C9#BF`{QqUS`m?wM8I~dlmSXUU z^r1vI27*W!|MT1tEy8#sHxd_&f6(KCnci$I!kE75W{rr%og|s_6n71s16bmc3jQur zImw-v5gXWDVlYORLK+5_N^51c$AnN=;AV#k!1{1L6t4340B;HBLt(4O2e>1g4+YQr z74SZ$9;poPd-JIRuEu;OE-&&8a>P@f$BJK-zCU%pTQ^mkaC>AKRDt# zSNPlq1;R|4g8o*}65~rZBLEA<0DdVjQu9K;=F#3AY!U^aTeP%?$$%K4H<^AlN!0YG z-0(VtG*Vl59nu_PJ-p8E0e}BAl>Tms~0}s*SeFm z01!4&L%%5xNH>4-x&!pOD~ar`1lAqzbq6@wC6z!aPlJd>#P7@)tKY+R#L8)?=ybaD zV5t614ApNb=G{Bemd|E^4|=qC;D36w1mF)mS|aejJlbgBe|xkv;Lki-2Jp4xjFxn| zy(NIcbwcD5PT)-*Ee-evk2V_kCXbc~{7a9P0DP-QiwEA~(H!9QGOe_NKjzViX{Ls9 z1>k0pWmZm<{wP#l*9CssixH(E>8?b;d8Zqak%-bSg-Q|u-z?I{T z3L@3-8)mH+Tc4Gqu);eTVkENy!&G5K5tcKn&vFZ<|1HdPV3^J~&tW$V2sZ}WGaoR9 zmid5RmXT+^!-8QB(|}=4G}D;xe`6Phk!1nHu7Nb9>BF5LhNqoE|6CI>oZJK$L+fku zbB5U0B$|W#L+xwwbNu3K^1pG>1F0q`*j`|`ik2UY{7#8(W&?(Mh|TW`BKb`v5=oMs@y+#5Dfz!)ext@){8f;Wf_5Nc^}p#T>VA7IphgTHiRzsEEY?t{rB z5fG+oJ`@nc95cWeb!zMPH`ZKlniT;)B8gak&jkv9aF^>jfG@hF0>FJPsSxm8SK37# zAr$`U@d0`RQG$8$7n$#Lt^oL^kmxs-IzlKQH4+~dhZXK#pak#|A(7YaZoftfTRgsd z1!6YP)eOLiZctVL7P_P$AYy>_=l-!LQshjj@Q*ujZS*avOvF6g z%3*;3M+7tNQknBBCYT5zQI`tz>?r|+UC|N~wT!f}B+|wbe`K?;NFz%S*a%`~^G7kP z#G=7Gz)!j{7KGslEM|*bErNb4=^84Oz>MOSz!(K$!$3e+BKcMQRMh!zSFJ)ojFDq4 zqi=;Ckuk#Eq#Eh4?Mzb!0-UE0U`vM&F>Bb8tkQ1xUC%;K^;wm zP8eEE^pBV(`uq4y63RR`p+roD&n44-?m|8zU#Bl&0|Mhk$f zn#HcQVW9!M(WQ+G0pIM>B7eeSxzvFtiW_UhSC`2#hTqN#!42?$q56m5N?A3plOsnD z@GUNFTnPA1mzEv^e!!)T4*@^w(oPQn?{sMsL%`3uv`Hc0mt9&$2zakcn;ZiEhfA9h z0{*8Kdk{ze(my&cUPj5WYGy&r-y*Y zy0nQQ;7KlRQV94=mzEI%&Ua~(L%?%g+LRD*(4|cc0b}N|z5ekYA$zORAKzm|vXuOo zlruyMM~$CndPGl!ewJ;*vNKE!@E(^oE(E;arA5w@N2CrsQRWH!vfA}oS_l|t&wPm% z7?~^D&#JVDjLYOm7Z3oiaK$fM4Gd9HuHSddmg742s^W47_}?Ba9{7+)bAbC~7}wG* zoOoczqdC9>JzBhfFrde)BA-+R{76XVo&-t|_7gV!-IY}gh}JBtIE0cXtJtsCuSLcl zPuBlctGSV_=KA}(Px{y%DB`8XafY8z~qV$SbLX3dW(lDX~ zMTrqGT<6H|AHPEsn<7I&7Zq{^qH`ia);8BA5$E?`!$Mck+!%rBE~y|!44La1^rN!| z9^sh`>}gp7EuVIUmpm`9-xM=4ba8T$z(0DV7X^Cel>p8b^SDdDN0|mUT<*G|WV1le zGbMmAG)0 z9}#t;9Q7AeL&zPj`~{I-SOA@2I-Q95Ek>Zd>`JF!l0o4WA=1(hh%upa*KHl>67n_C z-$T2Yvd%TB0MN6t=t?ofGpGpCJKSL{0K}j~8H~S21biU^eynIfzsDJm0ZMiqSO^H; zGMnF+#S$Q^$z+|1@_s&{0-r`b&Zs1T=y_QIU=X zYiuBd`xZAANidrgax7ylnv9)OJs{7u1pXc70`+cLbVb9q)C-Xk{`QE?#-k6Vpw`75iazskK_c1}7kJEG@h@=1ty*3H@7NF- z2Wpk=?SwRp9Y5MpDXsutK^MMZyAqlHpU0uQtV*OtRB>LG`@_vkkO^+@A>?$Iy@&hW zLsqMW@Ozd@6Y|6pvuO=O`w2+(uWiIXbzB4Sla6a7e$H_T;``4v9aEQ;HEjG7NC}c4 z{+8n!i63-a1MyDB)e|SrD+|KLnIKgV;u(%>B%bNG2I7?C>WOa!r+dQ27N?jXE;+7| z_zuT45N~%}J@Jph=^*};;20HA0=dW~{5B|a{mItvog(2Z1Tczh%>yeQ37Lse^i%1A z=eul#$OP`kp>>ezLm{sM|Iu-cs}Q>jQtA2OehGb!Pt4YEDa`-Ib|sS08SuiS)p?2d z8#pEx8ibsMaMN0#Xv3 zO`LXIl6a}(nuuE+mmps5xJKg39M?eH=D2#|`3nO5&|fJQihW)fbe`vwGv(q z%Ipekea0#-BmBc0)@!`x+wFqN$?Xb~5Y^cAy^Sm6ucP_0K+?rxMxal|_;H?2f`2O=sx;=61X zX+mZZx8(Z}K7@OD%ZJ`w7gv3U7sZ$}F>ee_#vtBf2Xoc0k;;j-$g84tUuEj)o>wCy z7k*{5oGYEaK@7jjhF?PX04RACxNC?xai(a}Hf*9x>HwL$){ABzc^xtZ!A`MxqzRc1 zKJ(bbHfOhl*g3QrHREKG^In4EXwy`Rwt+EG8PJ>*6&Uxe|#w}Pmk3hzTGlk9(D9Vwh%fR@!5!uxLM0CL&zj$qU{=Dnq?!kE3!w6am@C- zD{gzJK|DCY7=$@XMG~$x)91KJ6$!&-;<*^R{^Q zq~gL=J?XPcYFCLSo@Rl$CX^b>$aEFwC$#{{u!!*n!pLbj%@e7V? zAb!Ph^~5(UDoe(no*cHvQBrwTN613R^e1Hh%nLoXu0sXHmXLXiE#Zqu&DgTF@I2&CAN-1 zH)XpfWXFsmTSeQ=7QzpqPezfgCfm~%!k!96w)Qwh!XwdtDgtYAvh8Y`z3+F_M!<(4l_l{L zPL1W5i@qy0;)S+EX%^#ZM^&3R_u7pqSt4eE;w82|D+#%nR9?hf{NjyE zh;v;iLiVD(M{X=5cLF$;_mrhi?9yMw^qEU}Ufh7>HV5;1)K+>G;nS9CC1lECNEny> z#kTmZgd7*KB)ryX5xQj3i zmnu%hO5px^AX_OnlnJ)pD;5B9xx{RLs}YeWB6%^+vE*75D(ZVVeYe|ik(=Q3O-E9} zokPAWP5RC>>DQXYp*!`jiM}_*(HVQKIN#S4Y{X|ns%cHU*m6<3tqYB(#~_v6?|}D1 z%12_3g$sreikS{s@5$1?0`GzpwJ|8C8^xu5?kp>>C*-WdA)9PdXd#>eNH_6 zoZfE$N821)jsj#sBmir|+6%=FZFhzb1OCZTqa*!k;rO_j6FJeaiwr08VPD+L**D}n z)0%$8wque%YELvvqaBLWIck-TT1DPu;Vf-JEctlts1h5Wwh5#O+pM1aa6KFBzm%C( z;%tt&eZr74;Yv-)g}@9WQ_J_H)ci{Q8D^s~E0hlLv6h=wBIYcMdjat_d{HMR^DE)< zdh2>dBqd+xJ=_$nn`DXjTFXr<5xa2F+f{vDN^(EJFOq+uB}=QJ2(zo1%bJgEL zsuxVeUvXRm@y(8FB)-*g3F6xv*F=1~F4d*+vJzWY zVT47I@Jp6jM#wZo>;02xWfB*mL$Z3FYS@lpj$jKiq8y^K~1pmGFm_N~cj5mqBF9 zW!_YgbHK(8ewv!}6V;@jswVwpxpGs;OkGqEvtDBO-$Q=IG|9}El(Ht~xN1c|ZFs;lxBRTJvFNN0?ka9ja3G@FnyEM{-7g%cPrGOolN)vWl z>T(w1B3r~XVcJpvu0GM}k&H|adClTa4xubec~e}rkk~MZwX-!D7i|jDY3yJsc_;au>q0XR<)FIXfM}Xz7|^CM`2j32lBI3Q|m_MQhF#q zOrHDNG4d6A+*Hf;+`t>eP_&Dg{#0RzxV3g1(wb#6zTA)WMI5>Xa=f}vAm5WddP?Ky zDWgiHAF&?Nggo8qkK?f6wz$X{GG@Lo_%?V~eYg*pVPqh<3Gmbw*VV0KQ@U&49cQH9 z&n<@-=9`c^An%9t^*0`7m~D`+LpF}}HBI|K_3OtQyCWbcLN-GBQ6?R3n3<4gL!JjY zQvI(r7!OZEz5#jMk-lfs{wVln$mx(XAU_UyHl*)mr1o#X?^}>>Lyn)|M>6d!_#VhR zA$J@k{WB+;II|%?0eLRu0?37sewN`;hG~cFhU|m|TUC*!tf;)_GH5jIlOX+k7J@H8UIn=YGVu{(F&pw=+w(^>`HPfi9d9D6 zgbX3qK=LQI_yc=>J_p<17R0?1l0WIl-$~@J`Mpu4J|nf~k0e1FTe3;-u!$kJO&uX@4`~-vRkwko+Ed z{**|2v&n#8lkewqu>JYpP{eQ5;Wz5|@qatrFt0)KYyaLs+t=r}81b8a_$@zv9DZ{T zzdx>jrtitL54Jykp9{bFV;{cmgJ1jMXK|qV{&%FjpZ^2Z=l6c_W7HdGn~XmT+4f1( z?tt|BGg5p1qvh`x??Cl8e!^t@6eK^6+;+C%harP=OnW=zFr?q#*TFMSe)5)|sU4~Q zV9I#l|L^l3=HJBsp0As4j`N@1{dgm_=f6L1#Q#d}fMi@h-ht}#9o}KQrOJOVd(QEikWti#e$LDL_N7;w$L9m=kmpD z^PIU0PcLRxqqRCW*xWwY)7yD^PiN4qTHTp}?x4AIeNOxtSuB_%YqN!co_wyN5z4Vb zwl|{;fckrjL32;8N1lt>b@JRL4LO$Y%oH<0bGAF|DrEYyVRxt4vSlp7OreljZ!Czf z><~5ap6To9kkEN?C{N8git*S!Fc36%DF+o_u@tiH-g5zME(Kw%U|1LC^+bhHeD` zZyVO5O>waRb&HVpn`=|j3WCibh9O4_r|Lv|+}6;agRc{w_T7i1q!k3+2sla^l|8(s ze#i0Mviy5Tr?hsj3Mda=UNC>gp9{FMMzQ~KKt``w;B z=hihNdwB8JbT`k-l`^rJVq@ulFzhb`xXJ^@wc_5^r3BSS_DYLH00UOf2(lH zp7q}e`<-n<%Hu!0`^yQ}SKC^M_?%{+tKD^5WO8YZFH1`8qAC_Md)U6}9sG8(`l6`!|gn`%F8^ z*FF2h`ZlebSZ_?yM%d?sMFzYjLiu9<`(fV?d-juNjLY`B0#yD<5|FgVZGL-H>8b~1 zy#Qi!#5`Y%_-*B+U|;vxD)ukHeyZodx1UnQ{*Y%);2Svb$iugvR>l5HdyT;-kAYzo z`%l8&uis<)jlnGJL-fMuZvcIJb(nL9K9!vP ztkKMP23}K-C-=T``@O$3nh&D?Q{~`1`Q!X+gtFRSBvnpnTqjp0n`8OWa{Umee`vt#gK}qeQWc)}EBP@2 z&*zo=VRC+s^FP*}e=GIJ1w5}-^5X-ZFDv=O1D*#f`6B|J-zxcrfak4B{>Xsmqe^~) zJW88Nu`Qrlar&UL#@j= zUhNNYyy{U+5FM9Og|7|92m8jQ1i8n#0u`SapK_$2CE(jUezov5!EwPloX=F=>Y+~S zH9>Tq+%CNGztQva4_ZGu-*yQf*ROwvpB?ZsEN%7JEq~ho;VIP&w(92~ctND@*AXeh z-~vsZ_ccG!@F$`JqeUt{b(G<+0e^zX8g(Uw>%VT}EjStaJC8Q{3HYA{e(!OH--Atf zF8pkSA2ojJk*1$XDcv3e{T}eclMTN|+UhX`en%pu+v}l!Blx{18~$!wVB9Rc%D)?N z57SmbP;LI)tM!iz8rK>>P!GPN`RKfQO!y#}5ZNEpX{siO?gKADpVzbWzhCP|_knTJ zzX>ufTia4v72VaZgC_{HcZ}inL3wJ1esY%K+i;$mrFm*OxvUC*rSJ)-X3^&~AKjP! zR{I$rY?_kNx^twh9=B-T;PU7DgqJD@DXb%2r#w_e|KEgfkp02m_nxex|FY(z=ZoJ} z(XWw{y{hxZi&8qxxAZs#!5Gb#XKwHbRroWi@bjwhS5)D1nwNT>WAgbLE>NzjqW{Gz z{FW;Gjw<|5s_-uf-w<;?+E+z?l-((Gw{#rrOBALzW~2+aY`!> z;`PR_!S6)B9!A~%06vNJy8D*nH$`RMiMt->EE=W)ix@(KcVN4L2nC}szWXU!DQQ78@+2fMlihT(k8Fkf3NCAe{a|& zx1)PC%IEtBG+3P}c1zy5e6C$?0I%uEt=4p3U#4Gz_GXP;A)5^|#r6HoJp+YI^O>5I zrgT%e9mp1XvpI8YhG8<2#Cl`fR}4G4GXd)V&sn^1o@kXF z87O87#UQ+3(Is=|EDA4Ku%KmrYuGwx?xOk1U2ji&N7ykisE0zzpUtLH7c5#hcV0NX zd3v+US5&iwLM|UlIWt9h^Po~qZn)<<`uZ!$aAE7>(9NRO#q-o0YR$Au{nZWs(4?k^ zPyz>Q2Xg%dd5fc~(v3RaozJfct}65tz4XGYe&?WXV12Hm(#mv5@{%#EJfi$vDepe0 z$xwMjv^%;Bm0Vm#UB$v+PRigVBjY)cEmoSVU}``ESw91wzJwd-_mV4QGo6(lFh;so zGQD~{0|^=}d{|aq)v3tHgsc1VIa7ZWK?9AiS;Az z4?(eSFc%p;RU4g~S^OI6Bs(&_9WouVy`5pEQ{Jn}_xn>Kyl`!}6r0_=-ps&&YyoS# v;)XuEuE*<07|O)v@>DaPTV%z2SM#7ZpXm%_IAkH^y;-IgtQ?co;vM-PYQoHD literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test56.ans b/libs/libtpl-1.5/tests/test56.ans new file mode 100755 index 0000000000..f0746c8733 --- /dev/null +++ b/libs/libtpl-1.5/tests/test56.ans @@ -0,0 +1,4 @@ +hs2.s1 length: 5 +hs2.s1: draco +hs2.s2 length: 2 +hs2.s2: po diff --git a/libs/libtpl-1.5/tests/test56.c b/libs/libtpl-1.5/tests/test56.c new file mode 100755 index 0000000000..e0de8e6e64 --- /dev/null +++ b/libs/libtpl-1.5/tests/test56.c @@ -0,0 +1,42 @@ +#include "tpl.h" +#include +#include +#include + +#define S1_LEN 6 +#define S2_LEN 4 + +struct has_strings { + char a; + char s1[S1_LEN]; + char s2[S2_LEN]; +}; + +int main(int argc,char*argv[]) { + tpl_node *tn; + struct has_strings hs,hs2; + void *img; + size_t sz; + + strncpy(hs.s1, "draco",S1_LEN); + strncpy(hs.s2, "po",S2_LEN); + + tn = tpl_map("c#c#", hs.s1, S1_LEN, hs.s2, S2_LEN); + tpl_pack(tn,0); + tpl_dump(tn,TPL_MEM,&img,&sz); + tpl_free(tn); + + /* unpack */ + + tn = tpl_map("c#c#", hs2.s1, S1_LEN, hs2.s2, S2_LEN); + tpl_load(tn,TPL_MEM,img,sz); + tpl_unpack(tn,0); + tpl_free(tn); + free(img); + + printf("hs2.s1 length: %d\n", (int)strlen(hs2.s1)); + printf("hs2.s1: %s\n", hs2.s1); + printf("hs2.s2 length: %d\n", (int)strlen(hs2.s2)); + printf("hs2.s2: %s\n", hs2.s2); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test56.out b/libs/libtpl-1.5/tests/test56.out new file mode 100644 index 0000000000..f0746c8733 --- /dev/null +++ b/libs/libtpl-1.5/tests/test56.out @@ -0,0 +1,4 @@ +hs2.s1 length: 5 +hs2.s1: draco +hs2.s2 length: 2 +hs2.s2: po diff --git a/libs/libtpl-1.5/tests/test57 b/libs/libtpl-1.5/tests/test57 new file mode 100755 index 0000000000000000000000000000000000000000..63980a5601b2db2f43c94559f694f6ea541674a5 GIT binary patch literal 127427 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 +#include +#include + +#define S1_LEN 6 +#define S2_LEN 4 + +struct has_strings { + char a; + char s1[S1_LEN]; + char s2[S2_LEN]; +}; + +int main(int argc,char*argv[]) { + tpl_node *tn; + struct has_strings hs; + + strncpy(hs.s1, "draco",S1_LEN); + strncpy(hs.s2, "po",S2_LEN); + + tn = tpl_map("c#c#", hs.s1, S1_LEN, hs.s2, S2_LEN); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,"/tmp/test57.tpl"); + tpl_free(tn); + + return(0); +} diff --git a/libs/libtpl-1.5/tests/test57.out b/libs/libtpl-1.5/tests/test57.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test58 b/libs/libtpl-1.5/tests/test58 new file mode 100755 index 0000000000000000000000000000000000000000..a5c5a862b2a0a40ce76837d6640d23435af6f000 GIT binary patch literal 128071 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

    A^+lE&%w(a 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 bx( +#include +#include "tpl.h" + +#define TEST_LEN 10 + +int main() { + tpl_node *tn; + int i[TEST_LEN] = {1,2,3,4,5,6,7,8,9,10}; + + tn = tpl_map("i#", i, TEST_LEN); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,"/tmp/test65.tpl"); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test65.out b/libs/libtpl-1.5/tests/test65.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test66 b/libs/libtpl-1.5/tests/test66 new file mode 100755 index 0000000000000000000000000000000000000000..94ce5d8123a93dec063624291c1e2dccca05149d GIT binary patch literal 127291 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 +#include +#include "tpl.h" + +#define TEST_LEN1 10 +#define TEST_LEN2 5 + +int main() { + tpl_node *tn; + int i[TEST_LEN1] = {1,2,3,4,5,6,7,8,9,10}; + int j[TEST_LEN2] = {5,4,3,2,1}; + + tn = tpl_map("i#i#", i, TEST_LEN1, j, TEST_LEN2); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,"/tmp/test66.tpl"); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test66.out b/libs/libtpl-1.5/tests/test66.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test67 b/libs/libtpl-1.5/tests/test67 new file mode 100755 index 0000000000000000000000000000000000000000..b6d5363558a5aabf21ca6526ad09a7da7e05468e GIT binary patch literal 128665 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 +#include +#include "tpl.h" + +#define TEST_LEN1 10 +#define TEST_LEN2 5 + +extern tpl_hook_t tpl_hook; + +int main() { + tpl_node *tn; + int i[TEST_LEN1] = {1,2,3,4,5,6,7,8,9,10}; + int j[TEST_LEN2] = {5,4,3,2,1}; + + tpl_hook.oops = printf; /* errors to printf */ + + tn = tpl_map("i#i#", i, TEST_LEN1, j, TEST_LEN2); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,"/tmp/test67.tpl"); + tpl_free(tn); + + /* Expect success on the next line */ + tn = tpl_map("i#i#", i, TEST_LEN1, j, TEST_LEN2); + if (tpl_load(tn,TPL_FILE,"/tmp/test67.tpl") < 0) { + printf("load failed\n"); + } else { + printf("load succeeded\n"); + } + tpl_free(tn); + + /* Expect failure on the next line (TEST_LEN2 != TEST_LEN2-1) */ + tn = tpl_map("i#i#", i, TEST_LEN1, j, (TEST_LEN2 - 1)); + if (tpl_load(tn,TPL_FILE,"/tmp/test67.tpl") < 0) { + printf("load failed\n"); + } else { + printf("load succeeded\n"); + } + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test67.out b/libs/libtpl-1.5/tests/test67.out new file mode 100644 index 0000000000..3ec435578e --- /dev/null +++ b/libs/libtpl-1.5/tests/test67.out @@ -0,0 +1,3 @@ +load succeeded +/tmp/test67.tpl: array lengths mismatch +load failed diff --git a/libs/libtpl-1.5/tests/test68 b/libs/libtpl-1.5/tests/test68 new file mode 100755 index 0000000000000000000000000000000000000000..e8c337e37abfeaf24b7f0e57e71494a433265ffb GIT binary patch literal 129489 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 +#include +#include "tpl.h" + +#define TEST_LEN1 10 +#define TEST_LEN2 5 + +extern tpl_hook_t tpl_hook; + +int main() { + tpl_node *tn; + int i[TEST_LEN1] = {1,2,3,4,5,6,7,8,9,10}; + int j[TEST_LEN2] = {5,4,3,2,1}; + int i2[TEST_LEN1]; + int j2[TEST_LEN2]; + int x; + + tpl_hook.oops = printf; /* errors to printf */ + + tn = tpl_map("i#i#", i, TEST_LEN1, j, TEST_LEN2); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,"/tmp/test68.tpl"); + tpl_free(tn); + + tn = tpl_map("i#i#", i2, TEST_LEN1, j2, TEST_LEN2); + tpl_load(tn,TPL_FILE,"/tmp/test68.tpl"); + tpl_unpack(tn,0); + tpl_free(tn); + + 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∾qOYMEm5W+bk~1LfPirjNCq(H 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test69.ans b/libs/libtpl-1.5/tests/test69.ans new file mode 100755 index 0000000000..35775dd313 --- /dev/null +++ b/libs/libtpl-1.5/tests/test69.ans @@ -0,0 +1,4 @@ +2 3 4 5 6 7 8 9 10 11 +4 3 2 1 0 +3 4 5 6 7 8 9 10 11 12 +3 2 1 0 -1 diff --git a/libs/libtpl-1.5/tests/test69.c b/libs/libtpl-1.5/tests/test69.c new file mode 100755 index 0000000000..ad103a10a3 --- /dev/null +++ b/libs/libtpl-1.5/tests/test69.c @@ -0,0 +1,39 @@ +#include +#include +#include "tpl.h" + +#define TEST_LEN1 10 +#define TEST_LEN2 5 + +extern tpl_hook_t tpl_hook; + +int main() { + tpl_node *tn; + int i[TEST_LEN1] = {1,2,3,4,5,6,7,8,9,10}; + int j[TEST_LEN2] = {5,4,3,2,1}; + int i2[TEST_LEN1]; + int j2[TEST_LEN2]; + int x,y; + + tpl_hook.oops = printf; /* errors to printf */ + + tn = tpl_map("A(i#i#)", i, TEST_LEN1, j, TEST_LEN2); + for(y=0; y < 2; y++) { + for(x=0; x < TEST_LEN1; x++) i[x] += 1; + for(x=0; x < TEST_LEN2; x++) j[x] -= 1; + tpl_pack(tn,1); + } + tpl_dump(tn,TPL_FILE,"/tmp/test69.tpl"); + tpl_free(tn); + + tn = tpl_map("A(i#i#)", i2, TEST_LEN1, j2, TEST_LEN2); + tpl_load(tn,TPL_FILE,"/tmp/test69.tpl"); + while (tpl_unpack(tn,1) > 0) { + for(x=0; x < TEST_LEN1; x++) printf("%d ", i2[x]); + printf("\n"); + for(x=0; x < TEST_LEN2; x++) printf("%d ", j2[x]); + printf("\n"); + } + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test69.out b/libs/libtpl-1.5/tests/test69.out new file mode 100644 index 0000000000..35775dd313 --- /dev/null +++ b/libs/libtpl-1.5/tests/test69.out @@ -0,0 +1,4 @@ +2 3 4 5 6 7 8 9 10 11 +4 3 2 1 0 +3 4 5 6 7 8 9 10 11 12 +3 2 1 0 -1 diff --git a/libs/libtpl-1.5/tests/test7 b/libs/libtpl-1.5/tests/test7 new file mode 100755 index 0000000000000000000000000000000000000000..1b46d69b505be3fe1a63fd58c4e6f44db40cfcdc GIT binary patch literal 128038 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

    8Q0@4@6=s!CB0K}A{ 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test7.ans b/libs/libtpl-1.5/tests/test7.ans new file mode 100755 index 0000000000..85957f390e --- /dev/null +++ b/libs/libtpl-1.5/tests/test7.ans @@ -0,0 +1,3 @@ +t is wonderful +t is prince of peace +t is counselor diff --git a/libs/libtpl-1.5/tests/test7.c b/libs/libtpl-1.5/tests/test7.c new file mode 100755 index 0000000000..707655ec4d --- /dev/null +++ b/libs/libtpl-1.5/tests/test7.c @@ -0,0 +1,27 @@ +#include +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + char *strs[] = { "wonderful", "prince of peace", "counselor", NULL }; + int i; + char *s, *t; + + tn = tpl_map("A(s)",&s); + for(i=0; strs[i] != NULL; i++) { + s = strs[i]; + tpl_pack(tn,1); + } + tpl_dump(tn,TPL_FILE,"/tmp/test7.tpl"); + tpl_free(tn); + + tn = tpl_map("A(s)",&t); + tpl_load(tn,TPL_FILE,"/tmp/test7.tpl"); + while (tpl_unpack(tn,1) > 0) { + printf("t is %s\n", t); + free(t); + } + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test7.out b/libs/libtpl-1.5/tests/test7.out new file mode 100644 index 0000000000..85957f390e --- /dev/null +++ b/libs/libtpl-1.5/tests/test7.out @@ -0,0 +1,3 @@ +t is wonderful +t is prince of peace +t is counselor diff --git a/libs/libtpl-1.5/tests/test70 b/libs/libtpl-1.5/tests/test70 new file mode 100755 index 0000000000000000000000000000000000000000..ed9d7c5ff62e459958bf9cf41f087920fdd46295 GIT binary patch literal 128063 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 z z+x}d!CzrR!W>_XGNo=&Xy``wVD_gXxo!Zm7T&^#Y0M=rrQInqZm4!IRlchq`o9i`g zoz(iQJtSS}%jMQZg>`TrMGKbCSu#JGzw|;G6FWe}6*cKl(S@s)&RMc(o@kXF=`UrA zB^51PeCgadi=#^yENGtJ61B{kyLi5K*VEnB9<}!mn4ysJ=W^-v!o`c`&WoluPH*)2 zifXP{%oidlXSO779aO5x?e=_oZ(k)DEoxa3`B~JmWS*WwE!j4yzrNic+0@JsN?^6V zKi^lBH#j;g-RR?8g~B>@Rk6Diq!;DP`v$%J8}sdzR<=WumyBWM5$*3vdGA3_hRP$N z-QHEKgX>-UD;v1T|X6MRAiS)^ds*ML9urr z9~(Vg8&2Xj{FZ%{;vW6 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test70.ans b/libs/libtpl-1.5/tests/test70.ans new file mode 100755 index 0000000000..5c9557e8e0 --- /dev/null +++ b/libs/libtpl-1.5/tests/test70.ans @@ -0,0 +1,7 @@ +a +1 +hi +o +matilda +y +3.140000 diff --git a/libs/libtpl-1.5/tests/test70.c b/libs/libtpl-1.5/tests/test70.c new file mode 100755 index 0000000000..1433ed474d --- /dev/null +++ b/libs/libtpl-1.5/tests/test70.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include "tpl.h" + +struct ms_t { + char c; + int i; + char s[2]; + char o; + char *x; + char y; + double d; +}; + +int main() { + tpl_node *tn; + struct ms_t ms = {/*.c =*/ 'a', /*.i =*/ 1, /*.s =*/ {'h','i'}, /*.o =*/ 'o', /*.x =*/ "matilda", /*.y =*/ 'y', /*.d =*/ 3.14 }; + struct ms_t ms2; + + tn = tpl_map("S(cic#cscf)", &ms, 2); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,"/tmp/test70.tpl"); + tpl_free(tn); + + memset(&ms2,0,sizeof(struct ms_t)); + tn = tpl_map("S(cic#cscf)", &ms2, 2); + tpl_load(tn,TPL_FILE,"/tmp/test70.tpl"); + tpl_unpack(tn,0); + tpl_free(tn); + printf("%c\n%d\n%c%c\n%c\n%s\n%c\n%f\n", ms2.c, ms2.i, ms2.s[0], ms2.s[1], ms2.o, ms2.x, ms2.y, ms2.d); + free(ms2.x); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test70.out b/libs/libtpl-1.5/tests/test70.out new file mode 100644 index 0000000000..5c9557e8e0 --- /dev/null +++ b/libs/libtpl-1.5/tests/test70.out @@ -0,0 +1,7 @@ +a +1 +hi +o +matilda +y +3.140000 diff --git a/libs/libtpl-1.5/tests/test71 b/libs/libtpl-1.5/tests/test71 new file mode 100755 index 0000000000000000000000000000000000000000..90106c7e6cf472f0dd3400a2217cddccce54a138 GIT binary patch literal 128135 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test71.ans b/libs/libtpl-1.5/tests/test71.ans new file mode 100755 index 0000000000..48f248cc38 --- /dev/null +++ b/libs/libtpl-1.5/tests/test71.ans @@ -0,0 +1,7 @@ +# +1 +hi +o +matilda +y +3.140000 diff --git a/libs/libtpl-1.5/tests/test71.c b/libs/libtpl-1.5/tests/test71.c new file mode 100755 index 0000000000..d58527ac3f --- /dev/null +++ b/libs/libtpl-1.5/tests/test71.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include "tpl.h" + +struct ms_t { + int i; + char s[2]; + char o; + char *x; + char y; + double d; +}; + +int main() { + tpl_node *tn; + struct ms_t ms = { /*.i =*/ 1, /*.s =*/ {'h','i'}, /*.o =*/ 'o', /*.x =*/ "matilda", /*.y =*/ 'y', /*.d =*/ 3.14 }; + struct ms_t ms2; + char b = '#', b2; + + tn = tpl_map("cS(ic#cscf)", &b, &ms, 2); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,"/tmp/test71.tpl"); + tpl_free(tn); + + memset(&ms2,0,sizeof(struct ms_t)); + tn = tpl_map("cS(ic#cscf)", &b2, &ms2, 2); + tpl_load(tn,TPL_FILE,"/tmp/test71.tpl"); + tpl_unpack(tn,0); + tpl_free(tn); + printf("%c\n%d\n%c%c\n%c\n%s\n%c\n%f\n", b2, ms2.i, ms2.s[0], ms2.s[1], ms2.o, ms2.x, ms2.y, ms2.d); + free(ms2.x); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test71.out b/libs/libtpl-1.5/tests/test71.out new file mode 100644 index 0000000000..48f248cc38 --- /dev/null +++ b/libs/libtpl-1.5/tests/test71.out @@ -0,0 +1,7 @@ +# +1 +hi +o +matilda +y +3.140000 diff --git a/libs/libtpl-1.5/tests/test72 b/libs/libtpl-1.5/tests/test72 new file mode 100755 index 0000000000000000000000000000000000000000..444c6500baa6358298dd6b9ac7961305453ba4d0 GIT binary patch literal 128063 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test72.ans b/libs/libtpl-1.5/tests/test72.ans new file mode 100755 index 0000000000..5c9557e8e0 --- /dev/null +++ b/libs/libtpl-1.5/tests/test72.ans @@ -0,0 +1,7 @@ +a +1 +hi +o +matilda +y +3.140000 diff --git a/libs/libtpl-1.5/tests/test72.c b/libs/libtpl-1.5/tests/test72.c new file mode 100755 index 0000000000..afc9a262ad --- /dev/null +++ b/libs/libtpl-1.5/tests/test72.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include "tpl.h" + +struct ms_t { + char c; + int i; + char s[2]; + char o; + char *x; + char y; + double d; +}; + +int main() { + tpl_node *tn; + struct ms_t ms = {/*.c =*/ 'a', /*.i =*/ 1, /*.s =*/ {'h','i'}, /*.o =*/ 'o', /*.x =*/ "matilda", /*.y =*/ 'y', /*.d =*/ 3.14 }; + struct ms_t ms2; + + tn = tpl_map("S(cic#cscf)", &ms, 2); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,"/tmp/test72.tpl"); + tpl_free(tn); + + memset(&ms2,0,sizeof(struct ms_t)); + tn = tpl_map("S(cic#cscf)", &ms2, 2); + tpl_load(tn,TPL_FILE,"/tmp/test72.tpl"); + tpl_unpack(tn,0); + tpl_free(tn); + printf("%c\n%d\n%c%c\n%c\n%s\n%c\n%f\n", ms2.c, ms2.i, ms2.s[0], ms2.s[1], ms2.o, ms2.x, ms2.y, ms2.d); + free(ms2.x); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test72.out b/libs/libtpl-1.5/tests/test72.out new file mode 100644 index 0000000000..5c9557e8e0 --- /dev/null +++ b/libs/libtpl-1.5/tests/test72.out @@ -0,0 +1,7 @@ +a +1 +hi +o +matilda +y +3.140000 diff --git a/libs/libtpl-1.5/tests/test73 b/libs/libtpl-1.5/tests/test73 new file mode 100755 index 0000000000000000000000000000000000000000..1c32d97c41a667872efdc267381b20e2f3bbd3de GIT binary patch literal 128119 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test73.ans b/libs/libtpl-1.5/tests/test73.ans new file mode 100755 index 0000000000..6b1a4e686c --- /dev/null +++ b/libs/libtpl-1.5/tests/test73.ans @@ -0,0 +1,7 @@ +a +1 +hi +o +matilda +tdh +3.140000 diff --git a/libs/libtpl-1.5/tests/test73.c b/libs/libtpl-1.5/tests/test73.c new file mode 100755 index 0000000000..b44dafc6f6 --- /dev/null +++ b/libs/libtpl-1.5/tests/test73.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include "tpl.h" + +struct ms_t { + char c; + int i; + char s[2]; + char o; + char *x; + char y[3]; + double d; +}; + +int main() { + tpl_node *tn; + struct ms_t ms = {/*.c =*/ 'a', /*.i =*/ 1, /*.s =*/ {'h','i'}, /*.o =*/ 'o', /*.x =*/ "matilda", /*.y =*/ {'t','d','h'}, /*.d =*/ 3.14 }; + struct ms_t ms2; + + tn = tpl_map("S(cic#csc#f)", &ms, 2, 3); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,"/tmp/test73.tpl"); + tpl_free(tn); + + memset(&ms2,0,sizeof(struct ms_t)); + tn = tpl_map("S(cic#csc#f)", &ms2, 2, 3); + tpl_load(tn,TPL_FILE,"/tmp/test73.tpl"); + tpl_unpack(tn,0); + tpl_free(tn); + printf("%c\n%d\n%c%c\n%c\n%s\n%c%c%c\n%f\n", ms2.c, ms2.i, ms2.s[0], ms2.s[1], ms2.o, ms2.x, ms2.y[0],ms2.y[1],ms2.y[2], ms2.d); + free(ms2.x); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test73.out b/libs/libtpl-1.5/tests/test73.out new file mode 100644 index 0000000000..6b1a4e686c --- /dev/null +++ b/libs/libtpl-1.5/tests/test73.out @@ -0,0 +1,7 @@ +a +1 +hi +o +matilda +tdh +3.140000 diff --git a/libs/libtpl-1.5/tests/test74 b/libs/libtpl-1.5/tests/test74 new file mode 100755 index 0000000000000000000000000000000000000000..e16a6d77c95b304babea4e150471ec289565d95b GIT binary patch literal 128663 zcmdSCdwf*Y)jxdB%p^G>Bxkrp0$v!&V1sf=5HS&y8A#xaPBh3x>WxcC00ojJ6F@}> z%tSdIf>^J${+`lmEq%1bwpP(r666wZwSYIgf>v~n0i<3KQJLTOyU#w80ik`~_wzn~ zyrY@D*V=2Zz4qE`ueJ9+`wYt~!sA`4syH8)a*0Cd-Q0jc+24wC=$$T_fKsYxNADb2-c<7Q4A#WMunNev2w&or4j^(Y?et&{cE$$Cz@Lki}kPXE|9{+%KF zcZMqfh;V?3QZBx`QlSgrs`f=@Gyi3sP4H!1KxCZsT^p@9sZ(zv>QT=B>Bo_C*!+33 zhRvTnWd6K`O-qI>DIGavJ{IR?@{-`pRAG-MW zKfB?xv)bBj`o%ZdE6(%9#*hCQ%Q%*f{$oO4-gAjN9e@0EV+_KN( zXV}=2fBzWho+l~le+vAfQ{dk^1-{}G_{&a#51a!3_$lxooC5!&Q{b;W1^zduz?Yo@ zf5R#89jCz4{7$Clr%r+Au=?hNXGZ4LEo8;nEF`-{jSK4=<}HlW3Pk-)$^wV!Y}8T~ zG%Y0C>C!#y>LTr9Z8=hN_%)%om5!>4Qxg}c-6P*Cc#Hx1t{g;kV98a^it ze<%&#Jq>>(4WFBaSET(@#=JDVmWJ2U@ZL1MGsY|~NW=F?qxYrZ)5o_c4c{w`zBmn^ z9$-q-@Qh{7Cy<8k=OB?9Y54p!d{r9$v^4y*G<=^l{ERewK^lH;8oqBD-iYqkjCjVg zbw0&tX^&(i#=#nm=vHk@8WFO|3;r7<$$^jITkju0j__O(S$mWC4E!}=nzFS+zz-0n z30v&~{uyDKuJyQpe@d7pYpoOTO2RZ%YpsB9CQK8xng!fIn8R+>3-|`YG)ZfQfM*e= zDOyzmzM3#i&B?njs=WVH*pCt;e7^|*k$5vFNa>jdl~%%Qi|3i#+kz#MX`S-_tY z=1^Pp0{)aRhuE4S;13CNXss#%zfG7XW(5Sii!fb~RSY;dxn$RrNydu(dm&=2UN_{% zsTlXxa=*93^;}R4i-G{&DYxSZtFBfqCaz*(<|9EGu{^M7p&#ATg zAaAW+zw=*qdiRPTtks~0~H z+~@j_U;JF}5q?c;Vq@LJWS7wq^BdB0>HXP0B>M4-cKaIIf1d4c z0saNz(Y_(u?<3mJeFkhc&P;2+-EKd6WHwsgjMihXv4N(Ko}LY=XDF6oe%$ua%z#qT z9&UZuUk@uwymT(4Ic%6)46`F~undF;K(L7uz%ciew1-+B6LKcTo+mJg2QYRe?N1K@ zMcDl03*%A2IV?H)OxL7OI!wa@h5~VZI92U zXo(}=C6jvp7$l$~z3#T}A<;%5QFM!zcnifwS!dHnq1Fe5XcUn%hV%I(^uKfHjTKvI zB_-|GTo=4{%i6Ui2SVn~>kacmBl^*ys>z{__I5O6bZjmbNyoaJ0Q7^}U#?AkHogf5 zG{qRgIB7(W=ld{-J*J>$Vi_jvb=xy80ZRR13;SzCFFrIE1d-EI zBJ`Njc0YDupil0&&bkFvtVQ^;yMUQuK$Ed{!+gSjKN~gg_OBD^YX5qqVKe4`T%@c0 zWElzQgJS-6BD~RU-Utb`Mn~2!tWF5-~7c$h3zvnj~cCE zzh<;9_4_u_COI`ZHw_c>m1JveWcOl;EJ&TV#5skOT%Cp2qR}iF4PB=`>XUpVgC$$&}4tTKIlPzGwSGr z9u^H!?sWowLiAi8^f%F83bYq^!#rlhFWz#44>C;lYmU%JQ*uK1a=(w=C`eocsY=>m zYm{qC@T!WEWN>P5N^o+>{Bp{qzq-j0gWyAgN&$1Je=x-^pxAok2VGXQ9MEH15S2o4j~{lY$EE`)kJlpz=6WG&g?i9vd7-lUa2R^= zMzTX?ujse`1vEw+un{j!=I@+`9<@Mm+w@qi!-~y@s$Vy%muQCiSt1v0hvK9C$^1t_ z9gffUdqZ%n=mVs$&_XJvP$E>eO~0>Qf3h9+KWWo9GXpT94#Rxwi%0a9$3Pj3*L#A8 z18xk_)nV$hEt-k?s{D%>r?DtWec-UW%+!-`GO4`A1 zNp7fhyp|HY(mZ61fl1Y_EopCicovog`43@M3GR_>!TC|Z)Wl!Er|soGNYK&5ime<@ zb2t4;@Vemj!ReTrw*N{z`gJlHFO4QWddv^GqRE`ULT)AUq7grH445R&{RS3ZjW*#8 zVBfEDM9oh6lHZD98ZH}7<`<>4+4<8@*#Z5woscGMdi-r(@J!|(o&%v<+C%2{5RhST z(qm!jYtS}Qg{h)l4o#+AUVw7888$x+!ym;<%gwo3qW2MKR4BLQA&70w6%Aqdjn?`8 zfRzL&bsvE`Wb=z1)@=76Br?n*=-(^4RHa#ksMU54y2^Px3&hqcU`pNzMMwJ;J@y0| zYFkoc7Z;+K^{lUfg;ak<0=@eMng-dAIcEgo7n}~T?PkgQ<67{pK@E=QdT>nUzY0|P zc)kOe<7u=cBbmwkmkCO4e}&6WTIWz23Y*M-3WZdb^_qiY2Yv-?WqgECv-N;elFT;+ zXHXvl&M>d_W9rWLA2Q4@!scxM5d_;6``1G`h^^*#iEj_XD2^n}ZKgYN17eZ6y^Z#f z__KqLEaj9fE|0q_N?s^QK8<;xJVO%0Z1g4``wDHKK4!6Dj?*Gb;dq#8yB0iWRwx&YISoZ|43Qi4~$LJrijEn9s2*+!^ z^yOM*%SU?bXAoG(TNxkh55=)y2*rnXo>e>4nO|)g)waF#LQ~*p#1|ABEe9eKjOq#{ zdZhc}_s!>${@2&d4cL5)c!k%ft}HO(T+ThG8f7~Tv&yUA_D{5A#OG?L+_a^OKbAO^ z=Kf^3dP4r<5I9

    1)mfqDvklK8j4UVgKL*s$jH3W$j?un@c~m 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 buIIr(A={&5IAkFef>~x3tQ?co5*+y-&jfCn literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test74.ans b/libs/libtpl-1.5/tests/test74.ans new file mode 100755 index 0000000000..30913cf873 --- /dev/null +++ b/libs/libtpl-1.5/tests/test74.ans @@ -0,0 +1,301 @@ +1234 +0.00 +1.50 +3.00 +4.50 +6.00 +7.50 +9.00 +10.50 +12.00 +13.50 +15.00 +16.50 +18.00 +19.50 +21.00 +22.50 +24.00 +25.50 +27.00 +28.50 +30.00 +31.50 +33.00 +34.50 +36.00 +37.50 +39.00 +40.50 +42.00 +43.50 +45.00 +46.50 +48.00 +49.50 +51.00 +52.50 +54.00 +55.50 +57.00 +58.50 +60.00 +61.50 +63.00 +64.50 +66.00 +67.50 +69.00 +70.50 +72.00 +73.50 +75.00 +76.50 +78.00 +79.50 +81.00 +82.50 +84.00 +85.50 +87.00 +88.50 +90.00 +91.50 +93.00 +94.50 +96.00 +97.50 +99.00 +100.50 +102.00 +103.50 +105.00 +106.50 +108.00 +109.50 +111.00 +112.50 +114.00 +115.50 +117.00 +118.50 +120.00 +121.50 +123.00 +124.50 +126.00 +127.50 +129.00 +130.50 +132.00 +133.50 +135.00 +136.50 +138.00 +139.50 +141.00 +142.50 +144.00 +145.50 +147.00 +148.50 +150.00 +151.50 +153.00 +154.50 +156.00 +157.50 +159.00 +160.50 +162.00 +163.50 +165.00 +166.50 +168.00 +169.50 +171.00 +172.50 +174.00 +175.50 +177.00 +178.50 +180.00 +181.50 +183.00 +184.50 +186.00 +187.50 +189.00 +190.50 +192.00 +193.50 +195.00 +196.50 +198.00 +199.50 +201.00 +202.50 +204.00 +205.50 +207.00 +208.50 +210.00 +211.50 +213.00 +214.50 +216.00 +217.50 +219.00 +220.50 +222.00 +223.50 +225.00 +226.50 +228.00 +229.50 +231.00 +232.50 +234.00 +235.50 +237.00 +238.50 +240.00 +241.50 +243.00 +244.50 +246.00 +247.50 +249.00 +250.50 +252.00 +253.50 +255.00 +256.50 +258.00 +259.50 +261.00 +262.50 +264.00 +265.50 +267.00 +268.50 +270.00 +271.50 +273.00 +274.50 +276.00 +277.50 +279.00 +280.50 +282.00 +283.50 +285.00 +286.50 +288.00 +289.50 +291.00 +292.50 +294.00 +295.50 +297.00 +298.50 +0.00 +0.50 +1.00 +1.50 +2.00 +2.50 +3.00 +3.50 +4.00 +4.50 +5.00 +5.50 +6.00 +6.50 +7.00 +7.50 +8.00 +8.50 +9.00 +9.50 +10.00 +10.50 +11.00 +11.50 +12.00 +12.50 +13.00 +13.50 +14.00 +14.50 +15.00 +15.50 +16.00 +16.50 +17.00 +17.50 +18.00 +18.50 +19.00 +19.50 +20.00 +20.50 +21.00 +21.50 +22.00 +22.50 +23.00 +23.50 +24.00 +24.50 +25.00 +25.50 +26.00 +26.50 +27.00 +27.50 +28.00 +28.50 +29.00 +29.50 +30.00 +30.50 +31.00 +31.50 +32.00 +32.50 +33.00 +33.50 +34.00 +34.50 +35.00 +35.50 +36.00 +36.50 +37.00 +37.50 +38.00 +38.50 +39.00 +39.50 +40.00 +40.50 +41.00 +41.50 +42.00 +42.50 +43.00 +43.50 +44.00 +44.50 +45.00 +45.50 +46.00 +46.50 +47.00 +47.50 +48.00 +48.50 +49.00 +49.50 diff --git a/libs/libtpl-1.5/tests/test74.c b/libs/libtpl-1.5/tests/test74.c new file mode 100755 index 0000000000..e81f84b095 --- /dev/null +++ b/libs/libtpl-1.5/tests/test74.c @@ -0,0 +1,39 @@ +#include +#include +#include "tpl.h" + +#define F1_LEN 200 +#define F2_LEN 100 + +struct ms_t { + int i; + double f1[F1_LEN]; + double f2[F2_LEN]; +}; + +int main() { + tpl_node *tn; + struct ms_t ms, ms2; + int i; + + ms.i = 1234; + for(i=0; i < F1_LEN; i++) ms.f1[i] = i * 1.5; + for(i=0; i < F2_LEN; i++) ms.f2[i] = i * 0.5; + + tn = tpl_map("S(if#f#)", &ms, F1_LEN, F2_LEN); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,"/tmp/test74.tpl"); + tpl_free(tn); + + memset(&ms2,0,sizeof(struct ms_t)); + tn = tpl_map("S(if#f#)", &ms2, F1_LEN, F2_LEN); + tpl_load(tn,TPL_FILE,"/tmp/test74.tpl"); + tpl_unpack(tn,0); + tpl_free(tn); + + printf("%d\n", ms2.i); + for(i=0; i < F1_LEN; i++) printf("%.2f\n", ms2.f1[i]); + for(i=0; i < F2_LEN; i++) printf("%.2f\n", ms2.f2[i]); + + return(0); +} diff --git a/libs/libtpl-1.5/tests/test74.out b/libs/libtpl-1.5/tests/test74.out new file mode 100644 index 0000000000..30913cf873 --- /dev/null +++ b/libs/libtpl-1.5/tests/test74.out @@ -0,0 +1,301 @@ +1234 +0.00 +1.50 +3.00 +4.50 +6.00 +7.50 +9.00 +10.50 +12.00 +13.50 +15.00 +16.50 +18.00 +19.50 +21.00 +22.50 +24.00 +25.50 +27.00 +28.50 +30.00 +31.50 +33.00 +34.50 +36.00 +37.50 +39.00 +40.50 +42.00 +43.50 +45.00 +46.50 +48.00 +49.50 +51.00 +52.50 +54.00 +55.50 +57.00 +58.50 +60.00 +61.50 +63.00 +64.50 +66.00 +67.50 +69.00 +70.50 +72.00 +73.50 +75.00 +76.50 +78.00 +79.50 +81.00 +82.50 +84.00 +85.50 +87.00 +88.50 +90.00 +91.50 +93.00 +94.50 +96.00 +97.50 +99.00 +100.50 +102.00 +103.50 +105.00 +106.50 +108.00 +109.50 +111.00 +112.50 +114.00 +115.50 +117.00 +118.50 +120.00 +121.50 +123.00 +124.50 +126.00 +127.50 +129.00 +130.50 +132.00 +133.50 +135.00 +136.50 +138.00 +139.50 +141.00 +142.50 +144.00 +145.50 +147.00 +148.50 +150.00 +151.50 +153.00 +154.50 +156.00 +157.50 +159.00 +160.50 +162.00 +163.50 +165.00 +166.50 +168.00 +169.50 +171.00 +172.50 +174.00 +175.50 +177.00 +178.50 +180.00 +181.50 +183.00 +184.50 +186.00 +187.50 +189.00 +190.50 +192.00 +193.50 +195.00 +196.50 +198.00 +199.50 +201.00 +202.50 +204.00 +205.50 +207.00 +208.50 +210.00 +211.50 +213.00 +214.50 +216.00 +217.50 +219.00 +220.50 +222.00 +223.50 +225.00 +226.50 +228.00 +229.50 +231.00 +232.50 +234.00 +235.50 +237.00 +238.50 +240.00 +241.50 +243.00 +244.50 +246.00 +247.50 +249.00 +250.50 +252.00 +253.50 +255.00 +256.50 +258.00 +259.50 +261.00 +262.50 +264.00 +265.50 +267.00 +268.50 +270.00 +271.50 +273.00 +274.50 +276.00 +277.50 +279.00 +280.50 +282.00 +283.50 +285.00 +286.50 +288.00 +289.50 +291.00 +292.50 +294.00 +295.50 +297.00 +298.50 +0.00 +0.50 +1.00 +1.50 +2.00 +2.50 +3.00 +3.50 +4.00 +4.50 +5.00 +5.50 +6.00 +6.50 +7.00 +7.50 +8.00 +8.50 +9.00 +9.50 +10.00 +10.50 +11.00 +11.50 +12.00 +12.50 +13.00 +13.50 +14.00 +14.50 +15.00 +15.50 +16.00 +16.50 +17.00 +17.50 +18.00 +18.50 +19.00 +19.50 +20.00 +20.50 +21.00 +21.50 +22.00 +22.50 +23.00 +23.50 +24.00 +24.50 +25.00 +25.50 +26.00 +26.50 +27.00 +27.50 +28.00 +28.50 +29.00 +29.50 +30.00 +30.50 +31.00 +31.50 +32.00 +32.50 +33.00 +33.50 +34.00 +34.50 +35.00 +35.50 +36.00 +36.50 +37.00 +37.50 +38.00 +38.50 +39.00 +39.50 +40.00 +40.50 +41.00 +41.50 +42.00 +42.50 +43.00 +43.50 +44.00 +44.50 +45.00 +45.50 +46.00 +46.50 +47.00 +47.50 +48.00 +48.50 +49.00 +49.50 diff --git a/libs/libtpl-1.5/tests/test75 b/libs/libtpl-1.5/tests/test75 new file mode 100755 index 0000000000000000000000000000000000000000..d9919fc9426d9a712fea4fbc7ec2d88c3e4155dc GIT binary patch literal 128610 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test75.ans b/libs/libtpl-1.5/tests/test75.ans new file mode 100755 index 0000000000..43fce23cd6 --- /dev/null +++ b/libs/libtpl-1.5/tests/test75.ans @@ -0,0 +1,2 @@ +string +byte array diff --git a/libs/libtpl-1.5/tests/test75.c b/libs/libtpl-1.5/tests/test75.c new file mode 100755 index 0000000000..76b4fd3461 --- /dev/null +++ b/libs/libtpl-1.5/tests/test75.c @@ -0,0 +1,38 @@ +#include +#include +#include "tpl.h" + +#define S2_LEN 10 + +struct example { + char *s1; /* s1 is a pointer */ + char s2[S2_LEN]; /* s2 is a byte array */ +}; + +int main() { + tpl_node *tn; + int i; + struct example dst, src = { + /* .s1 = */ "string", + /* .s2 = */ {'b','y','t','e',' ','a','r','r','a','y'} + }; + + tn = tpl_map( "sc#", &src.s1, &src.s2, S2_LEN); + tpl_pack( tn, 0 ); + tpl_dump( tn, TPL_FILE, "/tmp/test75.tpl" ); + tpl_free( tn ); + + /* unpack it now into another struct */ + + tn = tpl_map( "sc#", &dst.s1, &dst.s2, S2_LEN); + tpl_load( tn, TPL_FILE, "/tmp/test75.tpl" ); + tpl_unpack( tn, 0 ); + tpl_free( tn ); + + printf("%s\n", dst.s1); + for(i=0; i < S2_LEN; i++) printf("%c", dst.s2[i]); + printf("\n"); + + free(dst.s1); /* tpl allocated it for us; we must free it */ + return(0); +} diff --git a/libs/libtpl-1.5/tests/test75.out b/libs/libtpl-1.5/tests/test75.out new file mode 100644 index 0000000000..43fce23cd6 --- /dev/null +++ b/libs/libtpl-1.5/tests/test75.out @@ -0,0 +1,2 @@ +string +byte array diff --git a/libs/libtpl-1.5/tests/test76 b/libs/libtpl-1.5/tests/test76 new file mode 100755 index 0000000000000000000000000000000000000000..67c28b70f57c057303127d64eef801cb76fb64f7 GIT binary patch literal 128570 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test76.ans b/libs/libtpl-1.5/tests/test76.ans new file mode 100755 index 0000000000..43fce23cd6 --- /dev/null +++ b/libs/libtpl-1.5/tests/test76.ans @@ -0,0 +1,2 @@ +string +byte array diff --git a/libs/libtpl-1.5/tests/test76.c b/libs/libtpl-1.5/tests/test76.c new file mode 100755 index 0000000000..cb57d2200a --- /dev/null +++ b/libs/libtpl-1.5/tests/test76.c @@ -0,0 +1,38 @@ +#include +#include +#include "tpl.h" + +#define S2_LEN 10 + +struct example { + char *s1; /* s1 is a pointer */ + char s2[S2_LEN]; /* s2 is a byte array */ +}; + +int main() { + tpl_node *tn; + int i; + struct example dst, src = { + /* .s1 = */ "string", + /* .s2 = */ {'b','y','t','e',' ','a','r','r','a','y'} + }; + + tn = tpl_map( "S(sc#)", &src, S2_LEN); /* NOTE S(...) */ + tpl_pack( tn, 0 ); + tpl_dump( tn, TPL_FILE, "/tmp/test76.tpl" ); + tpl_free( tn ); + + /* unpack it now into another struct */ + + tn = tpl_map( "S(sc#)", &dst, S2_LEN); /* NOTE S(...) */ + tpl_load( tn, TPL_FILE, "/tmp/test76.tpl" ); + tpl_unpack( tn, 0 ); + tpl_free( tn ); + + printf("%s\n", dst.s1); + for(i=0; i < S2_LEN; i++) printf("%c", dst.s2[i]); + printf("\n"); + + free(dst.s1); /* tpl allocated it for us; we must free it */ + return(0); +} diff --git a/libs/libtpl-1.5/tests/test76.out b/libs/libtpl-1.5/tests/test76.out new file mode 100644 index 0000000000..43fce23cd6 --- /dev/null +++ b/libs/libtpl-1.5/tests/test76.out @@ -0,0 +1,2 @@ +string +byte array diff --git a/libs/libtpl-1.5/tests/test77 b/libs/libtpl-1.5/tests/test77 new file mode 100755 index 0000000000000000000000000000000000000000..a1bfd3a8640c888015041c11fe00d0d2448387d0 GIT binary patch literal 128570 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 VK!!t>QPG=GdJW4lSu5U={{{LoKmGs! literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test77.ans b/libs/libtpl-1.5/tests/test77.ans new file mode 100755 index 0000000000..43fce23cd6 --- /dev/null +++ b/libs/libtpl-1.5/tests/test77.ans @@ -0,0 +1,2 @@ +string +byte array diff --git a/libs/libtpl-1.5/tests/test77.c b/libs/libtpl-1.5/tests/test77.c new file mode 100755 index 0000000000..58b41b5d90 --- /dev/null +++ b/libs/libtpl-1.5/tests/test77.c @@ -0,0 +1,38 @@ +#include +#include +#include "tpl.h" + +#define S2_LEN 10 + +struct example { + char *s1; /* s1 is a pointer */ + char s2[S2_LEN]; /* s2 is a byte array */ +}; + +int main() { + tpl_node *tn; + int i; + struct example dst, src = { + /* .s1 = */ "string", + /* .s2 = */ {'b','y','t','e',' ','a','r','r','a','y'} + }; + + tn = tpl_map( "S(sc#)", &src, S2_LEN); /* NOTE S(...) */ + tpl_pack( tn, 0 ); + tpl_dump( tn, TPL_FILE, "/tmp/test77.tpl" ); + tpl_free( tn ); + + /* unpack it now into another struct */ + + tn = tpl_map( "S(sc#)", &dst, S2_LEN); + tpl_load( tn, TPL_FILE, "/tmp/test77.tpl" ); + tpl_unpack( tn, 0 ); + tpl_free( tn ); + + printf("%s\n", dst.s1); + for(i=0; i < S2_LEN; i++) printf("%c", dst.s2[i]); + printf("\n"); + + free(dst.s1); /* tpl allocated it for us; we must free it */ + return(0); +} diff --git a/libs/libtpl-1.5/tests/test77.out b/libs/libtpl-1.5/tests/test77.out new file mode 100644 index 0000000000..43fce23cd6 --- /dev/null +++ b/libs/libtpl-1.5/tests/test77.out @@ -0,0 +1,2 @@ +string +byte array diff --git a/libs/libtpl-1.5/tests/test78 b/libs/libtpl-1.5/tests/test78 new file mode 100755 index 0000000000000000000000000000000000000000..af888db01c225cf94c6b4bcac9b47b31260dcf12 GIT binary patch literal 126475 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

    31&EnXbQ4snaAzsTQ{;9(^9U+SPBkuTvO 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 UJLIG(c_Yf4oN`Rg4DZPQ0}T(B4FCWD literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test78.ans b/libs/libtpl-1.5/tests/test78.ans new file mode 100755 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test78.c b/libs/libtpl-1.5/tests/test78.c new file mode 100755 index 0000000000..cbe896fc39 --- /dev/null +++ b/libs/libtpl-1.5/tests/test78.c @@ -0,0 +1,23 @@ +#include "tpl.h" + +int main() { + int i; + char c; + tpl_node *tn; + + tn = tpl_map("A(i)c", &i, &c); + + /* pack index number 0 (char c) */ + c = 'a'; + tpl_pack(tn, 0); + + /* pack A(i) (that is, index number 1) a few times */ + i = 3; + tpl_pack(tn, 1); + i = 4; + tpl_pack(tn, 1); + + tpl_dump(tn, TPL_FILE, "/tmp/test78.tpl"); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test78.out b/libs/libtpl-1.5/tests/test78.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test79 b/libs/libtpl-1.5/tests/test79 new file mode 100755 index 0000000000000000000000000000000000000000..ba5996756ff5746b82f1c38ed36d2291ca72a5fe GIT binary patch literal 127471 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test79.ans b/libs/libtpl-1.5/tests/test79.ans new file mode 100755 index 0000000000..33ae1856d5 --- /dev/null +++ b/libs/libtpl-1.5/tests/test79.ans @@ -0,0 +1,3 @@ +got a +got 3 +got 4 diff --git a/libs/libtpl-1.5/tests/test79.c b/libs/libtpl-1.5/tests/test79.c new file mode 100755 index 0000000000..15cbaa2b1b --- /dev/null +++ b/libs/libtpl-1.5/tests/test79.c @@ -0,0 +1,22 @@ +#include +#include "tpl.h" + +int main() { + int i; + char c; + tpl_node *tn; + + tn = tpl_map("A(i)c", &i, &c); + tpl_load(tn, TPL_FILE, "/tmp/test78.tpl"); + + /* unpack index number 0 (char c) */ + tpl_unpack(tn, 0); + printf("got %c\n", c); + + /* unpack A(i) (that is, index number 1) til we run out of elements */ + while (tpl_unpack(tn, 1) > 0) { + printf("got %d\n", i); + } + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test79.out b/libs/libtpl-1.5/tests/test79.out new file mode 100644 index 0000000000..33ae1856d5 --- /dev/null +++ b/libs/libtpl-1.5/tests/test79.out @@ -0,0 +1,3 @@ +got a +got 3 +got 4 diff --git a/libs/libtpl-1.5/tests/test8 b/libs/libtpl-1.5/tests/test8 new file mode 100755 index 0000000000000000000000000000000000000000..804800be2b919286f070637d3d57f4ea1a372568 GIT binary patch literal 128566 zcmd443wTsTwlBVScPH5)B)fS88boPGqY2Lh5fcIJh7Ro3juYhR10ggCpm~{eASyzj zyOC`ZjH5>#$1^hO%;3=@jN>r)7!u?WU*iCZ;uCzJy^Sb}Mnt9WZ&lUqG!bUb|9<~_ zzuTIwTB}yATD5A`s#UdXH>-;MQ!TPAnIDUEsYH+?)6G!)TasGd?V@o@g_0tTck=nEf<8(;WX-1w5Df$Y00HCv~Y+UxqbMV6;C zmvPWcCCSMURF7nxE6V3CTfp#UT1W!nqlwh4N8(YvT2Zf7)HBn)LNGHm`$v7Fzd@pZ zgDh@91iLAbyzILxWx4>a^hj_K<=?301aDNkS;kD?<7mlD&3e;OkL3KHeoQ&XR4!dO zrgG7!%B9r}jiVY1$B!C6ZghRk=&@i#yzTg-E>6307QXp#Q9DljQF&kdk;qse5i^Yw7kc>Zy#z($s&L>B~NxaOdEUKJ8hDC#^kp?}~~4U6fh$O>_{) zp85M~pnIR8Xz*F^G;C+0fBP)>;;7p1;!OH~@GSWMI1B#qv)~V%1yA;MrgpcV1z#ZW?hH3_ zU7r}T#OH9jy9qp?=hp|z>Vos6 znrGvs^2Vh>sXka&9jL06DuQ(l)q%2Lxl~tPR#{mSppyF9YN@KKtX8V3zqy)WD$9W> zuc|K(O7rKJ*VR?m%m-~*aA{37Ra``c#BN!Ab#2|!>R<&!)ZQ#rnM@aYHO>F1S zuV{o^K`BsKQ(rFC)Pg&j4J@f+3HSg4eN7!mNpR7NsHxZO1>)D4$N_(HRN1I!M_#=`ZR#1U!syFNqFYEIJs1tgg2KkDr!u^CzcZ6o09OR z&nEhHN%-V-ttAPc?APy4!jr7#XJZmRVRI32%-u6~~hBy^`pUCE=6D_e2uDPZGT(<|FAWd4W-q z@U)hhAA1shpov84NWy0);hjnNeo6S;Bz*rQe0~z%k%TWy!VgHoYoRX`Et=9??Ub}g zTQDUy1=gsAb}2iPh>(q6bPGu0!&cy19qdMq;3Y(49FF5Ntd3wZWn(XcZy=aV*l1($ zLW0S3jV%nmhF~&TV1e1vxO$?q)Fsa$7W$+~glSvv27(A9>GDV}5 z!NUnA6Exfm9!fBoo{`VsfdrGu8BPZGCYVgkurs&^!DM2F#9#}-D#6E20Ws`k6<{(c z<1mB2A(%|b*vsJ02__RV+8F#1!DKqd76!jVFqww2k-_^3rlB`l82mE9G~`ATgI^$+ zhT5oQ@UsNd5E}~^{1m}7v_>g||BK*(1iKmhFu~^#oDXQ-V=#1t93<>z?Z zY%lhoAdj@IdK+!WKExnmM%fG6uHD&EaMY*oyI#{j(n6mcE1l_UZimNtsk87*`oOVf`mx6IqQjbx#T`|Z3|DvBRg2R9LJ8$l-h zjuTeUYx)b?j?XXCC-MJOP_b;Bh{M2u2M?%lUlRirD)A7T+Z!_P_y0ZQpj^?y4MBk54&18vS+?PI%57G zlu+od`&kK8u^&#x}$WRr0)o_K$ikkHW z4rqZ!MU%gZ{R3_Lq7z;5>=B^$M=M=+U%SnPK0x|n#V2DL#e7A()%)7it!=RX8QU+y zVEOfSO@I6NAJxbcp!7s*ZJtiIRfZ_}!CZB#*OgE6_QG{u{9(ihQ$U!pz>Ec^07B-M zG>^+KDf+H{VsRv{uDcKt`q5B0g6@|fbGr>0Z9=6>QNu68lWO``@$3lZg7G{c(?4j@ znJy=Z6ZN|s@qHe>y`T;J8Z&*(Q)fo#;S3I|rN?_h35XJOVIj z;yL()cszR$fu<%_@6s?(`oU}Gd9L%!^IY$lkGaYHQ|!hQ@p!Z_6t}5i7vu`XGoFLo zQt)LhdT#4trxg4A2Uz%(XcOK5_We4IsNO-o|yK-3Mv> zy3N&U2hVu+GEktVPv7GM(hp8**iZV(+f7t{Qqff=O)4*Upq$$D>!17KkD`TMeTfo# z17dUKMjnCK#uC;LhF@#0bh(W<<5v9S)Af_HtPi7rVEKaGZ37cAn%kD!?98Q%j7sh&duy+6v(WRMR~&K!a0MZX2u zS}u5305Hl?gT}K39OKzDfJz?EYpFWMQ;Wodsqt(-fr8s}@GEiSe3FKQjb~qsLQJf~IV~H)<^|c&Q-%4CaCKERkq>y**ahi8fFl zvslxoD8UtQJ<$i5U(=#bFc0sKKI+;?^s9GKvoK9B_`m)g*(Hqdl5!YfIa>4UpJHih zeT3`qbv@Sc*NT?tgxJ++BKD|Bovv>!*C$FXd8hF)D?w=ECRZUDuXETl z$EUOP$)_K{5NP^8XcROpI?e9au{`^uwGO|v)*0yx`a`Eu)bMfGA0}1SLbp_0@JT%T z91;UdbMw@Aq!Trqt1f17Nt7zU%n3 zrvKCeR*d4Z+{8FPz7RT(UW-9~x8Wl+;so`xUHW089b==-+KJxkh{RXE<_~avT;A+Y zk!USkvlBx2^}_}G{dpgD^s7j;*E~-46?Lj>9zi+TNApP8FSiw)Y&hc6cXdRx=oHw` z6~DBfS1={D=v>7JoIYO7vuwViH|ys3qQA07i=}8fbYyQjqVRRlu5R_a`e4=Tv(E1V z;C1yPOmAR%1Jer~wClUCY+f|XrpX6Q5yYQ0Fd14ZG3hNGF}R!Fk_ zcf{-!JHAqY>_wQ~6k(J!yYhH%>$e!^pdRLRC?;bOmrs)RP+kO`s%uCUXi(D+P@A99 zniP5=A+x&X5X%22ZGva$guMK>1qj?a9$&J>!R3C$v`gTaP-()4SdrCi?Z9Yv0bVsS;& zU)LsJ%}~RyqS&i$y|6gksYYnqtkPAkM5&Zk&=Fkr+rgPPssp(C`aVrvje(emEz=)>ocFSLi*OZYenJ<-(3 z6TAg+$dn&EvJC+r40YGsq$!*5KOS{^XKNcgx2E@X#eVlCC=sGZ`y!y~jaCcVJWZ!^ z)O+Ancgh~j+(B%5xFyeOm6T`vC(MNG0OC2fVIbrFqR-XvN5FQhXMVXk$mLYKhax_*LhymK zM2*6#NWn-vTe%KPBJd5diWVRIPdiKil|s7|-YcwuQrxw>bctJPVe3iMPFw#0TJ#cH z+k3>bw_oc-BUouf)#wzgcQ8CUCcw!^hn}z(En1I|{MKBpeTtK{60KHZe?nhda{$n=( z3S6`>5^pe!SEx8z@6@nz$2NSyEyW$Z)gIf|fs*zqLRQ{g<0g=cDE+Q$xYCRPOwL;! z*bf0^TnUocC!bRb{^+nPfQl^x-`0@}-B2d>T%PzF9lsNCNs_;7zQ#rYX*88Qo}yc{ z=rW8G4&}ySGLrXZ^C@a`k(nbLcJPYzSSoXnrsQn>;!S>x4G^a)%El zX)J`cy5b36bexL?r20El8vBBVL*Hpk1Qqqy8!bj)dbAjaYMOBYLpDJb2&KM{?KR@@ zW=+;JsKw9^^0L0zZlgKBj#G$}e)-4PO0-LCJ)zyQcS4mzZT1=qeoz@Rb zl%2MYx5aoQ#j!X8DQH7Sf`i#s6`Pequ~A^C1!hT*O5JQbKq0SoKlKc*Q3vZ5)5sI^ zU94x=dLh_7Fax`??e(ltn)?WPqf2tJO^&(H7woHK{YG0wyERxlpl#0-OC?Ia-y1q? zSvSQBDV5jA+F4}_N=VgasmsaxXXtVL%a9<4__dO7wpJFuU5P17&O zeuh0ih+eK}MXv<+X!?snpIX2k?aTC}ZZ36bf&H3{jZoB`uNCcV_(;=Vp}6|)E_)!a z)y*3>u|Xp56ook~fQglJXBFBFJNtyJGn(Hp$uA!IwYsJOn4mgN^}f&RcN{=Bxt7|n6Wdz-y-9Lw>^!QcO&Zr-8Y?~~j7dK=%z zYk|&a&+n+|jvb^AI%fO{JL%|r`!CnA9ZBohC&)A7!+;0#68-I3&u&YYV&N>O)bS}F zM{d?poDO0E7*GL!G#`7~EKq7{{rM&lEdf z&SGH18fY%26-_SMyJBz0uTQt<*aQTRup=ypSf3kV@8m6MJu~TUwHw!V`AKi|oMI?E zUyI)8hPvX}ug^dyAmJoNgXVBD+e$b-!HnJlufJc=W)u*Ab8)=s2wxmW(&G5^Cn)K@ zI1XYqP77fbI2xG%WAA=U3!xSrH5sT_6?k+lgz*C%f2m-f#PgM;^-w>KgR5;!xhq`x ztr~LiY#WJ6@dZLTHM||q?cj0At`jE>t!@AaF<@_mb0VQMSETtObyLcNlX&)%S2>{o zIus|?lM%Yi!4tqu*y*)DON45q5-qtq+bwG37M`=Ikrw3ieFbeh3~T2Lw&U94!5-~t z#8wNn+d5yc1k)=B24o3+BnPc~($EOxrsJG^5)Hwg6zc&6@wTzIK+M{P^WVu%b$fvu zdx!A3*tYoex3qSztCq1whBSdLd0h)A120ASQpzJ;B2w5M)%*ugtm{bKqR1uEk(3I* z(meJ3i8Gc>Z=Jl5ABWyEoiu`Tz}Bk;W(~uvz!L|B{3-bH$cXi5^)4Ey(}L(Q5MaNx z4O8n_V*T)f+=bP=;bAeL7ZO``gsg_|?}-Vs!jTvn9(^r;F0Hg7A5 z9M2AvivCQ66)|yLU?1y3{A7ZPL2e#(<0ER0Uf<}&EZwEb&jP}8zA3B*2 zo#m>bWjN{4_iEND_RtH8-UmxDIs(h^(&R(xVv`VawbVEVV*~%^ZaNiE!+%W2Y-&2S z6i*9yt^s>Sp1VN}Ydp6Mu{(4HI-eSrF*?Z2Qp4x)T*Wgq)zo4?9%u+er#qnNiP;RXG$(!valfvpVg&)2)y% z(5Yg9KBaEnlVpcpsM^aOAH7#1x=dzR%uJ5kU!)0oK>%jg8^;*K-KV3bb=;y*Tk-6liMV2B_A5k9?hFZkgA5Chb^#W z!ml@=KgG;I+2aEW4asS2;!JTeHVcy)fuFtve>Wg*q= z7i(q0QLRQ7O7!pfjAk>rJM?fNY73 znjIH(>D$F*r?VI@cnG#MS`>eghx5Y&GA~yHA|o3kgYynPPT^W!k1;hJOUKJ}-oY(6 z{3{S(qzeo7lSp|{9L9NFh3Y*o;B2pwd5DMtZ&aek{LPQLn$RpL*>f#Fy!TvsY~5I* z?=IHgEYT19^g}-VjgAQwE&5)cbsBj$kKR9;8#%ht;|cwg?$tkDKF@~`ZHhi}BTmM= z>gMmT&y>-$l%qy2Lqncuf0%S#D+I(1gi^()&ryiMs@4KT({#-KW$U&@*x>3P$Frwi zjz|=I{phZJ*&pF28A0EtnVj!4h~z6a%dVz}K1caGvT ztOY(e2Rc;46mn7!Fc+Fc404p~vSXjjIs95o9u}c! zI(GB8@S*8i!l{Ofu;l%#$?wNPzM!P&(}pVJTy%hqi!WevMaS_416{Ry)Xg~h#`iMp z`8wm-JxwuSC~9~Qs`&zaU37J;T?8tiMIejs*|gn`{dkZLJQiWoS@f+M{wsBrM=iW}WitYr!BrL(4e46G zx*-B5DR6<1%Z>e}AO`2t@jJVxB#Z2NOTC+25`N3F4qLkM}? zqpq?cY~N!qIOrZ|fij+3n#^e-QGH=z za4!Zh**s>D$8NNI&Brc-baOFynTj+c1>-d`RnU8>lIEc>oc1`_*r?&_$PYy43-kq-9xJl<#?b0o;jkpSGXD94uvLJ!vA8jH{d55lX_f*1|v2RPsVyBQapi zF&fw4F@_ke`=+2Pk3&cS-wqh_*ls+Ktf-raYOINgXP22&pJP;L(`8R+a4L$}Jf*(b zjhQfH!Fr@wX(%*D#)CLUGWva+r2ceP8E)Pfh)F>-2m~=`<`BiRKbtJ%(?B2?zYZL8 zIYv1Yi)ShP>do^EO(y|j$7Jj$X~DG?OeNz(Ov{4(hLf#Su*d%!_W^N7PJsXlbsgy$ zZvpP2CwJlwAWl?%ah}3Y=|W#Dp}T)>w&kS|qm-^J&ZUFsD4wxnkw1XR?u`!i=-=Vk zNR4CzEWt|a<+|{)`z<6k>JzpkX{l^by(ZAOjLd#!;Zz9fyq!^$m{X>5SNh1K?-5r@_OB zuk@X<-X`HAXq`Qx_$qcDZy3=OaA0;lYh%}v(;l!e|0Ry+Fo{c=gQ+$n%$5f?R5-=S zF?GNoUY_BgM`v^wjjA+Xh0}l~iobcq0jXm!#w+&Qz0{31n@`^3FZx-dP_B@OL%R{d zV7-nvyvICb#|Nz4#Pg6TxYvU^U2z*WBZ+hBgSe+d+sgkB=hO!q-ZNU+uCobRmN0aP z66kIRxlSjIB8?6n^WdoxPF#Cl=H$mj?P_=n#>KBg)2B$&4}3~j$$swW%jEUteSoJN zc)Fv8|IF%tqv>CIq1w6IvqI~F598tau z1$pVY$_uT}E@a{N0o(^m#%@Y^)!_Yy3sE z@Flf&>X8!?scSZy;(r$V0LP&?zD;L?*@RN`3-=Ra_r8Y4NTZ(bcS|4-Vv0g51@F@G z>(}#*w@BMK?=iVTPq<8mF!hs3Oiy^ui0F{*Y_G{zIz$$tp4G9p`_Ap2c{?6hl` z*Ao9r(c#z*RuO8?rHV69QPV$2x)FGQNo0Hh-LeaMiPgdZdOEdIjPuZ!*v+N@hbMwh zMi(D``wxO*_-*J+$CDK;u`5KY=RQT$?*rXh1xdwaSWH!#>uZ5VrGJ8!-DL-^bxE@R z8c^A|3X&zxtM#8}U@eGA5?oQ3-AAXJ?rjXdhu!n08}Qo**4MjUWU1HHsGpz<@OuFc zYr~fxWe1VA^SkNDNt4>}r2%n2LHJO9Bg-)_R!hqQwbg`F4TsX;Nqz`@D8sS4)d;;W z%tNRW6lhUSwvFZ%Y^Rn|Y~Hl!HF%(Wi(NMo=enT}>0B*0cy8##81?qQr-18@P#Z33 z@1qDoi{g|TvCHZs)T&;IJJsQIG{uPNZJuUL(f9bHXA8Ny~)62vF z=Ir)IhvLi@^(8tz;kUeTngo0Ih2ps4LsuV?ulO8_t$dZ=oY7H&>oqr8qc_^Tx`Fl= z@E&{l{ip?Wizk4aB!P7^aSI>!dddj15SWF)l;PIb0_Od2`-^()Bq7wuL-^L3ufV0A zaT9PGQqy0?gG@fJ)vdVmuSUKj3c9AJ_jJ)ps^OWgmiG>23+X{?9%{Tr5DurVzQk!h zs&KML_FA+jp5#ZN9Xfq=YC0aB_H@PGeg)B91k;&HSDKBnOoj9m?V z4T#P|=<3QCE&4n&2zo3wREs|C+KAHFYhc9|qZwFwK+!_TbRe1gKzu;1H zS~JNaC`I23-t|XsP>c@DaOPJh@=HK3$T-mV$?aMZ{OVpca)g!+Q-Q{OOvkSMzneWj z{e(_^MiN=`(@Y*rvDoa_`8b|{m~?%ZOxq86HzH+sy`l6l^5_IE0HMDKTfXNy$Fz@U zpDJ|n)xd_!2^a}-2DkwZZge>AE!Hn(=i^^tNjBw~#h$e4I0?ks7y3$WfYDdFG+%o= zgvOKc@Ax>QyGzLs&-4Uhk^0pu`*=C0stY4_Nr@!QHS+^#tytl3TQnBpQ1+I#Kd7I^;b3r|Bfdn z7Fb%C-MR& ziS>x!F;|Dt37roVB z_~Z}h_|1dceKaq_N8pN~=vq?5niFJgIQMCsSg$qLA*>lr>qny+`H>YsnSOIpt(gVU zJkfrT2a~pxdyi7`6*J%~X24ef@VcfG<|<&W0%kf`mo}|%6-o_ha0OJaq zrG_8JIKc%p{|X&JNb1*r&_>WE&q@#Ximi*EUEbbr{<)xKhVQvCKWR*y9#| z@FJ|94?(!3r@5~iI<`{VFzKX@zqL9mcz|>{D4D;DXV0N*!dny&F`S{)amO}V1v*08 zutZ44&6tndXi+n2D91K)<&Ux&=I-ye#~yFrJ)o{l)H;!JSebHXzd-~6z88--$_lrC@N=A5iJ+-Y{zL- z-{3%{bqpB9v(r#O@2(_#q46D9Fw-!;f(K9957M2(Xd0fsj*oP1gWBT3V%q&7uB2xR zL1*Zc9Gt+8#XB;{@4>)}-VEl6@`hurni$sl3!M^UAnXhGcIciV-Npf*gLu^0kU`NZ zU@8i|81Hx&<%xI+H=%xnFojVy@>0VjTyw*H_26`zg)lirLJr(}g>`UQ`k3nhlLzjM zEuu{3hA&zt2{j%XD`YZSVHSKppr4A$Y-c+e9<=FI3r?y-m!|08J`0GF=*rxV{*WuN zuYC?Y0OOb%*L32+<-PzO#q|{TpiU(AwK#3DmjtH4v)92Z?ZF-XW13!vdr%oLe=T|o z-t~%OUmG2(=_lCw5kTZqt0W#KpLQ3@SJd9{0p5#1gAI3beX{o$3X_&$(7`LN4}A-9PzRfa5neqYws^s8aKS1U`4SA`*=?XF8r){l zbVslcxfll1p0FL7q~p*_Q`E?3uzH;L`J%I(c$d&(!?~f;*biiv{{WBRWU9;_LSc&n zhf_>TFIH`h%jMIjVXIdK!8mVC2a$P>E*?hl_LhS+&Xt^O%Azeiig8k#zV>NOlFFD( zZL@LqMCUkY^*I{Zzp9SyFN9s1vl4gKksU6r8G{|M^b#bOqW$D2N{Tbek)P zQZBd|nlhQfKY{_>?4tX4#YHu^*+uWfp~p%|bTQ`9IEPPu57#z>5f-wHbH(y@z*p=* z{DAdfkQ%-Lla2yQ7A9h6I~J{Dw0t@SjGBjkAvTBw>8*OaO30*){RLd;5s<=e?x1sF z>WUQYE1ngsqDKXD9KPss9Odqhg+WeZkq7$)&Mx-xpn=T>4$>to+zdqE`c>>|B9-6g zDz{N*0%@m_W8aT){+#x>c;3c`180wea9v@lQ(gNdSp~Y*JRNNIGMjieF)qpX*`Uq1l4Y$+Kn!vH9Sk6>*!dY zD0_^`=sq?1G4|Tr>M!=9Bmbw~fj$P_*s{vl5mFR@S!>HDz0qV%y!UJmmZRKGczTIW z{}d2yW}$a`>~C+QBfBmF6x#ZBd?3K ztO)?yI|pwe$6zKVPmCy-EU7rEWHn5R`YeGLNYUEsm9Eke!gIEU~1x<~>-7PrnrRT~Wf; zh+;_%H=!N!N%?g1Pq&M8E^ypuZ9w&psGG5io}IWpf?pz=znt_LjOn6KM?fi=2gm z23=1R@?gf4(s;0`3nxd%lX$t4F1(|!?pzvsxHrrzydq1T!@Vzb*B@8_(#%O{qeT7| zKPf=(Fe~(X0#dwA>x zF?tV=-WX%=;o$`_{vIB^F(%%_!~1i1_WoHtE*Zus$Ii!7X^}PC*GewA4vWZRUfc|4BKE?@obf7lVs@6 zSlotDXYbG}Nv!y5SqErsYzqf*#_>o>}l; zJg8M-AN`F<#m75hhm1x)v?G@3am0Y?(7-Q&4;J`Az!R?H$;A4c&QRr?lztt7=5;Kv zm8L5mZ>V9qtH*v2;w@w_fwv9A1pXM!Cr@A>8{5C4h)?A^SS%s6wqPV^6B|mD)S^U4 zvjIqYAi^zUY{8{#b(H0-t$i%=V2u?U@I{h>uMdHq=j7|Vy9ZZRR=qi`x_ zgFC>~v478gu2YTN0|!Ab1JF9rxf9pGA4jFmo!H1c08)DT=%hyRh>@PCfJln%!zzq9 zzv0(JfB@Oa=I-{P)SCVoR^@zj4GSA}z+BjNx;yt+8iwK>Us|RoX%5UYFAtMatv*VCoDLK>r~0Dc+R-3_nAF-79<;GR|0d z7ZWyI$ySMzYWN9cTHh0cw>HN#3mOg@7atrgc1YjT#h2La@FVDH#0i1*55OBO#Kv-t zk*C3ksqz`R!`m*=D~{xWIw#XBy5GX*(|MJ;^(rNdyEmgjUGP$uKWe^7ZaSHxdSAmH z5NFT!@cxD`w7^T+4jhFxU#G}E9O9nweWv3>**^X(zt6Cs3QHgTE(PWo-e)?)?=#R* z91AT^|9u8AUR|#!?KJfZrAMvN-f#jQ;CZoElnjYG_@D_i1sAhz`tjS%9!$ z$&fLN(FLo`n9Fn;reTFHW|{BNzb)RQ|18$NT^#G5VnP+$qkVK-=)j25Q+p+dyHmw@ znIHdaR-AjSgEmXimS$O3YFUT-Qq;%h88*#&9nK&z+Qz5wHe7D}q60lIJ^+MZsP9<) zp@bMB<;V%L4lFOVIM9> zQ58W?n0*eG=G zQL>zWH)xSd?6>~~KSUHZ&JzuNA38-AT1Y)U$aS;Rs0JslcU>`30AN3jQ4D?Te8$2i zhXs>E4Zn|0v`a&g|MO5|FMuw6wqCG^`_n#7EVFbgzu+a~8<4bqBj)NmgUz|R5l&hE zpfyv}*pVo>9R=LW-$s60TFhB)Ob}E69XfFm2li@sGfW_K;)me!)`OyjM$plH5cm`E z-t6o@GXo7Sq*sG}vjt<=?bRUOnhLh`DD@%1XiTC(IOkqbUGSG1UwSW$BlMq zk?fM6k23EZd>v<_aHCF&eXmDLaO0s9DO5!!>hNYr!wCG*>fDY2ti8lJWgl>7=af}A z05}@F&Uf1H&%6l#=8Kl#YUeCC`J31gC3|Lf6OJgKCZ8L z!t;E8QLN#(55N8Z_xC6hf=&R#KSNAd>`0vHHkxY|etn7#6g<)M@OvHbFyxVP$=&6X zyZcu^x&>moWb_f_q2Di{pOttC;e=8m;|)?Aj}$978f33m`-EF`BOXuuyvUYkgj)=< zVJe0Q{m3u!%S>>K;P5ZpB9;1@XWQ7%0Wi0?89t>LulBMx(CL-q9OFUeW=NUEc#C)! zj;(s)$8&b$=&u|{e=AYS``! z`5H{Ce`03QZ7!_sc+!U18Eg7)Ix2(kXVdH`XgP zoC}7Y=xzA*8g;{;;8wii2oUe$`vQ9t_JMOZw1Z>BgIeHSpLHINUJk|jqam_CvyK;T z_Dek2+q3Ufq;utk9vt@->@Nx6!SO*49;D;Reb0gGYy;^*dht4iP6LbHTy-Rw1DYgl z`{XxC(W`W$FGOMw2iiRpzTv0YVrn=Jzo+4@FqVm4+V}6U`IT(H#s?sv>-|o8pvF(z z9O_nFIzz+}en}1Ai%u8pr+UqGa?=lpGv4HJ21+T;*styQ$O3iQWph>54FXpv zo0NecJqqlN*`MHQ=sG+Fo?V)njY=N}p4X38>V8@Jj+zUx)?EUz$MmCgm zdcqH=W7{65z7vS4rx^5GD{P<>JAgEBV`EIVVH_bQO|KL>**NfECyf=UQvcYi{;NH=I=lu9p7rHNiAy|Y1 z2IQRdKsJ|76!PH=3(fPw<2zeg=ouS(=tWBC_MzXM4tR0{dD56*RqdEyd3~^Obg;Hk zTI5_>?;O@R(pki!inGOuBp43Q`Xj%S1fIGF0EcxR=E@;Q)(J27gb*XI{YxV zvjS|vlrv5g(a(3EUNn`p?+n&B>8HaJH5#hx8)|E7>VoBqoE0^7Rj3wNQdU8 zz?r{pewudJubK;t6SXTAK{K2;|AF!|mvIs4=f{^;FQ#^q>LtrWJy_IGRqL#(Sp+el z(C($R<>fbal@dL}h#o*ore?bh7u3au2zpvn-U!wt1*={bxRI2}O9^vBO^~(FUB$l? zrn07N(doi4%$bBCD=4e0E4x`36pU+WJw`NupHrr?YBXBrObEexfkEJ-UcYp4by={X zt~{wyvc#v$@k_&KsIEmXJ^9^xL`K8Q=<$EjjJSjhA-ELA1%)`5R+TL-cf!;I<%`Pe zoyEVR_dErC#UgVOl`Z6!y6|RaS#7N|fM2g)$aE`J*Hn+Ht*OW0FT(_c)v_PIcLr)2 zs)KBh88=A^)KmwTE^er4sCVWh<{%7yQ2^Gk$XU6xYH5&KX4Z5G8$D($)D)j0P$B68 z0OaOEg8p=c@QRox^K0sFAsZ&~>T00>YBWQY$Owq>CC-Hn6&3Ig!I~N;2CK4iq_Y~1 zfvjiY&2TTGg_))P`BUfmi?5vFEURARB+%=b=_xHPzQS465Ntrjo2fsQ4fW7Km$98j z$cLIwC83WqlqU=TVM`m-yzx;q^%clxO?gl<%dU|xx735|Eut(kzD@6BmVdL z;T-dZZJ|4sgfFXrWYi_V-j34EAIzoGBW zXN#a;a4qNa{Mm;hS{>;gdg}8M&^!$%#@%E}vtaa1cZT z@%QS3@i_e!g7xuTi;fS%6R?p;EAg1_I)Yz}$Dcs@JknPQ z#v3YwQotYgIVzF*vAw?sY0vlL@lPl{6pv3#m8A7}!)QIyS3BbIFOWX?HSlSYH1ZqB zi?pxkynM@5lH6#Q&*_<_w8&|8!qa6r?LXu3;ev*eGt*0w3uQ#V@wf5#a`ad7WZ6TO zE3%x{#d4N?N*0X`eW<<{e=+dgONeP%due>A?sfRv2)%AZ3jAT&a(|+pAE*`hb3)(D zFeYc&@3a(WIW|})XE~c~le2Qyr+BmS*QR>13PWlBtR|23pK_0^!YNt#o~&HZOwMwk z&g3k`mjON`@2mLR`*1u?FW*a-hiq%D)3dh7>n)b$J+hRkLr(XKbE)bcc11?EhxO41^*@Pf|?*atl>;&K4YQyiW@5lDkV^$#S>I)+>qKFD1V`gLUal?W{zFUn-bX zHxW&aM7ws_JG~f0?KjhSt+#rzoNH~~tlSWdm*x5%S-HS?%+c|7>Ae#54&zMi{nPb+ zCiyk!{b2|Lj@|S=t&89D;8%-zce9Y^P752yE`H2@nBM(aZmZ+W=A$u&WXC-*UpHd@ zlHHo0k;u4!j{)xy?X0(Wvm9%w-yxgj$sSn_%niS=FtV?ipjZA9k3UW)oBw*8F3&n9 zTOT{~I5E2(1Qw5i-;$m12gvhzwEnbtM1CfQ@&)h{XKb%)9(l7i%GN)eSrKf8ko@GY zPQWkyfhPG`<)1?KJS}UZ#k$dQMmw8Ailuo;|6t|ZeVA{^OWrKIWiIBUH)9UIJ$y9z zyj%~uEuee;Z2jo6?`c`J)^pFSHa?y+(G=a~a>9?E6!x~>0;?3`HVulmywxMiIfV@$ z+=!N8sZEA4O|DIbx#5w1#zDRp58|o={O{TI!~7P!p=_x-qk6cUWNTsYJMlq0ezD-U zf$X@M{NQ?;S8G!+B}1vctTx%QqX(N1FujEP^JG~61Wn{mVe>A5PMRmQejNM+{yCx7 zF8{>*Y?ofA!eLqq&#YKBRy3aDAm?0McGQuVE?=9vKBXed9ZGAqZLr>HvCL(*N%QGC z(6xb%rcL+H;Y>F}wTaX$r=g+`dnkakCxh_Yed%tN!%v;DkFCtj(g7UAzuUTi<<1eX zxjxYvPoD*%oaPgK%<}I}#cK#&U~%KS>)(!DlEPsc68hY4aZ@7oVBd&kgrKJVIs`sj zq-KJt$v#@+0+yP(*eEijC;DLNW}p5dRnpunXW|d0a@dqRU(ltC)NCI|=&V1R1btk< zre2Q;xKfmh>i@?R^WVem-q5FFTsuXY+QZFA`ib;>k&YMXRFTdWX@y9aiFB<g_dqn!CNIw;6r$|#XMEfE=U!>zjI#r~zMOq=!Wg=ZG(tAbPy}#Yz!&$sNr=WL> z)cp5E?V{YQH*Lz4OPsm**L3ro<3?XRx4uENe_&R9&nOE<(JB@u=aP!QjbxDcsT80 zRB+ffkxG<3ShH-8aqURT4wTsbiz`P_-XZ8ot{c0Qs??!EsqrTf97Rb1LCQQ1*|Vw}s-%?b zIi*862yQ9!sk@dOr_xAV77#;APOj39ex#IfC|?-^8WSp1<`cA#m$@O;r{H5Dfl>mL zRps9JmTlCGIlKEOEt_&673*cNT9Q*JN7i6pD#@wSk)bVFuZ5DFHU$~WU6s88iF}oP zkt8dGe;$(B%LQ;4K=0>-6A6LeV4EcMk!Ph_U1e?%6EG8;`pDBQcU4Kf{~<^p1nERh zYN;n0IbZ61D5>!3(+Ufu-d`sbF6&-s?a3P>ws&_g%uXuY(!KD4q{4r6FDyzb{JeYN z6-k9@7%%i%bOqARODc4AFRV!_^mH#=om6;z_rm`Wh0ma$>rO9(hSRO|uV1oH@Bb8( zZ-H`Sf>P@J7lEg-dWGY=ja4-ps~V~I%Yw86q~9f2&{!38YwQg{nGWyY8`NE@z^HbL z!t+sBzzfr@MF~Nz!ZxYym8aD$kou~kkb1$H((GJrm89(dMn6+G(d3rp>>mkuj064T z5}Hd5%+O`Bi2mf$9a2BpgEVD1b15>Zus_X!{uRKYFhYel^FnH`tI#10kS)Y>nJkks zSP5$UgK)R-8YF&ljehb_DsAMY)c3AZX`q~fNHFyVnV0q_FN2Wmb@*P3G!OL@zIgUP zM``giS6%woLh17p{@B84J5Y$MSUAm9k*}C3%4MvGEs}DSW1NW zS?qAVDQl-vmj0ogl-pUh8XQvAF#b3gClDfDs@~CpK01>v4c;gKs^642vCIQF2!ypH86#{V@vA z42RJ>(j_{`Q>+-lbcyvCE&LUgOvt8O!^%Emtt*N~jY%A`OP2n`zaj`8DasLi_ar$i z6YGB%M)SVWTX7}pMuNHYG5D~CrU8BcQE*kK;@ z4rq!(M!}4g`Xx*;MIrNG*nAV)M@sWx?zHqAt-?-~&tZf;^Xbrproewd)SegpjzNm@ z7?n+Wnn89&p|VRKV~|6koBloB>lidh*#K5OJ$Ez6sd%a06fU5PiO{o{w~(v6N0gWI zq03h$z(#srX|Q^Q%2a|%zh#hHalqI0yq0uh$i@8 ztZVsLN-Rvxx{ms2hN)TeIArfbVQSX(oRWvBS@U_@JWS16Kn%?=HLHw6JWMqq9;Rk3 z;E`rzV-lvT||Mjax|su>JA%QW!Gs=FRpZW4{ib&V~{Nok}*hkV;+ zlqo$SqP&vJEwMmcUPT3@r!iC}Aeykm%tDprCd#Ijp?|q@s238ZMVbAE1xB9wBuBUs zl|Bm*Vz0dfM3x-8qN8UfR28cp! zTBv<_T^mV7HRXERVv3#W$ zN%sinQV8k)N+MG;@}u`ri`QXlDe|Ajpi&>~K{l~9Q>gJVUd@Ju-S!Ij^mWK@Ed`;n z3zg)9yaST5ml}MV3P?1C1bxTsT#E7`Dq4QTyq4b`50dN%)lIj`L@(11`uD>IDcwq7 zKkSaut<-4$8zi|0%Q;xbGpy8eDZ3w}mkanpEx$okFo*@LvXuQ2^=iCTrmo9Bi^B1& zZ~#-ocq~Y`(hZsCt;zm_ifZ?YUcwsjE-kXszWxWyzIkNWv`6|9C};9pgo^;57aFn$c1UO#H42LU?|lU}}3$e-Bm+S0mesAr4?E>uS*zb7)1G^AZ9v>FO61rrQj>RnH?uDZvDu}!&a zUF)h;vW6a#Q_2}E+FQ)%P}+i0X~-0Tz6&fim_?$Za+{<$U5fL3Dd)H#dziOkS%&i~ zwHNP6%3b$^RVyo*o^sbl;+r!`6u!eNq+9P4Rww0@h@vmMc#Vw++*1%^>>mZt2B6?6 z0pL9G{NAjK>DDU~yuJ~oMZ8FMOF8{|bFoS|%7RVWkck3Ey)0+=>4eX@N#Gm1s{c-) z?&hd;Yg3}Jzl)+L&7uX1cvDi&Nm2BYSyY~=mDz_AePR~1Bx;>2icat%(rS)R;QI6t zo$YFWz9<^~i=qpciy~M+lEiS;e$b{Uv`t7+X5gFco0kGPj*fofgQbhCFlBikk0{Iu z_n&>a%umpy9E2ycd5>5b6-|{ac=PkBu*mF7rJ^c;&K6>_Ka~~+_>`67X{C8m$mB#r z^4qCOUrD-n1MuTu&KIvi<_2V3e-~75V`w0~TtHrI8M4zY%TaO2A4K_2C?5tEJ0gdF)X6YEX?mSM-J%*9ZYHfW06TcN#75R(eOPSvC^0s$gHKzd}N-d%u-~& zp$xqP(1_6)vmO~*@WN@73dXQS;D!p^vfPOzI86*`5{1o9(NFh4&hvh>Eyw$# zzj-K)+L4)rjK3E$bWP-G%&bc;L?-nleLs|(A2Sn}iI@sw79bO)OeHe!P^J-?Rt)2q zHOMHCX3Pd;2BV=d4D!oQEF^`gbW`ISNi^7>ToX}m6N0+!YPwON1kfJA*J&%yz`{v9Hf7p2~F8jsQ4 zDHy-6z=p{)VPJw^PPx$jW-wrboVAcMmvRn>qLqFabsn71dK*R5-wc9}+Dhy1 zdKRl)buQN9%ZNv_jn?0%2tF5t@&;CJ$Js1f-Z^+bz!7YF!QpQSW;;?2uOAGUZQD24 zN+4b*!LM|&o9P5QgeG^gjmkC#VdKHUzC%DEEMM3R`Dj~wKtymT0U@($Zb3~!hCm)f!JFp-}GA0~3v`3aGStPMP+UL?;OOLW;~Gy!8%rM?QiXe(^+2Q-KBjC3gt<79s#%@9 z6KNuq%dGRvs(E9;gR0I#W^{MTi-}D$N`wF=2l`2Jd7<@j;zA^UCN3n&8z#H&k#P+a z4N?eA^Q)ew6a~?|I}M`PX#uwztVc|l2IdQy79w*gJ=J85yah<~Xtk($uSn$^tryea zkSuC}kYy}oSl5to{aTQ6S!P;jB2K3Og6rrtQT)Bh@fz!$Cda7B@kx{8KH~WCX&ia) zDEu?~m=hW7CW)p00;6vB>J@cq2Jhv?mSu1dSl*ZEFK#oL>}XH{JN z)YQsGv|BnlY1Yn@9)1ne8~OInKNh3IdkUB-0gWb zLq=BIMv|d*Yh;z!Q8z-j$62@Agf&_>(TX$B#Y6H*LE5Me$>#%IgN%EZC9PV=coMh_C6=FuyP8#zSunolfR+!YLX*55~9=rcp|xv2%c%t_)ZqG(GW9Fk9v zw&X+d`9LdbTs0)V42g#!vEKw@Im1#E)~OVq`l9ItI<&`9jn2@Y4#_7T%gQGvyCm*0 z7RE*{A_lG1!vyjgs8$FznS(7($w|p)n#CKLT$0TxnZt*!05)1Fh)8ZS&8@XkpOjV&hSptq zyY!ofCQ4m`uOVtNv-By>SR^C#WF_yo+jL5>&ZM$fu^*JN+a}T`+GI( zZ0cf!zI1QOPg0q4ttoxQwfZjFeIdS!cG{U#KAT)>n{qRiCnldnT=bbD$FZ~#Hevgm zzSe&;F_~@LpM+zxA_?0Pa+G_)*f zM3{y_itElN!Q=*0`PKy_sFTCVl&>hJvc4s3%D0qI`8_u394+kHsoa`;V2ZDnQnilG zb8L>zL1k3U>-i*`*YjUf(VQBetMBXniOc%b`CM&e+B7QvjmN>1tGWCMho&iSqjFN1 zO)=%<64rFGy@p0cb#}ClIFHK(T2{|;>YApFDW!9XZbO^WN-B-ex4jGP)5%M}r}E@o z?9S6eFAXz8K9;98+elj8X2>qDAlau2>*rCj|N29+IUR1328UVp zb@l?5&FOAvB>_%=a~M2G;ARG#B=-==%OFqabeJ$h(%~r#I2}GnfHDTV^soamZ<}Ts)IBzeQN@Cmwj^n;+AB$Ot1lF@a>Sw1=E3nx8yNG{2AmYyNWv ztodF7dBw!9HSaN7G#|-;HGiFeX#R~z*Vmsvuv=I<`~2U;l6R0r@OW0tAU_!9n!7{RU*eLDKTp5K+r6pm~@2TVefOlPCGLSL`ButUnOnToc*fA_=2{C~ z;Ki(a+fci!iF5N=3<-Ki8u2?g+J?%x`CLJTGSfQcBVpl1e~@8|qdSEpH~tjEJJL|? zEGuQLkXVUx!OTjeJQ!6|)urb5Qo}p0%S??vsTBoMuaVH&D0NFo?&{fi$w=fh3=1zG3y}TG+rSx+Zb_4C0`H_vQ%p)7L!@SxcUZ4f?6@Y8> z!v^N*B*FS=rfZ`fVYyB}!lEBrx!!$jr9(fqV)f@&UG44iV9{>sb>JOJQ+N-rpJ&*v z9|anCtRXW?l74FL0sWxSv3zU(LGwJ(t=*}m!F03gL-J&Sex<8S81vD;7{ao3LMZ_a+zl_P;3(T}VZC^8xMVnHN#x zk_2jeK=FfBom^hUelhiLP-;7=+!>S$=Lv*D>^?2B}Qr;0RzK45Urq-VC;mTD#dopzrohkpeL#%w^H7 z*G0G9h}NsDN6)51(NZ6Zmik*rZM5Ra-FjFS&o#qfrMxJ$ ze72Tqs^u)dh4y}blv?hM8uBtiI`qPDpJ-XLrH#H}E|-_6Wy*=dlS>|4? zGKGb^-sEGkQYK0*cl{fwDs-a|-w7AEshPI))du#WZj?ekF>mM~&2K!%Xm$l92m7fUB=}GC<>%LzAi;kcXA=CL zmJxe7fq$m!KWn5MtMA~N^2be7Udwsal%Hv)vR)7l>&ti_kYh%y%H=# z`N}|djMa@@enLtOXW5mtgqvq zrE={$DvxG6O}XiEoJP0DUwDQYztf(jHSeN4Q>d4teO&x|<7jo*M|Jm6qclH5`a!A5 z_?Q4)<>IFs+NAY;kTN(vGb{SeZSdpsequpck$#*S;pcly4e+D#zsUH0B#Q z1`6Z($C-a{i{*ys}()@fG7ZQ~|XC#yNE^&K2FRDku zx<`YD9(ATs^`;7)LE<{USxrv{((Q5neP;6+%TLk%Lima~oR-FKBKad*iJr&L6{Y`- z(8w#9U60*q6Z08cwG;FCKo980e@6|*@so@vTt(m@fqVjKeoj4x^QcCT;S~({LKpLj z?58K@GqygOn9m1#CO*D!0`<@ysJDv zhn6?+YLQn>08d@cl~`RzYu~dZgqL2v8ya}pAhnOg*xQDy+fw?{w&Syow^GJQ1)qEV z(^S&q1AM-Esss~1qBkHrY9ZulZ>3%&)u)-NxK=B3sFm_>q4ExIlGN}JTPY)CKp&%l zU!-g3^i~gkiL=V;Mc;AqpFvj2u!+VytWJk?s-K^rwV79FO1-I>G7;`E^$DFFEeWZ# zeJc|>w|z<4YH#T0eDvy`nj&6*&(s@JQ(qA3_l6qv++yl`Qk9e=E1tI`eJ54pQT63q zqdc!YOG(kBb4Fzj;MUMN*}n<`_&=oLcM zt04abvH8S1oJ-^NqrU}oYl{NdHm6pbrNIf44DYWguN=?5!eG z|0=b%M@}>reypuXx!zd#v9|EHRALMNZY-QLA}vHMOsTPh&w=Pv*A$eQAxYM*GA)JeQWWhbB$N`$k86&Z8mq$Hzp?%qrRh9M+H`Sfl)@LQ;?yL?r;`ZKybyW1dYtCe?d66Mnfr1?2@mo-#F%lNSc)P_Es?NY}| zfwKZl!k(R5=pvZpwanR4$+>Cti-p8OA3aswd}0*)l`!s*qur<5PU6=g zIO1VRjfs-VM(>wepUPJ1WfDeNrb%~|JCD@mPwI10Rf;P2LO|-35;HZX%Fee^lVv1U z8d8WZRc2ljWm#&Ic7r6E_spUuC-bE{I5U+adA#6^;V^Lb82LyuQYCP*~qMFJC)m?#(n1^Uuaf$2IX3 z>sG?ganf;ZygBLUkgH19#d9QgQoY%0oASe4=IcP$$Mba`>sGF&e9@t$rE-xk8kyoG zF6v88o$-7Ls^k|`=Iej!;`RK7}`oZqFAuAAs5H&W06Urn!ZS*(;e@ecRb64l=zp>uz?y8NUK_m?h} z+~2cZD(Q)P?vEepUB%HYjNI#6E~AyQOz7O}mr=d`Oz7O}(KJ+gHn0!4*Plxz_d2Fa zWj?IDQ&_maDK3jO`URouXqq|C_?qq`Z|^}dakqKr$bOz04B)}MTfgx$K))Pxx5Fc+ zFMrnfH$^1yP4P)CHm;;qd$so2*_(Bli)`w(T-3(2Xz%W$vN`i^(btN5 z{gTT1-7QnzK;=`}J+1mpuT{5GkzKS#zv*>=ieq_RuRA}Vgwt6BuZV5 zy^p($z`1u2SV~|ufxI=ucHYfYQk@4|((fej5Rucj5lFm~z~cn&BA`zn5--SS(bjl5 z+D|&KPm(hceNK|*=g_AQqwgX?d^*xf0H+W4iJtt@R^M|?kn7F%QH_>)-Kx_X;%q*i zg1YA_K4HK+STm&a(@dkN{rlBY!y-$gM2Y|`htCO{KFfV4y6_Jv=xavbNP+V7%|=*v zwV=j0z{11RAog2|qPKqA~?lm&_AI zQcsYooIq7(p;WPs6dgRXM;DuRPxq$ixXIa00X{B)=Hu-&GUNV53`_4OaG1cK7#t#S z+^+~6ATXam-eGE(-j`YoxQD=r1ny^WDuL2_35+H1GX@h0e8k{<0!!|b2>Mw1?^|N@ zuv@zySJ35z*3Y3M=P z3hB98*YWaUrCuzwOEs-TZrr{s)Ef+ySYl8AXNuZ<-HbH zB31uF)nheAjFnm?ReflX%o1RwZWr1RL$hh`@{y2E_eeb@k_x0H*`1OmH1d<5 zyyotp!TK)XV27XJp__9r+r;#!**IM&ljo)xW;|w4W$Bd z+ps)5Cflert$HK$xUMezHDzpGElhFxcFOPiO6?B4$r|tg^8e2G4@sTg4-z|XvYv<^ zNyS-I9Lo#Rm~x{~@=>JF_wjwsr|Efw==T#t-WnpNCy*OYc!)qEffWpnC$NjbFapOs zOkgyDDGYK6>|rpOz(bD^C?gR14S@>@WHI=+h#$*eUV#1&bN@q}-%g?ayZ54(!H6?2 znFckzAC>+>C7JWxryGUS~w{igR`za-4Pv&=0sW0w!li1Z4cWb1eSF9!}=!?5+q@cH~ zT`umX^qFS*<~`ee)DbCUUQN{}I{c0+S-@KdD?rX&i_8|fzM*DBrnJgf@)=ka>h&4e zDmeqA&3WqO;;>cd_y{^qjY!pPsNx^a2`$43B|hivQa_Ta*HLvq#By6+ zhenChzXJpR1}=ZVFj*M-Q_j(GaG9%ESgJBm^#rO$ua_#_f`9eadR7L@ncTx=PTMzh;~Y5uDPq@` zR7{z_Tx^6+? z$hjZ#x;s~sJe?o^LcBUZ#y?B>(a)*n4yPI|w}}DgN9Gk><7OLO)8uHs+wIM+y81b^ z%$p$deFCDZ&bRS%jJ)Kd$$8Iq8&)cMCOjv4UP2&`ztlm?*+3<&+hYt^H?F5qfp63RseP-tK(ON-VdamF)F6Q=PVc_ql)C^u$ZxF|F zR)5J<>#O{d)mKNq71<$g^RA{oXNl9^Gi~BJKjIB*hfsNA_MNWL2_og&D0)(vRzfco zrq&7@{kc_!t~F_8gwP933wjFzcQ-1cTFi}Vu|nvpO^c`vV9IS$#n&2cH%<841n9d; zHn-}$zrEE;c~+P>?>}v17;kXiPyJ46--PtDu$rajUT94C8ddzuulh5(N~*Nu-F>wA z)`k-)PwA)8Mq1}Dq}|k@;Y8@g*-L+^LoTWltqYzHQ6zjgm8;yhTYHTJXDv8;Tg88N zi1VW*MCmmh^;e+2yLCZ5WfS{vzu+qOW?`>oTcu7=S7 zC7x+2`BkGtZLj{r%aB!J^X9R;^%nbvuW8x5|MJu&5o5@fzEg|{zGUxdOPYPj@~^hd zvyOZbTsI|WKgl{7XY*rTrjfQuJG<1LKwj)~lzg`sKgVQj*A`E=FD1EsD@~{TOp({A zF}>8jh1BX(Cj-up_n7vcX=QZBjw0$q+qU_(xt2io{)*alw;rIsb{4yg@2p0-tkOQf z<9@yA+N&^MpGn^?XP z^h+m^y-y}U7n`YxV|3sqebVeRdO@k9?Y{K&U^h+d#SIh3xQrpv{phG7wd?z{Hk)ju zFU2O-epj{8k39G2oJbYNpn^_)sfn0-MlXH^dw|#3uwDiIa&$k(#%sNjlE}#eqZv%~ zAeR(x+VEI-&SjPVH?CzDXy^V{*TR84;6Q$3$?9di*t@IakMbPfr@zg5Y7ZLAj%LgH zGFkhotN)MbXM3aDKaB>P#ztG3tOtBRycq==VY*%*W1tI3;$2-BNNl<#vysan#t1o% ze-z^Qu8uS{CwQz~2LD8_TORzuUdJIC<7BUEE~a3}*}frBv5;yim^>6b^yNO%XHWK1 zmtIenUMcdq*J08t7pa@!o~~$jqY2ehJnOmLsZrWeaYU51R6OkjidycrqGx41t2Q#; z8byb+o)lJn$x-QJsLXOQ7|=~%qxuaKdoXtzvPq98db4sR1Q}iN;v2Jd1lco@i&ga(alIbD~4WjFhM~$@3}8JvXXIlIYuqOaLBD z?ktEFf`O9`3S-qt7e&$IL}wz=4x}skdXUI3=gVO0YQ5x#!f6xvyeuSrKYC7S2ttoi{IidDhtQ*fArU>n^UVUsgAA(Zags zVL9Y*;M@3)AF(_XI@tM zLg3#FCwHw=IX(A-$WAL1XFJoKW7g95CDS&cKikgt-U7CZqFu~sT+!86 z5}Zd&@U7<8U6MGiujB5CYCKLFHPIl)05hqDDRQkE@ zIvGA5DtuX``Xtc~jqV%DAJB5<`=KHIW;!Wq?IoK+L;Hrt9kb?)$DRE%)yI7{WlT`x zwy1)N9nR@ayXv(`_2}4L)R>#y&f}MmmY}+KI5#-WAN;I2n<0vA?KNjX3m`DlM#3$2m0xQ=B3-w@{@Y z%FR~i)u^!@J6}^XJ978u7N}#7s1Fiy)Gt;P7O2I$oaWrUYIdPYEmX@6sbifcs&^Kv z6@}q-MK`G>P3owe&Fc5oq4sq3K&w-sR#vFQoUKKwu0r+Op(eEbK}{@FbsehTKGpq5 zvkE(#RLZ^=)P*@Dar}AeqzbLd94BpkLGH*R^*2?4!MJ%<+fp@xM9wQzCse5K;t#1$ zR}?zC+g1I(Z3UIv)k^0G9Xr*#Dkr_*vh?htB6ZiQjwzqb9A7j=E$vV}b5wKAS|7)q zt2)#%N7QdykGwdNny7Vg?&$yf(zaYR%&Ac;cd*>qQ=Uy%E4DB^-ywZWTF+m+y!6W*n4uRgg_|U+A&gVas>(qCv zoVFr$g(_6%?NFngeVuvbQ&g`e@=ud#+)?QGwy#x$vgGXbrNUZ_q@Q{@#ZE6pk52{>xYSL!^9%afd%q9TgR>4lf52}e|g(^RA$X)UCX zeA&uT54Gm(*5D{7O+DJHQ0;Eys-;d}XQ|rKx+Pt`W)-UYTH89a)u|O~c;WscB3IO^ zXRTdoXY0Pu$^F!GBqybVesJ*!`72E|RjBJ*3f1>^+nV##2di_`&7lhQ(dsny%Me9- z4#A3C`gzPk_3r8lbwh88j8B(TsM|w1Y7I48LltkYF8o5>MTD#)U#Urj?do_Zhio{H zd>l&PED}oC%zt0wKaCqzWsb@_q%NSLd};L-^&67#ht)LAenS#oTwRl{L60r!Pdy6N zw&udEs=h+Ky4p#m*0y>)NYNS@}F#KQQ@SttLIi% zG^@R#LplgTP99Z;I0MqRbf^bbIEBZKJ9E@|(~4B@w(REnGxk@i6&(@v&rr=OXZ=%^ zEa{6P^5||gh-HVq;6FwDXZ}l({eN9BGBQ#<*jlr0=dabEUFztX7rDh#{704V`l5*D z=WKHIV9Fai)XTjK)k8}PE1g>?i>xi`R0Uforkm8OEt_<}d`d%gUF#v$))LCFDRL%N zIO|A%t4%%8TG8B2A$3MuEeBqxw14IF_R86%SE!>ylWbL=6B^b}y=XV7#9dBGq*L9| z;_Oqyj;Qw5O=^uzBiG(qNbTFzwtwDw_dK<}HAns3s!$tSD;BDw z+Oj+E&)BKnw3^m(SIz1TOV8f~^H=3GY2(f|9{;q3^xtFedfnMMy~sI6m4}AgPZo{L z&DJhTs9|0`PzidZ#&h{H{^{Uq1ycFtEf zw(Oww;IAa&#uj$5`jFtQEbV_6{n zx)nx_IZShWS(}liCqu&iB4@$m89I{HJC<`ut!;Jm7$(pP-^bYziR^royH?$IB0TaKs~EfO>~RBWq@32bboXc!n8OZ-lbZnxW_&B{Q>bhD49 zn?SOe{6|0e$~u2)t@T{r9K8?wq00o77dbhbf}a$|+LIcc|fq)J&)EqhIE#W?Ehc zJ52@cPF^+*W13SK*_~bFq`Y=#?pd_gaQdBB>GX3V>ZVo-=FiBvwMElMO)hFzJ!@3G z)0R6@_1n~`CRV7tv?2=6qIPavqzWsVr>op8k?E>rOK4bsc0g!YlKMkDdHAy!RRa2Vk)kf>u&mJgsmVa^4 z2eip-*rod96kVV$PE-9mcwsOLlf5Hhtxn~#Oz9fED(GqcPww~}{-e{@az-Qg&pOqE zb_J7Zdzw>0Nlxuf=)i{U(G_iKTALctQA-1Hff}8Ywef-TC#jWfs(V}Q{_M&Ro&LMk zE0$x@VOxTFY{f2Trg|a4>~X$s(cxy3uXSqGNk;WbQ>X2lF?sGp8ZuQ}qXtn#)E26N zHSNywc6G8-(N2@6$jPO&xP{XAUaN4_B(=4*M*W!*y}W( z{^_~9r@s=JUN^mRtI97_&rrg6s#wJcZ~mD zVUko+LNl!z3qq;KMzV7wPD)re{~vHZfPdv7&I2xc&FZY$T{|3H>v>@YW@-R zy0wo)=q?vmsAug^rme1CSy-$79iOJwuB=Gk?NqC8;yZS4r&62xIzDGsWo#T zuC!@CcO_}rzTpX4IW9UkcS`%Of0>=DK3$fkHc$wBvaC?u z;1n+1Ox_&gG*wP1SI;dgEK*N6g_MkWW4bP~Q?E9vj3!A>+E$;@`DG<>|7jV`z+XFs zYt==x=_o2F(pD$vtyRL#55CB5|A3kta?A>1$m;UtPDMgR!dCTNH=Q37HYKPmXG{BZ zJy~dhqisx^?60=59eO66$LL)C<76w!e|>jmx7Si~(aVcIm-;M@whQW6@@Qh(uk$9e zM{ITLa-9j;DfR*WGlBo)EtqoJl-*0WH=kEjpypA2_^VNc&REP&WSr#Jvng?2x7W>}lwBWnJx-RdYhdvbENs#7-Yj?l${F%flZ zYnysuUXMj4oP4(_r?|ebA*{04svM{3P zgsn%;XVfP9?4p87m3n0Jnxf9#H@v87_c@mnTcJuiq7JOySL8IS_v{XJTT9`a>JJGO zYAl_6Or{g4A#!3rvrxTp>7hnCorpU$J$+;@ozKx#f^5FRaY2(h9HQX4cXgrjV*5_j zuQ0bLdt^~jHqF-d>8kpWGnB%lAg?@+&H|ju(M4*-KGj5nd*!9%pBv*zi8n(>)V<3$ zsZZma{+rZ$lwy9-jWgN9icU)T zjPUT%L+$OmX=%Q>d&dXrBRVZqH+IiaA1}?JW5pP?;E)=Wqvq$R9C}T*~@7 zPTCSeCm%DtQdQ_I@j-&#EQJz2U>$X`)TxEDQ;73hNZn!Ypxyf+^`^a}ptAWAO?#(B z@AtB}z?U3CS+vWL{ABD@*Du|tBHd}@zp{{$;C}UZe202|B}LR@w4`P2aw0UZ`(@{D z(-}_n2@SK=W3A31I*oSB()ShRaRIqs3KAF0Ni;E@)~g%a$x`sx~S%vR+!jtx~RU2oEvVanm@`MGR8xv_da)slp{G=R+w#z~9yh!fHHSohM{6rM*{q>a|r;^sQGl8AE`UCdrH zkQ_q>h8vkedM>H2Z?dWy8Wt_AZVWfohv@=%^E}VpVY=W<+_ekm6Yt!)b<4dN4A)gJ zvvlt)crkYzrnsRi-wW$lOk+cx#bMM?)!1a!H;@zA@$@B)9Ii_mb*Zs>Nw}UKXrmf_ ziG~?!tC|)Nb#e7#t7hT+<(k$|-&{98Jin@`N^WGN6KC2y3clq{VUCV)cz*R#(opw6 zY>TXmtE(F*3hEo^(z!)}wupKOhpXnzt8Qo-t@-Azput{79wKLChPnGQ!lQYxU@MJ7sYAL5PXofYTlBoDTCBa?OwaX1+0w)gT0$CXqHeOJ znzSctDMS`gtZFw4wv4q6OX}xaRTSx3!4-}3h%wx_sJ^b2x}_1RYn~TgS`}VI_X)Hl zas>sKj*+?bb=6kQa#Ft0bjh=p2bZ17y`BkY^XMDDGTF?ZGczpqbVGIZ#o>7#tf5Zz z%>|xYRZR=)>%6)K4{~fRrVK?&)-+&RP?DOz&`n@QGxBmn^}MF=BAtB5LmYSEWeexi z3^X~89i@kuL^h7nBSh(B3IF1q9(Wm*c@51p0<~oP!YYncaZ0$Us@5V!+0=UKzK((- zYE0(MrOHL*_=VM!%&O+kU!tSLWIzs5xTt}Hkn44z(ObrPO3{R%uBtNl56|GLOf6jB z8q(+@npV}z=T$d0hU+heb#*jIx^`Z}Qfs+rOy=s@$;#>2pnz^@ZqkX`YNpU7?@4Iu zY7R7uoDdd2l5_NA3(sRkfH|K4kG5*~4i`}2lu@5-nlJy@>*K_AKRV`dZ_Eb??p^VM~7Sz{suB}=`S)Hef7d=$q(OK9SH9(Zj zDPdYPw)}mq+@8~#4q41k?NB{a*$Ojfty(vl$SexP`X#zC3n4|8TAXYRg;t5Mp8gy^ zH56BM6b7_jaJJ2`mNwQk(EYR~j^~>BR{hfIB{hrcmxbx>9sRGa(lR*sjc&BA&YMej zPCbW9!l_xVeaZ&tL~F*2W0!8xUQEHn?x&D$Ucz0QG;YCPDC;7v?lz@x8`Inljcrod~&Oox^L$6EzE$P{XRG`o&S><*r#gaNLHS zRBP5D*HX&Bh;-cx>0L)NuzG%!`t$Vk;6v6m4ke_zb`n|Z}+b@g>~d2wg5;k0V>>QL9b zhuPOF?V7L%`eB8Pba;>Hzq^LP=^PH0*hu4|+*pdHq{YDy}#Rs%^li&y^dR+w)Zo zyPI_)XI3qVa)$N~yVO*0OfV}2H+h#WYgob2!O4{aO0USA9!6)9kGUsaik6!Am|X&6_q$|krcf+Q#YCcYXD7dZ^70|F4QX|D?@pLbm57>$slZE zU(}HSb4QC*C8Mhsnbg`fTox>`<}IqHeX3debc$aZ7Drbt=7h1dMy4(Kg;xqa96IP} zKC%{e`ex;UUEUt6fqVASA_B47E$5`U76((Gr1Ic(f$oOFddL zaH~ff4!p*rWdL8}(XxPN($g>eiL;ii`JIK*9HEj&vVg-LEd#j9qYVe1=h2dZt36s0 zaIHs61m<6W;17=kFn^Oae~g9(dw=26JH<8{A3(1m|B$EG#GqiqGBkuGwlxcIfhfiU zTNXhHJrLu67heMLXccGiuYLaahEroSq+bU0H|#Hy>Nq)4E(9zS?QN_4MS(f=JQaV4 z1jyg5#2?a&ezg>(%RENFD_v4C;0-RR{4;?tlX@_6y}yN`;%ryda=<#5R1p$YPjt1P z8rv_!I2{~0$&@=XxO~J=wXBOKzRx9UoL4DApdYIf6Tgp5;};LUPQ)PS5_I| z`!1;z5CTp1LTP|>N_!u`v?x8wA}F2XF#^u+!idrmj}Z_yn68bL-rr54D-^Y@>F5*< ziRAGcgjQQzON#*?bV-4v!@q05pY?L&p#;9q#O;lQ_fv<%>1 zdbBKH{#|(f@Sey*p5LnkCp*k>CuJ*&-7@?z_UGC5^&g~B?2$-Xby01*$`<3 zjjrBbc=RE$%(lt^y>|2qwO$K@?h^j7(jmn+V75z|mLm|R@oFq2NRKfwo)FpRxPoQ} zTLp6c^MO|7!B&BY`dy$^DO&MwTJVSF7U1PVQdZ;g2nx4)e1Myy`B3mI4xFc4Ec{oy zq5|pv_fqw;%R=uGcKu+RezMCl^?QL{-}IJl*H5rjaj;b&``#mheXws1SXl4{*e7MlXVP{qRqK@TadFdENsb>(LT{2YR$5;1fMsGVoxJHXJzB zqh$aO^JrPX{5!Awp=q_oMgb=uJnw;*dyO-IS9-MJz^go3GBCgM&L5JO1iZ$hB?4dR z(H!8t-A!AqAPR2?krf1f)1zeozwOb61HbFhl7au?(UO4Q_h^a0A9*wfn7{RrKUzTp zy}uapDPkEdzJM^A;tTLH;WCRaO8gTp{Gqmh(1+Rr9un0|Ta-?xH*`$fFyNIgX&N9* zh!N^Apv+ZbDj=eOw$(vZr$W_ZMK9vY7x;)r0^A`aWnHo=g2MAIUkU8FlV061_LScv z@DZ0(0=Ua1mG2kGZ_Ap7C4g`UX$CmU_03ekXIxVG^8)|ul1c!3N)V8&K>~-lq!K{S z&w&gc^m7IL4Cg938)`)X?zOE7Kp3IC+HDSqJ1pW5RGhDYM|#mRP9Or#wn~y^{KInOmh%L!c4MOq z;qtjhf}J;ug52^B!B4u8P>e`;D~j!X!QZ=VWx-GgEJ_hE(hL7mgg-`=7IUZtf5o_N zm?(lU2&_3U(lu>dFw_`jW&?(Ei4D+mYB6Aq>-t%Mn8V6i6&GVd&w@o`Tu09W#1Pq5 zC18`s1&HZST!5JVq%5G92`T|U@?-&~y5my`=y`e;;OeN61;!|ZtT7Q_1PW;e_^{i- zEI=d^;sQhnk^X>)CgKA8(vt;}u)j7CCav1K;n`Mn!-ha%sV{ z{0^xDPmHsC#4$1rUzrEKT;h>c0N(7s!B+`fhII76bD4AMht+E!E$Jz<99B zHVqK^YjMmI{h2EK7rL@CBEU;r+NcQdN|zRN#&oFzPmHld1oMx8^M`lwz+*gGBJfy` zmIR#T(UO73d$i%e6Fgc5aGpoY0=|a7VT3-k2ko#?xK@a~Nd~^oqh$bhc(mcb>pfaB z@CJ{T1bm}MO9bBR(Hvm@6%1EF6lMsK6$GB?(K3K%d$i%eVULy!T;lk!Xxf7)-0LxB0pI7*GJv;uwBf+pJX$jFc8`_>%wIyzA96w>@M9j$0q)($@M#4N z^!_3yFOt}xISlxw$fBvUrWJ(`gh+gVo_yl-BpU?zwXXa!K!_yySH_TE7DN7(0r_u< zT>fHp{?LZ)N{OPIawHtODX)@<1;e6ztEn(P(^<@TLPn-kToiTt{{r} zfM0NjWK;zBTbGs*0frk{o~MC9Nz(r?SJmP|5mD(5Nb!{dJ3W$;v3KP7BU$ONc#w7f zm*Ampf3slXUXKI_OSvV~!fc}*$sa`>j5m=0VLP|<+ng&Mo#}R13|K5AWi_-$P?#&k zZdPm7hPYA3y93Ze`gbe*Jwfb+ZckGIAv9#QX249xb?;O_bir(X>FpvF4y4%I+=>Qp zmnO~^!H5z~#0VlhG|}Hjsf-sAGo4JLyP2-G<&b}$M|wygq*KEml6{#w!^#1FE+l0w zRS^_06NwlXK>@)+MoNOexy+LH(CJF2GlXL>D1jBPbvi>0|~Flb&n>#1LxT zP(Z?`Ug4n)u7~DeFc7lT0pMpYS2-X8T6+Wq&$)q}>pJn^de^zdfbbJ-aFkzvrlHF( zT`h_M(J{06hZ7@mtn1hkK)9cjcifcrfX4^;TXz764+VIgMi`Do=xKRyErL%I5q@y8 zCZYg0lSCKl1m#E0p8=%g8SJAqz*hW zR*vzaFZAzW9r^8G(Frkt1Q%TgFTs-NI)A#0uJfDQL!2~Fj(m;+JjA7CM1aq5X`>>* z&@a~cjbA}JXXo?-+EN*peS*Q;pzNa-{v8zu6&i6`IqM z?C&kc&SSC&oazb=-139(AdU6}iIIN_KOCxwewFx}cKI{Ji%|!7s7Ff#KG~xs0T1_R z$-t+0wBf*~dbAASOplfYyjN&+rnbjI;Xo84@arBe1NcpkHXQhEkCqJlu18A({)r!;(n?VK7a7!1r9PV!(g8q|yPR z;W#-`L%ah{SsiFbJwoag{0qd__o>mKc82V(DuL|@Zc#LCnptGsL&Zhc1gZD5pA!`-=JdNQREk~M<{$`kY2vFLm z0Ad(<%9aGy0gNR2rES_9seb8F25;0X1?(-VQHEaiU;E%YCH^kH7jHq27`tn*AkbpC z0W44_#;it6B66Y)_6KKlonK+dS?CT*Dd6g8XP|&NpseOq5p)!lqX026VtNvtLV5Ni zWT9a!?_MGrAveaj%O7M3oRxqDCXsgmVI5sf^gHS)=^McxV`RbdvFppg#se%-Dcs+Y z)z45uIMPNOIL@Ob0w;L1Bw+fI5&fY=oDAH{qYVd6^k^Bt$9uFa;4#M-d9==MUHn`K0Ke;*cIUXmj#@E^gwMX4C`5F?2IB%RKbR$)03X^FtAJrZDtODYEZl}jpz zR_}SFe+fLvRjM3LgBN0KZib5K@FANAT;h&(U?GQjm~)iBV4l}mspmz5J{N)Cx`L+y zp6nV@JVp%g1O>X^8xT|iK`A1LE^8&i{sPw}C4dmlY<@Klh;&bv|KseuMM;izokDpYXvjjtScCtuX!I{R#@JB?Spvfb7MMhn77*6O*io*LG1=&5$Z3FY2`Tm- z1PyO<8th&29%JfG@bD3P1=nXJ#mQ;!FGy0`Z-$ ztf_!##j>UbaueKxp2?}f?xy*>gKuEMNmjG9AYww#-R{TXSNU^Q4vtP>+Bd%6c!Rw(MROnpP7z%R5b^P6{2Sl*K( zZO0wpzk0Mp;14}o67a?WMk=2#0N?1*l7MgbXo4<3Eb$B0HZVjgfD0ZU{vt_Vj$j- z?s)r&{#J-^ra{yrQ8b8!ry-DN%kMU@U zz+*jH5^$DBO9meA(S`$0@MsypXM40P;7Hj%!oQoj!ZjW@GElEjbX=Lclb#m)7Ja@6D@hTV#VA8wf<40Bw@Q4x&fLU9HQ%st5noFzx5eJ_}P0Zo6H_EUZJj`%1} z+`?^*6z}g(^va%=2Jy!ICz!_M_&qH#%-z#+RkGoDN{+N!0fg1M@eN`+;(_=O%%|19ChnArSM5K@t;z#z0lgz5-SGB3j<6(}% zo*(Z8=AM=rQn)0V*dhf?RNWl$jQOdF#<||#pE!b#wY=qvYx4I{8KOKnQU{NtAimVXa6P3>fJqz=A`<*9F4N`zxhG-oWY#In~2_x@(d5`(3Nx_!C@ z1uU<0nG0(wbSDyEngk1-dIMsSA}*}4hsa%kq6b7FT}jxpa@X5`Lua0O3cPOmJnMy9JsJxWXk> z0Pd1I!gK}6j-c?Z5J?&!hCuWA-KvRxFKVLSX`1NwktX_GqKQ7ASh2Dtq8*`46Xjrw zBkMDEEp%>#;La0=YCc31!s&-LT7E_Rvy*Ph2j^xOa}%o3l{CycY@vvRUDV_5NQVJ2 ziAdLv+(e84rlx>1yv^fBE!Z%9FG-sCuwR0?M1sZM1PTWyP#CiXDVG}h6E2a0vn3py z8sXqP2>adoQ^uDb{_qbaktPo{vQBc1o&#fH=?{&qKX6H!KNw>?aMCKHb%Q%<#ef*S zc&l}ILTVO@NRHikFcVU_3Z$rU-qnJg;LqL6SqzA2E|M|)-sJ4u)e@YXMD*K80ktdE z)@xTwaB>o--ygd9PZ_+cWeXFvZ#f)m-*UL+^Wcv9aI9taa7&EM$KfB{d_-+w569fX z#@JXKjJG&6 z;el8_Jn)lzNWCCqAYJghis8Wnu{?Mn;KAc%tr_7iM4g9QP{4vj7acLN5$iFoLuL#% zAvso#l=K0gb4l)IqR`D0<;avsle8Qo;T>^zspWv*x};)2GzZWVKEt1Jf|7zKShtDcugQ_4^;j8t#1yUG z{tU-#{_f_82sn<;D*V!k8Eb&w`o?Aq0E&dMHL|W zp?3GUx#3h?7O;u|qt3_g2~6)nz6F4G3pkU;I!7dISsL6q8TMy+;=)3Xix@=OE$ZMB z29biNoUyhnem{&5Jx9rr`~ZmjOq+n9>T`ms&k3qNC#d=ysJ_SZD4=J}oS-#xkZh0; zVr)+Qs|^j|-WIvprhUF;$B>-ifQr}y0P3Op46 zmIJ~v%xe09dz?*tkF&{1pc97#x?PC|Z%V^%bh~o&$)krxKtQMctxLLHVqIdT`ms&+)77-yP{-_lt@- z17fs1*b<{BT#F9b=WB-c9f=K@Gc|^L~={mC*5SJuqc0&WKb3_ViFb5huJB z<^(mE0}ZO&?ur3%HH4fOR4U+u`C=8)oK92zt0ysYSB#biTVk{f<}S3n*7ayHAk+xa zGdq4+G)eqn1xaW|0}*T$2*zd7FE*`o>CrFva$&h&j>D|wKd_!J=k0+I zWX3rOWv|bGG3e7{38dJAGTa}^k?+6*H=bgQpgZsfZ4{b>sBhK#jD)a@g@;ZB0nyAn z;^S*)t&s+8QNn@OdbC8~%RO2W@Rc4d8TcBHHXQg`kCp-4>Cv))$BuBV-)y5WUWojF z1n>lpmI0jO(S`%(d9-BUe2hQ(@L@K={QxaDmb!*Cn$7;Vr|6(jk|z4DdUbG#l^?ag=F` z(oENVvjO33!-&$)UB)uN&0Qp-w8Leb4LB&uePt1pFbZ_P1`r-KUHe1tTJct{0hd&MiWmY{#kh(o{d2iL5&!X%X}(!WV&|D zo+{l|xZM{6Vw7pY2x=5wDH^PCy+ECGcgOgw#a;xcj4@3<`R}wb3(ZwqFotB?5@AW&!th z2csC!8=q3lNrVZv1a5W5th7U*H)f@PL&ZJZ5*Sv{b^-8o*NdeS1U?eg5*TBwtnUAb zpny@PkOMr^b$3Pt7{jdFqJWtf>jEDPg(}5 zm%uIGqlFs*Mxm302tx=l4cHe>as|(eg&neTAtC?x3Wgxylr$}ZIPhHY6IU=~N32n_ zW&mQWOb;j_CI0`iT)iqTL58IWf~6RIB7H2;je#H%#{U9$L`yN=$c@AWV;JjGo@rvjF{q~f<^DyO&;Gq8c(B?e=3DWqZWbZM=umbeHCv)t@3 z2XJ9D9}3rce1N}*=0jnN#|OAGnhyof`*YxZOg&N=-uLFy9Jm_unYg^jH^>oBc^)f! zP5S=aRjUjTPK^299DD|!@I%T8{{G;I4X*HMzZM8HX$tyVK}(D;-HZS%5d-+8z@X+O ze$8XOJJ=u!K(|SdXsrd%)j64W++ZBKdnG zlE0G}F@T-tA#c_I!dzNqgWb)B>>78H76Za2YUnp*n{@NC*BzkOU3sv(a#(kw*B#(+ zmsAd=JPiVih~JrUR*#46z{+W;=ya0wV5t614ApNb=G}YJmd|E^4|%ji;JkL%*5~9Xtnf~j7|E=_FjZJlgyqcY zv)qE|e~vO87^d^hbJz_7qK$#}%m<92Wj^3nWaOFeh+vq*G+>w$%QWWu-`Is=WLdzl zt2Yg4<{;-kgECH`Kdy-wPHqB>q4hQSDMRdQ63apUq4qWTDSq)a`QNx`Te=Afwig(# zqU8r8|CB^GvjM|B#O8Mek^H6-38oB+ie6w0JF)rIC(;iE?z>Ui17m>c`t>)fp+9tu z9@aLALd}Q*!j&0;5xSbuAG@0PW0qk8YDT{ynUV_X<*1oZfD6e1epQGBMgB+3AktvT z76>UKA%Q?cBKdU~E&?)LLB)Wc2Bi@6lADE#0X^A)(+p&o`=SO47z0J8H9s~?@CLB~ zLM`nr6yPG_1B^Lv@Rx4v_n0QaeK46M0>V_yhXP`lV+I(bPHp}E#+vI*vr@oEBoXWH zxj^9=ce$Pl_y?C%47lGVl>ol)O1q>rg2G=tK0t3E$}vy=DD$1p6#(BB68*+fYXk+P zM&iTbu-x4XlmlKSB=XulE!Rt7v&VOzK+FcZngKZ04azxyB`zrph!~*#xqs}56r3q@ z{Nqks>wQZuDd8V=;zFK6l8SLD6EP3Ba#$e15y4EmT;}}pF(yJt)a3#_d&&V}SFFTD zErT|e2W>3(M>Y!!8d;9OMi4WbKZ;=`77gYBe!`8hFbqdvFY$1Yp75HGm2XR zV-$!D0|8x$~&gQGdYv;qxw^wM>- z041=r1LBqjdre1MFD>3S8V(CY(D*mg#7jpuy{&Ouy3+ zA4pj|eEz*9ja97p*e{vJOD_yU@xV@?Jdv<>S!W#!q94>f5bG=-^Uk{P-eIZB`_7fluY}*n|zA_ zYos+@CWVa{?HIS^usC5N(PP_yFqIZDC$NVmK8zcz*L*0z72SCEM&FPYm^*HTf7-Ye z{u$#|z@u=c?idA(waX1BV01ON-{oQ1*K~{89|I3?*U)0X3U>|dT+@P3fIp&R8g8I* zUekgCB7+%$ky11xTynHz15HE$ZsFFzh&{ED*R@a)xF^0b#_9 zz@AshKoov#0%4znD5IMoSW{m191Vy~ONbtx1V%a`TC0B?Z%(lp-kJcjrVYA{Ht3 zhfbtmSyW2-W;IgE|9fXmh#bU7j5DMqV%M6e&;VZV(ndvqf9}$PKVh*<>cA7jjn(3- zE94kw(HlY$xB(t8RR0iMBdg{HIdb#>|H7q>iU8m3(lR5!+g#e{2=H%Q+UXJCr(D|D z2=MbRZCnKS6_=J30p91*#z%nPacL7Gz<+gV*%4suD?(OI& z1jCE`(;D#Pw=UmkcO^Pm7M+lFdIWf+OB)*j9_P}=MS#zAX;~5AB9}Hk0zA#7O^5)8 zU0QYo7&DLU^^f=QvbUQ4!+WeCOZg8;IYXpy)cAQO1$rv+vuqcZr=r9F?{R6PBESb+ zT5z5`B6Z-2F;C!^Rj$u6BEUF%=1a7|$Xv00R;5v7Tp>rgfB<;4D}L!JV2Fxw{k}uC z92?xLipw0}e|WS+;KLrx0q&M%TuZlb5`i6$<^cEhXo>#8fF7@jd{Pzg6Cs&<5-35~ zkJ$8qaTb-q<<7$9S|v-~k>j2{_54B?AxiXv2XAd9)1R z6pxk#oHyQR$zPmhp>T!}`930WzDLUdp6Jnr1E1~Dl7T0Av?Sok9xV~L*rPeXFXcul z_(L9DD3(zG14dj@Dd5XFro9P%lzK@AwE6><3&}8|bcx3Z2;~gp4{3*Qwx$P00WTHp z%-lfv@5*)1%W*#n3182lj8*b-Xr}% zpl4n=;Q3-6cj@;i)8K}yTsM?&66krR91xD@mi|x)i4xF{f)PR?F~;unp!nExXvKHg zM)W|}p%sAev9gv2zb(5$eDzn?eY3iWsFUQVzn~gI?sDbN3VLA{bcX44BIdUkf%b|k zoqkCMg}p+gr5_MuLg%jAThS%tYofo07BOY5Yf>?wXJzR%Vu)u@DWtc$!&(f8L5VRK zZv_Ir1OY!%G@#$(OvC`Cx(+M>gm0P6Z_EM-kd<=eAbMT!hjNT@M=f2HnlDGn1O7lJ zlE1THt7*YjrT$iL`j56oS(15>PbUj6f1(GW)vOqea2=vNLcqmmdPl7-ePC@hAm z5Qdhls=r|@^}mn^OK|69AZ8GlUNFx3T3StaTg}1*$1I@4fQg3*9wS%m6hTPUbOOA+ zH82j~ipuSPXc%++&<;$o9B`AEaGz^RApEbCs{hm6)j&yEo#$^^#6?6GP*@Rl2vpZZ zHwz+=sBr-KQ+@_^A)vswv%9nG%I?gb*;#}{7c{1g{V|-@bBe!Pt2w@0PSZX)xWk8Kj*k=;scJW zA%4km3F61TVmhWSD=XOeE07W-LHt9<)e!G-Ts84N$5j#6Us)7{jY~kPAjH!gS3^AA zan;00$5j#E4Nmujjr*Kpg1FytHN^Kju9|q4F5!+cqC*dM$u2D4W1ve5h4?~8;3SQst<*{0sLQ%t67KGZIDXO5BDqR zb9`d9hOff>+qNr_jJ^mjOj@0ni2nk|?3nX!2CRklFoc2^m~hb`6cA>eQq zpOA}AcAG97-Q=_gxoSjfFOD*CDU6@g092lZ)Y}yB0moGn|H5%K#D^T0Ab!DdwZtzv zuAcZ6$IT>Ok~CS$njNTMV<|{Ua3*oearMN@9al@-=(q&&O2^d@uX0>9ag*b!i094= z^g}0TpnGOTuS^umUCgpY%gSAqNcm=kA;CT+te zx~vkAxof>>_L0{ilMw6zn@5U}`QS5;wQO^CONf1a+fg%4COPjVIF2?=rDz*SlwM;J z-`6({O6-6R#RexnJ+RHHYvpqFX7Vz_@9F)xC-1deaQMXgq{OI&X;U85B@M71P|585TzKu_DT?&LJcCFq<- zUSiyZmGcCooGHH!pWH=+;_`mnhD$NrjW%2=z)C;auK3hMz>6GpDd3kJsvHO}lh&;#k7*W-)c(jGEygk1^ZvN)d4He3J&Q3b$3>wd`_nRm-E)IG0}(P~*-n@* z&xb-09<|$Uijch$Esi476Ut9ZC_kyYkPOeoqC$AN4Y!KB{I!m{F0%2jVd{IG7L!Wa z6Zk47)$gdE0UmUepXX!9^JQB+ds1=X%AWMuCAF(W6Hl?gToX!-Wn{XF^OKr~WLQLb zolD3Om6@=|&Oye}BpVDW#;g`&Ydt1VG`IHj`I*FS=InJ*E(3A748+azfxei)(XWMj z5hZvXQk9ALL(5I+w-|FH?j3!O?GQVEA_JPj`D{6)dO=Ct=(uX)m5!?+zSeOG;qOaQI#-Yy`@$VvK*pS zt{8u5i_u7!uzhSGWcO8v8vEHAi*CwxO~{TJMYamIn+=5Lp-)DUty4P<`90g!6no$8sI7oMhE$fs&pI`hV>bG()QA__5~Wy-8y!_{;{3pFO!fW5ERbBz zu|A86I!?UI)@Lmt7n911n2TS$aS3s*3q{CY6!*xDW#mo($MTV)^od>i>zF=sDb9-< zklf~AUQgLduOmEYsYXJkEQW+}*)OrhZzSZnh$Z38PK(fWJ968EBgB5mNqwMi6UKqb zXp$MxnI`>75aaGh-%U|>NBUyiMZZ*WGFAfj&*RxjxuJ}<^DJW+U;0qJpBw(+5J24dyw*xm~n8yFhViYKI^@{|L=hJLyFpPl+%skazA&L zmDdw;*5QzyYg1?-oCHcf?lQEWjbAvu-vAD?IW(LB$bv`!)`YbeiXGbJ4EF-Q>!@Lo z{xooW+{}rbXxK%DllgEoZsr{A^POo;zhb*E$)B<(n&r_BMd}>2N=2A{)Lt-t?GXNqDqs#9`u=yB(JxzQ=L3#P>R`o_MF@ zW)i=&*kma$qIOrX@k@}B;7sDfj;kkr*>SbRuQ)D2{4b8HA^um#RTIDFxGLf%tW2F? zxr#o9p2_PGLi&{dv?QcUb!oh!pRF4(!lFp{$Cg?_$TURjvy*6K64#(ZvXTjJ!Jc8R z&)Iq&tSAyP8KcP7Gd8sb!nZ&fMYgU)-NYjy`(PCPZZN^;Y|d+0B4#Pqn|^je`FRNC zM-<8rcMrmR*M@5({Ci8KQmBi|AhP8$Z>q>SVCxn?O-=fVYSK?tlYX*Xxk+TEE-Hvw zFERY@KEGm`WM)iCSrc^OzuZ4#xMcx_7d0)L8Ue`d% z`CuaE|3!9bqzLC*YWY_ITP&3#Y`4^E7UCLP#1vu5QUI<#(dkhinI7_*#h)BPacb;G zVN|jFsUd37iBTV!7@`)P7WH;oaM(qSkeyXQi8%vA&GpZqS5R^{h>&hKZs89Vou5q5x*tF(%K zHaH|DPW&XcAd=gvmNO3R<(kX4;%R}yDgE2AI>DCb=!$m$8jpsZcY+1YobCcE!RalR|X`J?bt zTxJ}#mm3YIVj}QtAobxY4fxlPa$Wld zpz92#lS`J~ol1&njnx%T4JgPFOB_J^m4VQ77i||7MuqZQVp) zMff_O;^vR6oBDp@?UtL;Pwc`)v%b|!DdttgJ9JremK*|nrsbye6Q66jXt>|P7j%PQV-?l$a7yCD_^n4O|@9h4ZJ}NMZ1{kPZfrUTWe<_ ztr<4s)qbQu#G$(&N2>b-@;&LpCe;j^G_;@e6V^kDkf&SyaU3?>78f}~#>^K6e*oT9 zA07o}7#Rp|0z9?Fb#=#xr0&|dkw*IcyzeB#d=GLr11?sUj8kTsBglnJL9W;*0$kXJ$uR{z0j;H6|iTE~TP-EH?A^m(7g3m+V z0C^u|;(TK<6Y@mc^G7uKir!!npNVM? z)}B9`_X*-xoNN4E2ze3YOi1Q2rc6F3+8=-T?g_+y8uHhWzkz%Y@~<(EIM4m6ooIjj zQM$W7XCm!@+zZKHe&f%)`S}diehtPU4auKaGa|tiAuy^3RHQy!u2moUtNtzM|NW59LcR%k6!HT|Ki**N{db7{H;4UryhX{|Y}Jd62Jf+rMf+?> z-jn4mi2rMU{%z0C%FoYdu=c!N#5-1};5G|y4f*koSO0eS;|-vh%Z*3gv+?~OuYOS1 zv$?B~ZWdX{8`)0Oku7BM-9cS8SIE@On!WJiLV7(~>$AOe&AlC+trvH+26d{{p6+Q6 z>RLBv#h;Odyg9Nllke%sWlI{N9Lr}q)5-v-yR#6~b!0o_xscf;&u!9>W4YFJAsy6Z z+QYVdx+@d5w~8%W#v)AT^XbjTg82FtQ4{a!u8tN7ofC)hRHvgDkIg+jL0wC(t1FY0 zgRPn7-t}Uf&aTf0Z<-z1wj6P~xjCQN$W~`ZHbX4+BJ9jbFk=f({s8?i+h>bih5QYn z{g9+VAn)C(9r0Ck#nSD+nflNa&V(8tR}%Q{=hW{_-J7&0h}t$-3p9 ze0%kYjrTtJB**woLz2P-K@*5+x)lVxZCHgi#S#JP79s7o4@pWZ2)2V5fE*^AsuS&T zTSI>izEXJFx1W@hRuHr!;80~$^zfSc9mh|K^6wm$)Y_dYpgeea!TcGAa)ao6Tx7os z_PbzTue}6;pFil}YXVeF>F*Hi4|(>C@Av;!&%Wy9q%cw^HK_8~0msVzRQdDmZx>G0 z1mS{R!;{hqL~0TE^H1ek{J2dT#r6ZRAAtRUS8&`W4JhyM?0H{$hnf`fXkB3>pJ~VT zT>^^Z4^1cap`mG`fiz4*p8foH2&e2>{{-w4uz%FMznl==;>Rv&6x$!jCiUS1S)=t! zBkZ#u|A%s<*nW2|sdabfjL8EW7}K=lhi0%(z-jWQ)_{7f+SmlCMMR(DZ;l4RGXhSR zKiW6JzG>sJ*&h-$l|SvYnuFM$05*neQ$*k{^NzT?>^H#ceB~9v=1;kxO#BBcjK!`8+K2KcG_v3?(6_qNxA<4+GO4+S>ol|_UQZnK7ODR88u1Au^l*W~ERkA&n zA12oiar!3*ygn#)Rw-5CdB2n&9`Jl#%AX?V=Q#f(?D@A;|I~oz)lzw#;_4K4+aDnzd`7wq+2OT&`r1G=l48z|9e!R#Exspoa`mf!13noK9G1llO z;D0*!U`vyq|W3+Jx+36p!wp=4IW>HuPejPF2k=b!*^+3>Up`z=Rvg* z%41_0{oBg$_m<&*P=^1-YTPCDf>Y}XI%O;TKG{zYJvqAcOE@Y_|a?> z$*D?T)-TWR($tSxT3`07Ym>S?fO)unxN#XHd;&Vf;({{zSCrwG3a{pa-{0%X z`0v$zMg~odNgZ|u`qfv){~el-UVq*t{HVZPM`3vdfx4qx*Af&mJ%yPfTk?gTLT_7} zz%aae&hl{4!iL5$3|ce!%=(TVx#1iZy26&uTvqPF#!z9{nhV!==9<%;VQV3m?+Mer zn*zCu+ufNdWLoQ{&zL$xJjW=7>VC4hI~>X#-~8sl+)r-p?dsYrCPl4KC0(Lg=LPmM@(9Vpp%V#oSy0E#suA?WP zuDe8&(v)s0w>_DBXC`ZoO*2edlGto)y9!}Tdpd7a+mxpbnM`*m0gT0TttLI`E(&p} zBMZ5(E7PUhDyfZWb4a?@gjcOzGHda| zIigi`q^FS17lLs9qNTHEEee;;o7XV6F>IVQd(m9wuCt@LC2Z;G)k7iW&t#Ix`HL3L zo)b>3n_B1c71c~WpUs6*&U8WEJ1A9?`|a75uI^GYT-dlcbhD^&@f{Ee|5h< zG^yz!l)%Bpo@{qs-r;B~b)$~A=W-i@8}c0mFTF6M-#F;%*_>@DwK5%&ykrbZk0^iF z%bO2sGL#+>?Uwd@DHoSfTOr?@l`?qA$awZ-3Z>>Mm>SSP)=!V8FX4K+z2x$lbZe;x zjFGODOs@{lK!QdK9~PBYbt*D4;rgyz*3@6ms@9%d*q+X|%E%~(-J4wwQ>Mx9Q7jeR z){bo0+mmV46SX(noo?AsJb~1d3%b&sGC`cNnnJRUH%ay}g_$K|6UfS!sq3bKjEd|s zv3}(3At-kBW+S7gYNK;Ai(f;XWJ|iUMW#chvo%b&%3D>rZhuOIS8oiLW3!vnneOS4 zEns6?+|Xw>b$A^KLz&oIo@&N(i!7P%Y94gv(yf6Ehb*L=H_P;bm1DA6yd(bu#t#rG literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test8.ans b/libs/libtpl-1.5/tests/test8.ans new file mode 100755 index 0000000000..46603c5ecf --- /dev/null +++ b/libs/libtpl-1.5/tests/test8.ans @@ -0,0 +1,10 @@ +d is ff, e is 61 +d is ff, e is 62 +d is ff, e is 63 +d is ff, e is 64 +d is ff, e is 65 +d is ff, e is 66 +d is ff, e is 67 +d is ff, e is 68 +d is ff, e is 69 +d is ff, e is 6a diff --git a/libs/libtpl-1.5/tests/test8.c b/libs/libtpl-1.5/tests/test8.c new file mode 100755 index 0000000000..3f8067bbbe --- /dev/null +++ b/libs/libtpl-1.5/tests/test8.c @@ -0,0 +1,27 @@ +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + unsigned int i; + unsigned char b,c; + unsigned char d,e; + + tn = tpl_map("cA(c)",&b,&c); + b = 255; + tpl_pack(tn,0); + for (i=0; i < 10; i++) { + c = 'a' + i; + tpl_pack(tn,1); + } + tpl_dump(tn,TPL_FILE,"/tmp/test8.tpl"); + tpl_free(tn); + + tn = tpl_map("cA(c)",&d,&e); + tpl_load(tn,TPL_FILE,"/tmp/test8.tpl"); + tpl_unpack(tn,0); + while (tpl_unpack(tn,1) > 0) + printf("d is %x, e is %x\n", (unsigned)d, (unsigned)e); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test8.out b/libs/libtpl-1.5/tests/test8.out new file mode 100644 index 0000000000..46603c5ecf --- /dev/null +++ b/libs/libtpl-1.5/tests/test8.out @@ -0,0 +1,10 @@ +d is ff, e is 61 +d is ff, e is 62 +d is ff, e is 63 +d is ff, e is 64 +d is ff, e is 65 +d is ff, e is 66 +d is ff, e is 67 +d is ff, e is 68 +d is ff, e is 69 +d is ff, e is 6a diff --git a/libs/libtpl-1.5/tests/test80 b/libs/libtpl-1.5/tests/test80 new file mode 100755 index 0000000000000000000000000000000000000000..7cdd125748f000a46fedb95744f534d28e79b5ae GIT binary patch literal 128844 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 +#include "tpl.h" + +#define ILEN 10 + +struct st { + char c; + int i[ILEN]; +}; + +int main() { + struct st dst, s = {'a', {0,1,2,3,4,5,6,7,8,9}}; + tpl_node *tn; + int j; + + tn = tpl_map("A(S(ci#))", &s, ILEN); + tpl_pack(tn,1); + tpl_dump(tn,TPL_FILE,"/tmp/test80.tpl"); + tpl_free(tn); + + tn = tpl_map("A(S(ci#))", &dst, ILEN); + tpl_load(tn,TPL_FILE,"/tmp/test80.tpl"); + while (tpl_unpack(tn,1) > 0) { + printf("%c ", dst.c); + for(j=0;j#uAk577J>UO( zp071sbxxf+b?VfqQ>W_IZB|xBCcAW9b3QKZY>m*~yr4kIZ%v!?P7h5`E7QDMP#dNV z)v`gAg+GTbsB%u)sj4}t7qtAi@#kU2#V>qZL44uk3gS!C28r*U)M=e5+w1uRRaU0s zmPyb_HO(&&tVdbPRC(F5IRfvbvnUWg3smaVqj;=Wt?E^)dQQ4c3Ff3u|JXPF4Oaad z>KUOaZ9;*+EjFY}C(VCMw^`@d8<@`@Sj+|o_Eu1%I z(fm=17A|RCK5BW{>7z~`H@c~Q^jI(=Zy)~H#VO~{z_%POw&TYi%lqSxDr5OQXYG08 z_UgXnm4inNe`?$V-st%wZ)VwX_;d6h7y9yzAZ{@J`02{udDe}4@49}%AIkH}zeqS} zS$NoYDd4_`;Rwz>3Vz5@@GFjjfBz`>s-xhi9R+V51;61ac>5^$laGSGSbgg#z!l>31ZCp~bxIwFnHa0J*nH#Ou8k(au3+6UzjkR+ZEvl~}MN`8P zZSmr{4cg+SYnBMiqFP{T7dO>Lwb`?48ylC@&j#(>=)(FXtT>;AWV^I!NkikpCDA&8 zXt+jO>@b~=TH4~~C1g8$cHMHw7u9MO)i>2@^$p;TW@{ESiUfQBfxf;Gr0js|&EmNW zmuSlx7eeZ#b*i1Z#@bqKN+djS((JLLOUI?NV@IC`g}DBM|LAXyL?`vBql`X_fBf8e z+g)&1ZtZL2iEAFTFh_VX8YVveYvzcQKCPd~$uDP|xYnGIfe$MBUchBKDl-GGSc_WK z8F*)@W5KKpe0s?NeohA7@$IBvkb%!!{~9vz?1S@Jo`I*V&Zi{ z2EKP1t7-RS;BzzZ>oV|tGVl*(;PW!@>of5A8Tbtucq0SfnSpo4n8nX#;E&0m-5rQK9Ft?yNce*c{D2I+F9Tng zfiKL!56r;(Gw_2l@Mi2YubIdiRqxl#*3M{FavH4Ej6LJsoI!+a>a;;1Nevr}Z(~Rh zIl>D_WbaJjGpsLRnz+49z`Y66wCzp-y9m>y?ezjaummto*f= zw+Q$H!c>plAmBF%(^Ty_0^UxTCTdp;_<6!KO*<&yrwP*}?Ggb$NtmW+`vv?*!ZbnK zC*a=^&L^x1_}7FD!g~(_G3;lAX=?UP0pCuTCT4FF@Xds2T6U*^R}-d5+3N*-En%9H zy-vW5glQ^vyMV7EOjEF11U!#0O~7st@Fj#f^!6M9Ur3lkZdVKVT*4e`J1F3ZglTei ziGa@}Ojl+50Z)69s_OV?Zcr=jgi*{f+oFMztrdZixm^{3aVXP}mT`QMPT;sA4RSn@ zR&X4VnjAl*5sn+uYK|Au=^Q7dvp7DWuoVduC|bldRE# zX7w1F)$5FdXa(6a!V>_m1Z)h^%$nz8PXo7hoE|&SyLqo^y(d^EPX)6lKSwuI3-6V7 zCT~T9AV_`!^_kYknO#l3JVMb!638QJp~^@TirEBNj3F)f){Kqg0v!j1c9QFUNTm|d zfTzPXkJ?JMOW5ncEfVhIzzq`iIq)0__jllG2^TtWP{M;9xJ1H!2lh)i;J`i!7dx;9 zxP!x)touHda`ce=DPq;uPUF^6STD8l28;_ceNJiTrJLJJcZaQ)t}v|+%-BbJtEY#% zI=7*-X4j^mNV@js2DM}_F#f7td^X$-hcd$)#r4pP?aw!@UCUgTZ)O-P9LZOgcd#h6 zQ|WI5A%}j`emCe%>uGb-r{|dZHq+W_zI3n|^`DgWw@01&AE^2*XX%UlSf-Defttw` z=)&b&vp&DtujyZIrav-cXSFW?LG-w^2*=FmFqc6(YgcO9<@R-`VlTy)l;2$SnF$k& zcbe8?fqN*lb!T9mNY@4)L>jT;f%PI?8z9SQ&=?*MbRuUAUmMsa(mMk?Mf!`tUXk7( z;C{v!{&2u2(#HaRkv;`;Mhk86Ks8hAfY}xac+Ix!1OAQkQ4=%6%Nb%?6#*Z~+9k42 zi9!}8Up#;@_0J1}OElmw?MxLsd6i%5Kz~w6KSmk-*#TnqCmJX=t?7Xh(~1PjB48Pe zAZJF;Fot7B8p9)jImYnmfd*svF9I#7V+_AvG)TGE3HUM5b7S~ZqQ4YqC-A0q&`g}w zgl5gQ=>e}JG}5%35WXVdXEzFy*M65u!Ii9fhH`BVT~t|`3e6172u%-LU(J~I7dJU# z5d26`DQI0E7)h}UDYjtYO%R3d2A|YGmAnQjh}0xaYfC8hL&}Ih1YK6P?l$6^;f=xx zPXG&;5uXj9BGG_FEw6K-U#rwVH(Q^ps@WHTUVPDLT=S|~v)pUydy-XXJDivhNEKWP>PTWyz!&cF1keXaU+E3&m_EsH`4;2u zPUG=TETq#m9+(@15y8Q|@#O%*W7B^o@TeL=SlQA(o4#^Z2v#^ciir>?2MA4ZIr zQewseGZvUq2w76qHm;)35i!2SkUNc9&a z(EBR_O@n-%IcEeCr@a8M<4nc-E&z5dYH&Ok)N(vyKxK|+0x;ETwx*)lse?5{6Wo@zC(W|fySz9}3AIUHGDSY&LPT7)*guAlzxzf}V zmc7Ms>2Z}fV&p2RPNUo#UA3lASj+#gs+`c==cS(s)8_)kN{ zL>Y|ms#+M~F0>Z0KE~42v3#BwfS0Xg_n+$86XTO_fHE0y$j6iX@gDL!ddP1C@xvtk z<}1ZJpTt%V@gr$sdnR;@cqVjFXlB?tNdGuv8se|QNTSY1U+%4H{m6*l4uOTdRf&;- zaN@FnH=G#VeL~%6XMS~Tkt_=~&-a58^L=rN*}6MA#jL5+V*C3nd)In86?k>df}rGM zCMtbqO;w?psP>tNq|EY{Osm>w-1s3{G7}5DsNB4{hkwNSq{{j%Rd5;DSHbDFHbHI^ z9-6y{DL^8UDD0W{>2*Jn7#~iYql{|^=pq)zX|or055S%wdXI516Q`POHx#odxfk|g zkC%E$%qYad(YoEZWdsmC@|cP7WSRr}ukmZ33dOo~)((}we*Fjb4`3nmmGEo{)T7Uj zRu-D~nEGb>Ls5drCP-JI*)K~tbWzw6>r>cz6+>WJf8!{aW@3sjVqtlXBpM1M?goGB zzGx(NFw2O43H!sO`fy%Qt1SH}Rd61~z|!0{In}xkHT)~j5OGO@l`X8;P>|W9AXr}u znwL>37^JJM_**z}Ih@y9&3&w`-AQMB%^EjGacOaSoZp%UohL5EAivf80UGgx`pF*s zh|zvljJ9Yeab00+YQ^6pHBukvwnefuu7#^NLx_mAvvhl8`1{?*)}`BP8>ffM_Zh42 zLpklEZKNL2JIfC=?+RPbbhny`NwA;uer!K4U`m>aSzf#5(D7=U;R%<&)_74kae*&U zsU>otBVWrduUrRx#^aGdKdgHF)z0%T0^E;02jVf`8V_v9(< z=Dfnz=ZstE&P<42g@8@Se|H!bkMEY8u1{y+`4Zgn8SJBiSONf510(lHEeHmd?wFQRD-Zrhbk3&7o z>sV69BCa2x_E269of@mD3N&b1ud>aLxhBP)PRnepeh=mUNt@sq+pjPCc_{+7?w<)g zq~}RHxYDn*O{E@;)d}*{5~a`pyp&%Kqo0FTgiaJ;&;V2fP9$b1FhhYkkrM<`hMw|3 zOSV_Aj8kvWU-TR_I?S=ZSf^h8tP#H+MVb0HR`+AO&6@RfhIY2wKXCorS6SLwn(980 z^G@miO@_u9<7cdX8I%=?8Cs}qVk#6npd;#=+!Zz^CzVDWjc>Fc0wucUv;PZB=%3Th zc~&H`63&?e7Y!6vCF=d*M15g6_Jh~BaRvOslWvGD0ziaJ$@ll9Qix1jm!M={rCT>z zFM`1sk5{@M{N8At2ke8cP@-3JcFT*tkkuz>sG!;$eR@Ks`d4)0Jj{Q<|Nw zG&>!dMOX)ejrZa7Yn$Ocx2<9n9TQ`5uW7w(j>no|#9u^lh4J{QmGON>E4Mx2#7gWI zUW>Ff=}A)w%FRk>(?_m|wbvY;tg87aqVHsgxVn=Ci7926!zGNhhX6)gGq^2C58cXD z65?tXF}g=1TVy~MvnVJMM3aePH-3Nn>McWpqx2Sa^kR>qV~`=5}pabL$e zcy80`A4s0?IVcgLC;B6x>WfxOJ3}o8i;O$rRX6J)%-q3ZdIYu5Duc?i{~KmPJAiop z4H(E&r2JDO{sFMvYlUBKi%L0-9yufB`=S>>M(b(V>#3VQEnI_`+~b)c_1TXN*d+YO|Il+W`1a8Y1tZo!6D63O(0NyK4HN)36kQ6M!tn6V zBW`Ru5bqv`Xut6|a>Uj=GnB?Ui6UqYu~N$3gwAZhCM#wCnK==x{ed~4QZ}R24fsph zKV=T#NXovIIYc2TyOlYFwki8M%RaYJ0w-H|i z&Bt~QjqM+5#P37ilq*$qDB>eG1RumDY7|yQ1|zA0vdgd}0^gjhYY)T!bio8rDfWz4 z_6lpDmI`bsSs2vX#d?zPnXTKS1I@&lT-$r63O>Kok4CW4sH%xcSnptXJSM<-O}CY{ z7cko>x0vul!Hw31ljP5u^r?I;GAD!7xJxXGL3GvY4;r8pwScU&COLQ%CV=oe|? z(qcOR9SJ*{R#>_l^NEp2GjLMg3B?q&AXQMQ1WimUG`l=(QVYeNK|rzv0m&=ZzXWn2 zdFy1v_1}8qO3L5Y}+reIML)cv2rK#Ka-XcOkC$n zPVGiX*CZvY?5_P2kgF(t(LlH~kP*+L{S>^h*5`@pJ0uL(k# z*mH$auXO)X#U&a3uI&;J1JXn`J)YNcnTe$sr+ub14wI4ITg<0~CqOetpfm@@GopKt zoEPbM&?;P((%IHoVXPB!uI5ldIHTYuqvD!WbQoGyartb z!r2Pz6u1fxLRT|U63xXXk4Iojp^b>%9fnET^PsJscp{t_7Z3rd^(IS`pK&;>&GrOP zvA-3GN(836D_c8Pn)b;8*}_qeSl=Y8?NqAG)U8~$82eUV+8^6(G#9aO3UMH!f0sN6 z3bGBww&)e(7Z)0BAAvtNQB|$`n*Y+p^#c=Sv#0wFH69spEY3hmJJFHo5V2LoX63!) zAHdM8nV~@{<5AD640+9a*fY3B3#{86BTvtFwVq+?g<$v9Y1ox*Y!Z!f?jz_;EGWh{ zIeC8)j1d%AS9|KZ+|h=Com(fl7NO*uZLyuMHIv+s(wn@3RM>f;J5d}3Vgvm-r5eC) z3J0inn>7ot%W5bwH|=t9W0DIp(tOFP`a9gy6n7t=p3iB!`SK!VHzL%HE|Y=qviC%Q zt6deu$uakFW?~xR(I&*B=VCvz3HzD9o7TD5&rA|_bFSAce<8Znw4PP^G;4f`{z6a2 zqt%6G&304AMko<1G0QhMe_&cKFs{C%#~$dl4)ew>Vvy*a5-^83FtJ*Q0Wh`&cJ>ji zGf~ofRz%-rpH16Raw;#MG<_HdCF$#bG1nbu0 z((cZK-67I}={>h{vQ4`o9{aQ8j*q3?Rl#(&WEkEa>}ZAI{g7-0BN`o+Wp73K)rH0_ zTqh{?`3amfwSLt6cvmI+C0KO7k{%B;F%gb(qS!M*MMnH;){A|vr}gPIYpBRRe-p-M zJo=JpJo=hByhp2V+h+)2TgV>MB5ZAoo&#GeegX?NbhW&!ZSuFV{jO!Fnl%G}_eO?y zrpM@_LVa6Xg`UE4d|=2o-x`l@GVclNoe`@Os|d%xW?!Pu*KE3b6ZOGk#_zF{PR#cG zcpcjWn{d{#kB}F}hXIccPxrTHJ-Z=oiVJ4=weFAQI7+il;B*iRz`#2AquJQgo(&4{ zfn7I$?obq`3Qh((jJ>k2B5_e!W$X48hM8Ddk}5D9e5$~M?4_4u6tSJ&Ki#i|F5?y& zt7u@$0vI{?Uk5wug(WOn2zSOE_#4!k)s-rE7W6Dn6>Jo_tFf5uHsU`O>=~Pg5y%bXOd4YXGt&;4YXBqMbpc-UB9jS_CxJC zIUd0y><9}Y*5~E0cX~^%XAa$UKKs%hKUtADt`Z6_F%wq@p{`Vcn@vK(vjh#A!^!NP zY3!JoV0K@Hx85o3w8bL~XL0=JM{;o-$;ELTfFCW6gN2QAA^dM}wDSNaFa3}Up_v%f z2vl-6s`V^{saL!Iw@!T0=PMcOq4gyWt~LneULPpwFp*0YjH9TGFA&NZ@r`*2*CxLZfvN zS_}skC#G?cVpa=S%bV(cWFX$kvQ?dG3DcHN?HEuaPU8xmnM#e| z9I#`w!u(NSuE!GxFa0U_$;e3bXw@?us6&G2IJsl{)rqOK?J8&er~r8Yt9kRU)qvKJ ztvEt9;`iV&F?3TL?wagnWu!i)p{~hdI05?!BNcsWO(9o8OqI1F80yNVLXG(TY`C54 z0~NXv&jLs4)ii7L*aUGz)e9|DgpKq6j)N>g#Rnm#5kCi{ICLn+;#p?a9BU>fd(Bgz z*R*S#S*SnVHZec;bT1?PbZqB-oO8KR9=0ZX5wKNsP~=p>9o4EolVL?JVV@KbtS1L! zWjN5{Q&G_lCvY2v7e|A5e6%~#wivE@CZ-C(#*&EDQ08>c*x0Po99m~!N>wE02S!%n zw6gV5G2hY_m6+vAPS}aDXI-nV4SVPCE(cPq?^V_^#G|{btfgt=v**A_9sNRU0i1ud?!<-| zsxGFcUqN1J`oF4rH0?s?68-+2iXHvJrVdeYS2kv`X2jk?jDDzziHXKpmnt~PX^y>o zo}3*K)9nym17k~gGT~@lCA`MUAFb=m_j60vk+1?`I zAzHogMpafa(sqBK1*ZC}mP+fjDr;xhdM|9f(mlSe-P#s*PoZ}U zSpyQqt-Du*Lb302Dy$EeT^>e=Hpv>f4ku$3#-m?jpQ)p1t;lFS2MvW117OmP9S{&V z5URal>mn~1tn4U7G|gl7&pX;{vB9-IOcg9W7m+CVM$lc~(g)xt1xd#S5b)98Oq7eV z?wg%`Kw^?$Yg*I1b{q#{j-LCWRb%xo%o;>=X%cv5&KUb5Xi3a->)F`OAF$tyj*flX zD>^*(tt%R!^NA(Bz%DJ6`QFU;!Egr=?(D{CSUY@h5p-z88FDfRm<3HD2H7oj*}c$_ zLyTMW7%VQu*u9L821Xk3vuII?l|hWXohufZLxi-4^vqAR5whN?w7v+}Y>9x$@`&}F zxoM{>f^};ahjtc_i^6RS@DvEw383%_475+Vq5QBjmAM|k{QrTL51+$g?g8m%50DnC zG&7*UTBB83GZE4L#Z)Xgo9+iYI{XGq9uc9K7IyQv@L^hJ+Ns9NvE==$$sfT&KBubu z!zPBy&_>ER$5*%sV$nPAyz`e z6`1EXvi{4j9XgaWGbxWrlhN_e=Ely>sfp- zWX07Nw{c@%q17oXBxRYTiG$&GRd@FBA9Z5^LACpb;2LtkVO+l}XzTO7K%>ii=^5Vnb^WbLL0Tcc>HQ zQs%XJPl?j@Wd?69QX-`-|xv)u%2Ld5rkADC#*s zk{httr#MRO^4M3fO!R~P-Q?Gt4H#3n*MHideaZ7W+OsPBrzp42gk(Z2dfvAy{F?m* zw2{U7_!+l<{a6LP@yR2KZ-Ar3$EPBnC`4M*9*x#!#chvw!>d5K_T^28?;^ zvwxPUs9%w4tb<7v+~!byic#UF%a_*RQWS}K%D(yR=`du)`ZA}|P-u?EO(a_E#^sL5-cD)3 zwE;{u`+ZEy((N{{0t&nO|KdI%?#Ou|fVjGd^oX|rpW%}`bq5e9DnB|;k*9RA&ld3R zUr=m$8DdoP%Hk{@L?`f!9gF;{nCumaAtCE)92*&}1puqC()#7OaY1|fkZyCxj};5L zI?{P@!(wN@f7J70-b%wEGR}+N_z%yEcO3D&xGf%7hk@Zu&yvu-EjkqB zl^+KV%-$7kJhR}C2Q1Rg5es&x;+cqNY$O>}y~`qoJK4<g z2X%VlHf%=H=hQoJPlwye{~PDjJDT6NJH)QD1zOfHbchmow}YoG173z|MiP5%t1@e%8X?*2mF@bGu>lmkz9jQIbE`d^sV=M_+``yY_6 zW=HE=E8mWNmuh||`Sjm;Fp2w-(U)*rGWsHpDF1ObjwsKCf-3l2<>`)FYee|{D(+Gx zn?Nq!0FdiRhp$eC=6^vQ`wh4QiAO(N(QqiX%Om;`y(CiJ01w~bV~_lh$XNZTBmO7J zcX#3H!)7~23}y>T(J$OjOlGq&YBcoC77gT4Oi^g1^eryG5v#<0o!Z8EkHZyu!eugq zsr@02hhSO zg764)15n9Rp+BjWS%Mr7G40bycCABp8_D{l$(qt+hg`!qv6&Li<4&MYlPp!Q63Fu4m+ZUCbKJrQQ@Ofk&hX{gV_~U4-`;of# z`sLs+{Z8KPp{-O5!d%a2-K0;7UusL1p_wNR~dYwtkp~ zwIB(Vn{Y{f9Vu?QcMAAUanGAK;5QJq)&`yxX+>bUwLfCT#WnX~q>Z3#2huKiHyt_c ztWJEHK-@zJALiGIobX}|ToKt;3sNH<>jh8pZR~v=jy-6!^8IHSLRF!_Oh~c~oLjJ+ z2Bz4&nTbpAK>1pqWv9<|WAF1^tvGsoZ2uVJroU!^>!w&IE@{8S2*FI?lp3+is$Fc= zT7)~*@fcX)UuK4ikL*^Bq_mT%+kXL*xl;C>J)$YXAo(juG`*UQEE9CvCIlRSFgPSBZ zYo_BCKJN9*C1xHl^MIL)TVHd8_rvWk_SjD$jMjVcZML006P+RbIOr zGhF!93Gx!q(>f0H!+Mul4!^q1Xx+u7!%?6;8`H68{~r|3Pe0QfF?oHMrX7L2>yV1O-cWiRd2|97fY4urE#F9;W7?+*Mwk2LYT&`;1dIfo0d9bU z8xO}TDy_4{`S>0z$&NfT#FJJFCxKY|Vte#v82zGv8Sd(W(0DTbwH#-(S4@fTgv7>1 zJ+^;Zvrp_l5pPR4`c-Uyadb~?|M2Li97hBh7{q6urIG>R*5<}F^+7E;^f`Lh4=5WJ z00>#W%~(B*9k%|FoB{II&W>m6f-t++FmXi8d45~;uXtkOf~Cd9{kv$O0p?8w7o(yU zd*5Xa$Mbt$@-D5vNjz)J`4baZ5> zZAyyqinRw})8H$n z!B+sN2uvmBLSQZgW-3@$w_G16)0%t16|i1a+X_$X_A2Y35&u2L2`-@R0(1l+X~g>0 zJcXM)Hy`emV|Qb$exD@5Mbw=x>==)5=^u>v9gwD?tr03bh`1CnPI3awbK+LdshA#k zOjD%;f4O{9QrfHNC#E8t5~i}q>~|cx2n&9K0;s~CAdU|zIAYy@ zDDCXoFGOnOj6O zGAGV4E@e*alBY7q13G&Oa)-_H*Vk0L#jW2m>-9~a$~(W+dT`BhSK0x*VjqA6!dY_) zr^5?-90jIV!I;=noh>8#@^=&o>_t$Gbr8G8=W1|wpx`c6Nq6j4REh1>igN`I#qc*i@02*3d}>OzQBP>hi5*UKLZ7PcO~r$?XST? zn1;Ov9z0_|$UBFLUU>d`dh5OoP+KZm$=x5~N%oS6GLXrJu7N2zlVn#3CwWZvL#JFSI~48jehM2h2k5 z2dsk$UF>Wpdho*Qi!Pj0$Ii~Oz=R4&ZlOk9h1y;9iMCdQi9ezAVkAo6MO zrXMCBau+IG-qrjr-ittk&9_Q@iuV}GGL~v(-+Y|FOHg8c`v$WzZBz*3)N4^bbV2L^ zaDC`2h=V%VG@Mdl)u=6Av;bVN%C&wD2C0I*r8FNH0ZvA(!e~Fb7y)xn*ac1UIP~l+ zqxBP5J_LYrd zf1&KsnU%P+j_hDob6&%OQgEt*{+Ia0(-mlkQBo`3G4uqYD3yXcp{bB5{v8JP)M0PbrW0$-iwS|pGw>fv)I7@ceHK>pIiN|K*I#Xbb(%u%KJtICGO5bqRjq5@)JrtjIN%tG(J4O6BG%B--Khfm6pZ&CVeUcg zuNZgC9ze>^_Pn37>N9TJVks9xs0Oo59%JyG^*IbO7cljTP)=^;$0Z4SW1tM5TVtED;e8d3Tdzyu6l-z{dhgZCKVf1AGfQGg=Fpr zS%`Ni$TE@i{>xH_G`x4 zTwpeUjTT)U`_5~$9*>X%QGZDk>mWmk>jR|?M(f)$J9d%L`VzAH@Is5uE!nsVYd+p7 z8qVE=pSuV7w$>5fDI&e!Oq{lSgdcwG6D}S(X8A#5_1mzNuyr=>yP^a`9L9=d#9Pn~ zeNqW;{#ib?&eePwb~mH?2kd6@Pfv35`9)?AKc$w@v0H9N{fhDr8(-vnHd-$MD58A( zZj5sB_fNo^gD}^KcLI*>$0N2sv*30XF!XPYcJiuEr998&XL^Aq& zrQ5^Sj?hLZ2k&Wi8FxQj+KG2#(myMJ2Zj7ufn6xh{8<6<9-bIXzK6%r74PBU1u^*^ z9^V*K@8RM7IXrv+qzRWEjWs7y&T{PDL&kq?iST}R4KP(`_@+ z(ObB(TV0G@2j5JG#}6u1OdI zv9KgefASxg-S)4*wP!uSmS+Au&b!SgL%WoezefNeULY(qxrsTYMDfa(eMRO{@;elZ zpUx43bZ5HS%_4W&9T~OL@6XQ!Qocmh53C?VJ1i?za1LoRWSAmY+<;LR@6eZJu#&H3 zy~?#w#uL`de46XUvva#ItP+})hdL2xRmI84lfa(KL?tYPKOxWp9Yrj$!=q7J)m}L< zR)B3rz4fvlPI{cG(MIh3Nl`U?D~{q*1#J$A{8fZ#i2TGe3;Bx&4c_FuKMSekc(?i> zqkSyeQOopvGGHAJ`~vu3g^vJFT=ygC^|@T2Y9%Ru9f9*Y`Qe{9UGaFsi1V(V_(6!* zk--E`4#NblLGzgtI4s6?7mDOmzFEW)TE_y61ou||n=WZUiIQd`kbL9JUPQ?!&*z}s zoF<$?LLyneNsw|Tu1XV}1cK(ivgNCRE$wW#`vR9dNeIt=*b#InWB=;>w8{4~tgoku z8{+L4H0-w1i%=(EwFn(${o$gRx&EvHjOD|}TTF=e7)~WUa0i$=zHh|Oj~cCa!a?w5 z0In1JHsc!j?@?*rW^81B22wtK^s`YsV&oGQ5NXMmunJ?&-*P(%5Fq=-+}${oty!O7 zRW3o-u&}WM&ce1ixNobgc__ZYxm#4k{Dq_EQ!x7qF}N+D2SYWl8T5#QR-9*wcR=7& zxr4BUYksfH@ zM82Z?6?{I=tBl7l^u}@bW;CcvpX>2QZ9mal4ip&`f5#pWXV1R)_U6ybn&-?-I0|jM z%&UiShPTW@F-4%mWTd6gBq`%SClq8`i0UH z?nGZWftHWG(P75p@F-aK-8eOLufhAY2n5i9=>ZoIE-V>3W-+?p_Smz8PU9R_=wgQR z9{n5YJ^D|QT^rT0{y`yBr7zLX!i5fuD4*JUqqsX&iI@5Dzv;%g*BWTE8f}@bHPx;) zxG%+b{o1B^O!s9tgT!dtAH&;7x$%n*d|v!25Q?F-Y1R80rU+lTZ~YTQYJDzRUizGK zzUIab$b+%4x^P1ookbVMyG>)_yV&5CztsGmeKUEd?;j)ty&wkV*{L4NU8rnd4q`D5 zN{%YPc(+OHY4PGXc8Hry{aOB=1P>!Qp6Z~$E|PEei8dluFY+9!mb z4m-m8ves6Pz^2df3jpH+)>iSB@#lQY7^i{JfJ=P;FPU*J3dea{~Y2J+=K#2as&PL4&~yv zr3vbQj_p5y1A8O>C`=%>|J&%Yjz1_y4}y;OLEul+d$X^t7X})g$5(>}0yzBDAlaG$ zwtSQtRg7k*8{~Oq$4rGb)981JzD=P^f$qL3+51r$hmJZCaPk*uEaM3JRr^{@rVed^ zTyzee044F97)qD(EB*T;+{j}6h<&!)x%~pCz6C0;Oc=QKkMmKyDbXo>SI_b2iLvkW z=mdEr*+JpJ<`>k-_G&0ACqQzb+=mVQxQW`bJ;hkxM~SsHGe z=@CB%Al%}k@F|sewO71>&R33$>|Y2sLuFRtE#hZzY}E%pp0fo#7Fj&FNR*r87hv@#l>AUFdY_cGhca z)LXtqobj5BGf>JnW4pQO0~gfg)16sqUk#Q@H3(dxY$^jkdQ`J5+5UT}hMvPy;Kik> znWz-9b~uN*se;9W#BkzzvN&eM<6cO@v5(-#8pTlZ^h6#|C(FQ>0VKu|M_@L8Yefun zdIxX@xQQ{QZP>f0Dg>l+7?4(%c5cMfpM!aU7z>BX& z{5d-QM1vnTJrd((`NWx}pDg^!RX34EJ}`29#2rgsaT8id_wxeKWGLcAL9i$Qz0MEp zG}}h)DS#f@hV4YcN95ZgcMTYMRS-8Wu&)oEb8;{R%*=p{CXa_EI z5c?-y^~Xi>R4CQ|ZJhDr1^4b|Jm<%+y70aLhG0Gp7?AVxfow5P6iVO>%bfGVFE_Wh z^BJ3X=mj0{_pn37(~4^r77ZV+jfpO97!$2+ik6j*jy5dPhSm7BVe|b|mioX9c;PGk zH>^nm;p{8tMil?3;lnsrwbqkmK7cN;kchN$SOsa2QG=Is-pu?|;`|H3KOeN!V5r1?1 z(4xtreSfsx&)+*w*JxhS)ZEZe-x#f(@2{(GT#Rb`jr6%S(b~q|8h+orwsFZ^NXwrn zhX{W5sHwIQ68F|JSc+demoj8>tZ(4&ru&E0^wwnm*?z;^#wLmkob%J{hiFIq6uZLs zQM+zFG$VP-UsXSHnG}(~nZ9tzm24-YUZza!!TjdM4gSUT^C1QldU$C=ZSB=PrKA@a z)dOhB(d=Qv1$Bubf}ZBrE(dE$A*#=P-u;TrxM>+*q4YDO2J@<@m8- zG%smDFGD4V_lQO#%X+JM!v4!iaVBjcx)AmSoPXisxmVWuVeK`w^J|;@l^5`RPkcyU zH{Y2@bLUB8op+6YZbO5=2EV#LPpDU0Qom$WLwys*e`&2BzntGFezf0TQ{TKKD#ls0 zUsJy%y70>8`sOBoQF-|KjFoGb&!g{w!*4f(Cl*?GQpa+Hy82 zeH@`YZ37qwF*I`*Unyi}70S&CA$sUvFt-Uq+=L!1tXWtKO-pA6nH}pnd^R}NKt9qA zIK1=luPj{6nJX8>1f+8tz!yD)l8;vbD2 z^}s3hFD4KE35cesGJV=Pbpy}N(f7}*Ma5c~Ul?twT~w#Wn0%ej`huXyK6~tu(=`g; zpi=WFbVsYdQ}MrNfaJgJD5*A3wO=UHYLy<1{&2is(T_ht*8i`gq&}?S{H#~y4M(9n zT73s^`X!(C6OWww6<$;6v;T(va6ZcwealeEzoF>J={*WROQpp}p*vdr^@@M)Fv-9A zq$8(0Re7;0Z~r&+N8=M5Bl-JPdTX(S4^NY$C4Rk14=?}!3%q=k>c_|<_w(QNWABLn zXZ4Q8cimz9{@><*w00f*(c1fW_@k9OeE-vQ?_u`l@O9GlWm4bk&OCBjt?)sW79WM~ zX!Un0{%fX4{=svPoSI>Y-)73RM5RZgKODb7@vpu}*7sg~)z-_21AR&gW7^uO0SjRPaKiI1baARa%2o#~*)7&5OSf{`i?F z6Ri#@@nMzDQ0Y}jUHDt7(juh%ENrf6steD!iulY=Xj*Y#_{4OnAlHv`kKX~JLHL{S zi&TogjWFSt_$M0xkGvNr$yW)B95?zS;29Z&Io6kxuw6=pe{t*xU0w zZo(s})Ht`MMR1+g(QZ*;MLbqz@x~kucs^ z8Jq?FxZkk|=>%-|??n3j+o{w?Oy5nVCS+^c^?2iGEz+mDQ>o98uKg$Qz3^`-;VsAc zNc*eK>(^eW>C1ikaeaDu+x1>P;s@g|_}{722t~u>$n=^PKpE+MKgTf>`m2TVeKA*c zeuMi{J>NGepJT%h>sR1!2l#FyVoLrtjt}czhQD^`bsbXRcj~Tt()A)hU5`H>^ehZx zV!rQIS7muE)?SFh^=t)8>Ok1^6UkAAEc!`StXplKl|;D%g*T{1)AH!4Vmn zx$X!%IQd6SRYG*?>S46A4u>7@P{BQN_vkBA?snaMKH2?P@^f=VmyXoV3RL*9f~mR* zXmTXmg}vvf_S-mKYu%xI|BarC{NfnL%XLNX{9<52&gfM1=zS6DZNpLHJBRB1Nb;M| z`>!DkI3A|=DLwq20>3$!ch@L+Zgq)q?BOTuN9aA0A9NQU*?dgFkapY$^R*rGmv-xX zMj{gceh2U&)y`U1MSkIp?03xLdZc%LA?8LzSs3kWI_URf{{NmQo&S2A&duMeyB|98 zI0?HR3>No;->l8>2gu8LwDypBL_f0w<#XUCj@Vw$JgUfFr@Mc1WJQP>Liy>hlJHBv z;Uqt*{F7+UQ}Wlj-0NINw6jT6Ea&BX@H6qI>D>+>7uXlA|f-qn1$Pk|#k{>W;R<2fBo@otw7e)NE{x3w-P`vB)-ueDXV))=j%v@JP zCX8uvX(lWUkNO!0`8Mpp)d%?Bqw7cbEqFuSwfKnYk#f@3;^3Ere?LR2j1|Xo9ON`{`O!jNJNL%ywOMuf!C0?0&n@m-U9MTeHaVXz1KoPiaoQaI zS)U&isCJb)WLpL-QqJqr6s+BBIn>W1v_$=D7qY#I_)1!$^LB1mi4iEi~c!!-K*fWs$5n7 zKb|=M-tXZJozz>(dAdp`t8}JH>r}c_r8lbdE|or@(#KW0Ri&?~^kbFoQ)zatZ0}f= zo}|*#RXSOvGgVrr(xocBQKfgO^Z}JVuF|b4eNCkwtMu@G|EKVJL(1#?d#LS-pI`N7 z=V9|_%A`qW`it?e2@m&=8-2#;Qf(w!l1AqhZSo%|<3|K_B6sMQq`wz-C+VFA=3ICv zodf+Gl#0JT9ag3fLkZt}INHbc8_WsUs}oS}_V${DR@}PxPE>Hadc8@cr7fD3Y_5$vza9yR1-lekcU(VV+kI!KQqaTP7kSxxW+{ahsOq82@e@uX*nK1;x> z^_H2K~zDLjDYoeYr6ueH) z`G#BpyuHf~0P8Jw@&eTgq{SA7~@o=sl{M&^B?$mSou>5TO1=0R9y4E{L z2EXog9|#IP4^k!GH?XF89+KM8ysx0d^E;^=uXi`0N2G3iTDG?l6|%kSfX$_WuwQ*{ zMuu3Lhrqt&VEY04K7c&Z_TpqPvo84wY}Y#!Vq{&atjK$J4xr1Z1Xq#QTL^-z%O&K? zU(&o-%eq2R7J9qEEo(Nr>niel6XY_73|&RV-Z#;Ytho{@@s@$cfy%rK2+fmaK}hv6 z__!!gRt>X8Q&bzNXFmW=`8Ar}i}J#}^A~Emmq=HUN6V!Qj{^`L&e44OFx1oq+VKc` z@`50eAN`?h{Cmsu!CCLK8r9slwXZy;Ndd0gf_Xb! ziKab=((wqv`s*`t+#k)A$o~3tRPV1()z8%WH7LptKsifNx|%>g9X8SLuNj5ShZnx2 z3R9?g@1cd@o#W;|Y$-nd-cXds!%zJ=O{w+Ut?-oceThF*%4HBlNa;~}DFugI3={g} zNO@RWenoi!C`U-j95??lOeso9Mse6FcFl8&gBivA2?n9Jp5p3^;+uY4JSU_0fgcw) zWE5}tadAsVF~h~f+HTJ%c0*x@6|c)E9{S_r^%=#X9~XCK6wmo_@$;&9A(XmI7SncK zSLjxt@04g~RJ4LmR3Qgl4j1S6G8po)k69n{)8h&9NN>O+VzO$~8g>0{wMGzhU=n8CEU-_IHX*Q}*Rs}fnG-90RvWWw zrFV6~31;0%Ot#mxj&0p1C@&`02Sv7qZ9Ois$FPAXn9cGYhu*3H!Bq>A?8PbIdkp|X zU$5mesjh5{L$7P!1{%)P`wMvaUf1=el8U?(;B1iQkj-NJ^?sGL!M6!OE*-AsEnbOy z&aL?3pP&HES(sdfIU0`=y~kqwax~FnwD2q{IgrP@Sd@JtTK9S{Wn-Fze41+n`PW6k zBg?xB-+d^D>jHfBF8LbYGUmzsf!7~J%#(YN1BZU(9fLI2EzA-f$z#lu>rtRDk1CpSldWqFKwa(gQ`ay{ADw>nWm?yWd?m@3zMGNvcg1P;5*`tO$#yq)&3XJA4 z=E)tTcOXH`lee1S3HkygjCt}H^W+ZE>jk`8&l}Bhzup_X8S~^Z=E)7{g9N-r&tuG! zJ4%0E(6{S(jCpcT*EtmKqI>i_#yq)aD0rQo$CxL#Ou-N8d5n2-%N4v{&tuG!d!{~0 z)Zd`zG3LpgAf$H}b?SMHd2-Lzd6eibLd=uTm?u}oJh=~2B_ig@eMo9Y#yq*dlgg1X zPwpd9H$IpL-%8E$(kO(nvR}#+v%EA9fh}>c{j^@wF?ZVgj5c7W-XCCueM)$2!zu6} zMD26hF9qcFKE<-LXcDd>pZ7SHo&Au23cVd*+$Xq3K!d%%0;@iuI|StSUc`Enq<{hM z%cQK7EfjnAkn&tPbS2*Np^84|+oE2X_hLfTUkNDaJq44q&!wZ#Emx80{UggRlh7=0 zIibrXw7|Qa?Onz0z#Oz3&S3s5flz`=bDaXg^G+3Wun&5kcdhU`+o2H8UBYXGF!A%x zI}cS1F-n&q=X(!aj?rA-VOr)#t`udTK(b{lN{yAyiJzlg#j{Dg@F(OQ<5z02~lA6Z_CoaLo(E;gS( zivr0&IRBEjfDwUk{-ts(H4zBsU&cN2EzICWLXfhRkIGp0C6v~z1E;lzWloWNTf7Z%J#K>P1kDq3pnod-Y(MR zFXZEsUR$9QU;ZK!n0^ZvU#aCUrpBSzez?M-xY2ObqV<7H(r6PG>PTN z^^C2^X}xX+QK5drqbT$85KCVn<<>-~udieQ^+bDfAWm2^bFs4C!fdZ7`d6&SjzJ={ zsEc3Kpn&L;-YS*o?Kf|prr&rbh&UU6fu1=~VZWN@Moquz6EQA+trxrP(-WkXqO6tG zG_iNl+hzZ~5QS~J*uK7|lTxv!ekZZL-hws?^}E+1->+`Irr+ZjK^`Ulscg*aEh6+Y zDI?Y`*3y4IlMJrJ3=8VN+>gAsfhxGy;cyG$*-k^#onu7 z`ucrUqGKiA0HwQ6aw&uKf1=22M!)}Vwpfp;<<);X29^3@oAjVqGnE=2lGQv|*gfxp zPya&w^@SkxzK%-z4%q?C`ym^Ag9Q}rIEwbB)443~`>5#3XBXc(9V7+!ux^f9C%w*p zV&GWpnR46&kHy|B$IV6uVC&Rd!os`)?Z;23}UIMtQGKJTR+{c zv+Mc~s_=ACI8dnJbT^B%f>S8s^&a84^Z?`;fQE1IOh(xN=wOA1s?-MMph+DIsm_1f zf>P#XQ_6vTC7##;G_d^aPGk#z3g4yjd!G2_oX+yrqtc)ns<_6h z>jSU|4BStiHD0!RET=5;La$&nU*;fUtqAxAEMrb|xnLo?HX~bVW+NC;zcWNnr~s8? zpJs?Y4O}cMkhIXEsm;u$KN&#Jre7pPF3h21GEc?Kl8O;hT`YQ9crz(fp641)UT8z& zg*Gk`+CYz~pMuAzt9R5eenVlQuy;J{GuwGr3}fNnDAju&p}c}GS!J6?1RlB{4v1B@ zi7JKHvFs&9I2T&i&v8q_EhI$u&yiL-7qjggw=fE7;vBbVk(Lm2(-PQtNRSrJpn4_> z0;!%!ZmLI`LWNtHf*Afvw-|n57Lx^U(cvj>XZTGy8-zx}ZuVarG@gSz*`@1K^5jTO zcF{l!`I4hP#lk{Uo6^x}B4^(QZrxZ}rK+$(GH3kWVV3RhDUf>m7Msz<1;lKqD9vBKa@KFefJn?UFuWem(iZRAB48zHp2&@&2^QExo!4OR7y&v)t#mG!=r zrJ_|gc?`|q5pZ}+A=PNbV{w|t=nNjCMZJN7hss|JwWC&#OeK6lkA}V zT^_nxYWZVPMJsrZ{-M88=JOyMD9oq7FrR@uLPO~%=;W~+kp9vLjvr6_60h#;T%DtF zKj%@4p=l?G%MK<4JY1d1gT2RI};a8 zfE=pNAbu#$sJ!!s>Qmic>NAGw7qYHa^nfD1S`y~C{qusXj9SxKOA9yxm4F>sxpGn} zzHUbq5pdRM!>)$L_3wl=IP}#%$>=xi$X?K%Bs%gP$NvlV<7D>Zd)bW#R|F<2`byEx zbSdRj_iYcZK&a4{hTZKI4LFRe`^yH-X8$Mmqo&{ux`lh>+s!9jiKD%4FH2q^Sc4hf z?Y$5nPqBuJ0qGVlwg&JJ+*H=|&%Cox?zyeAW90}2PC#&~(DjeNC0qxlfsJT{73>zR zwF5k*l43}hA;l@}Fi!;!MfMa1+xq9i^=$y`=RYB?@A1-~cy3$Yv2x^g%%YlOWS z{aUu-T8j6V-cz`&+wK9Y4pA~S>$Y{|Ta?#VcJobHA;&#`oThM z7-N?zpc6ppY6aks?4-V;i#hJ1G_R*sX}K)YgIdwY3RNXhE^N|H?9)#+&R*6E{8ZwL zLJGgUr}`3wxSyT}2jkiBaGt?~ic@6-X6gxxvB8moR^{KL zd>B~JL0ymU>3WHF;$y0C&_$Ydo-EW$P?cOR)W;6hF9y}v-HJ*W*LMmK#?@Q(6UJr9 z>N)P^^MYuX4NXTw+Smb#<~+19cCZ2js}TwitjZMtRVic?vka@3Bzu1myA&7M(d3nd}4nzIP0_ z>63vRGYy$vGcy~R9n365CLe<`hHoR>$;?`0{>%(F1aC5PKQcZndt(?5OlGD9nH!KP z`l}M;d02!Hddoa1kv2Z0WYgc5WuDtM&_mQI^w$#WS_xxlQMjQBx3qWy1?R-j&SKcS zR}uJ*liVLe+j?pM`a2w@zx5$=7BUNtL53Gqwqa(Sc`7p52l#z&W`4|cV7M5JnS;!4 znOTI)K4z99^HzUkRwEODG-GZ-W;_}i^D|^_X66B8US{Tx$mA5_o*Di7)rC^BJ5;K- zWP3oA;olFZ5dQrf)EE9efsFF+r<32Dfs$V}RG_cTt~i9(*)70|`j0sE&mEYqFXS0J zNY=kZrTYBrI}hP8`fv)tFL#iV=OSd3JVmDskh~rR12M=S&XWkO=r^k9d8a5n{(<+E zCTNzNy(?+R`e~fuO~sg}Vz$q6-?o0`1db6VkfxpXU-UO?<<`L&?A^!9)~r-v=q*0`X;wG1H!~l62N>Nm=4&K3oeTxwykGkrGr7nN zEJkJkGJj&G2${2nBQpw_C^8`%wT4dgtHvg(wEj5Il!NAXpwUj}bZS*aJi6B}aJ>hL zGhP7xZ=e`^yDEGZnj3qs0>nc0wgSYO_^AT8CYF7p0I^^rFwtvdhp}FmC&=spG;-*A zapH5Th>O4=XoaKMq!t4BhN4$g`Dj(QJ-N?L(%<0@=_Eu6gP}vc8zvCgsAAuM0Jb+A}F`9Pv zdX!Gu2nd1INLG7UReN2f`ds(rPSr}(ID=Jxg3Rc{DbFCAhftyfa5(TukUr1-dvYPk z-^hiM>~+}nE5RE0scMiRv=|Y5iy&Hdr&1|bY-+D^?{Z{19d(6FE08(6+NB!#5|HZA zR8_N1rTW$GGdMVu<&;t-%lXWRt|1ecr%0tN(_Ng1QyD-=9sN=jcR3s{ao_52{H??B zd57a}a{S*zIP#u^4F8-y7R^xI{~Z_|X0QEKUC!Wbve>m04g$-YHi4$Z@FfsbRJ(-N zoB^4!%AJp4)r;gRw^I>Z90;Naf!0`*-BBc0xgxR3%{vvV9PjO*&L<#w1n>zwYA6z3 z+876oi8H={SoAI>ybs=4m+(fwezA%T6RVg$U9NG%#FF?8N=M+ZLqf-$#uW`~*h!+L z3jq!hYu3qP&C)MFrQ!eL?M>jTs;;*2bM8*UVbTbqL8&GLC5j{=AOtcPQIXuB1`;v| z=ea+0Yf~9FK$Bd^^1D*MsVjUOxO6e(a ze5q^;6-VidWT$GSkC;HC##foY75n3c7m#FfGR3i3%+0R&~CZBW;`HXlKW*BN=*j-NY)f$&W%eeuQGgB4Lfx zO|;?+l#^Ou@#hRV+QGQDSRxDh5`sodB&Yc~b*HnbMn(@3p5xIgiW@y#^jbwMTHM_X zc-Fs2V8j~f5PF%D#1$k>TiPkrS3$2SaW#lKKH1tH;$P?zv1w&_;R!mQ#_@E04nm_3d#y`{iNlzvaK0#yaY)*O?jVPdM zdS6VAfhCSzLEF^{_fh3n+J^+Pa@nf{Zf3BHz+nOzdkKunBk(qXY6c$?=$B9O&N0g0 z8?c`f$@a(s?#L>jYJ1qpCg0wxufZQ8(iDBI{yu&6-Htm~U#-7imxhnhm+K$Uto-N# zr$AFWNTpHwvi*aabs2RrN?*D+<=3dpxz?19I+JSkU9^V+d>3shm&?hewkh{edGeu? zs11FFootTdPeRzfps)2mMoeZKcb9N%P$Xe<;67s1+qiwik@YL7)Z4gcq@cHP??^#! z<35ps-o|||1-+;4y^Tu}t$s_L^j;QoR!fz=&(!hdUMqFCQ2%L&e6p8vy2$4ZUw;|^ z6Mp8*pX$f9p`JH_WaW@BCyY4T+@U;&T9`PD(}ZK`21mR`R@yi|cPcQ9i6f2UwoNd{ zqb5_`@^l(+y{;ALz?gRymHDc5fv&opilbT+i1ADvo41`!<#*%U^4xQ15a?!;sa-mS zYG3H%)=rvAWgY#d{(Ua5qye@kYiaX>CT7mkU8^Fh?c&x_K99xK!hr`K~?=GgYz9nqRk58xaXKd6tTG)d# zxHb8}6#rR5)jB%Qu{k=&mr^ya=TmH6&;LM0b8399zOVZsm-VUhx!TC!Oe%lN<6z2{ zbD6iZQr<=7q-Hk7)F;npO{dzcXk_^5-BA~Dxlqd*Sw>ycv@xY3F41jhQ@Vvpqx5a> zpnW=d=`AWxeS_V3df<*UGvwoWdY>Y3u$!mHdG_Ws+B2jR-O5iStuiJNyqMBv>Nw$B zM+_X1&Qxn`|I>{i9qKdZngTV|g1?qtirKi;cE3|--m&0aBrSgfWH(ok?D$hm(~l!$ zKk-AdIUTl3gF`I)MtcFv=5$w3Nq`gJat4nQc#Huj$$t^Z&m>RibU6G%Nr&e!;B@#$ z0-|}^#G2rEZo+{FaZlAzi9y17ljJJS8l==pSd;;^8YL)=YpA)Na>8IsqR&Cv()g8>vB_LPWwdt*%B}7q;4@eV6u$!1BOOj zr}j%XU2hZ8R4X+kq(2!_fG$v^_RBPEhYYQ+>aH;a-mc}f_p)J+lr zCzvXGs+CfcWm^B6ygpHr>5kqiy76bF*kiq_(q2`mgU6YwM)Wart|3^d|CVUIHoEF* ziKly`t9DA&bJ10AN!1(CRUb*!=h0RDB(RU7?B6@MQ%6YEY0*{nQgv>0)k>+F8&x%S ztyJ~yhwiTMbI*Ng2WNFtBYpq7uT^MYL{xjc*-JbpO-r+l|2ES6u)ij5vzHjJ7xb@) zXl~_CuyGIkM1KDyTQ9SA@rY^CoVPF(2j))rkaq(l>{_LttFW6g=mH|Oxz;?gK|9Rr z4B`b^AYTEvUO#MLo=y_1pJuut;t`e`^&>3$v6Y+L$5y)aV=LB>FF5yakq3)*Qm;ex zEx#@LmY;r}VT*ngXy~a*Gcrq(eroO!{h-mYd~5zu^E}b!zQkfMx$|A}WTAfD!2Yw+ z>-a@t_j7s1eOdE}fBWfX>-}eK-|G3aQlHR|=zrDhuTMJ4PVt(eP2t< zKfkPCoAT5;D&NdD?NzL550y{V4*=}dPiVZv^=nyAQ(m`#>e+;Sy1Os9$hZGZv7nxc z?B@O2%}Xw(#`6=X@qWb*R&C<)P3#v_|2dV%b2zLOLw7q=_m*m+OHC8_y55vaIL%Y< z8OKnmav_0a0`?*TqX+~UjAzCM0+R{!FgTyU6AUgS@Gk~61cHr}KAx4Hg4Bf$=ojW1 z-&$F1lMLbvJ@$nhQ_wt#wZcQ{a-c1mXv)RxmxF5JSW@@rL~o!TCfrEiLk67$*xmUX z*noSf6r^iG8IKTnn!z&!axSHP{WT(vZ{7Zn(aU65)o*fuPH$De$80NQvvBb}+~c#f z_IwXluIkxi`A#m~&aKdAAACPIzR?QYtVXy^*CB@o@@GIb*XjALgC>Ps#jdiXb2*uc123P2~u0E zcyhNM7XDpe{Ym+S)biO{s;QQU++)CLbJe}0T z0_mZH=z-hH@d#zGSh5o3}h&S~zp}k^gebs>)Bic$`CsiM! z>fzqnWrZP+rb^Z(DQMfCkpkUAIgK);4v>n7*5vi97b9EmiERCMul2=f-O{^t>Sw}p z1sG<|h2Gf`VH={V#%_};tx$m^5;JWnA=n*#D204r-q1msubE=x-c8BD-kysD|AD^z z{8=*+{D*NS!S8M#^)4syk92+iR?4xNoR~~Gp^eJ?fV7nV%4NME95Pp^mr(hJII1`0 z-*CCpD_^~o%8z;F0n4bYudRQquXrz@vc3RriYt~=^@GfA%ClFPrDnG}oi7CIz2uv#;%X}EdjOxu@eo|Y z<#jw*pT|8<<*qBJJcaEvD2SzyNRwC8Efn{RzNq z>3)Wc15%UuJ^{K?%1<}Ukk-o~<;3``?8rO6>3$A<7kK?uw9fF;aPJeq(-M3O^Bhr; zFOl0<#NS1-^tG>nSJO0^A(i^tSDh3%gJu2tY-5a0Ex(n5zV`Ks6!gN?>)O}kJI*wX zw#zYjB8~Y290S34esVNvQv`n0!$thetG_X|8C^>B(Np( zqdSP6zkvuD*AOZsN6OfJE6fwlGL7t&@n2Je3H&7E#A^v0ATXOix}Q^zVF%UdF}#}r zKhem%BD-5;J_XtHGG^oNpSgK8vjuYgqO$E2WPFAD?@EVJhkI z0X|>-T59+ay<>7B7DAr(R_Y`f$kR+!T!)o4!b*8rsJz3QA~ih3R?0V0^ArvILR~}W z*Lv`$J1eXK^erpjA7`a}G1+*B)#;W__45<7HuDPILaSRqCc*=zKB1?(Jt390ZzF`x zZC{qQ=I*Jxx~G0DJa3zNV`}QHG8W$%YQ%GksgFuk5@jU4z<5j2E~%P`s-5$U^1Sve zCPm*9hEgyz)fxsm37=w68>-%oXuFcyo+J$2VA$Zc&6KM9OqH==Y@txKl5z8;BRc8f zTpF(*{VlYs;%GM6=G3Z58hjwfKTu%V8}rPmkF8(4D7l_Wbd}TACsSc6ok%Bu0bOSo zk6%uytyNkdqUm7AC9I|P6K)|oGf%jl0L#cv?oX58Au658J9TRsx9pOZ#Z*T<=vMzk ztCSn4)hepV;0EPX%HZaY6X4I-XQi>WmVa)ld2T)ReMrCbbK%WY=1bcj>(^LzQgKvY zMamr3ijG`M=Sl2D`&?t%7IxyN34_lN_p>G1{cK?Vp&0HzQd(vXpqB3&_g9fv-D)j? z{EMhYyMGszwENT688_=&i+4;lU2l-1oz`a#ch5H_tB6tGQM{Hwx}Q_uef*u4r6s*B z65fZT>3!~pq<=tC@+~CEIXq8eI;x=G!7QfX8VZ)nE#;X8i!Qq`zrE}!0q2Yv^Y zb(i5nqx{`+w9oEy98t9LBW@Mtg9Ot3oVv?Ss-eaDU1`nPE;S)&L~@3quPf`YQer5+N}a_O5cRc6hOuq^d#vEz1O zprs(CPH61br-g1FUEtc^NG(75_7+-cljtEXezZ+5CpBW)*M=i9`L{{c5DJ~%mXEzI zwnO6eD;$OPZ{x|?*T?H?Ok0HYq4SOT?c{EI{@FO`xIUg@-5UN2oOIj}Z%#V8<*L$+ z@f^vUsNU?gO?fw$`8v=|@qFE9*zH_R`J!7(JA;dS(a03%a#3G$>WSw|P>b%MGGG5& z6VLa{yQyeyP(2!d-FZgIlu7}7MevBT*#1&}3_hh%=)6*l(sbE#@b!?(rSeZ1mUVuw zO1f^MpWH}62YfZX)@89$_C)m89?{?X5&iK^P#u@74fpqbM1Rlss-!3Gxj%lWcLhhc z_?~m|z@fd!Usk|@0%5=;; zdX1^PFTciQ-YF~Z`z~=Ds}-uyEsxc2DjA%lUrVag7p#-I`%r&^_3KC%YUxI)S$+9Y zXgWFHMd4>JH+F9k-<&klgy2bcQr&?d=E-tx-;(v1Czr`vX?zY!zFJ}4jtWcQo8oI+ zY*|jL_Db!ui#F&o7unPYxu}h4*WNu$Wpn1;uCEoR{gTT1-7QnzLgiE0JstW@uiNgT zBD-jne$(qyDvsxQJ@bMB5>B^7DYx2JJ4I6|Ti-x*?tQ}L1m@jMU@?K86UbjhZ0GU) zeARQHJ>wn%e*Mt>q$%U)maUt_gCz**>DhGOt_pSi_wS!zifxuiz5~yn}VBbbgv?6tRDw zB{eLvBtoPJz;d`w*z{TM=E%Y`QqWhNc1VHp^le61UsX_N47al8lp3UktdxRoca0RN z-R`J%shgzspQu^@k*U9vsstLc-U&Z-uT-U=ihtHse^Nh?s@$lmtm7n>Sx1Tvp4n=8 zfo}F3N5`$s77FkQ3FlbWb{d%p-w?x^`v@E&@F9bP1SZ^1fBOlnB9MQG8fFZl7FiDv zIDx=R3{EA`_#lDt1ny-pnLyk_1kNXLBLN*jTc!WEGJ-)El39X+)M^K-KNf1X+ z2?4x@afZkkLjouz)B7}h<~UENyedye&5m|{1CTGVrl!p>9;nfE`bnD99HCvNY18G- z=bb{m#c)QxySGWI9*PjMS7%STCHI~r)B3;BhJQw$KQu!6(Wk7-#ZUaEtTlwc8qOXnYtOYmN1Ac<( zID=?eG041}e!N~*j^)*6n9jWB)qR6`ITFMV?*2?C)1+mJ`Z+--UUPTQV0{7oO}bM=MSgkab5pHf0+IK=`0@A|v`*;vXAZTS_r4a>Nm|~81zLa> z_bqZg>Btv%pOwnptmA?B4h{f*KV=cwleJ4K^~K$NQqUK7$4emV73*v%=!?6>QqWu0 zUKe*$-kNC?;XT_!)DbCUUQN{}I{c0+S-@KdE5#}^tUQT#7*=Czz!`3(Trai!lHz-j zwQ((0_HkC~LsG9U5GV3)U+YiGPO0K+fybL_eY5PZ5h8Phu5YLrktr9*Sn?TIHR|;l z*a|rVqs@70nfPc0I(`Wqr#4E}ov3J(Q&}P&#OPF8B&#rD*laL{TVw~s&or$fskpldphT~8~f-j zc#|*{RGa$ypQ5@WW}4h~V;@ewUp-AF%A_~;;S)U)O}Z|yB$@B5n8G>RC{6LD zDN}rmiso8VcOTwnf5+9FsC%@a>Sw50UrRFO+Gjb*@mF=M(br6#=Q5}5oBMDMT(zCp z^(7TkuKf*_bt+%mXEfDc!)1M?%alK$vc7V)t`Dd5=I5xWx7fF6aSw2rQ|hg{_1jd` z7qZrfKdeOZ!##c8nocu{uOkloEdjoc_-6w7#Z;@WBkJo?!+s~167Q168@Ta}eRRVG zRH++2LLmPD)#x@~Q%PUTs`x!APamDn_RlWR1#6Bu+PnK?%;=RL{Tw=v-AFQYetexk zWPYp`IhR3RU*|fKr}N`?#H;gT%JY;T{hV6v*;J$Db~E7o$h@NK9+CNP$bPHO8@+Y) zb7+~rhRp8?h^{){zFK8$PCkm9_k5p`C8Fo>7evn+2;}pZI%qjtsHAn?;dKyJu zm>NPx)+&~@u}=ld;)Ur87O{mz@WRykA~#5VOGa%Oap}2&>$sTPc`_>e{gj&Fg}Fw& zl~N$ab5?)ZR0ks7=3N>2R%Exl&AXENJWY&!+q8-6d5<@&7YUU&W?$LLHQZ&I z@V5!jca?1D(0PALhn2Ecm^kl0XJi;}aNbYdCADurdQy$JF?C?IL7$^48R=^57^%{Z zpE*}rm~U-3f%24o8f~<7em(7`j!PrL0M1_eOC9o1ooHR~T7V+q-5FfvzTG-tG&t+P zInXNpheMq2H4|k(IqI)MeP8Q>PRb_s|J=b@iVkeWt#GlK{GW_ip(CHqk2y}~1{A`rziZxEuU$9he@1gNK>P~ajh@Xox zhBC)dR=Mqvrw5tu=CpZ-<7pWoNsIdpD^_BEPMRNCEj{vU+eVcN`w1HTzSeUb1I%yp zEltxGdx*N4L<5v~rm5stjS{uJ`X4VtR)zfz$?j`?#J=HcS~l;$JatLLxn#?rX+{KJ zviGzl&H7Ng#OrMHtRr6p*GXRxh~=-;0k*;I4}x)QQ^Jfs+3IGBt5 zAfH~ZvF*aa++skARX8|V*MEd_>Jsiz0O7s zC>)%t`$>w|Y7R{zpC1>=V5*OIN%3BrVJ@-%RRu?Q^q+ZjL*#Mv28QkX-wX@8PY=w0 z92PjgADqu`J6QwF2n_5!Xh(R1cH|J7^<;M^8aEupZWzR5CJv^S5o34sVA~tHA?Xw- zG_Kk$$vRk$i8t&N9pr2oFkMKJq0oh)#HL#^8@U`}jF98|)8z0R93h^(3)Wtda)Q@w zfI{O$uVW6JWUp&3rXW7pzTpvplWHoMJOVuQ#X!<$fA&+aUQd=@Y1VMBBc)d^Qa5Ry zu4s3QiR)85>$%;j5!zC5RD`xvJnd%`;@oXT|H^n)ZFIafh7RfdDXa#OqcX-(ndM|M zpl`J@s^2`hA9H6>$>Lc;C%~qH?r`W3p+tXrw2CtI#&fST=qta_>jdtVd&zdi)Af*a z(XAjsOq-ef~ zv$%(0L_6D+(@*4_35OUKA@mJ)?!rfGzqJ@Yd`x>4fNaGh64+uc=L6zNNXu|T;E7g z5w&R{0oqCtD`>fM+v*p#j;?RWXBo7>1rGHu&`9;OPkQ`<(!k7PDlgBQ{ZeHheef

    s7z*okcBqIbA$_3F!%{Z?|)^)Ar6aZ8=QoDRNFPDlbyo+tVv63k&H_{m$;Z?Y3Lh z5#74Q#soFnsc?q3ap@)1wtlB3wk^J>-j?rpEC zS>1X2@(R_lht)d?x$2H(!9ulYhtrm~N6iVU)Sy~&P#x>EQoXZCEenROD7sZOx2hv@ zH>lrR2fH%VBOOkKT3(?Nb2k;Kh6*)!tD4mL2Q@jU8oJfsy{hlwHWhN#tCYPjsf%(+ z;>7dRNfla^DkptSVczH>^*^ctgK^u6&c$jJiJTWyKdVq*#~)N5E(@{F9KB6aVI?r9&*npiYVE$&wRb5&dJY9GfvE4tOuht+R74(}RG zP1F@}?&yDeS!bRa>C~#_TUqX$Y0qbcKu_ZVT)F+R~tUpihO`Psaf? z(hGy?Xc~co>OkKLwPA4u9oN$_*mYr{nFGOuS%n!a@KCv`U$2(0r~l!*RLXjuE#EEQ z@wKyhdr?o38e5^J9aJw{wPE#G$KETpb!|}NT2(!b-KHag>c1`xt}dFjDW|BeuBfYP zwVJczldj6T11f#TE4#=)uc-SvHae+YT`GTvn(pMPMF-X8fxs!YDqpWo397Q7IyGID zRjBNAr-&!un2n#Q^C&J)a%zi;C@#x`m#RsJRfW@9q#o}GQb@jH<*HwIY*g-Q$VDp1WNB||F9yDI0DT&0c*OtDpCZeZkKwaac*i94K>aF4pX-Px-~9#&l)>(wfoMy{(P zNbS4SS0wD}j`S||xfN`ybF!{D_dKTIod@DwalvrDnXCbL@r;> z|E}PFmFl(j&anA7Yt(HWdr1+ewp{&OtE=82ZSUyFCB6S<1@r2hv9o46V`zQ_)jrbq zLDE+bTu`;-=Bs|WYH^VMSJEJ=m#o$`J*56l^`WK5Ex}1npxJV8o4TugtNI)J9C%A0*G?-H zs2-)s_G|kvkyg{t1$Um;JbG61G}X@;#JUDf;_X>r-+9;3y)<&nA)4b$I*lwn84~st zISZyiobY zd+IdxU+taFXI<)7Wa6LOE7;lx$jG9)oT3F6uF6}Zo0%|iHap9ll=3x`F04~a1F81D zHHAeq-}*bbt9pu_-alztol~@?yr|~A{Z~xA!b!==+f6bhDSH>r!(ny(VgJLS-Roh+V!y5H0z88%SGZZIwX(1Yzbw6b68#8LDT%sjveYC zg}oN=Co|jB5UThacY0_gP37OvJGT4Ux9Tn5FvmOJVD z9?p1;ej_HMRb5Mam?8?T+#ZraQs#&YU7A z<<)!g&Z51BGx)qpXRs4iw{}o4e?-o$D=Hr|wWv$=uT_msXWnQvczutWT%q#Qizqyc zy0~$X3Rbk0tGtcjay5NpVB`>XKwxB&`a?W<|AFQ7f~$7Psq58a@y^CT>fkNTzD;WT z@~zb19eX21Q@U#FRQ)^k|HGB4HC@qf7PeMg^GJ!a^plIr^hwl&;aMf}ZAIaL4EHKb^LgG8)DIu2B7GS1^^fr@0lB(cB)a`bumE6Oidx>O`gYds%c*?V8M0IT(Q-^W>`YKkE!*MDQZFT# zJa@KVPMtfMhD;ULs^cgk>Vj%$ZI`pOOP%agbkXD~a`GrG zZlpB6#|n;_qBeEZsy|bL+|l8_Fv;se+*T z9VLwI9o=$VPsiXYvNVvuSs;+WJM_S4{?|tHtu`?KXmx{~>&)3lBwM{7U!ksCc2Iqr z-~@B>>gK6iX#+eb*U_hpvSR4W!xHRml)>3)s}tNElg%@tl_pKld06dRzE?dM9~fb)9=mm?lSgyAf~IL;x~)C&Z9*_3 zr-rtPdFu6L!71ue?RJ&V4Q}S0ddorQ*l%u8$5g2Kht+G=UJ{|ZTvVZ+w*y(Wx^8)} zPJJ7nu2wIv$k^%Bs4wHYcW$9lr}{iTcXnl687(87>aL~Ept`P}K1KcAWKwql?lVxx{~qRlEw|7HAXi;& z(|+!1(z0vqGqiGCd~V*fu3!B!Cr^F2Bwekg5cpt8P~GeV7jGbM4tH8Brg$-2yfG?jVh%{(x0}~XY_npN!N}E3X8PW33_XluD%;uERjwxsEpW7r>6HD|X0}7mr1Kb^ z%m17lMfq>gww$gyN-lbN(dSYh#nE;_Jx?A@O#fB>RQ8CiZeOZ1Av?w1&;KUzzx)N$ zPMfxK@s_spiVD>{$`AiAs?ZsW*@;Y${CYMe&Ks9H$&_bm)kkqoMIepNlaK2vq$g!J z=d|@um{NS@WT>GPY5}?H*@;D)gjz(@#0ol5t*v}!QXUgC!p`8FjEm@8D_2#wsuR=I z#Rt{j;t#97ln|HXUZj@paBid1@nfle?m?BBPUk6f7BxJmLh0(Ht+Y7zIK$VKjalb> zS{_ypceru?rq$h+^Orm)Yj*a{PDYr$vQXXKQ9);f&K1r+bwcJv?S5$Tr{mm zy=NcX`3WV(hV_a()U%FoH>@h^ z*?IFWRkzo9E?ra&M8-rrx%@)t&9ZH`E^zD%5y7`It&4P{ZZKepXPue%Zkm zI-Q6+Se`LDkIv`lDnSlk;kckx9STtJJh(FG?CRR41_$$saz+;w<l! zh52RqbQa)LjxAEl_NrDI+^a7m|J)K!O1u#`tR7stUVRwnB%iBBr<;?}B08hXL%Tee ztSW+h&R5aNa(;Um_1w}~dAZ(1@~n9~jy4{h%ZR)#(E76KxBi{m=`3+4osQ<^ESR-R zy}7hPpBRMu(5kln6V*g@L)NReDaG8;hcnq@icU)TjPTIngI!%aX=%Q#Z}&UuJvuE^ zxAe_b?=Q}!W5qbN;GjA#SIy5=!#WpHmOT791zWI3P25YTYtv|e0*>DK7OthWAXmL* zRqUsIg_Eu?O8ne*FG{@E-g#xqm}!&p7OOw13iaj+a%0aX;&=V{OWLlNvqW1JSCDG8 zsyV3Wthu>!gBEtJ7FN!K@kM)gW!qV58J{xdQP$US(wPuA`RMXWRiU%QI|+KT6i9f7 zb=1jHrxwmm0nTp$b+^5hcJBw(8}`=1%C<{2?XT^6zn9GgzT^TnLyX|!XOzRxI^ ztL7c*0ovF(8w%G@H+DjIg1URT*bV5NfWe zo*!zWhnGV07F5&gbM6J+P|JeG=2m{ip{coMvF4>hXl`{&jh4_S#wsjq9OnV-x*(;jMS zG<~;JFRn3KhZZ(!m07JUmfzTBoKf3cQ)9K%FR$T?vJqXf%B*HvgE5wrV-e&+)^keX zv~w)_mHXtgV;*fp=ODtduPFmxZ{vJ z?j)wAslnoaYN~E&wHlkqiR^g#;zy3)<`!LQsc8;1(nE4o!#{n-40YA53y8X?W|37} zKYyvFH8r+1%n!}4ZmpIZ92vx!K945B($)}1M<_JEW-)1~dmy%j)+IGHO%w%{Ng zqLEriy@W#5^XAnwwT{(%bC=OzFCh<+GqOV5{h1+6vuc*slR+(YRy9+bszXLY8o`G8 z)@5v^aVT|2*X3zI_%@85VbzPYm)q!Bp$J=A*+I>up(g4k%{8PwSxX_ZkYZK4S+HfS zZE9|uZ&g#IYXz6J%p=B7%fiNnI_j22q@itIXmNFDA>BIAlE@VlTslVPHa65)wM$9) z7SkoqUmjd`D))LOoXw+e{K{lAf6mOb*wallHJ60ud9ao`)%P2CZdJF|H#T^6O&;Xf zT0}{Ul&o#Sw4l5-zuwJhMl z)6Bo3rw3j}WnNPojX)h4Uti6!DozQtR@YgiD4W_y-8WEBM2yM2xm3B39A95UX{~zx z{AL{`CKqy$!bMFSgj}x!jow_=Q;H@8byc0o|9A#hXKCU3ZjnY8)3mBtIHVR$xo`klp=0LN^2_f+#IY&>n&^%TI znDYtnSgV$AdJ%;Jm+mQ%w3g-C9PX3mNQ-4gfs9^Uvyk}e8ycC3eZUcytp9Pon>)9) zx_%+qQ%z}wGCB)b(Adbiwt69Db)G6-^iY9Er@kd(fGC?&!n9~?`8!~_J*PDtvY4OR zp?apW6=u#_b#63~Srmwk&AKrQAw?EjoNNt+R*8_F{v1EG6ju!t2DDyqw#~E_w=^`- zEw)yUXL>=RadAy^?ZU<-A-bVQe>K%w1_!^bGRg&+NIj3Y=BO*X1q9d z>DKKf6ikvz+nTv+lg6!Db{;ZZ^-_+DhIzEM(y_@}LSagXQ<+7H)+7jC^Fo{kEWZ8N zLQ}??rxPJ}taErRd7`$ynHpBNHZF=7FL%x2f#Wvpq&l+>xt3A}Mx^UrNbd%kfi?3Z z)SsuP2QUAmC*{)+b-9S*$sOnx8t7iRpKS_-SYrwd$~wGfsI8~;#52ImZq~mfVmWA8 zKGw{kMP5dv{Cx@MZ{`)RH8eKN<;9)JhSRFmt3yNELhgxsW_CTsI<0cfSVX?&i5%hu zjE8bwV?%2_8KRRUsoGrA(zcM6sd=r9t+bz_o8&YS^C`@%MJ>x3=J6t+ozS{C)X+j> zKzpruHI!89tR|9f7PE$$n)xlff1*4T(kqLnx96)`b~o!p&a7^ZaEA5|yVO*0OfV}2 zH+h#WYg)$9!O4{aO0USA9>!*okGUsaiWZyrm|X&6_q$| zkrcf+Q#YCcYXD7dZ^70|*6S6Lm7zRAy6{BcWDqj3FY3sExuZp@lF>B_O=|5OE(@Bi zc?%n9$73|#EevckX@ zxwNri;3k(gE)2ZNrJWuI?sjS8!@wI{+JrFh7MGSC27b<^O$-C?a%q#oes`iw&xz^} z#|Q9kp($(0ZhF2V_UCFL+ty6LU%RB~fDjdD(HE~rDS_I3(vXz^ZluRR_(Mt@ps#~A z1^%5H{xG9K-hT+o6CP3wu*M~o0zy)3#ZcQE(I4;bDk3RYE0?WCMphS|)I{M@s|d--6~3wM_=D@n}iFbsjAd zn169X+B(2Z^jHpmjD`k#|KZbn#5NiqK(8VHaH!YBpy-CBXb4MeYc}8lQH%$+G>j5@ zAjbbJemcaXRh-4YF8ZGv&WO>Feu>oIaEMH*{W0(0r{EB+7(ut-Rx z7yU{qN|$?#fLFVuV!)eSQrSlWVJ7upy7K-9Ma4O;s%3x;E~z3Qs-EC#U*(A~Xse9+ zWVh8Ej13I6tvP-Ji3C%iERp=Oq0!Z@>|$s#+|{Vq-^w3Wyr5wGAknr$ur1D$1c*+E zE83P&v@M}%TS9)VJ{Ld1@wQb3h}fV}r=QJ**U*ijo+(3$o(vTwZ|tj{5Ju0fRe%Tw z)7GzGmpHjcj_fwzyItCtFz~}JEi3Gog#iN(O$0v+l(|lF3uk^8)3d<*p(SDqeKnaW zIC5l0;2RR=cuF0srojN&q3yWG|GC zkxpq_1ehM7M`;+Pb38`CIlUNBYW5fbVT0+~^N&I6MOP?lTjl5!4Tf=L8zQZs@t^k}9{sggW?Q9z zUOW0lT(5;e_XtBp&RTkYU zY8m@&RI3uSTIF_M0(hm6l-05{jKb|6AK->aJ`_BQqfTKi5&r93QBmpt_fqwW%R=ui z_Wod-ezMCl<2!*~-}F{+?@x5A;^ArmOnJD zR@o@vl0PpD=p&$yc3y~EBe#4_> z0>A0e(tzLcXvx5T^Jq!H{Nqjhp*|9U-}7h=Fn`M=f3yb;^!{VWr-@~>_yWRciZ8&+ zh083yD0O>n0ih4I1w1IKnYJjMPH*+_hZq5`c1beCNt2zU! z9xHkgSAoFCJrdwnAt~$96=4)!bor*k9{zE3V^7%w0v~rt(*bw5q%!`oD*pW4B~1r} zLr62g*{*M90RGM;mAxqN&n{^?V1Ee$l69QGkuGUEpy%hP3?A+03iuh$RdhDgfdbrX zTNQvXLi3@3AtpXRXrcLxcf9}eWt`CuF?Dyu=%KqKhPdvi1(v@?mOl~VHpCLQp<}T) zHA1@$QQ{7XI0O~vYv9pdv`i3)fa7alGX5bsa?5#wSGuuLig5YZBf-wwL_uzOx8P^p zNGL`m{3U|z?}EQ`*-E2BA!<X+L}4i<62{xpE9w%; zREZ*lkZsL~9*wAtUv#VD=vGm4>^kY|=W^tj2Y%S4jR^z)+NDLG<#$URcw(I8BaV@2 z0`%+dz*kBBxn7mkGgQgDP z8zPIQ&Z-U+-Vq}40ebR@&y#Erb%uIwZ!4m5zfG;zKNMwDnG zMiAkliT*xHWW11=>0}b!&2qIZgZzg)(ys+VIyL+u*_XRBtPJoMLQ>XZ6-EIwk%)0& z6cAiA7Xj&OarB2yKL9bMXx9hzU-q~F|0E>32-y)v0kKHZ05R#wCO{0K)(r(DeCib* zTI+hK3WI@=r49f;a=FR?5zyKrD0t3|+PPjK9$e!(w-^w9q79Dn>(4ZF`KhZ#F(5i- zHve#9M2>YGI~@@2C*>VCr9I;D0sh7v0OCUdUZ)X;V-b2<9$bsy(?o&u`iH;zL9ejVB;1h_7SNAPmGmgqUa0# z`&oxml0_%P01{ke9lQifBJ2F=F0#&VZa;C-P&x8B3h;23mKg>EHX05jkH3^6Z%*7%DIgIy@f12MlF+69?QVU26`Mr2U=0*+Fp?n$wc(?=8m8W2y+8 z;R=qr?bJDFx_o9eTqOBOj955ZI`PU@C%nza*Sv=L5|cAFxMp& z1J=8wl1_p5d!z>izUz@b5(tAxyypOep!zgdsZzi{3W@Te1-#p3D+a{KGaE2WrS1Qg z4iumTGx|SsMJ|NW{PH)8G3Dk&wVI7q8Lk&*1H!X(seWk~1t=9G4IC2beMMBjYI1-v zaI`;~C)Jm`JJAaSU5+F;Iu45c1ArJq zpRDq=QT<0f#<3x)vl-Ey&G2^y?_p#D)(ZML9K$tMjx-_zy;L+p zZj5o4Kbj@#tOP7DiM$I4>*#8t-%;D8Zv=mgkp;{9t}mlD9$<+`;r@=S!G;pRkv8JM zaULxZIKiVO0n>Mq=np00WZ(fFEe$x)qh$gQ^Jv+?$=+ zJjtV_0q1(OWZ-;{mIPej(Gr2DdNc=k8GTVFf3$)IM*J6xM#_;!7w}e>G#e12%;P5! zQVf&^Np8bZ!1G*E3E-tdqFJysj6!4wrBN9K!#~QEHXU%LODY45log#7OT<&NT#q$5 zz!wWGfp(|~38~H-QvOF!uZE#xo{bB^*C%=0=c>E%c&d@KULas|%-JlQp*c$^sE z35x1|Pn4kP5R@W<=(1KK>@Rd(G93`Yna!`}ev$6!R2nU*)GtX{t#;H*f-5l@$xna? zzW>F%WF6^8|jsB{eQeKmNr|{#445?jG1-6xxIsBW%zPaS&q$ zfCYMy>40#)(aMR^YNd4C{lf}?1yeW14hAgiTqz~SSnofQ6A}^aQudwfRrf;RjhMcG zXik@4qql5m2c}q?iUkt1;E8db5Y1BBOFb$?vqasvxJx?nQc2YI;Pxn%sE(ppqB=sl z^it&PAujxw4hYS_R6lW5Wc!nznc%2hHZ>)Z@E6YwuWioFLx!#mxE zrGWPciE>GwFbaQ&kX9N-34O$vz35AOxB-Gn72>)BOyecvP&)&xXvR1MrZ&CU(gP~sNns_K)f#9@%9t_ zEfe8PgQ&+NXb=leF`p;dAeaMJF^^x-|0a6T zyaN1ENSv2S!zeW#Z)6c8;8Q{}j3{kSb{PSur+^d!95WoG62O@*DFk@Gc!N3xd{IcI zQtQedq42VT75&;RPYhsdkexetc zyW206!ljYKb}3+@>gI@N%uh`;&h`HP#1VX|{V%?_CV!8RA1__}_e6buG z%QKIQXW$H;5}u|8#nSfy$>s0Mky10@F-v4Y_VzAUux6iesfaR4g zb74(|?nDAimtdh&Z$KXF{dJdqM z;wk`<>PU&XvJfKckrIILC2?V8ge!@Jg%JsfNPx&qBnuGnLR^5zOT-0;>_l9ENL0iH zh;&6h!zg?uM3M%GA<%q&w`!u_i<;vq=|l)Xrj+2R;+A^Xh&$%L^;sz$oh<3 z3!NJwxbwxKnhz0$aQdN*mR}M7?4+CW(Q`9|xe3+iN*ZPzwopXEF6wDfj7Wf(M5OC` zZX(726CdD(-sbVWc5IlwlO#=i*e}6cBEe#B0)?U{PzbXHDVG}h6E2aWXG);G{!F>t=VHpa%{ zP^^u`p`Uab1)H&rBWLYzM*$l-+C~CK_-21B-|TmNgMFNqhyr$UBoQ!TQ@1~s5BJCN z;r^fGL+S+?1L=b2RSXaAkLAJrQ63y7Yt1NkA?i8Qjsg}Wy6A|BjaZLy9WwJo6O!ZQ zNJ$^?1()P*CW3CJC_|=1nxy3z3GcAGODzNZ$|V&8A}7XJ$6uG!{Dr&rMqT5+SaR28 za-{u!r@$LrQZc6R2st<6B~9QdE-C6tIAkw!1(gD#yI4;d{86&nS8jGIJ5tgSauwN% z{Db8uhWXLkm?~^zkj(gm0+I?{FI540!Y}k^oM=hWCs=oi;jhY(qxD!Bdc+j1-u?{7 zZ2s=5LwHAQWWW_YA|ZU>eIi9)bP4&FY~u1O zev>G*PL4Dw0I|iO;EUF?Dq7E~Xg#Z-=iA;40Q6L^idMZUTJi*r44tBq&m@^50HjvFi#pL(4=dkTm2||x<+k-psU9cHKpGZsXZqcUyz@0-vm1dB4NLe zjVh6FhI*d6Q;G`quSE9ua-?7f^t!8x?yd^mIo`ey(9@tQT7#&Vy+^G2-HEPs*zKO{ zEsU7^1Kn8@dQu>k6fzk5S1cAp@`umk(%m-KnZHh|vFKZIQxG~wYCSD){?JmkO9L|izPUGu|(zDl~g&fRww19}=%MQczM ztw9wusCK(62E^46a$dAjQ9hV2Rw2#lH08f~5;J$jXnCMLM$72jg_bwC9xVoh8UcD{ z$1jT}i9f6$3C(CAqFY4;;}Yo?n^wB?=ofsYuskfsk=D{5SkIU8dcM@nNocTH8YWOO z2iImH-3ci<1$D6|Su->UZ+31OEA51k4EqM3Qb z$JfqUB@H?wgafbkXoVB(XxTZk8-WwV52Zmi2Q&A z@Fb6x37qTE(tz_lS~75fM@s^p?9mc|r+PF8_&|Duf2(c$SdN z=%Do9rx~fl2>7N;nhAK#XqOA{Mwc`baED8p4d{serc;!1g-V?QPU*#nQj^CBcw;X{ zl;Ecr*IW>Ha1A{<3Ha)%Fl!DV{9+!sKxvBWk~x6zmSIHcpvzba__a%#19*lw%Ctpk zmg~MbfN-{9MClhUV=3TN3s&JTAh0rD2pX3Ut2)5FRyM`$O*r@myaw&Pt+X zmCTjS*1N+P^*CFtc;^z=OCi8VTvFL7VhCIn<1$W2Sl}djHU?1yHDWw2^P$+0<=Qc4 zhICuuc3%vLQKkhWTBFc%(O{M9^cX0E&!hHda-1Zz{ew60%MGo)%W`_ z3K(SyIlwbrcV~uyG0eIx3YdAZF7Uxnm_pk%sO!y*sO?&bsExEjMm7lP8adL8LjT@$ ziMr)`lyD=!D0Gq#VF)3n0sF#9uHbpGuvJzrB;+4o!4L$Tl4gbx2c9c_;tGcBh&77V z3_y&P=>a9A#Q$HGt3QcLkYOo;U?~QlNbgH@V<3ox@xQi@ zB^c9J-K-InxKku^p5m^dGXTq6Qt@A8DyO&;Gin37Lkz~~Qb@z#a%rus_P8(#v)$}a z1y~=+hr$gWAK)F4d?;-6_yD&>@}b~)zY5;R)FYMQeQ!Qh!PS`0#N|c4L5_IJ^H}Mt z()Y)%TBU$+V$ApE;4}DyA5u>6_XkI;b%oFTl|YzDQ_$ZET4H?ZW(44LF@RqRjMjX* zU-MY+4mODb&@EQl!(>2=(3?!3Ob|8wDL1kXA&t})S%)--SdXmpd%)j64W++ZBKdnG zlE0G}F@T-tL2uRo!dzNqqq~~}*|qK@Ee3>5)X;CrX6fb?uRB1myRzu+%3$3IUUz_L zE~yMkc^X75B7SGaS^XZfqgGBsMW<7w2SfFDVyJ#gG4I}%wtO}Ve9)sM0{_FKB>}(Z z(UO7x$D^eI|I4Fg0)OJsvVm_NW3;5x?F|7G)(VkNIDyxBv`pYzJz5&@&plc)@a-Ng z3HVNrmI%DTqdCA=$h6W5{*XtZVd$Ynb6T~yj3S2$bs321PzG2pSvGoNx3M;&mEk-gcFiaIz6k$2D z`Yg9#`ky0A2Zrf<^Bi`=fJkGYJ@Wx$XqgZAk23PicUUmYVHz;ZiDeq|{cr5TFtRLQ z*fo%bH0wC$`{OcCp?|K47*1{ijG^^4`6)x}YZA*r{-O3Y`6+(!HTmDTXmf@M3bq#* zuA=1!Bfnjuo7sTj9%A#mf=GT-i3C%Qi-=xe3_G#;)hE&q1@2oB+5=;N>H77TE1^Gh zjU3iai9*eY0>YIUff2fz(I2~-_+yq~0%}ITAz6|N8s(^&P=E``0e)481V#QWW)SH_ z$rcDHA|Zi5Ln8TgND~2BuApK-PlFN&dfCmw#ekmdsM8E&n1><;3K#=Lr!_w|Oz;M= z0YWY9EfnA);scC1aPXII?Dv=^!hJBABm%-z&4&VFm}3SQqfTx8{>GZ?O|uff$0ZT# z@3}zXckXgM1Mm+nsTgpdOPUV&cURh_9bpvy;qd`_15t)~@?SFF>0ANuO(D^5EOmrY zKx!mDEDlTEy+9e@FmogFaa4Uxe0vr*{v@2!KFCAwhghX8_(6gru5O&2% zOw=;k#zEI0Wn67wV1vYdRX=_caw&g^=d%D82006PB5)NgB=5O z9W6i!EE8jgeAK(vKXkoo{iE2s76bZA3EoJZK*IogmVg2m_m&CgR>?9QDHAk!-IM8e zI^qKC}6BzZa4v>tGWFy56Ql!PsIKh_!xH$Ee5P`*U+9-?Fa?*NiAU;_dJN;T+9}0vyBwfr}+)Xhswe zM$8E8d6f)A;m0Nr_Bn_$x(R|c@aYVOPd%5p6Svi zg@HpZEhh|&naB3}$9tIUt;&CRj}^^Q_Cr$65Gforex4~&Jx%wsY!R025n_OMyRN9HPvDmouFo>Vz&Ly6OSHhqT(N#urA1_1B}ck|0C=4%e(?%mh>CIj zzFW2&Yu&4gOB~>Td9*~}Lmtfm?vrg?OSfmOCy2nxsop3ujM${(Cm<{sA&H+B!qa^|#pL2zmy(F;TBqNh9PEHW` zdyn)7fu4C~fai;O+@;^6OoJP)b=^?5UZCfhGC(+5!xpXROw zNUo|(-^oB29)V7PWO&+`D1*Y#69O3pq?3@4U=li+2@gqfr)Q=oGi0W_x2Go$l$oH^ zuC5fD+NH|KtAil2s6{~5MHkoj!az|vi&2Eg8qie~S0f-ID%t;>^L^)ZpL-j~PPS^h zYWn}qcmLP<&*R>{J>4xY#QYv}qJ7VLmtT@$V>d|IL#(CjAJb=*kVY zOBq7f%Z?k-5!ay(dLOgHnjz$%#0wUj6mmC_`M~ zWa4Vkq@Nrut2Qx0ZWcPLsI!<<>5P^tRo^f!{g*MrCfjuxnKPW2ZZfWZ6;@YRtJPfK zTm`Z*aN%)*$LtmV21negm2q+#s%(T+-S1^5)YaG&i;Wcq&`hwiZ| zks49OdAZylZeD^+b9)aVr@QPu-1oj}wK@pDVW|uuPdqW3);P4EgjE09M*IWEC5U%B zu91HNRs%=j%y}<*l`KsosMfFPF++LgpG4RsvyL39M?>I zp5qe4X~#7Y-wICmgpE6#Vv@MxxMt!z9hV@!*Ktk6kAu@e{3*dPDx(B)kxTd$Q0DrR zt=~CC!np`w6xmt;Ry-0i6Qk&-(g)A?*a(pcT*RSGkm^GrF9N^pxaPHp-3O`k{BS>q zKF23!Yq$dD|6sck$>?l&VbbcnM0_8P$%O_XXQ5mz60)$OML5f*Eg$^=Zm~IJ2szut z86k@=&Ip;j%8dA*oHIhsDse{m8K*_a5me6nfe!bd%E}(tYj(VWjmtnvg6+f^$EAo@InGpjwfwtzbow z@Xs}hY`x(W2}>7Odt~e5V8tUL>k_}k^`wm(<}OQwscd&a%L|PbeZ?#!R`?P)RO^wI z`#j2|IN}|aYpW37iHJ&%_#T@@hLBmrE%_mY58+sZ3BtYYfR!h zN9RC^9nhiJ;KZi~wpn$pT(90tUS{~sUh4A7k(slKqQz9`J!WZ~irSrQr}CN%pbNLg zuaw-FkA_>raO_mfi(oE+1DkMBtIOFXuD6)3(TW?QT9U+1*(KOPPusBWW?@rCY81) z@GF^A#Ziv|KIJGs&j*p`Pi^t+NyUY$d(vl@)UFauJi`KWO(->%k?AVVPihg8VG-qZ zE+I!$X2QdE4l<4=*oI|7UK6hE=hcr7?`jYqat*s638j?^f!C{+``RKb+BVJ-llwmPG;;4EP=YG2}r7FZMkX+8O zK1-`QPQ1d_XAL12lgf*ji(kBP3309qMaW)M_sET9adgIBE6(>d6C3gQ zkZM{JFSA_KZu=7B=`l!U_us&;Ldr*CX21o*2*pfCt@l*r>%hApMeT5u(~aUvKX;au z*AsHq;gFqbQ|KU^2}(Zha!7@ZA342W15UO%bQ}lBf=B??gtZrn9lF;UJ_7g$M@^3O zr-S3;W=`Zp!!9zM%!hq(GiTqZ?@Vj@6}uOc{84+NSsCq6q|Q;ROw=m!CJSe23u4K~ zYY(ZgakWh#L)c~YLPc`3>L z1iwiBg_bO>M8&_T(xh*>73Zpdgj6q>h(G1H1o5XG*Gzn?db%OOO z`XG8HuSW>!Q~uMEkS^7w@u~`28!^J7NO+^ARuM7{(R%A7I+?@=(IHvMgdfG8VXn{F z`XN|RBxEv1k*z0eY8`~X17#H1x(Ia>kA&=lQS`gP1b<+2Uc(YGOS#_kvlGhCLnuF@ zP=2`E5ax3>TqogoES1TiE-r(}mdm`UBIkfDV}6>N^b^&jpQS5VKxl z_?JzJR$$FK(Pw!6d%!kwUw46c)}beEr5X-dAk!gOY{ zWzGlw>@+NU!%1291mzFt1kXlHn>osPmkF|ZLNO?77jt&@9jVFgds3Y5N^$-ud=r-$ z`|RaL$5EIFJR3-TxC*(4&-O6W;M<#r1em~lRWpe>GBnO+*GUe+`t>eP_&Dg{#0RzxV3fy(wb{C zzRHjE_c(M5

    $EK)xq^^33MRGY_ed{+9KSA>`>+e;kJmx5Y)ykTLUx!S9B5)rSXw z8Ab+zn*dL3ab4YaWLkIacT@_b0& z%S7$}2*0mG{uOe{G(VDQ=fDp@-UYeiAnBiTtclYO`F_X`KrVt@0_kTN9%qYW$u7c_w5#B=b17PCf_QAAk7nTZsQ%$X`PK8uC@hf5klFJol@1u>J8z z>27_eiL@Q^5lH^>8-M1_&u60ct1%8)NdCkcf0fMteKkM+MC~6s!+7j^kCFWStd=uP z`^S*`ApQ6gwdZ%*e;V=cg#0ZezsH_GCDPq$GT_(b`}rJffBrWV@mqEHjXHk(-^@15 z?;-iMe{Z1e>+@TT_)S0jmLES3zqyCsA6Goj_hi}!+aJHrh2Q+K4__9-ul?||I8c56 zJ5t`t|AFfBdq4Ow>MiXiy+Z9MS*_xTU=ui<~sH!U>B`A_eDyouWL-=DYO zeOF4<-Zp`jrI$WU6-0jAAxMfyYCrDzKQJT^LG8G@aE_o$ce_| z``!Lq)AjOuyZRqR|L=r+67n~Y`ygL~^y5v`-hYSKe{qxt!Z1&wbL6V};&qIUBU* z`oq3bb|@G2_lhlB#v;s?O4-fEg7}&qQ4{akp@AL=T@Z)z)T*NxkKMz=L2FN8XegJL zgT1-#k#%C6&9BP|Z<+)7z5;Q!yStRzz}DbEK1VF|A{;D8Fk=f({s8^2+9!!sgZxdR z^`x{xAn;<9N42hP2$(5U6Iiva~E|FRsZw%=MzYu&9yV{$hK#x(8tp&9HHpl)cZHJ~2t8@nL2i0E_t z&CwuuLclTdNBcDF(;MHO{f|XWTvER7I*pG4GO*0a|t&aVx&l!W+(_vW0{zBOM^=o;}7@UKBh+afpKPVT& zp2sP#ZZsNSf0T@ov?JS5$Nt2}jpkl&0DXIPm~)3dm3)1V(ad@VUQ^eTdtbHv_Fovy zarA$d99$rOoPRw3sQooAe(@z^|81VQ;M|W7I#x8Q>?Wln#~Nj~=5!A8l1*DtmF zA#y#EuBJ3@l(YJ_SbnlxKg8)D7V!F@+F7Gih3EZRUaEuhaV>vD!1Hu1f22MC*78RM zJg?UBQv#kZYx$!Co(F6BV*;MvYWYOK^HwcCHQ@QEmY-(NGqwD&0nZ<`{BZ%#3$^_5 z0r&e_e!A@6UDcGvjlqn7`*ZcdMtN(D`))0NLcsmBmOrt&X>ntquEwK}#^B^ADNJL4 zw<^4&jRD>Qi16?57}IPFl6CmgBD`8ZhXlV@+kVYMt;;xG?GJIh>QO@w9hWnNpA<|9 zl1HZnxre$AR(!_eSAgH@@#}(Lv7f@zWc;Tf$T-3NXKeO}Mf|EpR*x(^&B{hKD^GM-IqRdiRs4xT1V@(9E0gYwj> z_1SWA0sM5er#0Dy^ViZk`q$Lq$AnKhw-(*1`RIOikM=Vq*f}e$b>~T2J?_`M!PU=? z3O`l$y)LXTUcY?5j{ft)CuHC7_rqV+(f^C)qvw%Ha27R=B1t&ntVR1Hb{BgSVzB7hyPL?{yTN}pV#4E6Fw1ho;pI1_{M1R!!D5U%kDgn{&tj!7>ze0%Y3j!nT3`0DtJAtYj(Oeu}(+!mD|>-OK+z=<8y?nk0|NcCG2Kq3!;!|&hw=aX=vE0NR!RwGWsK3bYkDzXciB$Vf7uN4; zM3|v@8_t3=giqR*0~glO@2JD)gje&y@9*E#@&8HfXG)M-mDWM$qF*=H@qeG@qt~VC zzX7Mp`JHjGyn;a8=WXo?%DLfkdz*lsQhB&M($^<23@=@a4Fk*jwYok-BfOebEUyt-W;1_n5-nR z+1L)1!=CWc0q}wW~4Ow$Yx>C&L)`x}l za36+?R?b_tFkHC&Vi^-NK*TjQ=?%h*uUbBD*^&jKRdr;zoGq1u@RFsM&7Ze4yll~; zj)k3J=e+q#7b*^Ck+SM$Evc%bdM5U{ zQYl{urN-H^yw6apCimv^JwwG>GF;NREOb+=bJ+qlu{yKeGAQc3fzafu$5pZkHVo&B zC3!cbuhxw^-d`xJ4>pzt%3jW4PQS@8G`uMNH<@=^vb85!i^T)Ebz3Z_OmkVQ4@=}WlbqL*ALm+h_ffPvGsk~ufv8A#A* z;lrx(s!l~lCR{gE$ea4>sn$DO2>Y}7UKttXu(;Xf&^AYYyW%p@?H$O6Bg45~J$py; z#ca>|>RF}cVK9^(lnLUD)x46$y-Bin?SY$na^%2$f(HH6YEFbN`m6hNIo)p zsx~?|vm*%vnS#SMLK(}35J nFqDbSHLGSk_syF5uI9mDA=?|saL7U`c(Y8eVmT(O#XIspJ>_e) literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test81.ans b/libs/libtpl-1.5/tests/test81.ans new file mode 100755 index 0000000000..63b077cd65 --- /dev/null +++ b/libs/libtpl-1.5/tests/test81.ans @@ -0,0 +1,2 @@ +a 0 1 2 3 4 5 6 7 8 9 +b 1 2 3 4 5 6 7 8 9 10 diff --git a/libs/libtpl-1.5/tests/test81.c b/libs/libtpl-1.5/tests/test81.c new file mode 100755 index 0000000000..335f91ca47 --- /dev/null +++ b/libs/libtpl-1.5/tests/test81.c @@ -0,0 +1,36 @@ +#include +#include "tpl.h" + +#define ILEN 10 + +struct st { + char c; + int i[ILEN]; +}; + +int main() { + struct st dst, s = {'a', {0,1,2,3,4,5,6,7,8,9}}; + tpl_node *tn; + int j; + + tn = tpl_map("A(S(ci#))", &s, ILEN); + tpl_pack(tn,1); + + /* fiddle with the fields and pack another element */ + s.c++; + for(j=0;j 0) { + printf("%c ", dst.c); + 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

    iaX&jB#ExEVgB7_auSH_+*o<80$m=4MEl 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 Ay#N3J literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test82.ans b/libs/libtpl-1.5/tests/test82.ans new file mode 100755 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test82.c b/libs/libtpl-1.5/tests/test82.c new file mode 100755 index 0000000000..497f98cc3f --- /dev/null +++ b/libs/libtpl-1.5/tests/test82.c @@ -0,0 +1,43 @@ +#include +#include "tpl.h" + +#define ILEN 10 +#define KLEN 8 +#define FLEN 5 + +struct st { + char c; + double f[FLEN]; +}; + +int main() { + tpl_node *tn; + /* some meaningless test data */ + struct st s = {'z', {0.9, 0.8, 0.7, 0.6, 0.5 }}; + int j; + int i[ILEN] = {-1, -2, -3, -4, -5, -6, -7, -8, -9, -10}; + int k[KLEN] = {100, 200, 300, 400, 500, 600, 700, 800}; + char a = '&'; + char b = 'x'; + + tn = tpl_map("cA(i#)S(cf#)A(ci#)", &a, i, ILEN, &s, FLEN, &b, k, KLEN); + tpl_pack(tn,0); + + tpl_pack(tn,1); + for(j=0; j < ILEN; j++) i[j]--; + tpl_pack(tn,1); + for(j=0; j < ILEN; j++) i[j]--; + tpl_pack(tn,1); + + tpl_pack(tn,2); + b++; + for(j=0; j < KLEN; j++) k[j] += 50; + tpl_pack(tn,2); + b++; + for(j=0; j < KLEN; j++) k[j] += 50; + tpl_pack(tn,2); + + tpl_dump(tn,TPL_FILE,"/tmp/test82.tpl"); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test82.out b/libs/libtpl-1.5/tests/test82.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test83 b/libs/libtpl-1.5/tests/test83 new file mode 100755 index 0000000000000000000000000000000000000000..e9e1e6415f8c2e8ed4189aeaa0c282a4e12a1064 GIT binary patch literal 129532 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%0D*r0v-+~w7 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 +#include "tpl.h" + +#define ILEN 10 +#define KLEN 8 +#define FLEN 5 + +struct st { + char c; + double f[FLEN]; +}; + +int main() { + tpl_node *tn; + /* some meaningless test data */ + struct st s; + int j; + int i[ILEN]; + int k[KLEN]; + char a; + char b; + + tn = tpl_map("cA(i#)S(cf#)A(ci#)", &a, i, ILEN, &s, FLEN, &b, k, KLEN); + tpl_load(tn,TPL_FILE,"/tmp/test82.tpl"); + + tpl_unpack(tn,0); + printf("%c %c %.2f %.2f %.2f %.2f %.2f \n", a, s.c, s.f[0], s.f[1], s.f[2], s.f[3], s.f[4]); + + while( tpl_unpack(tn,1) > 0) { + for(j=0;j 0) { + printf("%c ", b); + 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 +#include "tpl.h" + +#define ILEN 10 +#define KLEN 8 +#define FLEN 5 + +struct st { + char c; + double f[FLEN]; +}; + +int main() { + tpl_node *tn; + /* some meaningless test data */ + struct st s; + int j; + int i[ILEN]; + int k[KLEN]; + char a; + char b; + + tn = tpl_map("cA(i#)S(cf#)A(ci#)", &a, i, ILEN, &s, FLEN, &b, k, KLEN); + tpl_load(tn,TPL_FILE,"test84_0.tpl"); + + tpl_unpack(tn,0); + printf("%c %c %.2f %.2f %.2f %.2f %.2f \n", a, s.c, s.f[0], s.f[1], s.f[2], s.f[3], s.f[4]); + + while( tpl_unpack(tn,1) > 0) { + for(j=0;j 0) { + printf("%c ", b); + for(j=0;j 0) { + for(j=0;j 0) { + printf("%c ", b); + for(j=0;j-Wh}D>Z#D5_82gHAY_zw{O z2I5~p{1b?O0P%Mq{szRvsQC(1N5~wInlC_Hb@mJhys@7(69it`r-8vUdt)$oY!7rB z5InF4IkF-JNSpv-9iXo!0PzMs!g0pj04 z{0oSG0`U(Z{tm?7fS4FHUxDffnFCVurON)z84x&Y|8gb>%(8!$1_t(zjlsbF0nm96 zz+3^OQ-Jsc&{sM@JOPNmFfcGh0P!B6Clo4ylGA|r7f>P&hz|iJfZk*30^)Z-1wmE# JbORN%003Eaoz(yU literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test85 b/libs/libtpl-1.5/tests/test85 new file mode 100755 index 0000000000000000000000000000000000000000..3cdf5fe8d919ef23ffb5d4c400351000eb890ca9 GIT binary patch literal 126901 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 +#include +#include "tpl.h" + +int main() { + char *fmt; + fmt = tpl_peek(TPL_FILE, "test85.tpl"); + if (fmt) { + printf("%s\n",fmt); + free(fmt); + } + return 0; +} diff --git a/libs/libtpl-1.5/tests/test85.out b/libs/libtpl-1.5/tests/test85.out new file mode 100644 index 0000000000..7d8448aae8 --- /dev/null +++ b/libs/libtpl-1.5/tests/test85.out @@ -0,0 +1 @@ +cA(i#)S(cf#)A(ci#) diff --git a/libs/libtpl-1.5/tests/test85.tpl b/libs/libtpl-1.5/tests/test85.tpl new file mode 100755 index 0000000000000000000000000000000000000000..bb934e3e4cbf3aee43273e665d5a478dc46c7c0e GIT binary patch literal 308 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 RMmc9jspU$?XstL${uf7>y2=0m literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test86.ans b/libs/libtpl-1.5/tests/test86.ans new file mode 100755 index 0000000000..66c7f89b08 --- /dev/null +++ b/libs/libtpl-1.5/tests/test86.ans @@ -0,0 +1 @@ +A(A(i)) diff --git a/libs/libtpl-1.5/tests/test86.c b/libs/libtpl-1.5/tests/test86.c new file mode 100755 index 0000000000..b87070eca7 --- /dev/null +++ b/libs/libtpl-1.5/tests/test86.c @@ -0,0 +1,27 @@ +#include +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + int o,i; + void *addr; + int sz; + char *fmt; + + tn = tpl_map("A(A(i))",&i); + for(o=0;o<10;o++) { + for(i=o; i < o+10; i++) tpl_pack(tn,2); + tpl_pack(tn,1); + } + tpl_dump(tn,TPL_MEM,&addr,&sz); + tpl_free(tn); + + fmt = tpl_peek(TPL_MEM, addr, sz); + if (fmt) { + printf("%s\n",fmt); + free(fmt); + } + free(addr); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test86.out b/libs/libtpl-1.5/tests/test86.out new file mode 100644 index 0000000000..66c7f89b08 --- /dev/null +++ b/libs/libtpl-1.5/tests/test86.out @@ -0,0 +1 @@ +A(A(i)) diff --git a/libs/libtpl-1.5/tests/test87 b/libs/libtpl-1.5/tests/test87 new file mode 100755 index 0000000000000000000000000000000000000000..32313a740adec264227250c7f9d0707d08e16b64 GIT binary patch literal 129564 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test87.ans b/libs/libtpl-1.5/tests/test87.ans new file mode 100755 index 0000000000..494c321c46 --- /dev/null +++ b/libs/libtpl-1.5/tests/test87.ans @@ -0,0 +1 @@ +sum is 49995000 diff --git a/libs/libtpl-1.5/tests/test87.c b/libs/libtpl-1.5/tests/test87.c new file mode 100755 index 0000000000..b11db98afe --- /dev/null +++ b/libs/libtpl-1.5/tests/test87.c @@ -0,0 +1,47 @@ +#include +#include +#include "tpl.h" +#include +#include +#include +#include +#include +#include +#include + +int main() { + tpl_node *tn; + unsigned i, sum=0; + int fd[2], pid,rc; + void *img; + size_t sz; + + pipe(fd); + if ( (pid = fork()) == 0) { /* child */ + + rc = tpl_gather(TPL_GATHER_BLOCKING,fd[0],&img,&sz); + if (rc != 1) { + printf("error: rc non-zero: %d\n", rc); + exit(-1); + } + tn = tpl_map("A(u)",&i); + tpl_load(tn, TPL_MEM, img,sz); + while (tpl_unpack(tn,1) > 0) sum += i; + tpl_free(tn); + printf("sum is %d\n", sum); + + } else if (pid > 0) { /* parent */ + + tn = tpl_map("A(u)",&i); + for(i=0;i<10000;i++) tpl_pack(tn,1); + tpl_dump(tn,TPL_FD, fd[1] ); + tpl_free(tn); + + close(fd[1]); + waitpid(pid,NULL,0); + + } else if (pid == -1) { + perror("fork error"); + } + return(0); +} diff --git a/libs/libtpl-1.5/tests/test87.out b/libs/libtpl-1.5/tests/test87.out new file mode 100644 index 0000000000..494c321c46 --- /dev/null +++ b/libs/libtpl-1.5/tests/test87.out @@ -0,0 +1 @@ +sum is 49995000 diff --git a/libs/libtpl-1.5/tests/test88 b/libs/libtpl-1.5/tests/test88 new file mode 100755 index 0000000000000000000000000000000000000000..7e665d14a91e864ded1c96213e8639223432192b GIT binary patch literal 126475 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 J(Vk&#`9Jq-uVDZH literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test88.ans b/libs/libtpl-1.5/tests/test88.ans new file mode 100755 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test88.c b/libs/libtpl-1.5/tests/test88.c new file mode 100755 index 0000000000..57e5e82843 --- /dev/null +++ b/libs/libtpl-1.5/tests/test88.c @@ -0,0 +1,18 @@ +#include "tpl.h" + +struct ms_t { + int i; + char c[3]; + double f; +}; + +int main() { + tpl_node *tn; + struct ms_t ms = {1, {'a','b','c'}, 3.14}; + + tn = tpl_map( "S(ic#f)", &ms, 3); + tpl_pack( tn, 0 ); + tpl_dump( tn, TPL_FILE, "/tmp/test88.tpl" ); + tpl_free( tn ); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test88.out b/libs/libtpl-1.5/tests/test88.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test89 b/libs/libtpl-1.5/tests/test89 new file mode 100755 index 0000000000000000000000000000000000000000..5849716ba10251d06893199dbf0d0c90d9afaa0f GIT binary patch literal 127407 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 + +struct ms_t { + int i; + char c[3]; + double f; +}; + +int main() { + tpl_node *tn; + struct ms_t ms; + + tn = tpl_map( "S(ic#f)", &ms, 3); + tpl_load( tn, TPL_FILE, "/tmp/test88.tpl" ); + tpl_unpack( tn, 0 ); + tpl_free( tn ); + + printf("%d\n%c%c%c\n%.2f\n", ms.i, ms.c[0],ms.c[1],ms.c[2], ms.f); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test89.out b/libs/libtpl-1.5/tests/test89.out new file mode 100644 index 0000000000..626f9b8a80 --- /dev/null +++ b/libs/libtpl-1.5/tests/test89.out @@ -0,0 +1,3 @@ +1 +abc +3.14 diff --git a/libs/libtpl-1.5/tests/test9 b/libs/libtpl-1.5/tests/test9 new file mode 100755 index 0000000000000000000000000000000000000000..ed6ac3b017dbba3f5193547980d7bcff6cd9dc6b GIT binary patch literal 127326 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 JliA`O`Csci6FUF^ literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test9.ans b/libs/libtpl-1.5/tests/test9.ans new file mode 100755 index 0000000000..903c08cf1f --- /dev/null +++ b/libs/libtpl-1.5/tests/test9.ans @@ -0,0 +1,10 @@ +i is 0 +i is 1 +i is 2 +i is 3 +i is 4 +i is 5 +i is 6 +i is 7 +i is 8 +i is 9 diff --git a/libs/libtpl-1.5/tests/test9.c b/libs/libtpl-1.5/tests/test9.c new file mode 100755 index 0000000000..f4a72514b8 --- /dev/null +++ b/libs/libtpl-1.5/tests/test9.c @@ -0,0 +1,13 @@ +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + int i; + + tn = tpl_map("A(i)",&i); + tpl_load(tn,TPL_FILE,"test9.tpl"); + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test9.out b/libs/libtpl-1.5/tests/test9.out new file mode 100644 index 0000000000..903c08cf1f --- /dev/null +++ b/libs/libtpl-1.5/tests/test9.out @@ -0,0 +1,10 @@ +i is 0 +i is 1 +i is 2 +i is 3 +i is 4 +i is 5 +i is 6 +i is 7 +i is 8 +i is 9 diff --git a/libs/libtpl-1.5/tests/test9.tpl b/libs/libtpl-1.5/tests/test9.tpl new file mode 100755 index 0000000000000000000000000000000000000000..d928efa399903c22fe4ecff4dd6d8ccf129971a1 GIT binary patch literal 57 ucmXRZ$YEq)V6b%5$kYVV3|t@r2ta~NK+FupEI`Z(#B4y!4#XTl%n1O8Rsy{M literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test90 b/libs/libtpl-1.5/tests/test90 new file mode 100755 index 0000000000000000000000000000000000000000..8097d117d429fa13637318f62a42f886085028cf GIT binary patch literal 127831 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 G$!jc literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test90.ans b/libs/libtpl-1.5/tests/test90.ans new file mode 100755 index 0000000000..4f2784a1b3 --- /dev/null +++ b/libs/libtpl-1.5/tests/test90.ans @@ -0,0 +1 @@ +cn is equal to cn2 diff --git a/libs/libtpl-1.5/tests/test90.c b/libs/libtpl-1.5/tests/test90.c new file mode 100755 index 0000000000..5c6115222f --- /dev/null +++ b/libs/libtpl-1.5/tests/test90.c @@ -0,0 +1,23 @@ +#include +#include + +#include + +int main ( int n , char* a [ ] ) +{ + + tpl_node* tn ; + int64_t cn = 100,cn2 ; + + tn = tpl_map ( "I" , &cn ) ; + tpl_pack ( tn , 0 ) ; + tpl_dump ( tn , TPL_FILE , "/tmp/test90.tpl" ) ; + tpl_free ( tn ) ; + + tn = tpl_map ( "I" , &cn2 ) ; + tpl_load ( tn , TPL_FILE , "/tmp/test90.tpl" ) ; + tpl_unpack ( tn , 0 ) ; + printf("cn is %sequal to cn2\n", (cn == cn2) ? "" : "not"); + tpl_free ( tn ) ; + return ( 0 ) ; +} diff --git a/libs/libtpl-1.5/tests/test90.out b/libs/libtpl-1.5/tests/test90.out new file mode 100644 index 0000000000..4f2784a1b3 --- /dev/null +++ b/libs/libtpl-1.5/tests/test90.out @@ -0,0 +1 @@ +cn is equal to cn2 diff --git a/libs/libtpl-1.5/tests/test91 b/libs/libtpl-1.5/tests/test91 new file mode 100755 index 0000000000000000000000000000000000000000..70108c0e5ab53c2f554ff5e27c8af23a402a192c GIT binary patch literal 127831 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 Sg_Lt +#include + +#include + +int main ( int n , char* a [ ] ) +{ + + tpl_node* tn ; + uint64_t cn = 100, cn2 ; + + tn = tpl_map ( "U" , &cn ) ; + tpl_pack ( tn , 0 ) ; + tpl_dump ( tn , TPL_FILE , "/tmp/test91.tpl" ) ; + tpl_free ( tn ) ; + + tn = tpl_map ( "U" , &cn2 ) ; + tpl_load ( tn , TPL_FILE , "/tmp/test91.tpl" ) ; + tpl_unpack ( tn , 0 ) ; + printf("cn is %sequal to cn2\n", (cn == cn2) ? "" : "not"); + tpl_free ( tn ) ; + return ( 0 ) ; +} diff --git a/libs/libtpl-1.5/tests/test91.out b/libs/libtpl-1.5/tests/test91.out new file mode 100644 index 0000000000..4f2784a1b3 --- /dev/null +++ b/libs/libtpl-1.5/tests/test91.out @@ -0,0 +1 @@ +cn is equal to cn2 diff --git a/libs/libtpl-1.5/tests/test92 b/libs/libtpl-1.5/tests/test92 new file mode 100755 index 0000000000000000000000000000000000000000..96207afea2fd9b990801f8424ced50b007db42f8 GIT binary patch literal 128485 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 +#include + +#include + +int main ( int n , char* a [ ] ) +{ + + tpl_node* tn ; + char c='a',c2='b',c3,c4; + int64_t cn = -100, cn2 ; + uint64_t ucn = 200, ucn2; + + tn = tpl_map ( "A(cIcU)" , &c, &cn, &c2, &ucn ) ; + tpl_pack ( tn , 1 ) ; + c += 1; + cn -= 1; + c2 += 1; + ucn += 1; + tpl_pack ( tn , 1 ) ; + tpl_dump ( tn , TPL_FILE , "/tmp/test92.tpl" ) ; + tpl_free ( tn ) ; + + tn = tpl_map ( "A(cIcU)" , &c3, &cn2, &c4, &ucn2 ) ; + tpl_load(tn,TPL_FILE,"/tmp/test92.tpl"); + /* Hesitant to rely on portability of %lld to print int64_t. + At least on MinGW it is questionable. */ + /* + * while (tpl_unpack(tn,1) > 0) { + * printf("%c %lld %c %llu\n", c3, cn2, c4, ucn2); + * } + */ + tpl_unpack(tn,1); + if (c3 != 'a' || cn2 != -100 || c4 != 'b' || ucn2 != 200) printf("unpack error 1\n"); + tpl_unpack(tn,1); + if (c3 != 'b' || cn2 != -101 || c4 != 'c' || ucn2 != 201) printf("unpack error 2\n"); + return ( 0 ) ; + +} diff --git a/libs/libtpl-1.5/tests/test92.out b/libs/libtpl-1.5/tests/test92.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test93 b/libs/libtpl-1.5/tests/test93 new file mode 100755 index 0000000000000000000000000000000000000000..b26847e20829352fd15b80a0b2602f4069c67302 GIT binary patch literal 127704 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 vb< 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 + +const char *filename="/tmp/test93.tpl"; +int main() { + tpl_node *tn; + char *s = NULL; + tn = tpl_map("s", &s); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,filename); + tpl_free(tn); + + s = (char*)0x1; /* overwritten below */ + tn = tpl_map("s", &s); + tpl_load(tn,TPL_FILE,filename); + tpl_unpack(tn,0); + tpl_free(tn); + printf("s %s null\n", (s==NULL?"is":"is NOT")); + return(0); +} + diff --git a/libs/libtpl-1.5/tests/test93.out b/libs/libtpl-1.5/tests/test93.out new file mode 100644 index 0000000000..8023187790 --- /dev/null +++ b/libs/libtpl-1.5/tests/test93.out @@ -0,0 +1 @@ +s is null diff --git a/libs/libtpl-1.5/tests/test94 b/libs/libtpl-1.5/tests/test94 new file mode 100755 index 0000000000000000000000000000000000000000..4b55885189f6bb62e78f25134fcdbfd62e76f1d3 GIT binary patch literal 128176 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 Hyd(bu + +const char *filename="/tmp/test94.tpl"; +int main() { + tpl_node *tn; + int i; + char *s = NULL; + tn = tpl_map("A(s)", &s); + for(i=0;i<5;i++) { + s = (i&1) ? NULL : "hello"; /* odd i are NULL string */ + tpl_pack(tn,1); + } + tpl_dump(tn,TPL_FILE,filename); + tpl_free(tn); + + s = (char*)0x1; /* overwritten below */ + tn = tpl_map("A(s)", &s); + tpl_load(tn,TPL_FILE,filename); + while( tpl_unpack(tn,1) > 0) { + printf("s is %s\n", (s?s:"NULL")); + } + tpl_free(tn); + return(0); +} + diff --git a/libs/libtpl-1.5/tests/test94.out b/libs/libtpl-1.5/tests/test94.out new file mode 100644 index 0000000000..572008b421 --- /dev/null +++ b/libs/libtpl-1.5/tests/test94.out @@ -0,0 +1,5 @@ +s is hello +s is NULL +s is hello +s is NULL +s is hello diff --git a/libs/libtpl-1.5/tests/test95 b/libs/libtpl-1.5/tests/test95 new file mode 100755 index 0000000000000000000000000000000000000000..0ad682341b0e242eab0c67cdaae0f2d9e878600e GIT binary patch literal 127968 zcmd443w%_?`9FNl?j~#qORE*ypQU&y2_nQ>TR>5~f){j;0i<3KQQ7zVoik^%Ahdno&-;Hr z?`n4DdFGjCo_Xe(=b4!^XIWVmp5Rbb#r`;y%M?P-bO{KQ^{pu0H#%qnO0nWr0?I&T zfRYKS4E))20hzPYR$0wX-Js>ii9Z)J4u0X|2;d7JM*v@n(noxEq;~5}*}LaKYSR z3+D}4xL|Sp@*&HMM-3S@a%kO>p~Jz5ygm417bjjd72noyu^k`&Sl$zVR2j>szqE1B zqb~-(ZLRtIof&^P@7%uy_B6AMV`=L@CiLYQMBKUfz@=-B-nU}xA4|HHd=~F( zVbA>i1E9N~p{USDpnQI17H$S@7?j1%KgL@YkFL|C_VmOU{D7 z@hteZv*4GU1^?Hx;5n>5{GI-30OCygfAB2$pPmK(=vnal&w{6YovGceXTcXqd>}i3 zT*oJYEcqPB3UnZmyAyxJ`%a_38@O&tZ>8dv*~lsIlkzib)(wl6ES^;tnNu5?HA}&? ztK>WzrBp3n5K-zPwTmkk)hN}G+WN(nb0SqrZPlEG3zt-~q^@SMvS`tq8f8)4EsF(a zVHGe{i|VQ(%B)#cwY7_v%mVG4$buz{S#cf<$!=-g;+on8izC$nQFDv3$YweZwUkBm zi^+D@tm@^EE22~`TvAu1EU5u^G+Q~pRwUp92=q&8K}x}8FBZ*Nuvl4Ey8zNIt(NUn z*H%?26T_i#<7W*YS~N119X|A8D8lg{|D!iK6O{@qeG&iox%Zy?;D(&aVdROc@3SC_ z{ExGcpXIYfLSL0`2lluyhMXrTtS_IW?*!2HODxGx!wc7Ckt>C1csqo#s5lLu3MIe? z((ty=CcU19PmgOAY4~)%J|hiJS?$m4GBaa zq~X`5;k%~co73<)Y4``y@LC#veHz{#V-{~n!*@%g-;{<=AKxu$_#SEWt!eo50P}nr zp0UjS>`KGam)M_uY4}_liS$4k{+u*?A`Raw4SzHZ?@hxWPs8_4!|TyQZatn+zSyVe zjjfT4#CTYv9(~TeJ&g$220lfYCS@KF z@Sh3Ol+0ZM{sUo}kl8BWhX~Vj%uNFRIboWHxn96OCd{EXn+1FqVGg<3AmG)6In-v2 zfNv$tAvR|VxRx-7)~pcljf81pW25b)%df6fjlMXeZrpWYPqd-bL%evjT1 z@w@f5Qooq$%y>Sn3@FTaUjTjLFM|}N=$LM_>BjcNJ}e6Kcy50%-pYa3jr~QfiQyNC zT;eXsdKzcDO|lae*npjJGn1Ht2Eg<03w>a>9SsT2VEgDqtL6QP_sT^BPd`V2{A?u- zsaswFs5c(dwbIW)e(1Yol6X(co2TGkm3VKhB&`#WX(+apawiS-5F|x&iwj zS+j-gQYew$#ADwilP$+N9xz#qS~B+!H~N$o^e356IF_pp?E^9U6Y=Nk#uR^{ZiM~C zVXzE@k<%liwSrQAg;o&u&(;d2_-nL+2mKAGqZK?N8l>Fo1^k5QxmNIu=r0920K9IT z)Z>>{qFK%zw=Fc%l$;R0)bC?AyoqbSO(rqlRy{|#wg;z|6(xhyf>VQ2LdF+UCqGTk z$U*QSL8XAP!atZ|dnvYH;f@o9?gpMxK$Z9bR1mIA=*Es<^t+@M`#p47)_7QpZFeY2 zDDLvZp=+^O07~OEaPnO@E$}I2>Jh#1h4RW{Vd%vZ$qJSHL%Z`Ypb?Wrj~6F%Zw48v zg0B{+P~~2|a=BYqKTQll+oAYae=_$

    Xa4 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test96.ans b/libs/libtpl-1.5/tests/test96.ans new file mode 100755 index 0000000000..6f463a1987 --- /dev/null +++ b/libs/libtpl-1.5/tests/test96.ans @@ -0,0 +1,15 @@ +s1 NULL +s2 +s3 hello +s1 NULL +s2 +s3 hello +s1 NULL +s2 +s3 hello +s1 NULL +s2 +s3 hello +s1 NULL +s2 +s3 hello diff --git a/libs/libtpl-1.5/tests/test96.c b/libs/libtpl-1.5/tests/test96.c new file mode 100755 index 0000000000..8e45befbcc --- /dev/null +++ b/libs/libtpl-1.5/tests/test96.c @@ -0,0 +1,27 @@ +#include "tpl.h" +#include + +const char *filename="/tmp/test96.tpl"; +int main() { + tpl_node *tn; + int i; + char *s1 = NULL, *s2 = "", *s3 = "hello"; + tn = tpl_map("A(sss)", &s1, &s2, &s3); + for(i=0;i<5;i++) { + tpl_pack(tn,1); + } + tpl_dump(tn,TPL_FILE,filename); + tpl_free(tn); + + s1 = s2 = s3 = (char*)0x1; /* overwritten below */ + tn = tpl_map("A(sss)", &s1, &s2, &s3); + tpl_load(tn,TPL_FILE,filename); + while( tpl_unpack(tn,1) > 0) { + printf("s1 %s\n", s1?s1:"NULL"); + printf("s2 %s\n", s2?s2:"NULL"); + printf("s3 %s\n", s3?s3:"NULL"); + } + tpl_free(tn); + return(0); +} + diff --git a/libs/libtpl-1.5/tests/test96.out b/libs/libtpl-1.5/tests/test96.out new file mode 100644 index 0000000000..6f463a1987 --- /dev/null +++ b/libs/libtpl-1.5/tests/test96.out @@ -0,0 +1,15 @@ +s1 NULL +s2 +s3 hello +s1 NULL +s2 +s3 hello +s1 NULL +s2 +s3 hello +s1 NULL +s2 +s3 hello +s1 NULL +s2 +s3 hello diff --git a/libs/libtpl-1.5/tests/test97 b/libs/libtpl-1.5/tests/test97 new file mode 100755 index 0000000000000000000000000000000000000000..962283dfba6bfb84923a689907f97e1e844f5fe6 GIT binary patch literal 127824 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test97.ans b/libs/libtpl-1.5/tests/test97.ans new file mode 100755 index 0000000000..2fe2921b43 --- /dev/null +++ b/libs/libtpl-1.5/tests/test97.ans @@ -0,0 +1 @@ +j is -128, v is 65535 diff --git a/libs/libtpl-1.5/tests/test97.c b/libs/libtpl-1.5/tests/test97.c new file mode 100755 index 0000000000..c1ed67bc9c --- /dev/null +++ b/libs/libtpl-1.5/tests/test97.c @@ -0,0 +1,27 @@ +#include "tpl.h" +#include +#include + +const char *filename = "/tmp/test97.tpl"; + +int main() { + tpl_node *tn; + int16_t j = -128; + uint16_t v=65535; + + tn = tpl_map("jv", &j, &v); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,filename); + tpl_free(tn); + + j = v = 0; + + tn = tpl_map("jv", &j, &v); + tpl_load(tn,TPL_FILE,filename); + tpl_unpack(tn,0); + tpl_free(tn); + + printf("j is %d, v is %d\n", (int)j, (int)v); + return(0); + +} diff --git a/libs/libtpl-1.5/tests/test97.out b/libs/libtpl-1.5/tests/test97.out new file mode 100644 index 0000000000..2fe2921b43 --- /dev/null +++ b/libs/libtpl-1.5/tests/test97.out @@ -0,0 +1 @@ +j is -128, v is 65535 diff --git a/libs/libtpl-1.5/tests/test98 b/libs/libtpl-1.5/tests/test98 new file mode 100755 index 0000000000000000000000000000000000000000..ed86027110e5e104c14108a4198b7b0bc0cc6daa GIT binary patch literal 128024 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test98.ans b/libs/libtpl-1.5/tests/test98.ans new file mode 100755 index 0000000000..6a2a1ccf37 --- /dev/null +++ b/libs/libtpl-1.5/tests/test98.ans @@ -0,0 +1,3 @@ +j is -128, v is 65535 +j is -129, v is 65534 +j is -130, v is 65533 diff --git a/libs/libtpl-1.5/tests/test98.c b/libs/libtpl-1.5/tests/test98.c new file mode 100755 index 0000000000..1eb9541279 --- /dev/null +++ b/libs/libtpl-1.5/tests/test98.c @@ -0,0 +1,28 @@ +#include "tpl.h" +#include +#include + +const char *filename = "/tmp/test98.tpl"; + +int main() { + tpl_node *tn; + int16_t j = -128; + uint16_t v=65535; + + tn = tpl_map("A(jv)", &j, &v); + tpl_pack(tn,1); j -= 1; v-= 1; + tpl_pack(tn,1); j -= 1; v-= 1; + tpl_pack(tn,1); + tpl_dump(tn,TPL_FILE,filename); + tpl_free(tn); + + j = v = 0; + + tn = tpl_map("A(jv)", &j, &v); + tpl_load(tn,TPL_FILE,filename); + while (tpl_unpack(tn,1) > 0) { + printf("j is %d, v is %d\n", (int)j, (int)v); + } + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test98.out b/libs/libtpl-1.5/tests/test98.out new file mode 100644 index 0000000000..6a2a1ccf37 --- /dev/null +++ b/libs/libtpl-1.5/tests/test98.out @@ -0,0 +1,3 @@ +j is -128, v is 65535 +j is -129, v is 65534 +j is -130, v is 65533 diff --git a/libs/libtpl-1.5/tests/test99 b/libs/libtpl-1.5/tests/test99 new file mode 100755 index 0000000000000000000000000000000000000000..c4f065e5958515bcc9aaae11d40b63e210118510 GIT binary patch literal 127225 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%0A8_L=4IN0+eEj3UpJ90R=V+?MF~sobR5O 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 Ge7i}?bEiv;V>drxKSJ-}ynwsl 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test99.ans b/libs/libtpl-1.5/tests/test99.ans new file mode 100755 index 0000000000..3267dcfeb9 --- /dev/null +++ b/libs/libtpl-1.5/tests/test99.ans @@ -0,0 +1,2 @@ +cA(i#)S(cf#)A(ci#) +& diff --git a/libs/libtpl-1.5/tests/test99.c b/libs/libtpl-1.5/tests/test99.c new file mode 100755 index 0000000000..f4ac12aa43 --- /dev/null +++ b/libs/libtpl-1.5/tests/test99.c @@ -0,0 +1,14 @@ +#include +#include +#include "tpl.h" + +int main() { + char *fmt, c; + fmt = tpl_peek(TPL_FILE|TPL_DATAPEEK, "test99.tpl", "c", &c); + if (fmt) { + printf("%s\n",fmt); + free(fmt); + printf("%c\n", c); + } + return 0; +} diff --git a/libs/libtpl-1.5/tests/test99.out b/libs/libtpl-1.5/tests/test99.out new file mode 100644 index 0000000000..3267dcfeb9 --- /dev/null +++ b/libs/libtpl-1.5/tests/test99.out @@ -0,0 +1,2 @@ +cA(i#)S(cf#)A(ci#) +& diff --git a/libs/libtpl-1.5/tests/test99.tpl b/libs/libtpl-1.5/tests/test99.tpl new file mode 100755 index 0000000000000000000000000000000000000000..bb934e3e4cbf3aee43273e665d5a478dc46c7c0e GIT binary patch literal 308 zcmXRZ$YC&HWMD{k)W}rU4Aw|aQ`U6UNCvVQxEL51Sb>-Wh}D>Z#D5_82gHAY_zw{O z2I5~p{1b?O0P%Mq{szRvsQC(1N5~wInlC_Hb@mJhys@7(69it`r-8vUdt)$oY!7rB z5InF4IkF-JNSpv-9iXo!0Pz +#include +#include "tpl.h" +#include +#include +#include +#include +#include +#include +#include +#include + +int fd[2]; + +void *thread_routine( void *arg ) { + tpl_node *tn; + int i,sum=0; + + /* child */ + tn = tpl_map("A(u)",&i); + tpl_load(tn, TPL_FD, fd[0]); + while (tpl_unpack(tn,1) > 0) sum += i; + tpl_free(tn); + printf("sum is %d\n", sum); + return NULL; +} + +int main() { + tpl_node *tn; + unsigned i; + int status; + pthread_t thread_id; + void *thread_result; + + pipe(fd); + if ( status = pthread_create( &thread_id, NULL, thread_routine, NULL )) { + printf("failure: status %d\n", status); + exit(-1); + } + /* parent */ + tn = tpl_map("A(u)",&i); + for(i=0;i<10000;i++) tpl_pack(tn,1); + tpl_dump(tn,TPL_FD, fd[1] ); + tpl_free(tn); + + status = pthread_join( thread_id, &thread_result ); + printf("thread result: %d %s\n", status, thread_result ? "non-null":"null"); +} diff --git a/w32/Library/FreeSwitchCore.2008.vcproj b/w32/Library/FreeSwitchCore.2008.vcproj index d8785d7bae..d8f95d8d28 100644 --- a/w32/Library/FreeSwitchCore.2008.vcproj +++ b/w32/Library/FreeSwitchCore.2008.vcproj @@ -47,7 +47,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1400,6 +1488,14 @@ RelativePath="..\..\libs\stfu\stfu.h" > + + + + diff --git a/w32/Library/FreeSwitchCore.vcproj b/w32/Library/FreeSwitchCore.vcproj index 604d773fe1..52e5406457 100644 --- a/w32/Library/FreeSwitchCore.vcproj +++ b/w32/Library/FreeSwitchCore.vcproj @@ -43,7 +43,7 @@ + + + + + + + + + + + + + + + + @@ -880,6 +928,14 @@ RelativePath="..\..\libs\stfu\stfu.h" > + + + + From c28c99c39445294e1172bdacaca7fc5e6151f733 Mon Sep 17 00:00:00 2001 From: William King Date: Thu, 13 Sep 2012 15:12:35 -0700 Subject: [PATCH 764/822] If the timer value isn't available it isn't an error. Instead just don't add the field. --- .../xml_int/mod_xml_radius/mod_radius.diff | 59 ------------------- .../xml_int/mod_xml_radius/mod_xml_radius.c | 6 +- 2 files changed, 3 insertions(+), 62 deletions(-) delete mode 100644 src/mod/xml_int/mod_xml_radius/mod_radius.diff diff --git a/src/mod/xml_int/mod_xml_radius/mod_radius.diff b/src/mod/xml_int/mod_xml_radius/mod_radius.diff deleted file mode 100644 index f32d39e1b6..0000000000 --- a/src/mod/xml_int/mod_xml_radius/mod_radius.diff +++ /dev/null @@ -1,59 +0,0 @@ -diff --git src/mod/xml_int/mod_xml_radius/mod_xml_radius.c src/mod/xml_int/mod_xml_radius/mod_xml_radius.c -index 0707388..e9e6e2a 100644 ---- src/mod/xml_int/mod_xml_radius/mod_xml_radius.c -+++ src/mod/xml_int/mod_xml_radius/mod_xml_radius.c -@@ -367,6 +367,10 @@ switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch - switch_time_t time = profile->times->created; - switch_time_exp_t tm; - -+ if ( !time ) { -+ goto err; -+ } -+ - switch_time_exp_lt(&tm, time); - av_value = switch_mprintf("%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d%02d", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, -@@ -381,6 +385,10 @@ switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch - switch_caller_profile_t *profile = switch_channel_get_caller_profile(channel); - switch_time_t time = profile->times->answered; - switch_time_exp_t tm; -+ -+ if ( !time ) { -+ goto err; -+ } - - switch_time_exp_lt(&tm, time); - -@@ -397,6 +405,10 @@ switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch - switch_caller_profile_t *profile = switch_channel_get_caller_profile(channel); - switch_time_t time = profile->times->hungup; - switch_time_exp_t tm; -+ -+ if ( !time ) { -+ goto err; -+ } - - switch_time_exp_lt(&tm, time); - -diff --git src/mod/xml_int/mod_xml_radius/xml_radius.conf.xml src/mod/xml_int/mod_xml_radius/xml_radius.conf.xml -index eb3070c..6349d05 100644 ---- src/mod/xml_int/mod_xml_radius/xml_radius.conf.xml -+++ src/mod/xml_int/mod_xml_radius/xml_radius.conf.xml -@@ -22,7 +22,7 @@ - - - -- -+ - - - -@@ -48,7 +48,7 @@ - - - -- -+ - - - diff --git a/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c b/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c index e9e6e2ac82..035a16f7f3 100644 --- a/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c +++ b/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c @@ -368,7 +368,7 @@ switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch switch_time_exp_t tm; if ( !time ) { - goto err; + return SWITCH_STATUS_SUCCESS; } switch_time_exp_lt(&tm, time); @@ -387,7 +387,7 @@ switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch switch_time_exp_t tm; if ( !time ) { - goto err; + return SWITCH_STATUS_SUCCESS; } switch_time_exp_lt(&tm, time); @@ -407,7 +407,7 @@ switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch switch_time_exp_t tm; if ( !time ) { - goto err; + return SWITCH_STATUS_SUCCESS; } switch_time_exp_lt(&tm, time); From d5e5fb032ae633d0efad915bc9130a20d2c04029 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 13 Sep 2012 17:46:13 -0500 Subject: [PATCH 765/822] add funcs to binary seralize/deserialize switch_events into a contiguous binary frame --- src/include/switch_event.h | 16 +++++++ src/switch_event.c | 93 +++++++++++++++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 1 deletion(-) diff --git a/src/include/switch_event.h b/src/include/switch_event.h index d0474a6929..cc78336655 100644 --- a/src/include/switch_event.h +++ b/src/include/switch_event.h @@ -102,6 +102,20 @@ struct switch_event { int flags; }; +typedef struct switch_serial_event_s { + int event_id; + int priority; + int flags; + char *owner; + char *subclass_name; + char *body; +} switch_serial_event_t; + +typedef struct switch_serial_event_header_s { + char *name; + char *value; +} switch_serial_event_header_t; + typedef enum { EF_UNIQ_HEADERS = (1 << 0), EF_NO_CHAT_EXEC = (1 << 1), @@ -295,6 +309,8 @@ SWITCH_DECLARE(switch_status_t) switch_event_free_subclass_detailed(const char * \return SWITCH_STATUS_SUCCESS if the operation was successful \note you must free the resulting string when you are finished with it */ +SWITCH_DECLARE(switch_status_t) switch_event_binary_deserialize(switch_event_t **eventp, void **data, switch_size_t len, switch_bool_t destroy); +SWITCH_DECLARE(switch_status_t) switch_event_binary_serialize(switch_event_t *event, void **data, switch_size_t *len); SWITCH_DECLARE(switch_status_t) switch_event_serialize(switch_event_t *event, char **str, switch_bool_t encode); SWITCH_DECLARE(switch_status_t) switch_event_serialize_json(switch_event_t *event, char **str); SWITCH_DECLARE(switch_status_t) switch_event_create_json(switch_event_t **event, const char *json); diff --git a/src/switch_event.c b/src/switch_event.c index 242165d69f..fdb397de01 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -34,7 +34,7 @@ #include #include - +#include "tpl.h" //#define SWITCH_EVENT_RECYCLE #define DISPATCH_QUEUE_LEN 100 @@ -1284,6 +1284,97 @@ SWITCH_DECLARE(switch_status_t) switch_event_dup_reply(switch_event_t **event, s return SWITCH_STATUS_SUCCESS; } +#define SWITCH_SERIALIZED_EVENT_MAP "S(iiisss)A(S(ss))" + +SWITCH_DECLARE(switch_status_t) switch_event_binary_deserialize(switch_event_t **eventp, void **data, switch_size_t len, switch_bool_t destroy) +{ + switch_event_t *event; + tpl_node *tn; + switch_serial_event_t e; + switch_serial_event_header_t sh; + int how = TPL_MEM; + + switch_event_create(&event, SWITCH_EVENT_CLONE); + switch_assert(event); + + tn = tpl_map(SWITCH_SERIALIZED_EVENT_MAP, &e, &sh); + + if (!destroy) { + how |= TPL_EXCESS_OK; + } + + tpl_load(tn, how, data, len); + + tpl_unpack(tn, 0); + + event->event_id = e.event_id; + event->priority = e.priority; + event->flags = e.flags; + + event->owner = e.owner; + event->subclass_name = e.subclass_name; + event->body = e.body; + + + while(tpl_unpack(tn, 1)) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, sh.name, sh.value); + } + + *eventp = event; + + tpl_free(tn); + + if (destroy) { + free(*data); + } + + *data = NULL; + + return SWITCH_STATUS_SUCCESS; + +} + +SWITCH_DECLARE(switch_status_t) switch_event_binary_serialize(switch_event_t *event, void **data, switch_size_t *len) +{ + tpl_node *tn; + switch_serial_event_t e; + switch_serial_event_header_t sh; + switch_event_header_t *eh; + int how = TPL_MEM; + + e.event_id = event->event_id; + e.priority = event->priority; + e.flags = event->flags; + + e.owner = event->owner; + e.subclass_name = event->subclass_name; + e.body = event->body; + + tn = tpl_map(SWITCH_SERIALIZED_EVENT_MAP, &e, &sh); + + tpl_pack(tn, 0); + + for (eh = event->headers; eh; eh = eh->next) { + if (eh->idx) continue; // no arrays yet + + sh.name = eh->name; + sh.value = eh->value; + + tpl_pack(tn, 1); + } + + if (*len > 0) { + how |= TPL_PREALLOCD; + } + + tpl_dump(tn, how, data, len); + + tpl_free(tn); + + return SWITCH_STATUS_SUCCESS; +} + + SWITCH_DECLARE(switch_status_t) switch_event_serialize(switch_event_t *event, char **str, switch_bool_t encode) { switch_size_t len = 0; From 70898c09ef500d46adb6fc7d92b6b36316a7b71a Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 13 Sep 2012 17:58:25 -0500 Subject: [PATCH 766/822] run serialize test in skel --- src/mod/applications/mod_skel/mod_skel.c | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/mod/applications/mod_skel/mod_skel.c b/src/mod/applications/mod_skel/mod_skel.c index f412cd6e7c..374010c605 100644 --- a/src/mod/applications/mod_skel/mod_skel.c +++ b/src/mod/applications/mod_skel/mod_skel.c @@ -112,8 +112,48 @@ static switch_status_t do_config(switch_bool_t reload) SWITCH_STANDARD_API(skel_function) { + switch_event_t *event; + unsigned char frame_buffer[8192] = {0}; + do_config(SWITCH_TRUE); + if (switch_event_create(&event, SWITCH_EVENT_TRAP) == SWITCH_STATUS_SUCCESS) { + switch_size_t len = 0; + int x = 0; + + /* populate the event with some headers */ + + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "testing", "true"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "foo", "bar"); + + for (x = 0; x < 10; x++) { + char name[128]; + switch_snprintf(name, sizeof(name), "test-header-%d", x); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, name, "value-%d", x); + } + + + /* Nothing up my sleeve, here is the event */ + + DUMP_EVENT(event); + + + /* ok, serialize it into frame_buffer and destroy the event *poof* */ + len = sizeof(frame_buffer); + switch_event_binary_serialize(event, (void *)frame_buffer, &len); + switch_event_destroy(&event); + + + /* wave the magic wand and feed frame_buffer to deserialize */ + switch_event_binary_deserialize(&event, (void *)frame_buffer, len, SWITCH_FALSE); + + /* TA DA */ + DUMP_EVENT(event); + + switch_event_destroy(&event); + } + + return SWITCH_STATUS_SUCCESS; } From e8c7bb3a88bbc46de44dca54c049f0bf0de21ced Mon Sep 17 00:00:00 2001 From: Seven Du Date: Fri, 14 Sep 2012 09:36:35 +0800 Subject: [PATCH 767/822] for consistency --- src/mod/applications/mod_conference/mod_conference.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index eb70d53ea2..2ffd8194d8 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -5248,7 +5248,7 @@ static void conference_xlist(conference_obj_t *conference, switch_xml_t x_confer switch_xml_set_attr_d(x_conference, "name", conference->name); switch_snprintf(i, sizeof(i), "%d", conference->count); - switch_xml_set_attr_d(x_conference, "member-count", ival); + switch_xml_set_attr_d(x_conference, "member_count", ival); switch_snprintf(i, sizeof(i), "%u", conference->rate); switch_xml_set_attr_d(x_conference, "rate", ival); switch_xml_set_attr_d(x_conference, "uuid", conference->uuid_str); From a32244fe38a5f4811d6487abc66776c9119cf43e Mon Sep 17 00:00:00 2001 From: Seven Du Date: Fri, 14 Sep 2012 09:41:10 +0800 Subject: [PATCH 768/822] Revert "for consistency" This reverts commit e8c7bb3a88bbc46de44dca54c049f0bf0de21ced. --- src/mod/applications/mod_conference/mod_conference.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 2ffd8194d8..eb70d53ea2 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -5248,7 +5248,7 @@ static void conference_xlist(conference_obj_t *conference, switch_xml_t x_confer switch_xml_set_attr_d(x_conference, "name", conference->name); switch_snprintf(i, sizeof(i), "%d", conference->count); - switch_xml_set_attr_d(x_conference, "member_count", ival); + switch_xml_set_attr_d(x_conference, "member-count", ival); switch_snprintf(i, sizeof(i), "%u", conference->rate); switch_xml_set_attr_d(x_conference, "rate", ival); switch_xml_set_attr_d(x_conference, "uuid", conference->uuid_str); From bf04f8b0c8af345f0a03df9de185e08bc87396aa Mon Sep 17 00:00:00 2001 From: William King Date: Fri, 14 Sep 2012 00:26:31 -0700 Subject: [PATCH 769/822] Mod_sonar can be useful for collecting specific round trip delay information about a call route. This is a first working draft, so expect it to interfere with the migration habits of your creatures. To use setup a destination with echo, originate a call to that destination and drop the call into &sonar(). Then watch the logs for the results. --- src/mod/applications/mod_sonar/Makefile | 2 + src/mod/applications/mod_sonar/mod_sonar.c | 136 +++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 src/mod/applications/mod_sonar/Makefile create mode 100644 src/mod/applications/mod_sonar/mod_sonar.c diff --git a/src/mod/applications/mod_sonar/Makefile b/src/mod/applications/mod_sonar/Makefile new file mode 100644 index 0000000000..2c35e6e98f --- /dev/null +++ b/src/mod/applications/mod_sonar/Makefile @@ -0,0 +1,2 @@ +BASE=../../../.. +include $(BASE)/build/modmake.rules diff --git a/src/mod/applications/mod_sonar/mod_sonar.c b/src/mod/applications/mod_sonar/mod_sonar.c new file mode 100644 index 0000000000..5cdcd35188 --- /dev/null +++ b/src/mod/applications/mod_sonar/mod_sonar.c @@ -0,0 +1,136 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2012, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * William King + * + * mod_sonar.c -- Sonar ping timer + * + * + */ + +/* + TODO: + 1. Use libteltone directly + 2. Use an energy detection to listen for first set of sound back. Use timestamp of detection of energy as the recv stamp if a tone is eventually detected. + 3. Check for milliwatt pings. Listen for frequency changes, and audio loss + */ + + +#include + +/* Prototypes */ +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sonar_shutdown); +SWITCH_MODULE_RUNTIME_FUNCTION(mod_sonar_runtime); +SWITCH_MODULE_LOAD_FUNCTION(mod_sonar_load); + +/* SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime) + * Defines a switch_loadable_module_function_table_t and a static const char[] modname + */ +SWITCH_MODULE_DEFINITION(mod_sonar, mod_sonar_load, mod_sonar_shutdown, NULL); + +switch_time_t start, end, diff; + +switch_bool_t sonar_ping_callback(switch_core_session_t *session, const char *app, const char *app_data){ + + if ( end ) { + return SWITCH_TRUE; + } + + end = switch_time_now(); + diff = end - start; + start = 0; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Sonar ping took %lu milliseconds\n", diff / 1000); + + return SWITCH_TRUE; +} + +SWITCH_STANDARD_APP(sonar_app) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + char *tone = "%(500,0,1004)"; + int loops = atoi(data); + + if ( ! loops ) { + loops = 5; + } + + switch_channel_answer(channel); + switch_ivr_sleep(session, 1000, SWITCH_FALSE, NULL); + + switch_ivr_tone_detect_session(session, + "ping", "1004", + "r", 0, + 1, NULL, NULL, sonar_ping_callback); + + switch_ivr_sleep(session, 1000, SWITCH_FALSE, NULL); + + for( int x = 0; x < loops; x++ ) { + end = 0; + start = switch_time_now(); + switch_ivr_gentones(session, tone, 1, NULL); + switch_ivr_sleep(session, 2000, SWITCH_FALSE, NULL); + if ( start ) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Lost sonar ping\n"); + } + } + + switch_ivr_sleep(session, 1000, SWITCH_FALSE, NULL); + switch_ivr_stop_tone_detect_session(session); +} + +/* Macro expands to: switch_status_t mod_sonar_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */ +SWITCH_MODULE_LOAD_FUNCTION(mod_sonar_load) +{ + switch_application_interface_t *app_interface; + + /* connect my internal structure to the blank pointer passed to me */ + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + + SWITCH_ADD_APP(app_interface, "sonar", "sonar", "sonar", sonar_app, "", SAF_NONE); + + /* indicate that the module should continue to be loaded */ + return SWITCH_STATUS_SUCCESS; +} + +/* + Called when the system shuts down + Macro expands to: switch_status_t mod_sonar_shutdown() */ +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sonar_shutdown) +{ + + return SWITCH_STATUS_SUCCESS; +} + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 + */ From 2e9b4c23ded14fc69ed5eaf428464d822ae069f5 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Fri, 14 Sep 2012 07:38:03 -0500 Subject: [PATCH 770/822] FS-4618 --resolve --- libs/esl/src/esl_json.c | 4 ++-- src/switch_json.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/esl/src/esl_json.c b/libs/esl/src/esl_json.c index 3de776b3a8..767c29da02 100644 --- a/libs/esl/src/esl_json.c +++ b/libs/esl/src/esl_json.c @@ -275,8 +275,8 @@ ESL_DECLARE(cJSON *)cJSON_Parse(const char *value) } /* Render a cJSON item/entity/structure to text. */ -char *cJSON_Print(cJSON *item) {return print_value(item,0,1);} -char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);} +ESL_DECLARE(char *) cJSON_Print(cJSON *item) {return print_value(item,0,1);} +ESL_DECLARE(char *) cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);} /* Parser core - when encountering text, process appropriately. */ static const char *parse_value(cJSON *item,const char *value) diff --git a/src/switch_json.c b/src/switch_json.c index 005b32fd34..c68e678ebf 100644 --- a/src/switch_json.c +++ b/src/switch_json.c @@ -27,11 +27,11 @@ #include #include #include -#include #include #include -#include "switch_json.h" #include "switch.h" +#include "switch_json.h" +#include static const char *ep; @@ -275,8 +275,8 @@ SWITCH_DECLARE(cJSON *)cJSON_Parse(const char *value) } /* Render a cJSON item/entity/structure to text. */ -char *cJSON_Print(cJSON *item) {return print_value(item,0,1);} -char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);} +SWITCH_DECLARE(char *)cJSON_Print(cJSON *item) {return print_value(item,0,1);} +SWITCH_DECLARE(char *)cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);} /* Parser core - when encountering text, process appropriately. */ static const char *parse_value(cJSON *item,const char *value) From 4100c3b5323358a901d41b7c5c3c14935f0121d9 Mon Sep 17 00:00:00 2001 From: Brian West Date: Fri, 14 Sep 2012 10:29:25 -0500 Subject: [PATCH 771/822] FS-4599 --resolve --- src/mod/endpoints/mod_sofia/sofia.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 967a5502bd..f475882e65 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -4939,6 +4939,12 @@ switch_status_t config_sofia(int reload, char *profile_name) } else { profile->ndlb &= ~PFLAG_NDLB_ALLOW_BAD_IANANAME; } + } else if (!strcasecmp(var, "NDLB-allow-crypto-in-avp")) { + if (switch_true(val)) { + profile->ndlb |= PFLAG_NDLB_ALLOW_CRYPTO_IN_AVP; + } else { + profile->ndlb &= ~PFLAG_NDLB_ALLOW_CRYPTO_IN_AVP; + } } else if (!strcasecmp(var, "NDLB-allow-nondup-sdp")) { if (switch_true(val)) { profile->ndlb |= PFLAG_NDLB_ALLOW_NONDUP_SDP; From dc599db6830da503125ea8acaa09bc8b6fd57f78 Mon Sep 17 00:00:00 2001 From: Brian West Date: Fri, 14 Sep 2012 10:30:13 -0500 Subject: [PATCH 772/822] FS-4600 --resolve --- src/mod/say/mod_say_hu/mod_say_hu.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/mod/say/mod_say_hu/mod_say_hu.c b/src/mod/say/mod_say_hu/mod_say_hu.c index 33d07b1b65..3e45496130 100644 --- a/src/mod/say/mod_say_hu/mod_say_hu.c +++ b/src/mod/say/mod_say_hu/mod_say_hu.c @@ -335,20 +335,23 @@ static switch_status_t hu_say_time(switch_core_session_t *session, char *tosay, say_today = say_yesterday = 0; } + if (say_year) { + say_num(tm.tm_year + 1900, SSM_PRONOUNCED); + } + if (say_month) { say_file("time/mon-%d.wav", tm.tm_mon); } if (say_day) { - say_num(tm.tm_mday, SSM_COUNTED); - } - if (say_year) { - say_num(tm.tm_year + 1900, SSM_PRONOUNCED); + say_num(tm.tm_mday, SSM_PRONOUNCED); } if (say_time) { say_num(tm.tm_hour, SSM_PRONOUNCED); say_file("time/hour.wav"); + say_num(tm.tm_min, SSM_PRONOUNCED); + say_file("time/minute.wav"); } From 6721cd918a65540b4c3f224be76edaafb44c1906 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 14 Sep 2012 11:19:36 -0500 Subject: [PATCH 773/822] hangup unauth calls with rejected cause --- src/mod/endpoints/mod_sofia/sofia.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index f475882e65..40b1a9778b 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -1712,7 +1712,7 @@ void sofia_event_callback(nua_event_t event, switch(event) { case nua_i_terminated: - if ((status == 401 || status == 407) && sofia_private && sofia_private->uuid) { + if ((status == 401 || status == 407 || status == 403) && sofia_private && sofia_private->uuid) { switch_core_session_t *session; if ((session = switch_core_session_locate(sofia_private->uuid))) { @@ -1722,19 +1722,22 @@ void sofia_event_callback(nua_event_t event, if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND && !switch_channel_test_flag(channel, CF_ANSWERED)) { private_object_t *tech_pvt = switch_core_session_get_private(session); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "detaching session %s\n", sofia_private->uuid); - - if (!zstr(tech_pvt->call_id)) { - tech_pvt->sofia_private = NULL; - tech_pvt->nh = NULL; - sofia_set_flag(tech_pvt, TFLAG_BYE); - switch_mutex_lock(profile->flag_mutex); - switch_core_hash_insert(profile->chat_hash, tech_pvt->call_id, strdup(switch_core_session_get_uuid(session))); - switch_mutex_unlock(profile->flag_mutex); + if (status == 403) { + switch_channel_hangup(channel, SWITCH_CAUSE_CALL_REJECTED); } else { - switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "detaching session %s\n", sofia_private->uuid); + + if (!zstr(tech_pvt->call_id)) { + tech_pvt->sofia_private = NULL; + tech_pvt->nh = NULL; + sofia_set_flag(tech_pvt, TFLAG_BYE); + switch_mutex_lock(profile->flag_mutex); + switch_core_hash_insert(profile->chat_hash, tech_pvt->call_id, strdup(switch_core_session_get_uuid(session))); + switch_mutex_unlock(profile->flag_mutex); + } else { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + } } - end++; } From 83007777a0841440c55aeca3a8e40fbf245ddd45 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 14 Sep 2012 11:24:23 -0500 Subject: [PATCH 774/822] lower console output to debug for avmd --- src/mod/applications/mod_avmd/mod_avmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod/applications/mod_avmd/mod_avmd.c b/src/mod/applications/mod_avmd/mod_avmd.c index ce3aed0916..f94dc69151 100644 --- a/src/mod/applications/mod_avmd/mod_avmd.c +++ b/src/mod/applications/mod_avmd/mod_avmd.c @@ -535,7 +535,7 @@ static void avmd_process(avmd_session_t *session, switch_frame_t *frame) /* calculate variance */ v = session->sqa_b.sma - (session->sma_b.sma * session->sma_b.sma); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_INFO, "<<< AVMD v=%f f=%f %fHz sma=%f sqa=%f >>>\n", v, f, TO_HZ(session->rate, f), session->sma_b.sma, session->sqa_b.sma); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_DEBUG, "<<< AVMD v=%f f=%f %fHz sma=%f sqa=%f >>>\n", v, f, TO_HZ(session->rate, f), session->sma_b.sma, session->sqa_b.sma); } /*! If variance is less than threshold then we have detection */ @@ -558,7 +558,7 @@ static void avmd_process(avmd_session_t *session, switch_frame_t *frame) switch_core_session_queue_event(session->session, &event); switch_event_fire(&event_copy); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_INFO, "<<< AVMD - Beep Detected >>>\n"); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_DEBUG, "<<< AVMD - Beep Detected >>>\n"); switch_channel_set_variable(channel, "avmd_detect", "TRUE"); RESET_SMA_BUFFER(&session->sma_b); RESET_SMA_BUFFER(&session->sqa_b); From d8cada59eec784ea3ae1d3179a33aa68c390afac Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Fri, 14 Sep 2012 12:13:36 -0500 Subject: [PATCH 775/822] windows fix for recent tpl additions to switch_event.c and revert a search and replace error for libtiff building --- libs/spandsp/src/libtiff.2008.vcproj | 200 ++++++++-------- w32/Library/FreeSwitchCore.2008.vcproj | 216 +++++++++--------- w32/Library/FreeSwitchCore.2010.vcxproj | 35 ++- .../FreeSwitchCore.2010.vcxproj.filters | 9 + 4 files changed, 249 insertions(+), 211 deletions(-) diff --git a/libs/spandsp/src/libtiff.2008.vcproj b/libs/spandsp/src/libtiff.2008.vcproj index a83dc87027..4a29650333 100644 --- a/libs/spandsp/src/libtiff.2008.vcproj +++ b/libs/spandsp/src/libtiff.2008.vcproj @@ -16,8 +16,8 @@ Name="x64" /> - - + + - + - - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - + - - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - + - + diff --git a/w32/Library/FreeSwitchCore.2008.vcproj b/w32/Library/FreeSwitchCore.2008.vcproj index d8f95d8d28..e4303b904d 100644 --- a/w32/Library/FreeSwitchCore.2008.vcproj +++ b/w32/Library/FreeSwitchCore.2008.vcproj @@ -47,8 +47,8 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + @@ -938,6 +898,54 @@ RelativePath="..\..\src\switch_xml_config.c" > + + + + + + + + + + + + + + @@ -1480,6 +1488,10 @@ RelativePath="..\..\src\include\g711.h" > + + @@ -1488,14 +1500,6 @@ RelativePath="..\..\libs\stfu\stfu.h" > - - - - @@ -1636,6 +1640,10 @@ RelativePath="..\..\src\include\switch_xml_config.h" > + + Disabled - ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-4.0.2\libtiff;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;%(AdditionalIncludeDirectories) + ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-4.0.2\libtiff;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;libs\libtpl-1.5\src;libs\libtpl-1.5\src\win;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;PCRE_STATIC;STATICLIB;ENABLE_ZRTP;%(PreprocessorDefinitions) true EnableFastChecks @@ -146,8 +146,8 @@ if not exist "$(OutDir)htdocs" xcopy "$(SolutionDir)htdocs\*.*" "$(OutDir)htdocs Disabled - ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-4.0.2\libtiff;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;PCRE_STATIC;STATICLIB;ENABLE_ZRTP;%(PreprocessorDefinitions) + ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-4.0.2\libtiff;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;libs\libtpl-1.5\src;libs\libtpl-1.5\src\win;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;PCRE_STATIC;STATICLIB;ENABLE_ZRTP;TPL_NOLIB;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL @@ -198,8 +198,8 @@ if not exist "$(OutDir)htdocs" xcopy "$(SolutionDir)htdocs\*.*" "$(OutDir)htdocs MaxSpeed - ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-4.0.2\libtiff;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;STATICLIB;CRASH_PROT;PCRE_STATIC;ENABLE_ZRTP;%(PreprocessorDefinitions) + ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-4.0.2\libtiff;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;..\..\libs\libtpl-1.5\src;..\..\libs\libtpl-1.5\src\win;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;STATICLIB;CRASH_PROT;PCRE_STATIC;ENABLE_ZRTP;TPL_NOLIB;%(PreprocessorDefinitions) MultiThreadedDLL Use switch.h @@ -247,8 +247,8 @@ if not exist "$(OutDir)htdocs" xcopy "$(SolutionDir)htdocs\*.*" "$(OutDir)htdocs MaxSpeed - ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-4.0.2\libtiff;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;STATICLIB;CRASH_PROT;PCRE_STATIC;ENABLE_ZRTP;%(PreprocessorDefinitions) + ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-4.0.2\libtiff;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;libs\libtpl-1.5\src;libs\libtpl-1.5\src\win;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;STATICLIB;CRASH_PROT;PCRE_STATIC;ENABLE_ZRTP;TPL_NOLIB;%(PreprocessorDefinitions) MultiThreadedDLL Use switch.h @@ -286,6 +286,26 @@ if not exist "$(OutDir)htdocs" xcopy "$(SolutionDir)htdocs\*.*" "$(OutDir)htdocs + + NotUsing + false + NotUsing + false + NotUsing + false + NotUsing + false + + + NotUsing + false + NotUsing + false + NotUsing + false + NotUsing + false + @@ -690,6 +710,7 @@ if not exist "$(OutDir)htdocs" xcopy "$(SolutionDir)htdocs\*.*" "$(OutDir)htdocs + diff --git a/w32/Library/FreeSwitchCore.2010.vcxproj.filters b/w32/Library/FreeSwitchCore.2010.vcxproj.filters index 79369a8bb3..9766295d13 100644 --- a/w32/Library/FreeSwitchCore.2010.vcxproj.filters +++ b/w32/Library/FreeSwitchCore.2010.vcxproj.filters @@ -202,6 +202,12 @@ Source Files + + Source Files + + + Source Files + @@ -321,6 +327,9 @@ Header Files + + Header Files + From dba0b0e40aacd25b409e8fada2bfc939637fac94 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Fri, 14 Sep 2012 12:28:15 -0500 Subject: [PATCH 776/822] vs2010 reswig --- .../mod_managed/freeswitch_wrap.2010.cxx | 440 ++++++++++++++++++ .../mod_managed/managed/swig.2010.cs | 403 +++++++++++++++- 2 files changed, 842 insertions(+), 1 deletion(-) diff --git a/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx b/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx index c04fa86d95..567ac0f0e8 100644 --- a/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx +++ b/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx @@ -5894,6 +5894,132 @@ SWIGEXPORT void SWIGSTDCALL CSharp_delete_switch_app_log(void * jarg1) { } +SWIGEXPORT void SWIGSTDCALL CSharp_switch_hold_record_t_on_set(void * jarg1, void * jarg2) { + switch_hold_record_t *arg1 = (switch_hold_record_t *) 0 ; + switch_time_t arg2 ; + switch_time_t *argp2 ; + + arg1 = (switch_hold_record_t *)jarg1; + argp2 = (switch_time_t *)jarg2; + if (!argp2) { + SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "Attempt to dereference null switch_time_t", 0); + return ; + } + arg2 = *argp2; + if (arg1) (arg1)->on = arg2; +} + + +SWIGEXPORT void * SWIGSTDCALL CSharp_switch_hold_record_t_on_get(void * jarg1) { + void * jresult ; + switch_hold_record_t *arg1 = (switch_hold_record_t *) 0 ; + switch_time_t result; + + arg1 = (switch_hold_record_t *)jarg1; + result = ((arg1)->on); + jresult = new switch_time_t((const switch_time_t &)result); + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_hold_record_t_off_set(void * jarg1, void * jarg2) { + switch_hold_record_t *arg1 = (switch_hold_record_t *) 0 ; + switch_time_t arg2 ; + switch_time_t *argp2 ; + + arg1 = (switch_hold_record_t *)jarg1; + argp2 = (switch_time_t *)jarg2; + if (!argp2) { + SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "Attempt to dereference null switch_time_t", 0); + return ; + } + arg2 = *argp2; + if (arg1) (arg1)->off = arg2; +} + + +SWIGEXPORT void * SWIGSTDCALL CSharp_switch_hold_record_t_off_get(void * jarg1) { + void * jresult ; + switch_hold_record_t *arg1 = (switch_hold_record_t *) 0 ; + switch_time_t result; + + arg1 = (switch_hold_record_t *)jarg1; + result = ((arg1)->off); + jresult = new switch_time_t((const switch_time_t &)result); + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_hold_record_t_uuid_set(void * jarg1, char * jarg2) { + switch_hold_record_t *arg1 = (switch_hold_record_t *) 0 ; + char *arg2 = (char *) 0 ; + + arg1 = (switch_hold_record_t *)jarg1; + arg2 = (char *)jarg2; + { + if (arg1->uuid) delete [] arg1->uuid; + if (arg2) { + arg1->uuid = (char *) (new char[strlen((const char *)arg2)+1]); + strcpy((char *)arg1->uuid, (const char *)arg2); + } else { + arg1->uuid = 0; + } + } +} + + +SWIGEXPORT char * SWIGSTDCALL CSharp_switch_hold_record_t_uuid_get(void * jarg1) { + char * jresult ; + switch_hold_record_t *arg1 = (switch_hold_record_t *) 0 ; + char *result = 0 ; + + arg1 = (switch_hold_record_t *)jarg1; + result = (char *) ((arg1)->uuid); + jresult = SWIG_csharp_string_callback((const char *)result); + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_hold_record_t_next_set(void * jarg1, void * jarg2) { + switch_hold_record_t *arg1 = (switch_hold_record_t *) 0 ; + switch_hold_record_s *arg2 = (switch_hold_record_s *) 0 ; + + arg1 = (switch_hold_record_t *)jarg1; + arg2 = (switch_hold_record_s *)jarg2; + if (arg1) (arg1)->next = arg2; +} + + +SWIGEXPORT void * SWIGSTDCALL CSharp_switch_hold_record_t_next_get(void * jarg1) { + void * jresult ; + switch_hold_record_t *arg1 = (switch_hold_record_t *) 0 ; + switch_hold_record_s *result = 0 ; + + arg1 = (switch_hold_record_t *)jarg1; + result = (switch_hold_record_s *) ((arg1)->next); + jresult = (void *)result; + return jresult; +} + + +SWIGEXPORT void * SWIGSTDCALL CSharp_new_switch_hold_record_t() { + void * jresult ; + switch_hold_record_t *result = 0 ; + + result = (switch_hold_record_t *)new switch_hold_record_t(); + jresult = (void *)result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_delete_switch_hold_record_t(void * jarg1) { + switch_hold_record_t *arg1 = (switch_hold_record_t *) 0 ; + + arg1 = (switch_hold_record_t *)jarg1; + delete arg1; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_MESSAGE_STRING_ARG_MAX_get() { int jresult ; int result; @@ -7591,6 +7717,16 @@ SWIGEXPORT void * SWIGSTDCALL CSharp_switch_core_session_id() { } +SWIGEXPORT void * SWIGSTDCALL CSharp_switch_core_session_id_dec() { + void * jresult ; + switch_size_t result; + + result = switch_core_session_id_dec(); + jresult = new switch_size_t((const switch_size_t &)result); + return jresult; +} + + SWIGEXPORT void * SWIGSTDCALL CSharp_switch_core_session_request_by_name(char * jarg1, int jarg2, void * jarg3) { void * jresult ; char *arg1 = (char *) 0 ; @@ -26110,6 +26246,18 @@ SWIGEXPORT char * SWIGSTDCALL CSharp_switch_channel_get_partner_uuid(void * jarg } +SWIGEXPORT void * SWIGSTDCALL CSharp_switch_channel_get_hold_record(void * jarg1) { + void * jresult ; + switch_channel_t *arg1 = (switch_channel_t *) 0 ; + switch_hold_record_t *result = 0 ; + + arg1 = (switch_channel_t *)jarg1; + result = (switch_hold_record_t *)switch_channel_get_hold_record(arg1); + jresult = (void *)result; + return jresult; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_switch_buffer_create(void * jarg1, void * jarg2, void * jarg3) { int jresult ; switch_memory_pool_t *arg1 = (switch_memory_pool_t *) 0 ; @@ -26906,6 +27054,258 @@ SWIGEXPORT void SWIGSTDCALL CSharp_delete_switch_event(void * jarg1) { } +SWIGEXPORT void SWIGSTDCALL CSharp_switch_serial_event_t_event_id_set(void * jarg1, int jarg2) { + switch_serial_event_t *arg1 = (switch_serial_event_t *) 0 ; + int arg2 ; + + arg1 = (switch_serial_event_t *)jarg1; + arg2 = (int)jarg2; + if (arg1) (arg1)->event_id = arg2; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_serial_event_t_event_id_get(void * jarg1) { + int jresult ; + switch_serial_event_t *arg1 = (switch_serial_event_t *) 0 ; + int result; + + arg1 = (switch_serial_event_t *)jarg1; + result = (int) ((arg1)->event_id); + jresult = result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_serial_event_t_priority_set(void * jarg1, int jarg2) { + switch_serial_event_t *arg1 = (switch_serial_event_t *) 0 ; + int arg2 ; + + arg1 = (switch_serial_event_t *)jarg1; + arg2 = (int)jarg2; + if (arg1) (arg1)->priority = arg2; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_serial_event_t_priority_get(void * jarg1) { + int jresult ; + switch_serial_event_t *arg1 = (switch_serial_event_t *) 0 ; + int result; + + arg1 = (switch_serial_event_t *)jarg1; + result = (int) ((arg1)->priority); + jresult = result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_serial_event_t_flags_set(void * jarg1, int jarg2) { + switch_serial_event_t *arg1 = (switch_serial_event_t *) 0 ; + int arg2 ; + + arg1 = (switch_serial_event_t *)jarg1; + arg2 = (int)jarg2; + if (arg1) (arg1)->flags = arg2; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_serial_event_t_flags_get(void * jarg1) { + int jresult ; + switch_serial_event_t *arg1 = (switch_serial_event_t *) 0 ; + int result; + + arg1 = (switch_serial_event_t *)jarg1; + result = (int) ((arg1)->flags); + jresult = result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_serial_event_t_owner_set(void * jarg1, char * jarg2) { + switch_serial_event_t *arg1 = (switch_serial_event_t *) 0 ; + char *arg2 = (char *) 0 ; + + arg1 = (switch_serial_event_t *)jarg1; + arg2 = (char *)jarg2; + { + if (arg1->owner) delete [] arg1->owner; + if (arg2) { + arg1->owner = (char *) (new char[strlen((const char *)arg2)+1]); + strcpy((char *)arg1->owner, (const char *)arg2); + } else { + arg1->owner = 0; + } + } +} + + +SWIGEXPORT char * SWIGSTDCALL CSharp_switch_serial_event_t_owner_get(void * jarg1) { + char * jresult ; + switch_serial_event_t *arg1 = (switch_serial_event_t *) 0 ; + char *result = 0 ; + + arg1 = (switch_serial_event_t *)jarg1; + result = (char *) ((arg1)->owner); + jresult = SWIG_csharp_string_callback((const char *)result); + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_serial_event_t_subclass_name_set(void * jarg1, char * jarg2) { + switch_serial_event_t *arg1 = (switch_serial_event_t *) 0 ; + char *arg2 = (char *) 0 ; + + arg1 = (switch_serial_event_t *)jarg1; + arg2 = (char *)jarg2; + { + if (arg1->subclass_name) delete [] arg1->subclass_name; + if (arg2) { + arg1->subclass_name = (char *) (new char[strlen((const char *)arg2)+1]); + strcpy((char *)arg1->subclass_name, (const char *)arg2); + } else { + arg1->subclass_name = 0; + } + } +} + + +SWIGEXPORT char * SWIGSTDCALL CSharp_switch_serial_event_t_subclass_name_get(void * jarg1) { + char * jresult ; + switch_serial_event_t *arg1 = (switch_serial_event_t *) 0 ; + char *result = 0 ; + + arg1 = (switch_serial_event_t *)jarg1; + result = (char *) ((arg1)->subclass_name); + jresult = SWIG_csharp_string_callback((const char *)result); + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_serial_event_t_body_set(void * jarg1, char * jarg2) { + switch_serial_event_t *arg1 = (switch_serial_event_t *) 0 ; + char *arg2 = (char *) 0 ; + + arg1 = (switch_serial_event_t *)jarg1; + arg2 = (char *)jarg2; + { + if (arg1->body) delete [] arg1->body; + if (arg2) { + arg1->body = (char *) (new char[strlen((const char *)arg2)+1]); + strcpy((char *)arg1->body, (const char *)arg2); + } else { + arg1->body = 0; + } + } +} + + +SWIGEXPORT char * SWIGSTDCALL CSharp_switch_serial_event_t_body_get(void * jarg1) { + char * jresult ; + switch_serial_event_t *arg1 = (switch_serial_event_t *) 0 ; + char *result = 0 ; + + arg1 = (switch_serial_event_t *)jarg1; + result = (char *) ((arg1)->body); + jresult = SWIG_csharp_string_callback((const char *)result); + return jresult; +} + + +SWIGEXPORT void * SWIGSTDCALL CSharp_new_switch_serial_event_t() { + void * jresult ; + switch_serial_event_t *result = 0 ; + + result = (switch_serial_event_t *)new switch_serial_event_t(); + jresult = (void *)result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_delete_switch_serial_event_t(void * jarg1) { + switch_serial_event_t *arg1 = (switch_serial_event_t *) 0 ; + + arg1 = (switch_serial_event_t *)jarg1; + delete arg1; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_serial_event_header_t_name_set(void * jarg1, char * jarg2) { + switch_serial_event_header_t *arg1 = (switch_serial_event_header_t *) 0 ; + char *arg2 = (char *) 0 ; + + arg1 = (switch_serial_event_header_t *)jarg1; + arg2 = (char *)jarg2; + { + if (arg1->name) delete [] arg1->name; + if (arg2) { + arg1->name = (char *) (new char[strlen((const char *)arg2)+1]); + strcpy((char *)arg1->name, (const char *)arg2); + } else { + arg1->name = 0; + } + } +} + + +SWIGEXPORT char * SWIGSTDCALL CSharp_switch_serial_event_header_t_name_get(void * jarg1) { + char * jresult ; + switch_serial_event_header_t *arg1 = (switch_serial_event_header_t *) 0 ; + char *result = 0 ; + + arg1 = (switch_serial_event_header_t *)jarg1; + result = (char *) ((arg1)->name); + jresult = SWIG_csharp_string_callback((const char *)result); + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_serial_event_header_t_value_set(void * jarg1, char * jarg2) { + switch_serial_event_header_t *arg1 = (switch_serial_event_header_t *) 0 ; + char *arg2 = (char *) 0 ; + + arg1 = (switch_serial_event_header_t *)jarg1; + arg2 = (char *)jarg2; + { + if (arg1->value) delete [] arg1->value; + if (arg2) { + arg1->value = (char *) (new char[strlen((const char *)arg2)+1]); + strcpy((char *)arg1->value, (const char *)arg2); + } else { + arg1->value = 0; + } + } +} + + +SWIGEXPORT char * SWIGSTDCALL CSharp_switch_serial_event_header_t_value_get(void * jarg1) { + char * jresult ; + switch_serial_event_header_t *arg1 = (switch_serial_event_header_t *) 0 ; + char *result = 0 ; + + arg1 = (switch_serial_event_header_t *)jarg1; + result = (char *) ((arg1)->value); + jresult = SWIG_csharp_string_callback((const char *)result); + return jresult; +} + + +SWIGEXPORT void * SWIGSTDCALL CSharp_new_switch_serial_event_header_t() { + void * jresult ; + switch_serial_event_header_t *result = 0 ; + + result = (switch_serial_event_header_t *)new switch_serial_event_header_t(); + jresult = (void *)result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_delete_switch_serial_event_header_t(void * jarg1) { + switch_serial_event_header_t *arg1 = (switch_serial_event_header_t *) 0 ; + + arg1 = (switch_serial_event_header_t *)jarg1; + delete arg1; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_switch_event_init(void * jarg1) { int jresult ; switch_memory_pool_t *arg1 = (switch_memory_pool_t *) 0 ; @@ -27286,6 +27686,46 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_event_free_subclass_detailed(char * jar } +SWIGEXPORT int SWIGSTDCALL CSharp_switch_event_binary_deserialize(void * jarg1, void * jarg2, void * jarg3, int jarg4) { + int jresult ; + switch_event_t **arg1 = (switch_event_t **) 0 ; + void **arg2 = (void **) 0 ; + switch_size_t arg3 ; + switch_bool_t arg4 ; + switch_size_t *argp3 ; + switch_status_t result; + + arg1 = (switch_event_t **)jarg1; + arg2 = (void **)jarg2; + argp3 = (switch_size_t *)jarg3; + if (!argp3) { + SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "Attempt to dereference null switch_size_t", 0); + return 0; + } + arg3 = *argp3; + arg4 = (switch_bool_t)jarg4; + result = (switch_status_t)switch_event_binary_deserialize(arg1,arg2,arg3,arg4); + jresult = result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_event_binary_serialize(void * jarg1, void * jarg2, void * jarg3) { + int jresult ; + switch_event_t *arg1 = (switch_event_t *) 0 ; + void **arg2 = (void **) 0 ; + switch_size_t *arg3 = (switch_size_t *) 0 ; + switch_status_t result; + + arg1 = (switch_event_t *)jarg1; + arg2 = (void **)jarg2; + arg3 = (switch_size_t *)jarg3; + result = (switch_status_t)switch_event_binary_serialize(arg1,arg2,arg3); + jresult = result; + return jresult; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_switch_event_serialize(void * jarg1, void * jarg2, int jarg3) { int jresult ; switch_event_t *arg1 = (switch_event_t *) 0 ; diff --git a/src/mod/languages/mod_managed/managed/swig.2010.cs b/src/mod/languages/mod_managed/managed/swig.2010.cs index 4c3360c043..8fcc92d7e4 100644 --- a/src/mod/languages/mod_managed/managed/swig.2010.cs +++ b/src/mod/languages/mod_managed/managed/swig.2010.cs @@ -1449,6 +1449,11 @@ public class freeswitch { return ret; } + public static SWIGTYPE_p_switch_size_t switch_core_session_id_dec() { + SWIGTYPE_p_switch_size_t ret = new SWIGTYPE_p_switch_size_t(freeswitchPINVOKE.switch_core_session_id_dec(), true); + return ret; + } + public static SWIGTYPE_p_switch_core_session switch_core_session_request_by_name(string endpoint_name, switch_call_direction_t direction, SWIGTYPE_p_p_apr_pool_t pool) { IntPtr cPtr = freeswitchPINVOKE.switch_core_session_request_by_name(endpoint_name, (int)direction, SWIGTYPE_p_p_apr_pool_t.getCPtr(pool)); SWIGTYPE_p_switch_core_session ret = (cPtr == IntPtr.Zero) ? null : new SWIGTYPE_p_switch_core_session(cPtr, false); @@ -4188,6 +4193,12 @@ public class freeswitch { return ret; } + public static switch_hold_record_t switch_channel_get_hold_record(SWIGTYPE_p_switch_channel channel) { + IntPtr cPtr = freeswitchPINVOKE.switch_channel_get_hold_record(SWIGTYPE_p_switch_channel.getCPtr(channel)); + switch_hold_record_t ret = (cPtr == IntPtr.Zero) ? null : new switch_hold_record_t(cPtr, false); + return ret; + } + public static switch_status_t switch_buffer_create(SWIGTYPE_p_apr_pool_t pool, SWIGTYPE_p_p_switch_buffer buffer, SWIGTYPE_p_switch_size_t max_len) { switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_buffer_create(SWIGTYPE_p_apr_pool_t.getCPtr(pool), SWIGTYPE_p_p_switch_buffer.getCPtr(buffer), SWIGTYPE_p_switch_size_t.getCPtr(max_len)); if (freeswitchPINVOKE.SWIGPendingException.Pending) throw freeswitchPINVOKE.SWIGPendingException.Retrieve(); @@ -4419,6 +4430,17 @@ public class freeswitch { return ret; } + public static switch_status_t switch_event_binary_deserialize(SWIGTYPE_p_p_switch_event eventp, SWIGTYPE_p_p_void data, SWIGTYPE_p_switch_size_t len, switch_bool_t destroy) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_event_binary_deserialize(SWIGTYPE_p_p_switch_event.getCPtr(eventp), SWIGTYPE_p_p_void.getCPtr(data), SWIGTYPE_p_switch_size_t.getCPtr(len), (int)destroy); + if (freeswitchPINVOKE.SWIGPendingException.Pending) throw freeswitchPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + + public static switch_status_t switch_event_binary_serialize(switch_event arg0, SWIGTYPE_p_p_void data, SWIGTYPE_p_switch_size_t len) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_event_binary_serialize(switch_event.getCPtr(arg0), SWIGTYPE_p_p_void.getCPtr(data), SWIGTYPE_p_switch_size_t.getCPtr(len)); + return ret; + } + public static switch_status_t switch_event_serialize(switch_event arg0, ref string str, switch_bool_t encode) { switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_event_serialize(switch_event.getCPtr(arg0), ref str, (int)encode); return ret; @@ -7978,6 +8000,36 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_delete_switch_app_log")] public static extern void delete_switch_app_log(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_hold_record_t_on_set")] + public static extern void switch_hold_record_t_on_set(HandleRef jarg1, HandleRef jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_hold_record_t_on_get")] + public static extern IntPtr switch_hold_record_t_on_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_hold_record_t_off_set")] + public static extern void switch_hold_record_t_off_set(HandleRef jarg1, HandleRef jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_hold_record_t_off_get")] + public static extern IntPtr switch_hold_record_t_off_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_hold_record_t_uuid_set")] + public static extern void switch_hold_record_t_uuid_set(HandleRef jarg1, string jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_hold_record_t_uuid_get")] + public static extern string switch_hold_record_t_uuid_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_hold_record_t_next_set")] + public static extern void switch_hold_record_t_next_set(HandleRef jarg1, HandleRef jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_hold_record_t_next_get")] + public static extern IntPtr switch_hold_record_t_next_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_new_switch_hold_record_t")] + public static extern IntPtr new_switch_hold_record_t(); + + [DllImport("mod_managed", EntryPoint="CSharp_delete_switch_hold_record_t")] + public static extern void delete_switch_hold_record_t(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_MESSAGE_STRING_ARG_MAX_get")] public static extern int MESSAGE_STRING_ARG_MAX_get(); @@ -8374,6 +8426,9 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_id")] public static extern IntPtr switch_core_session_id(); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_id_dec")] + public static extern IntPtr switch_core_session_id_dec(); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_request_by_name")] public static extern IntPtr switch_core_session_request_by_name(string jarg1, int jarg2, HandleRef jarg3); @@ -12865,6 +12920,9 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_channel_get_partner_uuid")] public static extern string switch_channel_get_partner_uuid(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_channel_get_hold_record")] + public static extern IntPtr switch_channel_get_hold_record(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_buffer_create")] public static extern int switch_buffer_create(HandleRef jarg1, HandleRef jarg2, HandleRef jarg3); @@ -13045,6 +13103,66 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_delete_switch_event")] public static extern void delete_switch_event(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_serial_event_t_event_id_set")] + public static extern void switch_serial_event_t_event_id_set(HandleRef jarg1, int jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_serial_event_t_event_id_get")] + public static extern int switch_serial_event_t_event_id_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_serial_event_t_priority_set")] + public static extern void switch_serial_event_t_priority_set(HandleRef jarg1, int jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_serial_event_t_priority_get")] + public static extern int switch_serial_event_t_priority_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_serial_event_t_flags_set")] + public static extern void switch_serial_event_t_flags_set(HandleRef jarg1, int jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_serial_event_t_flags_get")] + public static extern int switch_serial_event_t_flags_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_serial_event_t_owner_set")] + public static extern void switch_serial_event_t_owner_set(HandleRef jarg1, string jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_serial_event_t_owner_get")] + public static extern string switch_serial_event_t_owner_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_serial_event_t_subclass_name_set")] + public static extern void switch_serial_event_t_subclass_name_set(HandleRef jarg1, string jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_serial_event_t_subclass_name_get")] + public static extern string switch_serial_event_t_subclass_name_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_serial_event_t_body_set")] + public static extern void switch_serial_event_t_body_set(HandleRef jarg1, string jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_serial_event_t_body_get")] + public static extern string switch_serial_event_t_body_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_new_switch_serial_event_t")] + public static extern IntPtr new_switch_serial_event_t(); + + [DllImport("mod_managed", EntryPoint="CSharp_delete_switch_serial_event_t")] + public static extern void delete_switch_serial_event_t(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_serial_event_header_t_name_set")] + public static extern void switch_serial_event_header_t_name_set(HandleRef jarg1, string jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_serial_event_header_t_name_get")] + public static extern string switch_serial_event_header_t_name_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_serial_event_header_t_value_set")] + public static extern void switch_serial_event_header_t_value_set(HandleRef jarg1, string jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_serial_event_header_t_value_get")] + public static extern string switch_serial_event_header_t_value_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_new_switch_serial_event_header_t")] + public static extern IntPtr new_switch_serial_event_header_t(); + + [DllImport("mod_managed", EntryPoint="CSharp_delete_switch_serial_event_header_t")] + public static extern void delete_switch_serial_event_header_t(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_event_init")] public static extern int switch_event_init(HandleRef jarg1); @@ -13123,6 +13241,12 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_event_free_subclass_detailed")] public static extern int switch_event_free_subclass_detailed(string jarg1, string jarg2); + [DllImport("mod_managed", EntryPoint="CSharp_switch_event_binary_deserialize")] + public static extern int switch_event_binary_deserialize(HandleRef jarg1, HandleRef jarg2, HandleRef jarg3, int jarg4); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_event_binary_serialize")] + public static extern int switch_event_binary_serialize(HandleRef jarg1, HandleRef jarg2, HandleRef jarg3); + [DllImport("mod_managed", EntryPoint="CSharp_switch_event_serialize")] public static extern int switch_event_serialize(HandleRef jarg1, ref string jarg2, int jarg3); @@ -23225,7 +23349,8 @@ public enum switch_call_cause_t { SWITCH_CAUSE_INVALID_GATEWAY = 608, SWITCH_CAUSE_GATEWAY_DOWN = 609, SWITCH_CAUSE_INVALID_URL = 610, - SWITCH_CAUSE_INVALID_PROFILE = 611 + SWITCH_CAUSE_INVALID_PROFILE = 611, + SWITCH_CAUSE_NO_PICKUP = 612 } } @@ -23399,6 +23524,8 @@ public enum switch_channel_flag_t { CF_RECOVERING_BRIDGE, CF_TRACKED, CF_TRACKABLE, + CF_NO_CDR, + CF_EARLY_OK, CF_FLAG_MAX } @@ -25316,10 +25443,12 @@ public enum switch_core_session_message_types_t { SWITCH_MESSAGE_INDICATE_JITTER_BUFFER, SWITCH_MESSAGE_INDICATE_RECOVERY_REFRESH, SWITCH_MESSAGE_INDICATE_SIGNAL_DATA, + SWITCH_MESSAGE_INDICATE_MESSAGE, SWITCH_MESSAGE_INDICATE_INFO, SWITCH_MESSAGE_INDICATE_AUDIO_DATA, SWITCH_MESSAGE_INDICATE_BLIND_TRANSFER_RESPONSE, SWITCH_MESSAGE_INDICATE_STUN_ERROR, + SWITCH_MESSAGE_INDICATE_MEDIA_RENEG, SWITCH_MESSAGE_INVALID } @@ -27817,6 +27946,100 @@ namespace FreeSWITCH.Native { using System; using System.Runtime.InteropServices; +public class switch_hold_record_t : IDisposable { + private HandleRef swigCPtr; + protected bool swigCMemOwn; + + internal switch_hold_record_t(IntPtr cPtr, bool cMemoryOwn) { + swigCMemOwn = cMemoryOwn; + swigCPtr = new HandleRef(this, cPtr); + } + + internal static HandleRef getCPtr(switch_hold_record_t obj) { + return (obj == null) ? new HandleRef(null, IntPtr.Zero) : obj.swigCPtr; + } + + ~switch_hold_record_t() { + Dispose(); + } + + public virtual void Dispose() { + lock(this) { + if (swigCPtr.Handle != IntPtr.Zero) { + if (swigCMemOwn) { + swigCMemOwn = false; + freeswitchPINVOKE.delete_switch_hold_record_t(swigCPtr); + } + swigCPtr = new HandleRef(null, IntPtr.Zero); + } + GC.SuppressFinalize(this); + } + } + + public SWIGTYPE_p_switch_time_t on { + set { + freeswitchPINVOKE.switch_hold_record_t_on_set(swigCPtr, SWIGTYPE_p_switch_time_t.getCPtr(value)); + if (freeswitchPINVOKE.SWIGPendingException.Pending) throw freeswitchPINVOKE.SWIGPendingException.Retrieve(); + } + get { + SWIGTYPE_p_switch_time_t ret = new SWIGTYPE_p_switch_time_t(freeswitchPINVOKE.switch_hold_record_t_on_get(swigCPtr), true); + if (freeswitchPINVOKE.SWIGPendingException.Pending) throw freeswitchPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + } + + public SWIGTYPE_p_switch_time_t off { + set { + freeswitchPINVOKE.switch_hold_record_t_off_set(swigCPtr, SWIGTYPE_p_switch_time_t.getCPtr(value)); + if (freeswitchPINVOKE.SWIGPendingException.Pending) throw freeswitchPINVOKE.SWIGPendingException.Retrieve(); + } + get { + SWIGTYPE_p_switch_time_t ret = new SWIGTYPE_p_switch_time_t(freeswitchPINVOKE.switch_hold_record_t_off_get(swigCPtr), true); + if (freeswitchPINVOKE.SWIGPendingException.Pending) throw freeswitchPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + } + + public string uuid { + set { + freeswitchPINVOKE.switch_hold_record_t_uuid_set(swigCPtr, value); + } + get { + string ret = freeswitchPINVOKE.switch_hold_record_t_uuid_get(swigCPtr); + return ret; + } + } + + public switch_hold_record_t next { + set { + freeswitchPINVOKE.switch_hold_record_t_next_set(swigCPtr, switch_hold_record_t.getCPtr(value)); + } + get { + IntPtr cPtr = freeswitchPINVOKE.switch_hold_record_t_next_get(swigCPtr); + switch_hold_record_t ret = (cPtr == IntPtr.Zero) ? null : new switch_hold_record_t(cPtr, false); + return ret; + } + } + + public switch_hold_record_t() : this(freeswitchPINVOKE.new_switch_hold_record_t(), true) { + } + +} + +} +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 2.0.1 + * + * Do not make changes to this file unless you know what you are doing--modify + * the SWIG interface file instead. + * ----------------------------------------------------------------------------- */ + +namespace FreeSWITCH.Native { + +using System; +using System.Runtime.InteropServices; + public class switch_input_args_t : IDisposable { private HandleRef swigCPtr; protected bool swigCMemOwn; @@ -31610,6 +31833,184 @@ public class switch_scheduler_task : IDisposable { namespace FreeSWITCH.Native { +using System; +using System.Runtime.InteropServices; + +public class switch_serial_event_header_t : IDisposable { + private HandleRef swigCPtr; + protected bool swigCMemOwn; + + internal switch_serial_event_header_t(IntPtr cPtr, bool cMemoryOwn) { + swigCMemOwn = cMemoryOwn; + swigCPtr = new HandleRef(this, cPtr); + } + + internal static HandleRef getCPtr(switch_serial_event_header_t obj) { + return (obj == null) ? new HandleRef(null, IntPtr.Zero) : obj.swigCPtr; + } + + ~switch_serial_event_header_t() { + Dispose(); + } + + public virtual void Dispose() { + lock(this) { + if (swigCPtr.Handle != IntPtr.Zero) { + if (swigCMemOwn) { + swigCMemOwn = false; + freeswitchPINVOKE.delete_switch_serial_event_header_t(swigCPtr); + } + swigCPtr = new HandleRef(null, IntPtr.Zero); + } + GC.SuppressFinalize(this); + } + } + + public string name { + set { + freeswitchPINVOKE.switch_serial_event_header_t_name_set(swigCPtr, value); + } + get { + string ret = freeswitchPINVOKE.switch_serial_event_header_t_name_get(swigCPtr); + return ret; + } + } + + public string value { + set { + freeswitchPINVOKE.switch_serial_event_header_t_value_set(swigCPtr, value); + } + get { + string ret = freeswitchPINVOKE.switch_serial_event_header_t_value_get(swigCPtr); + return ret; + } + } + + public switch_serial_event_header_t() : this(freeswitchPINVOKE.new_switch_serial_event_header_t(), true) { + } + +} + +} +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 2.0.1 + * + * Do not make changes to this file unless you know what you are doing--modify + * the SWIG interface file instead. + * ----------------------------------------------------------------------------- */ + +namespace FreeSWITCH.Native { + +using System; +using System.Runtime.InteropServices; + +public class switch_serial_event_t : IDisposable { + private HandleRef swigCPtr; + protected bool swigCMemOwn; + + internal switch_serial_event_t(IntPtr cPtr, bool cMemoryOwn) { + swigCMemOwn = cMemoryOwn; + swigCPtr = new HandleRef(this, cPtr); + } + + internal static HandleRef getCPtr(switch_serial_event_t obj) { + return (obj == null) ? new HandleRef(null, IntPtr.Zero) : obj.swigCPtr; + } + + ~switch_serial_event_t() { + Dispose(); + } + + public virtual void Dispose() { + lock(this) { + if (swigCPtr.Handle != IntPtr.Zero) { + if (swigCMemOwn) { + swigCMemOwn = false; + freeswitchPINVOKE.delete_switch_serial_event_t(swigCPtr); + } + swigCPtr = new HandleRef(null, IntPtr.Zero); + } + GC.SuppressFinalize(this); + } + } + + public int event_id { + set { + freeswitchPINVOKE.switch_serial_event_t_event_id_set(swigCPtr, value); + } + get { + int ret = freeswitchPINVOKE.switch_serial_event_t_event_id_get(swigCPtr); + return ret; + } + } + + public int priority { + set { + freeswitchPINVOKE.switch_serial_event_t_priority_set(swigCPtr, value); + } + get { + int ret = freeswitchPINVOKE.switch_serial_event_t_priority_get(swigCPtr); + return ret; + } + } + + public int flags { + set { + freeswitchPINVOKE.switch_serial_event_t_flags_set(swigCPtr, value); + } + get { + int ret = freeswitchPINVOKE.switch_serial_event_t_flags_get(swigCPtr); + return ret; + } + } + + public string owner { + set { + freeswitchPINVOKE.switch_serial_event_t_owner_set(swigCPtr, value); + } + get { + string ret = freeswitchPINVOKE.switch_serial_event_t_owner_get(swigCPtr); + return ret; + } + } + + public string subclass_name { + set { + freeswitchPINVOKE.switch_serial_event_t_subclass_name_set(swigCPtr, value); + } + get { + string ret = freeswitchPINVOKE.switch_serial_event_t_subclass_name_get(swigCPtr); + return ret; + } + } + + public string body { + set { + freeswitchPINVOKE.switch_serial_event_t_body_set(swigCPtr, value); + } + get { + string ret = freeswitchPINVOKE.switch_serial_event_t_body_get(swigCPtr); + return ret; + } + } + + public switch_serial_event_t() : this(freeswitchPINVOKE.new_switch_serial_event_t(), true) { + } + +} + +} +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 2.0.1 + * + * Do not make changes to this file unless you know what you are doing--modify + * the SWIG interface file instead. + * ----------------------------------------------------------------------------- */ + +namespace FreeSWITCH.Native { + public enum switch_session_ctl_t { SCSC_PAUSE_INBOUND, SCSC_PAUSE_OUTBOUND, From d1ddb73c0b326ee8d5b0efd489665022bb819338 Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Fri, 14 Sep 2012 14:40:16 -0400 Subject: [PATCH 777/822] fix build of mod_freetdm --- src/include/switch_json.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/include/switch_json.h b/src/include/switch_json.h index c7baf9970d..b4ca229c39 100755 --- a/src/include/switch_json.h +++ b/src/include/switch_json.h @@ -79,17 +79,17 @@ SWITCH_DECLARE(cJSON *)cJSON_GetArrayItem(cJSON *array,int item); SWITCH_DECLARE(cJSON *)cJSON_GetObjectItem(cJSON *object,const char *string); /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ -SWITCH_DECLARE(const char *)cJSON_GetErrorPtr(); +SWITCH_DECLARE(const char *)cJSON_GetErrorPtr(void); /* These calls create a cJSON item of the appropriate type. */ -SWITCH_DECLARE(cJSON *)cJSON_CreateNull(); -SWITCH_DECLARE(cJSON *)cJSON_CreateTrue(); -SWITCH_DECLARE(cJSON *)cJSON_CreateFalse(); +SWITCH_DECLARE(cJSON *)cJSON_CreateNull(void); +SWITCH_DECLARE(cJSON *)cJSON_CreateTrue(void); +SWITCH_DECLARE(cJSON *)cJSON_CreateFalse(void); SWITCH_DECLARE(cJSON *)cJSON_CreateBool(int b); SWITCH_DECLARE(cJSON *)cJSON_CreateNumber(double num); SWITCH_DECLARE(cJSON *)cJSON_CreateString(const char *string); -SWITCH_DECLARE(cJSON *)cJSON_CreateArray(); -SWITCH_DECLARE(cJSON *)cJSON_CreateObject(); +SWITCH_DECLARE(cJSON *)cJSON_CreateArray(void); +SWITCH_DECLARE(cJSON *)cJSON_CreateObject(void); /* These utilities create an Array of count items. */ SWITCH_DECLARE(cJSON *)cJSON_CreateIntArray(int *numbers,int count); From fd60ef6db43b0d96619d66a3ca600aafba630f41 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Fri, 14 Sep 2012 14:14:48 -0500 Subject: [PATCH 778/822] windows missing copy for libjpeg vs2008 --- libs/win32/libjpeg/libjpeg.2008.vcproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/win32/libjpeg/libjpeg.2008.vcproj b/libs/win32/libjpeg/libjpeg.2008.vcproj index 881078ca9b..84fa2394b4 100644 --- a/libs/win32/libjpeg/libjpeg.2008.vcproj +++ b/libs/win32/libjpeg/libjpeg.2008.vcproj @@ -96,6 +96,7 @@ > Date: Fri, 14 Sep 2012 14:23:28 -0500 Subject: [PATCH 779/822] vs2008 add missing file mod_sofia --- src/mod/endpoints/mod_sofia/mod_sofia.2008.vcproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.2008.vcproj b/src/mod/endpoints/mod_sofia/mod_sofia.2008.vcproj index 733d3bdcd9..7ad10b804d 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.2008.vcproj +++ b/src/mod/endpoints/mod_sofia/mod_sofia.2008.vcproj @@ -301,6 +301,10 @@ RelativePath=".\mod_sofia.h" > + + From 5bbc372c560a612d0219bbf27240f21e42c20530 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 14 Sep 2012 14:25:15 -0500 Subject: [PATCH 780/822] fix crash in mod_fifo when deleting a node when its in use --- src/mod/applications/mod_fifo/mod_fifo.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/mod/applications/mod_fifo/mod_fifo.c b/src/mod/applications/mod_fifo/mod_fifo.c index 2ef5c7fca9..f500c4683a 100644 --- a/src/mod/applications/mod_fifo/mod_fifo.c +++ b/src/mod/applications/mod_fifo/mod_fifo.c @@ -1224,10 +1224,15 @@ static void *SWITCH_THREAD_FUNC ringall_thread_run(switch_thread_t *thread, void node_name = cbh->rows[0]->node_name; switch_mutex_lock(globals.mutex); - node = switch_core_hash_find(globals.fifo_hash, node_name); - switch_thread_rwlock_rdlock(node->rwlock); + if ((node = switch_core_hash_find(globals.fifo_hash, node_name))) { + switch_thread_rwlock_rdlock(node->rwlock); + } switch_mutex_unlock(globals.mutex); + if (!node) { + goto end; + } + for (i = 0; i < cbh->rowcount; i++) { struct call_helper *h = cbh->rows[i]; From 6b8e177c5894028df0ac4a8c624fecb1f78785c0 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Fri, 14 Sep 2012 14:55:21 -0500 Subject: [PATCH 781/822] fix strange code analysis error --- libs/esl/src/esl_json.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/esl/src/esl_json.c b/libs/esl/src/esl_json.c index 767c29da02..5e7157cfe4 100644 --- a/libs/esl/src/esl_json.c +++ b/libs/esl/src/esl_json.c @@ -523,7 +523,7 @@ ESL_DECLARE(cJSON *)cJSON_CreateArray() {cJSON *item=cJSON_New_Item();if(it ESL_DECLARE(cJSON *)cJSON_CreateObject() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} /* Create Arrays: */ -ESL_DECLARE(cJSON *)cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} -ESL_DECLARE(cJSON *)cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} -ESL_DECLARE(cJSON *)cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} -ESL_DECLARE(cJSON *)cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +ESL_DECLARE(cJSON *)cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a!=0 && ichild=n;else suffix_object(p,n);p=n;}return a;} +ESL_DECLARE(cJSON *)cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a!=0 && ichild=n;else suffix_object(p,n);p=n;}return a;} +ESL_DECLARE(cJSON *)cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a!=0 && ichild=n;else suffix_object(p,n);p=n;}return a;} +ESL_DECLARE(cJSON *)cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a!=0 && ichild=n;else suffix_object(p,n);p=n;}return a;} From 7b0f8ace6968c27ac546631f4a219f18d8199d96 Mon Sep 17 00:00:00 2001 From: William King Date: Fri, 14 Sep 2012 13:16:58 -0700 Subject: [PATCH 782/822] Adding debugging and a default value for disconnect time. Also handle unset times better. --- .../xml_int/mod_xml_radius/mod_xml_radius.c | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c b/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c index 035a16f7f3..d80e9e7d54 100644 --- a/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c +++ b/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c @@ -368,7 +368,7 @@ switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch switch_time_exp_t tm; if ( !time ) { - return SWITCH_STATUS_SUCCESS; + goto end_loop; } switch_time_exp_lt(&tm, time); @@ -381,13 +381,16 @@ switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n"); goto err; } + if ( GLOBAL_DEBUG ) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: value: %s\n", (char *) av_value); + } } else if ( strncmp( var, "h323-connect-time", 17) == 0 ) { switch_caller_profile_t *profile = switch_channel_get_caller_profile(channel); switch_time_t time = profile->times->answered; switch_time_exp_t tm; if ( !time ) { - return SWITCH_STATUS_SUCCESS; + goto end_loop; } switch_time_exp_lt(&tm, time); @@ -401,13 +404,20 @@ switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n"); goto err; } + if ( GLOBAL_DEBUG ) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: value: %s\n", (char *) av_value); + } } else if ( strncmp( var, "h323-disconnect-time", 20) == 0 ) { switch_caller_profile_t *profile = switch_channel_get_caller_profile(channel); switch_time_t time = profile->times->hungup; switch_time_exp_t tm; if ( !time ) { - return SWITCH_STATUS_SUCCESS; + if ( variable_secondary != NULL && strncmp(variable_secondary, "now", 3) == 0 ) { + time = switch_time_now(); + } else { + goto end_loop; + } } switch_time_exp_lt(&tm, time); @@ -421,6 +431,9 @@ switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n"); goto err; } + if ( GLOBAL_DEBUG ) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: value: %s\n", (char *) av_value); + } } else if ( strncmp( var, "h323-disconnect-cause", 21) == 0 ) { switch_call_cause_t cause = switch_channel_get_cause(channel); av_value = switch_mprintf("h323-disconnect-cause=%x", cause); @@ -500,6 +513,8 @@ switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: all params must have a name attribute\n"); goto err; } + + end_loop: if ( av_value != NULL ) { free(av_value); av_value = NULL; From b9e562cc5e5b3d2bebc77ef182d039d5ba2ac876 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Fri, 14 Sep 2012 15:21:08 -0500 Subject: [PATCH 783/822] vs2010 add missing includes --- w32/Library/FreeSwitchCore.2010.vcxproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/w32/Library/FreeSwitchCore.2010.vcxproj b/w32/Library/FreeSwitchCore.2010.vcxproj index 44fc58ea93..bb3042dac6 100644 --- a/w32/Library/FreeSwitchCore.2010.vcxproj +++ b/w32/Library/FreeSwitchCore.2010.vcxproj @@ -88,7 +88,7 @@ Disabled - ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-4.0.2\libtiff;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;libs\libtpl-1.5\src;libs\libtpl-1.5\src\win;%(AdditionalIncludeDirectories) + ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-4.0.2\libtiff;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;..\..\libs\libtpl-1.5\src;..\..\libs\libtpl-1.5\src\win;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;PCRE_STATIC;STATICLIB;ENABLE_ZRTP;%(PreprocessorDefinitions) true EnableFastChecks @@ -146,7 +146,7 @@ if not exist "$(OutDir)htdocs" xcopy "$(SolutionDir)htdocs\*.*" "$(OutDir)htdocs Disabled - ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-4.0.2\libtiff;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;libs\libtpl-1.5\src;libs\libtpl-1.5\src\win;%(AdditionalIncludeDirectories) + ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-4.0.2\libtiff;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;..\..\libs\libtpl-1.5\src;..\..\libs\libtpl-1.5\src\win;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;PCRE_STATIC;STATICLIB;ENABLE_ZRTP;TPL_NOLIB;%(PreprocessorDefinitions) true EnableFastChecks @@ -247,7 +247,7 @@ if not exist "$(OutDir)htdocs" xcopy "$(SolutionDir)htdocs\*.*" "$(OutDir)htdocs MaxSpeed - ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-4.0.2\libtiff;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;libs\libtpl-1.5\src;libs\libtpl-1.5\src\win;%(AdditionalIncludeDirectories) + ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-4.0.2\libtiff;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;..\..\libs\libtpl-1.5\src;..\..\libs\libtpl-1.5\src\win;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;STATICLIB;CRASH_PROT;PCRE_STATIC;ENABLE_ZRTP;TPL_NOLIB;%(PreprocessorDefinitions) MultiThreadedDLL Use From e74d4ac6e6dfdac63d0a9388083fa445e57b126c Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Fri, 14 Sep 2012 16:08:23 -0500 Subject: [PATCH 784/822] FS-4586 --resolve add mod_spy to vs2010 --- Freeswitch.2010.express.sln | 14 ++ Freeswitch.2010.sln | 20 +++ .../applications/mod_spy/mod_spy.2010.vcxproj | 131 ++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 src/mod/applications/mod_spy/mod_spy.2010.vcxproj diff --git a/Freeswitch.2010.express.sln b/Freeswitch.2010.express.sln index 6833f61bc3..a143ddbf3f 100644 --- a/Freeswitch.2010.express.sln +++ b/Freeswitch.2010.express.sln @@ -241,6 +241,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_modem_filter", "libs\s EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_skel", "src\mod\applications\mod_skel\mod_skel.2010.vcxproj", "{11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spy", "src\mod\applications\mod_spy\mod_spy.2010.vcxproj", "{A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_skypopen", "src\mod\endpoints\mod_skypopen\mod_skypopen.2010.vcxproj", "{C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khz music", "libs\win32\Dowload 32khz music.2010.vcxproj", "{1F0A8A77-E661-418F-BB92-82172AE43803}" @@ -1594,6 +1596,17 @@ Global {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Debug|x64.ActiveCfg = Debug|x64 {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Release|Win32.ActiveCfg = Release|Win32 {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Release|x64.ActiveCfg = Release|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.All|Win32.ActiveCfg = Release|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.All|x64.ActiveCfg = Release|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.All|x64.Build.0 = Release|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Debug|Win32.ActiveCfg = Debug|Win32 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Debug|Win32.Build.0 = Debug|Win32 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Debug|x64.ActiveCfg = Debug|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Debug|x64.Build.0 = Debug|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Release|Win32.ActiveCfg = Release|Win32 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Release|Win32.Build.0 = Release|Win32 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Release|x64.ActiveCfg = Release|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Release|x64.Build.0 = Release|x64 {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.All|Win32.ActiveCfg = Release|Win32 {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.All|Win32.Build.0 = Release|Win32 {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.All|x64.ActiveCfg = Release|Win32 @@ -2068,6 +2081,7 @@ Global {329FD5B0-EF28-4606-86D0-F6EA21CF8E36} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} {3C977801-FE88-48F2-83D3-FA2EBFF6688E} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} {432DB165-1EB2-4781-A9C0-71E62610B20A} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} diff --git a/Freeswitch.2010.sln b/Freeswitch.2010.sln index 68f0b9dc84..fd8eda1919 100644 --- a/Freeswitch.2010.sln +++ b/Freeswitch.2010.sln @@ -521,6 +521,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_callcenter", "src\mod\a EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_blacklist", "src\mod\applications\mod_blacklist\mod_blacklist.2010.vcxproj", "{50AAC2CE-BFC9-4912-87CC-C6381850D735}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spy", "src\mod\applications\mod_spy\mod_spy.2010.vcxproj", "{A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_httapi", "src\mod\applications\mod_httapi\mod_httapi.2010.vcxproj", "{4748FF56-CA85-4809-97D6-A94C0FAC1D77}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_abstraction", "src\mod\applications\mod_abstraction\mod_abstraction.2010.vcxproj", "{60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}" @@ -3554,6 +3556,23 @@ Global {50AAC2CE-BFC9-4912-87CC-C6381850D735}.Release|x64.Build.0 = Release|x64 {50AAC2CE-BFC9-4912-87CC-C6381850D735}.Release|x64 Setup.ActiveCfg = Release|x64 {50AAC2CE-BFC9-4912-87CC-C6381850D735}.Release|x86 Setup.ActiveCfg = Release|Win32 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.All|Win32.ActiveCfg = Release|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.All|x64.ActiveCfg = Release|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.All|x64.Build.0 = Release|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.All|x64 Setup.ActiveCfg = Release|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.All|x86 Setup.ActiveCfg = Release|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Debug|Win32.ActiveCfg = Debug|Win32 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Debug|Win32.Build.0 = Debug|Win32 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Debug|x64.ActiveCfg = Debug|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Debug|x64.Build.0 = Debug|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Debug|x64 Setup.ActiveCfg = Debug|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Debug|x86 Setup.ActiveCfg = Debug|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Release|Win32.ActiveCfg = Release|Win32 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Release|Win32.Build.0 = Release|Win32 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Release|x64.ActiveCfg = Release|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Release|x64.Build.0 = Release|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Release|x64 Setup.ActiveCfg = Release|x64 + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Release|x86 Setup.ActiveCfg = Release|Win32 {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.All|Win32.ActiveCfg = Release|x64 {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.All|x64.ActiveCfg = Release|x64 {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.All|x64.Build.0 = Release|x64 @@ -3750,6 +3769,7 @@ Global {B889A18E-70A7-44B5-B2C9-47798D4F43B3} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} {50AAC2CE-BFC9-4912-87CC-C6381850D735} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} {4748FF56-CA85-4809-97D6-A94C0FAC1D77} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} diff --git a/src/mod/applications/mod_spy/mod_spy.2010.vcxproj b/src/mod/applications/mod_spy/mod_spy.2010.vcxproj new file mode 100644 index 0000000000..6438e8a630 --- /dev/null +++ b/src/mod/applications/mod_spy/mod_spy.2010.vcxproj @@ -0,0 +1,131 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + mod_spy + {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921} + mod_spy + Win32Proj + + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + + + + + + + + false + + + + + + + X64 + + + + + + + false + + + MachineX64 + + + + + + + + + false + + + + + + + X64 + + + + + + + false + + + MachineX64 + + + + + + + + {202d7a4e-760d-4d0e-afa1-d7459ced30ff} + false + + + + + + From 3359f04a3f6bf81783be4eed3d1c436cf73c97a9 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 14 Sep 2012 16:16:30 -0500 Subject: [PATCH 785/822] only use the wait_for_aleg_ack when the call is unanswered --- src/mod/endpoints/mod_sofia/sofia.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 40b1a9778b..0f3d478f69 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -6419,19 +6419,22 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, break; case nua_callstate_completing: { - const char *wait_for_ack = switch_channel_get_variable(channel, "sip_wait_for_aleg_ack"); int send_ack = 1; - if (switch_true(wait_for_ack)) { - switch_core_session_t *other_session; - - if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { - if (switch_core_session_compare(session, other_session)) { - private_object_t *other_tech_pvt = switch_core_session_get_private(other_session); - sofia_set_flag(other_tech_pvt, TFLAG_PASS_ACK); + if (!switch_channel_test_flag(channel, CF_ANSWERED)) { + const char *wait_for_ack = switch_channel_get_variable(channel, "sip_wait_for_aleg_ack"); + + if (switch_true(wait_for_ack)) { + switch_core_session_t *other_session; + + if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { + if (switch_core_session_compare(session, other_session)) { + private_object_t *other_tech_pvt = switch_core_session_get_private(other_session); + sofia_set_flag(other_tech_pvt, TFLAG_PASS_ACK); send_ack = 0; + } + switch_core_session_rwunlock(other_session); } - switch_core_session_rwunlock(other_session); } } From 84bace07018c253a0435e6b1c136ef9b7b99d1c2 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Fri, 14 Sep 2012 16:51:43 -0500 Subject: [PATCH 786/822] freetdm trivial build warnings on windows --- libs/freetdm/src/ftdm_io.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 57d13a69af..d99561566c 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -4523,7 +4523,7 @@ static struct { ftdm_io_interface_t *pika_interface; } interfaces; -static void print_channels_by_flag(ftdm_stream_handle_t *stream, ftdm_span_t *inspan, uint32_t inchan_id, int32_t flagval, int not, int *count) +static void print_channels_by_flag(ftdm_stream_handle_t *stream, ftdm_span_t *inspan, uint32_t inchan_id, unsigned long long flagval, int not, int *count) { ftdm_hash_iterator_t *i = NULL; ftdm_span_t *span; @@ -4615,7 +4615,7 @@ end: ftdm_mutex_unlock(globals.mutex); } -static void print_spans_by_flag(ftdm_stream_handle_t *stream, ftdm_span_t *inspan, int32_t flagval, int not, int *count) +static void print_spans_by_flag(ftdm_stream_handle_t *stream, ftdm_span_t *inspan, unsigned long long flagval, int not, int *count) { ftdm_hash_iterator_t *i = NULL; ftdm_span_t *span; @@ -5750,13 +5750,15 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_signaling(ftdm_span_t *span, const static void *ftdm_span_service_events(ftdm_thread_t *me, void *obj) { - int i; + uint32_t i; unsigned waitms; ftdm_event_t *event; ftdm_status_t status = FTDM_SUCCESS; ftdm_span_t *span = (ftdm_span_t*) obj; short *poll_events = ftdm_malloc(sizeof(short) * span->chan_count); + if (me == 0) {}; + memset(poll_events, 0, sizeof(short) * span->chan_count); for(i = 1; i <= span->chan_count; i++) { From 3b660a06e5715404d879545c1628fbee20d1c6ee Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 14 Sep 2012 17:07:49 -0500 Subject: [PATCH 787/822] fix small leak in var arrays --- src/switch_event.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/switch_event.c b/src/switch_event.c index fdb397de01..3a02e3a449 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -1022,6 +1022,7 @@ static switch_status_t switch_event_base_add_header(switch_event_t *event, switc } } else { + switch_safe_free(header->value); header->value = data; } From dd4a995b344d522cffae791cea73f51cb29b6bf4 Mon Sep 17 00:00:00 2001 From: Stefan Knoblich Date: Sun, 16 Sep 2012 14:07:55 +0200 Subject: [PATCH 788/822] ftmod_libpri: Default disable NT-mode idle b-channel restart Some people, it seems, were having sleepless nights from the log messages this feature produces every 15 minutes. Default disable the feature, because i hate repeating myself over and over, explaining them this is a non-issue and intended behaviour and how to disable it in the config. Signed-off-by: Stefan Knoblich --- libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h index f439694886..26db8d3155 100644 --- a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h +++ b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h @@ -41,7 +41,7 @@ #define OVERLAP_TIMEOUT_MS_MAX 30000 /* 30 sec */ /* NT-mode idle b-channel restart timer */ -#define IDLE_RESTART_TIMEOUT_MS_DEFAULT 900000 /* 15 min */ +#define IDLE_RESTART_TIMEOUT_MS_DEFAULT 0 /* disabled */ #define IDLE_RESTART_TIMEOUT_MS_MIN 10000 /* 10 sec */ #define IDLE_RESTART_TIMEOUT_MS_MAX 86400000 /* 1 day */ From e22f42334d95c48dd04524736de12d74ee77cf2a Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Sun, 16 Sep 2012 14:15:49 -0500 Subject: [PATCH 789/822] FS-4099 --resolve switch windows to use posix delimiter (/) for base paths. This will correct numerous problems with escaped chars. This change only effects windows builds. Please test. --- src/include/switch_types.h | 2 +- src/switch_core.c | 4 ++++ src/switch_xml.c | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 088050f86a..9ddadd1a3e 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -113,7 +113,7 @@ SWITCH_BEGIN_EXTERN_C #define SWITCH_MAX_DTMF_DURATION 192000 #define SWITCH_DEFAULT_DIR_PERMS SWITCH_FPROT_UREAD | SWITCH_FPROT_UWRITE | SWITCH_FPROT_UEXECUTE | SWITCH_FPROT_GREAD | SWITCH_FPROT_GEXECUTE #ifdef WIN32 -#define SWITCH_PATH_SEPARATOR "\\" +#define SWITCH_PATH_SEPARATOR "/" #else #define SWITCH_PATH_SEPARATOR "/" #endif diff --git a/src/switch_core.c b/src/switch_core.c index 3f1a6d5075..53bd4b8762 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -520,12 +520,16 @@ SWITCH_DECLARE(void) switch_core_set_globals(void) DWORD dwBufSize = BUFSIZE; char base_dir[1024]; char *lastbacklash; + char *tmp; GetModuleFileName(NULL, base_dir, BUFSIZE); lastbacklash = strrchr(base_dir, '\\'); base_dir[(lastbacklash - base_dir)] = '\0'; /* set base_dir as cwd, to be able to use relative paths in scripting languages (e.g. mod_lua) when FS is running as a service or while debugging FS using visual studio */ SetCurrentDirectory(base_dir); + tmp = switch_string_replace(base_dir, "\\", "/"); + strcpy(base_dir, tmp); + free(tmp); #else char base_dir[1024] = SWITCH_PREFIX_DIR; diff --git a/src/switch_xml.c b/src/switch_xml.c index 585b867995..95a51c39e8 100644 --- a/src/switch_xml.c +++ b/src/switch_xml.c @@ -3076,7 +3076,7 @@ done: #define RANGE '-' #define RBRACKET ']' #define SEP '/' -#define WIN_SEP '\\' +#define WIN_SEP '/' #define STAR '*' #define TILDE '~' #define UNDERSCORE '_' From 3b5aa066c7ec982ffbdf988f4698e0ec3424d93d Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Sun, 16 Sep 2012 14:21:30 -0500 Subject: [PATCH 790/822] FS-4623 --resolve --- libs/libtpl-1.5/src/tpl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/libtpl-1.5/src/tpl.c b/libs/libtpl-1.5/src/tpl.c index 24a9383a2e..649da903b6 100755 --- a/libs/libtpl-1.5/src/tpl.c +++ b/libs/libtpl-1.5/src/tpl.c @@ -1620,7 +1620,7 @@ static void tpl_free_atyp(tpl_node *n, tpl_atyp *atyp) { */ static int tpl_serlen(tpl_node *r, tpl_node *n, void *dv, size_t *serlen) { uint32_t slen; - int num,fidx; + int num = 0,fidx; tpl_node *c; size_t len=0, alen, buf_past, itermax; tpl_pound_data *pd; From fdf7623f904d2b2528d3a511f48195a4239b758e Mon Sep 17 00:00:00 2001 From: Brian West Date: Mon, 17 Sep 2012 10:14:27 -0500 Subject: [PATCH 791/822] freetdm_outbound_npi is actually useful. --- libs/freetdm/mod_freetdm/mod_freetdm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 7a8e10593e..a0b54b8834 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1629,6 +1629,12 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi caller_data.dnis.type = outbound_profile->destination_number_ton; } + if ((var = channel_get_variable(session, var_event, "freetdm_outbound_npi"))) { + ftdm_set_npi(var, &caller_data.dnis.plan); + } else { + caller_data.dnis.plan = outbound_profile->destination_number_numplan; + } + if ((var = channel_get_variable(session, var_event, "freetdm_calling_party_category"))) { ftdm_set_calling_party_category(var, (uint8_t *)&caller_data.cpc); } From 416f026f8cbdde933d629efe1bfc1cf13059f612 Mon Sep 17 00:00:00 2001 From: Stefan Knoblich Date: Mon, 17 Sep 2012 21:26:00 +0200 Subject: [PATCH 792/822] FreeSWITCH: Add preprocessor constant for default callerid number SWITCH_DEFAULT_CLID_NUMBER and replace all occurrences in the FreeSWITCH codebase. Signed-off-by: Stefan Knoblich --- src/include/switch_types.h | 1 + src/mod/applications/mod_conference/mod_conference.c | 2 +- src/mod/endpoints/mod_rtmp/mod_rtmp.c | 2 +- src/mod/endpoints/mod_skinny/skinny_server.c | 4 ++-- src/switch_caller.c | 2 +- src/switch_ivr_originate.c | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 9ddadd1a3e..9fa47ac2b8 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -108,6 +108,7 @@ SWITCH_BEGIN_EXTERN_C #define SWITCH_SEQ_CLEARSCR SWITCH_SEQ_ESC SWITCH_SEQ_CLEARSCR_CHAR SWITCH_SEQ_HOME #endif #define SWITCH_DEFAULT_CLID_NAME "" +#define SWITCH_DEFAULT_CLID_NUMBER "0000000000" #define SWITCH_DEFAULT_DTMF_DURATION 2000 #define SWITCH_MIN_DTMF_DURATION 400 #define SWITCH_MAX_DTMF_DURATION 192000 diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index eb70d53ea2..0b1adcab57 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -8223,7 +8223,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c /* Caller ID Number */ if (zstr(caller_id_number)) { - caller_id_number = "0000000000"; + caller_id_number = SWITCH_DEFAULT_CLID_NUMBER; } if (!pool) { diff --git a/src/mod/endpoints/mod_rtmp/mod_rtmp.c b/src/mod/endpoints/mod_rtmp/mod_rtmp.c index d43ae73d01..0bdc4531de 100644 --- a/src/mod/endpoints/mod_rtmp/mod_rtmp.c +++ b/src/mod/endpoints/mod_rtmp/mod_rtmp.c @@ -874,7 +874,7 @@ switch_call_cause_t rtmp_session_create_call(rtmp_session_t *rsession, switch_co caller_profile = switch_caller_profile_new(pool, switch_str_nil(auth_user), dialplan, SWITCH_DEFAULT_CLID_NAME, - !zstr(auth_user) ? auth_user : "0000000000", + !zstr(auth_user) ? auth_user : SWITCH_DEFAULT_CLID_NUMBER, rsession->remote_address /* net addr */, NULL /* ani */, NULL /* anii */, diff --git a/src/mod/endpoints/mod_skinny/skinny_server.c b/src/mod/endpoints/mod_skinny/skinny_server.c index 95f7e6c83e..6c0e01f8a0 100644 --- a/src/mod/endpoints/mod_skinny/skinny_server.c +++ b/src/mod/endpoints/mod_skinny/skinny_server.c @@ -326,7 +326,7 @@ switch_status_t skinny_session_send_call_info(switch_core_session_t *session, li zstr((caller_party_number = switch_channel_get_variable(channel, "caller_id_number"))) && zstr((caller_party_number = switch_channel_get_variable_partner(channel, "effective_caller_id_number"))) && zstr((caller_party_number = switch_channel_get_variable_partner(channel, "caller_id_number")))) { - caller_party_number = "0000000000"; + caller_party_number = SWITCH_DEFAULT_CLID_NUMBER; } /* Called party */ if (zstr((called_party_name = switch_channel_get_variable(channel, "effective_callee_id_name"))) && @@ -340,7 +340,7 @@ switch_status_t skinny_session_send_call_info(switch_core_session_t *session, li zstr((called_party_number = switch_channel_get_variable_partner(channel, "effective_callee_id_number"))) && zstr((called_party_number = switch_channel_get_variable_partner(channel, "callee_id_number"))) && zstr((called_party_number = switch_channel_get_variable(channel, "destination_number")))) { - called_party_number = "0000000000"; + called_party_number = SWITCH_DEFAULT_CLID_NUMBER; } if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { call_type = SKINNY_INBOUND_CALL; diff --git a/src/switch_caller.c b/src/switch_caller.c index 021a901590..15da20bbe5 100644 --- a/src/switch_caller.c +++ b/src/switch_caller.c @@ -66,7 +66,7 @@ SWITCH_DECLARE(switch_caller_profile_t *) switch_caller_profile_new(switch_memor } if (zstr(caller_id_number)) { - caller_id_number = "0000000000"; + caller_id_number = SWITCH_DEFAULT_CLID_NUMBER; } profile_dup_clean(username, profile->username, pool); diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index 23e4f857a2..0b02d2ba2c 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -2496,7 +2496,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess cid_name_override = SWITCH_DEFAULT_CLID_NAME; } if (!cid_num_override) { - cid_num_override = "0000000000"; + cid_num_override = SWITCH_DEFAULT_CLID_NUMBER; } new_profile = switch_caller_profile_new(oglobals.pool, From e561709f5acd3c31ad5d346373ba708cb9e26423 Mon Sep 17 00:00:00 2001 From: Stefan Knoblich Date: Mon, 17 Sep 2012 21:30:37 +0200 Subject: [PATCH 793/822] mod_freetdm: Use new SWITCH_DEFAULT_CLID_NUMBER constant Signed-off-by: Stefan Knoblich --- libs/freetdm/mod_freetdm/mod_freetdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index a0b54b8834..271f532a70 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1320,7 +1320,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi callerid_num = switch_sanitize_number(switch_core_strdup(outbound_profile->pool, outbound_profile->caller_id_number)); } - if (!zstr(callerid_num) && !strcmp(callerid_num, "0000000000")) { + if (!zstr(callerid_num) && !strcmp(callerid_num, SWITCH_DEFAULT_CLID_NUMBER)) { callerid_num = NULL; } From bc414df510d17e230b471f8129cd87abc2f1d5e0 Mon Sep 17 00:00:00 2001 From: Stefan Knoblich Date: Mon, 17 Sep 2012 21:40:59 +0200 Subject: [PATCH 794/822] ftmod_misdn: Discard incoming audio data if b-channel is not active Silences the "Device or resource busy" error messages caused by the RX pipe filling up. Signed-off-by: Stefan Knoblich --- .../src/ftmod/ftmod_misdn/ftmod_misdn.c | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_misdn/ftmod_misdn.c b/libs/freetdm/src/ftmod/ftmod_misdn/ftmod_misdn.c index 84133601f3..d5fdc54bfc 100644 --- a/libs/freetdm/src/ftmod/ftmod_misdn/ftmod_misdn.c +++ b/libs/freetdm/src/ftmod/ftmod_misdn/ftmod_misdn.c @@ -2265,18 +2265,21 @@ static ftdm_status_t handle_b_channel_event(ftdm_channel_t *chan) int datalen = retval - MISDN_HEADER_LEN; char *data = buf + MISDN_HEADER_LEN; - /* Convert audio data */ - misdn_convert_audio_bits(data, datalen); + /* Discard incoming audio if not active */ + if (!priv->active) { + /* Convert audio data */ + misdn_convert_audio_bits(data, datalen); - /* Write audio into receive pipe */ - if ((retval = write(priv->rx_audio_pipe_in, data, datalen)) < 0) { - ftdm_log_chan(chan, FTDM_LOG_ERROR, "mISDN failed to write audio data into rx pipe: %s\n", - strerror(errno)); - return FTDM_FAIL; - } else if (retval < datalen) { - ftdm_log_chan(chan, FTDM_LOG_ERROR, "mISDN short write into rx pipe, written: %d, expected: %d\n", - retval, datalen); - return FTDM_FAIL; + /* Write audio into receive pipe */ + if ((retval = write(priv->rx_audio_pipe_in, data, datalen)) < 0) { + ftdm_log_chan(chan, FTDM_LOG_ERROR, "mISDN failed to write audio data into rx pipe: %s\n", + strerror(errno)); + return FTDM_FAIL; + } else if (retval < datalen) { + ftdm_log_chan(chan, FTDM_LOG_ERROR, "mISDN short write into rx pipe, written: %d, expected: %d\n", + retval, datalen); + return FTDM_FAIL; + } } /* Get receive buffer usage */ From 715c5389227041f100480d8b01ac343eb72fbb96 Mon Sep 17 00:00:00 2001 From: Stefan Knoblich Date: Mon, 17 Sep 2012 21:43:59 +0200 Subject: [PATCH 795/822] ftmod_misdn: Handle incoming PH_CONTROL_IND messages on b-channels Also add a few more PH_CONTROL_IND message types. Signed-off-by: Stefan Knoblich --- .../src/ftmod/ftmod_misdn/ftmod_misdn.c | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_misdn/ftmod_misdn.c b/libs/freetdm/src/ftmod/ftmod_misdn/ftmod_misdn.c index d5fdc54bfc..0aa770e19a 100644 --- a/libs/freetdm/src/ftmod/ftmod_misdn/ftmod_misdn.c +++ b/libs/freetdm/src/ftmod/ftmod_misdn/ftmod_misdn.c @@ -144,10 +144,36 @@ const static struct { } misdn_control_types[] = { #define MISDN_CONTROL_TYPE(x) { x, #x } MISDN_CONTROL_TYPE(DTMF_HFC_COEF), + MISDN_CONTROL_TYPE(DSP_CONF_JOIN), + MISDN_CONTROL_TYPE(DSP_CONF_SPLIT), + MISDN_CONTROL_TYPE(DSP_RECEIVE_OFF), + MISDN_CONTROL_TYPE(DSP_RECEIVE_ON), + MISDN_CONTROL_TYPE(DSP_ECHO_ON), + MISDN_CONTROL_TYPE(DSP_ECHO_OFF), + MISDN_CONTROL_TYPE(DSP_MIX_ON), + MISDN_CONTROL_TYPE(DSP_MIX_OFF), + MISDN_CONTROL_TYPE(DSP_DELAY), + MISDN_CONTROL_TYPE(DSP_JITTER), + MISDN_CONTROL_TYPE(DSP_TXDATA_ON), + MISDN_CONTROL_TYPE(DSP_TXDATA_OFF), + MISDN_CONTROL_TYPE(DSP_TX_DEJITTER), + MISDN_CONTROL_TYPE(DSP_TX_DEJ_OFF), + MISDN_CONTROL_TYPE(DSP_TONE_PATT_ON), + MISDN_CONTROL_TYPE(DSP_TONE_PATT_OFF), + MISDN_CONTROL_TYPE(DSP_VOL_CHANGE_TX), + MISDN_CONTROL_TYPE(DSP_VOL_CHANGE_RX), + MISDN_CONTROL_TYPE(DSP_BF_ENABLE_KEY), + MISDN_CONTROL_TYPE(DSP_BF_DISABLE), + MISDN_CONTROL_TYPE(DSP_BF_ACCEPT), + MISDN_CONTROL_TYPE(DSP_BF_REJECT), + MISDN_CONTROL_TYPE(DSP_PIPELINE_CFG), + MISDN_CONTROL_TYPE(HFC_VOL_CHANGE_TX), + MISDN_CONTROL_TYPE(HFC_VOL_CHANGE_RX), + MISDN_CONTROL_TYPE(HFC_SPL_LOOP_ON), + MISDN_CONTROL_TYPE(HFC_SPL_LOOP_OFF), #undef MISDN_CONTROL_TYPE }; -#ifdef MISDN_DEBUG_EVENTS static const char *misdn_control2str(const int ctrl) { int x; @@ -158,7 +184,6 @@ static const char *misdn_control2str(const int ctrl) } return "unknown"; } -#endif /*********************************************************************************** @@ -759,13 +784,11 @@ out: static int misdn_handle_ph_control_ind(ftdm_channel_t *chan, const struct mISDNhead *hh, const void *data, const int data_len) { -#ifdef MISDN_DEBUG_EVENTS ftdm_log_chan(chan, FTDM_LOG_DEBUG, "PH_CONTROL_IND:\n" - "\tMessage:\t%s\n" + "\tMessage:\t%s (%#x)\n" "\tPayload:\t%d\n", - misdn_control2str(hh->id), data_len); -#endif + misdn_control2str(hh->id), hh->id, data_len); switch (hh->id) { case DTMF_HFC_COEF: @@ -2351,6 +2374,13 @@ static ftdm_status_t handle_b_channel_event(ftdm_channel_t *chan) case PH_ACTIVATE_IND: priv->active = 1; break; + case PH_CONTROL_IND: { + int datalen = retval - MISDN_HEADER_LEN; + char *data = buf + MISDN_HEADER_LEN; + + misdn_handle_ph_control_ind(chan, mh, data, datalen); + break; + } default: ftdm_log_chan(chan, FTDM_LOG_ERROR, "mISDN received unknown/unhandled event primitive: (%d) %s\n", mh->prim, misdn_event2str(mh->prim)); From 0d21c81015d030bbc0d8a7c056307bcfbe4da7d2 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Mon, 17 Sep 2012 18:59:29 -0500 Subject: [PATCH 796/822] FS-4595 please update to this revision and supply full debug logs --- src/mod/endpoints/mod_sofia/sofia_presence.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index 4eaf4ab4a1..045ea7a827 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -2479,6 +2479,10 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * char *ip = NULL; char *port = 0; const char *call_state = NULL; + const char *astate = NULL; + const char *event_status = NULL; + const char *force_event_status = NULL; + if (mod_sofia_globals.debug_presence > 0) { int i; @@ -2596,8 +2600,16 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * if (helper->hup && helper->calls_up > 0) { call_state = "CS_EXECUTE"; + astate = "active"; + event_status = "Active"; + force_event_status = NULL; } else { - call_state = switch_event_get_header(helper->event, "channel-state"); + if (helper->event) { + call_state = switch_event_get_header(helper->event, "channel-state"); + astate = switch_str_nil(switch_event_get_header(helper->event, "astate")); + event_status = switch_str_nil(switch_event_get_header(helper->event, "status")); + force_event_status = switch_str_nil(switch_event_get_header(helper->event, "force-status")); + } } if (helper->event) { @@ -2605,10 +2617,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * const char *direction = switch_str_nil(switch_event_get_header(helper->event, "presence-call-direction")); //const char *force_direction = switch_str_nil(switch_event_get_header(helper->event, "force-direction")); const char *uuid = switch_str_nil(switch_event_get_header(helper->event, "unique-id")); - const char *event_status = switch_str_nil(switch_event_get_header(helper->event, "status")); const char *resub = switch_str_nil(switch_event_get_header(helper->event, "resub")); - const char *force_event_status = switch_str_nil(switch_event_get_header(helper->event, "force-status")); - const char *astate = switch_str_nil(switch_event_get_header(helper->event, "astate")); const char *answer_state = switch_str_nil(switch_event_get_header(helper->event, "answer-state")); const char *dft_state; const char *from_id = NULL, *from_name = NULL; From 61f4648aa7129e12b68cf69cd21538dda4edbc5d Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Mon, 17 Sep 2012 20:02:14 -0500 Subject: [PATCH 797/822] FS-4621 --resolve everyone will want this patch omfg --- src/mod/endpoints/mod_sofia/sofia.c | 2 +- src/mod/endpoints/mod_sofia/sofia_glue.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 0f3d478f69..d1cdb2068c 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -1210,7 +1210,7 @@ static void our_sofia_event_callback(nua_event_t event, break; case nua_i_invite: if (session && sofia_private) { - if (sofia_private->is_call > 1) { + if (sofia_private->is_call > 1 || switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { sofia_handle_sip_i_reinvite(session, nua, profile, nh, sofia_private, sip, de, tags); } else { sofia_private->is_call++; diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 464af9410b..4c0ae8de1f 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -2526,7 +2526,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) } memset(sofia_private, 0, sizeof(*sofia_private)); - sofia_private->is_call++; + sofia_private->is_call = 2; sofia_private->is_static++; if (switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING)) { From 6803346c948b052f5f9a40dd864dc5cfc1565ea9 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Mon, 17 Sep 2012 23:18:17 -0500 Subject: [PATCH 798/822] fix for last commit - tony please check --- src/mod/endpoints/mod_sofia/sofia.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index d1cdb2068c..e8a1c1e7ef 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -1210,7 +1210,7 @@ static void our_sofia_event_callback(nua_event_t event, break; case nua_i_invite: if (session && sofia_private) { - if (sofia_private->is_call > 1 || switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { + if (sofia_private->is_call > 1 || (channel && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND)) { sofia_handle_sip_i_reinvite(session, nua, profile, nh, sofia_private, sip, de, tags); } else { sofia_private->is_call++; From 33b22c485d2fe2779e61058be73a28ede0a15d3b Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Mon, 17 Sep 2012 23:28:10 -0500 Subject: [PATCH 799/822] FS-4099 --resolve windows only regression --- src/mod/formats/mod_sndfile/mod_sndfile.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mod/formats/mod_sndfile/mod_sndfile.c b/src/mod/formats/mod_sndfile/mod_sndfile.c index fdb40e9a8a..05e306d7a2 100644 --- a/src/mod/formats/mod_sndfile/mod_sndfile.c +++ b/src/mod/formats/mod_sndfile/mod_sndfile.c @@ -67,7 +67,7 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha int i; sf_count_t frames = 0; #ifdef WIN32 - char ps = '\\'; + char ps = '/'; #else char ps = '/'; #endif @@ -169,8 +169,8 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha if ((last = strrchr(alt_path, ps))) { last++; #ifdef WIN32 - if (strrchr(last, '/')) { - last = strrchr(alt_path, '/'); /* do not swallow a forward slash if they are intermixed under windows */ + if (strrchr(last, '\\')) { + last = strrchr(alt_path, '\\'); /* do not swallow a back slash if they are intermixed under windows */ last++; } #endif From 475522b52076e155ae118114b2839422686f463d Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 18 Sep 2012 11:13:09 -0500 Subject: [PATCH 800/822] tweak --- src/mod/endpoints/mod_sofia/sofia.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index e8a1c1e7ef..0f3d478f69 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -1210,7 +1210,7 @@ static void our_sofia_event_callback(nua_event_t event, break; case nua_i_invite: if (session && sofia_private) { - if (sofia_private->is_call > 1 || (channel && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND)) { + if (sofia_private->is_call > 1) { sofia_handle_sip_i_reinvite(session, nua, profile, nh, sofia_private, sip, de, tags); } else { sofia_private->is_call++; From 90cfac744e1b9513d92d3197a4822ea0667ea18e Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 18 Sep 2012 11:31:34 -0500 Subject: [PATCH 801/822] FS-4628 --resolve --- w32/Library/FreeSwitchCore.2010.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/w32/Library/FreeSwitchCore.2010.vcxproj b/w32/Library/FreeSwitchCore.2010.vcxproj index bb3042dac6..5e466c3f10 100644 --- a/w32/Library/FreeSwitchCore.2010.vcxproj +++ b/w32/Library/FreeSwitchCore.2010.vcxproj @@ -89,7 +89,7 @@ Disabled ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-4.0.2\libtiff;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;..\..\libs\libtpl-1.5\src;..\..\libs\libtpl-1.5\src\win;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;PCRE_STATIC;STATICLIB;ENABLE_ZRTP;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;PCRE_STATIC;STATICLIB;ENABLE_ZRTP;TPL_NOLIB;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL From dd62f08f0450617f10656d368218a242edde0fd2 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 18 Sep 2012 11:34:45 -0500 Subject: [PATCH 802/822] FS-4596 --resolve --- conf/autoload_configs/oreka.conf.xml | 11 + src/mod/applications/mod_oreka/Makefile | 2 + src/mod/applications/mod_oreka/mod_oreka.c | 679 +++++++++++++++++++++ src/switch_core_media_bug.c | 10 +- 4 files changed, 699 insertions(+), 3 deletions(-) create mode 100644 conf/autoload_configs/oreka.conf.xml create mode 100644 src/mod/applications/mod_oreka/Makefile create mode 100644 src/mod/applications/mod_oreka/mod_oreka.c diff --git a/conf/autoload_configs/oreka.conf.xml b/conf/autoload_configs/oreka.conf.xml new file mode 100644 index 0000000000..0ef565a883 --- /dev/null +++ b/conf/autoload_configs/oreka.conf.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/src/mod/applications/mod_oreka/Makefile b/src/mod/applications/mod_oreka/Makefile new file mode 100644 index 0000000000..2c35e6e98f --- /dev/null +++ b/src/mod/applications/mod_oreka/Makefile @@ -0,0 +1,2 @@ +BASE=../../../.. +include $(BASE)/build/modmake.rules diff --git a/src/mod/applications/mod_oreka/mod_oreka.c b/src/mod/applications/mod_oreka/mod_oreka.c new file mode 100644 index 0000000000..64f5e8ffd3 --- /dev/null +++ b/src/mod/applications/mod_oreka/mod_oreka.c @@ -0,0 +1,679 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2011, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Oreka Recording Module + * + * The Initial Developer of the Original Code is + * Moises Silva + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Moises Silva + * + * mod_oreka -- Module for Media Recording with Oreka + * + */ + +#include +#include + +static const char SIP_OREKA_HEADER_PREFIX[] = "oreka_sip_h_"; +#define OREKA_PRIVATE "_oreka_" +#define OREKA_BUG_NAME_READ "oreka_read" +#define OREKA_BUG_NAME_WRITE "oreka_write" +#define SIP_OREKA_HEADER_PREFIX_LEN (sizeof(SIP_OREKA_HEADER_PREFIX)-1) + +SWITCH_MODULE_LOAD_FUNCTION(mod_oreka_load); +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_oreka_shutdown); +SWITCH_MODULE_DEFINITION(mod_oreka, mod_oreka_load, mod_oreka_shutdown, NULL); + +typedef struct oreka_session_s { + switch_core_session_t *session; + switch_port_t read_rtp_port; + switch_port_t write_rtp_port; + switch_rtp_t *read_rtp_stream; + switch_rtp_t *write_rtp_stream; + switch_codec_implementation_t read_impl; + switch_codec_implementation_t write_impl; + uint32_t read_cnt; + uint32_t write_cnt; + switch_media_bug_t *read_bug; + switch_media_bug_t *write_bug; + switch_event_t *invite_extra_headers; + switch_event_t *bye_extra_headers; + int usecnt; +} oreka_session_t; + +struct { + char local_ipv4_str[256]; + char sip_server_addr_str[256]; + char sip_server_ipv4_str[256]; + int sip_server_port; + switch_sockaddr_t *sip_server_addr; + switch_socket_t *sip_socket; + pid_t our_pid; +} globals; + +typedef enum { + FS_OREKA_START, + FS_OREKA_STOP +} oreka_recording_status_t; + +typedef enum { + FS_OREKA_READ, + FS_OREKA_WRITE +} oreka_stream_type_t; + +static int oreka_write_udp(oreka_session_t *oreka, switch_stream_handle_t *udp) +{ + switch_size_t udplen = udp->data_len; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(oreka->session), SWITCH_LOG_DEBUG, "Oreka SIP Packet:\n%s", (const char *)udp->data); + switch_socket_sendto(globals.sip_socket, globals.sip_server_addr, 0, (void *)udp->data, &udplen); + if (udplen != udp->data_len) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(oreka->session), SWITCH_LOG_ERROR, "Failed to write SIP Packet of len %zd (wrote=%zd)", + udp->data_len, udplen); + } + return 0; +} + +static int oreka_tear_down_rtp(oreka_session_t *oreka, oreka_stream_type_t type) +{ + if (type == FS_OREKA_READ && oreka->read_rtp_stream) { + switch_rtp_release_port(globals.local_ipv4_str, oreka->read_rtp_port); + switch_rtp_destroy(&oreka->read_rtp_stream); + oreka->read_rtp_port = 0; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(oreka->session), SWITCH_LOG_DEBUG, "Destroyed read rtp\n"); + } else if (oreka->write_rtp_stream) { + switch_rtp_release_port(globals.local_ipv4_str, oreka->write_rtp_port); + switch_rtp_destroy(&oreka->write_rtp_stream); + oreka->write_rtp_port = 0; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(oreka->session), SWITCH_LOG_DEBUG, "Destroyed write rtp\n"); + } + return 0; +} + +static int oreka_setup_rtp(oreka_session_t *oreka, oreka_stream_type_t type) +{ + switch_port_t rtp_port = 0; + switch_rtp_flag_t flags = 0; + switch_rtp_t *rtp_stream = NULL; + switch_codec_implementation_t *codec_impl = NULL; + switch_status_t status = SWITCH_STATUS_SUCCESS; + int res = 0; + const char *err = "unknown error"; + const char *type_str = type == FS_OREKA_READ ? "read" : "write"; + + if (type == FS_OREKA_READ) { + status = switch_core_session_get_read_impl(oreka->session, &oreka->read_impl); + codec_impl = &oreka->read_impl; + } else { + status = switch_core_session_get_write_impl(oreka->session, &oreka->write_impl); + codec_impl = &oreka->write_impl; + } + + if (status != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No %s codec implementation available!\n", type_str); + res = -1; + goto done; + } + + if (!(rtp_port = switch_rtp_request_port(globals.local_ipv4_str))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to allocate %s RTP port for IP %s\n", type_str, globals.local_ipv4_str); + res = -1; + goto done; + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Allocated %s port %d for local IP %s, destination IP %s\n", type_str, + rtp_port, globals.local_ipv4_str, globals.sip_server_ipv4_str); + rtp_stream = switch_rtp_new(globals.local_ipv4_str, rtp_port, + globals.sip_server_ipv4_str, rtp_port, + 0, /* PCMU IANA*/ + codec_impl->samples_per_packet, + codec_impl->microseconds_per_packet, + flags, NULL, &err, switch_core_session_get_pool(oreka->session)); + if (!rtp_stream) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to create %s RTP stream at %s:%d: %s\n", + type_str, globals.local_ipv4_str, rtp_port, err); + res = -1; + goto done; + } +done: + if (res == -1) { + if (rtp_port) { + switch_rtp_release_port(globals.local_ipv4_str, rtp_port); + } + if (rtp_stream) { + switch_rtp_destroy(&rtp_stream); + } + } else { + if (type == FS_OREKA_READ) { + oreka->read_rtp_stream = rtp_stream; + oreka->read_rtp_port = rtp_port; + } else { + oreka->write_rtp_stream = rtp_stream; + oreka->write_rtp_port = rtp_port; + } + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Successfully created %s RTP stream at %s:%d at %dms@%dHz\n", + type_str, globals.local_ipv4_str, rtp_port, codec_impl->microseconds_per_packet/1000, codec_impl->samples_per_second); + return res; +} + +static void save_extra_headers(switch_event_t *extra_headers, switch_channel_t *channel) +{ + switch_event_header_t *ei = NULL; + for (ei = switch_channel_variable_first(channel); + ei; + ei = ei->next) { + const char *name = ei->name; + char *value = ei->value; + if (!strncasecmp(name, SIP_OREKA_HEADER_PREFIX, SIP_OREKA_HEADER_PREFIX_LEN)) { + switch_event_add_header_string(extra_headers, SWITCH_STACK_BOTTOM, name, value); + } + } + switch_channel_variable_last(channel); + + /* Remove the custom header variables that were saved */ + for (ei = extra_headers->headers; + ei; + ei = ei->next) { + char *varname = ei->name; + switch_channel_set_variable(channel, varname, NULL); + } +} + +static switch_event_t *get_extra_headers(oreka_session_t *oreka, oreka_recording_status_t status) +{ + switch_event_t *extra_headers = NULL; + switch_channel_t *channel = NULL; + switch_core_session_t *session = oreka->session; + + channel = switch_core_session_get_channel(session); + if (status == FS_OREKA_START) { + if (!oreka->invite_extra_headers) { + switch_event_create_subclass(&oreka->invite_extra_headers, SWITCH_EVENT_CLONE, NULL); + switch_assert(oreka->invite_extra_headers); + save_extra_headers(oreka->invite_extra_headers, channel); + } + extra_headers = oreka->invite_extra_headers; + } else if (status == FS_OREKA_STOP) { + if (!oreka->bye_extra_headers) { + switch_event_create_subclass(&oreka->bye_extra_headers, SWITCH_EVENT_CLONE, NULL); + switch_assert(oreka->bye_extra_headers); + save_extra_headers(oreka->bye_extra_headers, channel); + } + extra_headers = oreka->bye_extra_headers; + } + return extra_headers; +} + +static void oreka_destroy(oreka_session_t *oreka) +{ + oreka->usecnt--; + if (!oreka->usecnt) { + if (oreka->invite_extra_headers) { + switch_event_destroy(&oreka->invite_extra_headers); + } + if (oreka->bye_extra_headers) { + switch_event_destroy(&oreka->bye_extra_headers); + } + /* Actual memory for the oreka session was taken from the switch core session pool, the core will take care of it */ + } +} + +static int oreka_send_sip_message(oreka_session_t *oreka, oreka_recording_status_t status, oreka_stream_type_t type) +{ + switch_stream_handle_t sip_header = { 0 }; + switch_stream_handle_t sdp = { 0 }; + switch_stream_handle_t udp_packet = { 0 }; + switch_caller_profile_t *caller_profile = NULL; + switch_channel_t *channel = NULL; + switch_event_t *extra_headers = NULL; + switch_event_header_t *ei = NULL; + switch_core_session_t *session = oreka->session; + const char *method = status == FS_OREKA_START ? "INVITE" : "BYE"; + const char *session_uuid = switch_core_session_get_uuid(oreka->session); + const char *caller_id_number = NULL; + const char *caller_id_name = NULL; + const char *callee_id_number = NULL; + const char *callee_id_name = NULL; + int rc = 0; + + channel = switch_core_session_get_channel(session); + + SWITCH_STANDARD_STREAM(sip_header); + SWITCH_STANDARD_STREAM(sdp); + SWITCH_STANDARD_STREAM(udp_packet); + + extra_headers = get_extra_headers(oreka, status); + + caller_profile = switch_channel_get_caller_profile(channel); + + /* Get caller meta data */ + caller_id_number = switch_caller_get_field_by_name(caller_profile, "caller_id_number"); + + caller_id_name = switch_caller_get_field_by_name(caller_profile, "caller_id_name"); + if (!caller_id_name) { + caller_id_name = caller_id_number; + } + + callee_id_number = switch_caller_get_field_by_name(caller_profile, "callee_id_number"); + if (!callee_id_number) { + callee_id_number = switch_caller_get_field_by_name(caller_profile, "destination_number"); + } + + callee_id_name = switch_caller_get_field_by_name(caller_profile, "callee_id_name"); + if (!callee_id_name) { + callee_id_name = callee_id_number; + } + + /* Setup the RTP */ + if (status == FS_OREKA_START) { + if (oreka_setup_rtp(oreka, type)) { + rc = -1; + goto done; + } + } + + if (status == FS_OREKA_STOP) { + oreka_tear_down_rtp(oreka, type); + } + + /* Fill in the SDP first if this is the beginning */ + if (status == FS_OREKA_START) { + sdp.write_function(&sdp, "v=0\r\n"); + sdp.write_function(&sdp, "o=freeswitch %s 1 IN IP4 %s\r\n", session_uuid, globals.local_ipv4_str); + sdp.write_function(&sdp, "c=IN IP4 %s\r\n", globals.sip_server_ipv4_str); + sdp.write_function(&sdp, "s=Phone Recording (%s)\r\n", type == FS_OREKA_READ ? "RX" : "TX"); + sdp.write_function(&sdp, "i=FreeSWITCH Oreka Recorder (pid=%d)\r\n", globals.our_pid); + sdp.write_function(&sdp, "m=audio %d RTP/AVP 0\r\n", type == FS_OREKA_READ ? oreka->read_rtp_port : oreka->write_rtp_port); + sdp.write_function(&sdp, "a=rtpmap:0 PCMU/%d\r\n", type == FS_OREKA_READ + ? oreka->read_impl.samples_per_second : oreka->write_impl.samples_per_second); + } + + /* Request line */ + sip_header.write_function(&sip_header, "%s sip:%s@%s:5060 SIP/2.0\r\n", method, callee_id_name, globals.local_ipv4_str); + + /* Via */ + sip_header.write_function(&sip_header, "Via: SIP/2.0/UDP %s:5061;branch=z9hG4bK-%s\r\n", globals.local_ipv4_str, session_uuid); + + /* From */ + sip_header.write_function(&sip_header, "From: \r\n", caller_id_number, globals.local_ipv4_str); + + /* To */ + sip_header.write_function(&sip_header, "To: \r\n", callee_id_number, globals.local_ipv4_str); + + /* Call-ID */ + sip_header.write_function(&sip_header, "Call-ID: %s\r\n", session_uuid); + + /* CSeq */ + sip_header.write_function(&sip_header, "CSeq: 1 %s\r\n", method); + + /* Contact */ + sip_header.write_function(&sip_header, "Contact: sip:freeswitch@%s:5061\r\n", globals.local_ipv4_str); + + /* Max-Forwards */ + sip_header.write_function(&sip_header, "Max-Forwards: 70\r\n", method); + + /* Subject */ + sip_header.write_function(&sip_header, "Subject: %s %s recording of %s\r\n", + status == FS_OREKA_START ? "BEGIN": "END", + type == FS_OREKA_READ ? "RX" : "TX", caller_id_name); + + /* Add any custom extra headers */ + for (ei = extra_headers->headers; + ei; + ei = ei->next) { + const char *name = ei->name; + char *value = ei->value; + if (!strncasecmp(name, SIP_OREKA_HEADER_PREFIX, SIP_OREKA_HEADER_PREFIX_LEN)) { + const char *hname = name + SIP_OREKA_HEADER_PREFIX_LEN; + sip_header.write_function(&sip_header, "%s: %s\r\n", hname, value); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Adding custom oreka SIP header %s: %s\n", hname, value); + } + } + + if (status == FS_OREKA_START) { + /* Content-Type */ + sip_header.write_function(&sip_header, "Content-Type: application/sdp\r\n"); + + } + + /* Content-Length */ + sip_header.write_function(&sip_header, "Content-Length: %d\r\n", sdp.data_len); + + udp_packet.write_function(&udp_packet, "%s\r\n%s\n", sip_header.data, sdp.data); + + oreka_write_udp(oreka, &udp_packet); + +done: + if (sip_header.data) { + free(sip_header.data); + } + + if (sdp.data) { + free(sdp.data); + } + + if (udp_packet.data) { + free(udp_packet.data); + } + + if (status == FS_OREKA_STOP) { + oreka_destroy(oreka); + } + + return rc; +} + +static switch_bool_t oreka_core_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type, oreka_stream_type_t stype, const char *stype_str) +{ + oreka_session_t *oreka = user_data; + switch_core_session_t *session = oreka->session; + switch_frame_t pcmu_frame; + switch_frame_t linear_frame = { 0 }; + switch_status_t status = SWITCH_STATUS_SUCCESS; + uint8_t pcmu_data[SWITCH_RECOMMENDED_BUFFER_SIZE]; + uint8_t linear_data[SWITCH_RECOMMENDED_BUFFER_SIZE]; + uint32_t i = 0; + int16_t *linear_samples = NULL; + + if (type == SWITCH_ABC_TYPE_READ || type == SWITCH_ABC_TYPE_WRITE) { + memset(&linear_frame, 0, sizeof(linear_frame)); + linear_frame.data = linear_data; + linear_frame.buflen = sizeof(linear_data); + status = switch_core_media_bug_read(bug, &linear_frame, SWITCH_TRUE); + if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error reading media bug: %d\n", status); + goto done; + } + if (!linear_frame.datalen) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Linear frame with no length!\n"); + goto done; + } + /* convert the L16 frame into PCMU */ + linear_samples = linear_frame.data; + memset(&pcmu_frame, 0, sizeof(pcmu_frame)); + for (i = 0; i < linear_frame.datalen/sizeof(int16_t); i++) { + pcmu_data[i] = linear_to_ulaw(linear_samples[i]); + } + pcmu_frame.source = __FUNCTION__; + pcmu_frame.data = pcmu_data; + pcmu_frame.datalen = i; + pcmu_frame.payload = 0; + } + + switch (type) { + case SWITCH_ABC_TYPE_INIT: + { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Starting Oreka recording for %s stream\n", stype_str); + oreka_send_sip_message(oreka, FS_OREKA_START, stype); + } + break; + case SWITCH_ABC_TYPE_CLOSE: + { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Stopping Oreka recording for %s stream\n", stype_str); + oreka_send_sip_message(oreka, FS_OREKA_STOP, stype); + } + break; + case SWITCH_ABC_TYPE_READ: + { + if (pcmu_frame.datalen) { + if (switch_rtp_write_frame(oreka->read_rtp_stream, &pcmu_frame) > 0) { + oreka->read_cnt++; + if (oreka->read_cnt < 10) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Oreka wrote %u bytes! (read)\n", pcmu_frame.datalen); + } + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to write %u bytes! (read)\n", pcmu_frame.datalen); + } + } + } + break; + case SWITCH_ABC_TYPE_WRITE: + { + if (pcmu_frame.datalen) { + if (switch_rtp_write_frame(oreka->write_rtp_stream, &pcmu_frame) > 0) { + oreka->write_cnt++; + if (oreka->write_cnt < 10) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Oreka wrote %u bytes! (write)\n", pcmu_frame.datalen); + } + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to write %u bytes! (write)\n", pcmu_frame.datalen); + } + } + } + break; + default: + break; + } +done: + return SWITCH_TRUE; +} + +static switch_bool_t oreka_read_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type) +{ + return oreka_core_callback(bug, user_data, type, FS_OREKA_READ, "read"); +} + +static switch_bool_t oreka_write_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type) +{ + return oreka_core_callback(bug, user_data, type, FS_OREKA_WRITE, "write"); +} + +SWITCH_STANDARD_APP(oreka_start_function) +{ + switch_status_t status; + switch_channel_t *channel = switch_core_session_get_channel(session); + oreka_session_t *oreka = NULL; + switch_media_bug_t *bug = NULL; + char *argv[6]; + int argc; + char *lbuf = NULL; + + if ((oreka = (oreka_session_t *) switch_channel_get_private(channel, OREKA_PRIVATE))) { + if (!zstr(data) && !strcasecmp(data, "stop")) { + switch_channel_set_private(channel, OREKA_PRIVATE, NULL); + if (oreka->read_bug) { + switch_core_media_bug_remove(session, &oreka->read_bug); + oreka->read_bug = NULL; + } + if (oreka->write_bug) { + switch_core_media_bug_remove(session, &oreka->write_bug); + oreka->write_bug = NULL; + } + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Stopped oreka recorder\n"); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Cannot run oreka recording 2 times on the same session!\n"); + } + return; + } + + oreka = switch_core_session_alloc(session, sizeof(*oreka)); + switch_assert(oreka); + memset(oreka, 0, sizeof(*oreka)); + + if (data && (lbuf = switch_core_session_strdup(session, data)) + && (argc = switch_separate_string(lbuf, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) { +#if 0 + if (!strncasecmp(argv[x], "server", sizeof("server"))) { + /* parse server=192.168.1.144 string */ + } +#endif + } + + oreka->session = session; + status = switch_core_media_bug_add(session, OREKA_BUG_NAME_READ, NULL, oreka_read_callback, oreka, 0, + (SMBF_READ_STREAM | SMBF_ANSWER_REQ), &bug); + if (status != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to attach oreka to read media stream!\n"); + return; + } + oreka->read_bug = bug; + oreka->usecnt++; + bug = NULL; + status = switch_core_media_bug_add(session, OREKA_BUG_NAME_WRITE, NULL, oreka_write_callback, oreka, 0, + (SMBF_WRITE_STREAM | SMBF_ANSWER_REQ), &bug); + if (status != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to attach oreka to write media stream!\n"); + return; + } + oreka->write_bug = bug; + oreka->usecnt++; + switch_channel_set_private(channel, OREKA_PRIVATE, oreka); + +} + +#define OREKA_XML_CONFIG "oreka.conf" +static int load_config(void) +{ + switch_xml_t cfg, xml, settings, param; + if (!(xml = switch_xml_open_cfg(OREKA_XML_CONFIG, &cfg, NULL))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open XML configuration '%s'\n", OREKA_XML_CONFIG); + return -1; + } + + if ((settings = switch_xml_child(cfg, "settings"))) { + for (param = switch_xml_child(settings, "param"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Found parameter %s=%s\n", var, val); + if (!strcasecmp(var, "sip-server-addr")) { + snprintf(globals.sip_server_addr_str, sizeof(globals.sip_server_addr_str), "%s", val); + } else if (!strcasecmp(var, "sip-server-port")) { + globals.sip_server_port = atoi(val); + } + } + } + + switch_xml_free(xml); + return 0; +} + +SWITCH_MODULE_LOAD_FUNCTION(mod_oreka_load) +{ + switch_application_interface_t *app_interface = NULL; + int mask = 0; +#if 0 + switch_status_t status = SWITCH_STATUS_FALSE; + int x = 0; + switch_size_t len = 0; + switch_size_t ilen = 0; + char dummy_output[] = "Parangaricutirimicuaro"; + char dummy_input[sizeof(dummy_output)] = ""; + switch_sockaddr_t *from_addr = NULL; +#endif + + memset(&globals, 0, sizeof(globals)); + + if (load_config()) { + return SWITCH_STATUS_UNLOAD; + } + + if (zstr(globals.sip_server_addr_str)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No sip server address specified!\n"); + return SWITCH_STATUS_UNLOAD; + } + + if (!globals.sip_server_port) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No sip server port specified!\n"); + return SWITCH_STATUS_UNLOAD; + } + + //switch_sockaddr_info_get(&globals.sip_server_addr, "sigchld.sangoma.local", SWITCH_UNSPEC, 5080, 0, pool); + switch_sockaddr_info_get(&globals.sip_server_addr, globals.sip_server_addr_str, SWITCH_UNSPEC, globals.sip_server_port, 0, pool); + + if (!globals.sip_server_addr) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid sip server address specified: %s!\n", globals.sip_server_addr_str); + return SWITCH_STATUS_UNLOAD; + } + + if (switch_socket_create(&globals.sip_socket, switch_sockaddr_get_family(globals.sip_server_addr), SOCK_DGRAM, 0, pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to create socket!\n"); + return SWITCH_STATUS_UNLOAD; + } + + switch_find_local_ip(globals.local_ipv4_str, sizeof(globals.local_ipv4_str), &mask, AF_INET); + switch_get_addr(globals.sip_server_ipv4_str, sizeof(globals.sip_server_ipv4_str), globals.sip_server_addr); + globals.our_pid = getpid(); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + "Loading mod_oreka, sip_server_addr=%s, sip_server_ipv4_str=%s, sip_server_port=%d, local_ipv4_str=%s\n", + globals.sip_server_addr_str, globals.sip_server_ipv4_str, globals.sip_server_port, globals.local_ipv4_str); + +#if 0 + if (switch_socket_bind(globals.sip_socket, globals.sip_addr) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to bind to SIP address: %s!\n", strerror(errno)); + return SWITCH_STATUS_UNLOAD; + } +#endif + +#if 0 + len = sizeof(dummy_output); +#ifndef WIN32 + switch_socket_opt_set(globals.sip_socket, SWITCH_SO_NONBLOCK, TRUE); + + status = switch_socket_sendto(globals.sip_socket, globals.sip_addr, 0, (void *)dummy_output, &len); + if (status != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to send UDP message! (status=%d)\n", status); + } + + status = switch_sockaddr_create(&from_addr, pool); + if (status != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to creat socket address\n"); + } + + while (!ilen) { + ilen = sizeof(dummy_input); + status = switch_socket_recvfrom(from_addr, globals.sip_socket, 0, (void *)dummy_input, &ilen); + if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { + break; + } + + if (++x > 1000) { + break; + } + + switch_cond_next(); + } + + switch_socket_opt_set(globals.sip_socket, SWITCH_SO_NONBLOCK, FALSE); +#endif +#endif + + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + + SWITCH_ADD_APP(app_interface, "oreka_record", "Send media to Oreka recording server", "Send media to Oreka recording server", + oreka_start_function, "[stop]", SAF_NONE); + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_oreka_shutdown) +{ + switch_socket_close(globals.sip_socket); + return SWITCH_STATUS_UNLOAD; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:nil + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/src/switch_core_media_bug.c b/src/switch_core_media_bug.c index 8b466b111e..370b22a5f7 100644 --- a/src/switch_core_media_bug.c +++ b/src/switch_core_media_bug.c @@ -201,9 +201,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_read(switch_media_bug_t *b return SWITCH_STATUS_FALSE; } - if (!(bug->raw_read_buffer && (bug->raw_write_buffer || !switch_test_flag(bug, SMBF_WRITE_STREAM)))) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_ERROR, "%s Buffer Error\n", - switch_channel_get_name(bug->session->channel)); + if ((!bug->raw_read_buffer && (!bug->raw_write_buffer || !switch_test_flag(bug, SMBF_WRITE_STREAM)))) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_ERROR, + "%s Buffer Error (raw_read_buffer=%p, raw_write_buffer=%p, read=%s, write=%s)\n", + switch_channel_get_name(bug->session->channel), + (void *)bug->raw_read_buffer, (void *)bug->raw_write_buffer, + switch_test_flag(bug, SMBF_READ_STREAM) ? "yes" : "no", + switch_test_flag(bug, SMBF_WRITE_STREAM) ? "yes" : "no"); return SWITCH_STATUS_FALSE; } From 0cdcf7ff86e207ed7e8a0413bb57843629e14d36 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 18 Sep 2012 15:41:28 -0400 Subject: [PATCH 803/822] Move oreka.conf.xml to vanilla/autoload_configs/ --- conf/{ => vanilla}/autoload_configs/oreka.conf.xml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename conf/{ => vanilla}/autoload_configs/oreka.conf.xml (100%) diff --git a/conf/autoload_configs/oreka.conf.xml b/conf/vanilla/autoload_configs/oreka.conf.xml similarity index 100% rename from conf/autoload_configs/oreka.conf.xml rename to conf/vanilla/autoload_configs/oreka.conf.xml From 350fbdbfb0bb0b6b9cfec1197554d4d914b898fe Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 18 Sep 2012 15:46:22 -0400 Subject: [PATCH 804/822] Update oreka.conf.xml comments --- conf/vanilla/autoload_configs/oreka.conf.xml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/conf/vanilla/autoload_configs/oreka.conf.xml b/conf/vanilla/autoload_configs/oreka.conf.xml index 0ef565a883..29eabd5c29 100644 --- a/conf/vanilla/autoload_configs/oreka.conf.xml +++ b/conf/vanilla/autoload_configs/oreka.conf.xml @@ -4,8 +4,10 @@ the sip-server-addr and sip-server-port to the oreka server --> - - - + + + + + From 1b2b4565102539c830adf495182f1f2c1d92cb07 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 18 Sep 2012 15:38:34 -0500 Subject: [PATCH 805/822] add transfer_to variable for call processing --- src/mod/endpoints/mod_sofia/sofia.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 0f3d478f69..ddbbead883 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -635,7 +635,7 @@ void sofia_handle_sip_i_bye(switch_core_session_t *session, int status, switch_channel_set_flag(other_channel, CF_REDIRECT); switch_channel_set_state(new_channel, CS_RESET); - + switch_ivr_uuid_bridge(new_uuid, other_uuid); cmd = switch_core_session_sprintf(session, "sleep:500,sofia_sla:%s inline", new_uuid); @@ -6554,6 +6554,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, switch_core_session_rwunlock(tmp); } + switch_channel_set_variable_printf(channel, "transfer_to", "att:%s", br_b); + mark_transfer_record(session, br_a, br_b); switch_ivr_uuid_bridge(br_a, br_b); switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); @@ -7143,8 +7145,10 @@ void *SWITCH_THREAD_FUNC nightmare_xfer_thread_run(switch_thread_t *thread, void if (switch_true(switch_channel_get_variable(channel_a, "recording_follow_transfer"))) { switch_core_media_bug_transfer_recordings(session, a_session); } + tuuid_str = switch_core_session_get_uuid(tsession); + switch_channel_set_variable_printf(channel_a, "transfer_to", "att:%s", tuuid_str); mark_transfer_record(session, nhelper->bridge_to_uuid, tuuid_str); switch_ivr_uuid_bridge(nhelper->bridge_to_uuid, tuuid_str); switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); @@ -7413,6 +7417,8 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t + switch_channel_set_variable_printf(channel_b, "transfer_to", "satt:%s", br_a); + switch_channel_set_variable(channel_b, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); @@ -7517,7 +7523,8 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t switch_core_session_rwunlock(tmp); } - + switch_channel_set_variable_printf(channel_a, "transfer_to", "att:%s", br_b); + mark_transfer_record(session, br_b, br_a); switch_ivr_uuid_bridge(br_b, br_a); @@ -7725,11 +7732,12 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t if (exten) { switch_channel_t *channel = switch_core_session_get_channel(session); - const char *br; + const char *br = switch_channel_get_partner_uuid(channel); switch_core_session_t *b_session; - if ((br = switch_channel_get_partner_uuid(channel)) && (b_session = switch_core_session_locate(br))) { - + switch_channel_set_variable_printf(channel, "transfer_to", "blind:%s", br ? br : exten); + + if (!zstr(br) && (b_session = switch_core_session_locate(br))) { const char *var; switch_channel_t *b_channel = switch_core_session_get_channel(b_session); From c5204c212887b7b8fbb6f3d01e2cde3fd6ac14a9 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 18 Sep 2012 15:39:23 -0500 Subject: [PATCH 806/822] FS-4614 --resolve update to dynamic line buffer and use internal buffering to boot for file I/O on preprocessing XML --- src/include/switch_utils.h | 3 +- src/switch_core.c | 20 ++++---- src/switch_utils.c | 97 ++++++++++++++++++++++++++++++++++++++ src/switch_xml.c | 80 ++++++++++++++++++++----------- 4 files changed, 163 insertions(+), 37 deletions(-) diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index 6b1824a153..c9e2c189c8 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -234,7 +234,8 @@ static inline uint32_t switch_known_bitrate(switch_payload_t payload) } SWITCH_DECLARE(switch_size_t) switch_fd_read_line(int fd, char *buf, switch_size_t len); - +SWITCH_DECLARE(switch_size_t) switch_fd_read_dline(int fd, char **buf, switch_size_t *len); +SWITCH_DECLARE(switch_size_t) switch_fp_read_dline(FILE *fd, char **buf, switch_size_t *len); SWITCH_DECLARE(switch_status_t) switch_frame_alloc(switch_frame_t **frame, switch_size_t size); SWITCH_DECLARE(switch_status_t) switch_frame_dup(switch_frame_t *orig, switch_frame_t **clone); diff --git a/src/switch_core.c b/src/switch_core.c index 53bd4b8762..71c30f295e 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -930,19 +930,21 @@ SWITCH_DECLARE(switch_status_t) switch_core_mime_add_type(const char *type, cons static void load_mime_types(void) { char *cf = "mime.types"; - int fd = -1; - char line_buf[1024] = ""; + FILE *fd = NULL; + char *line_buf; + switch_size_t llen = 0; char *mime_path = NULL; mime_path = switch_mprintf("%s/%s", SWITCH_GLOBAL_dirs.conf_dir, cf); switch_assert(mime_path); - fd = open(mime_path, O_RDONLY | O_BINARY); - if (fd <= 0) { + fd = fopen(mime_path, "rb"); + + if (fd == NULL) { goto end; } - while ((switch_fd_read_line(fd, line_buf, sizeof(line_buf)))) { + while ((switch_fp_read_dline(fd, &line_buf, &llen))) { char *p; char *type = line_buf; @@ -966,9 +968,11 @@ static void load_mime_types(void) } - if (fd > -1) { - close(fd); - fd = -1; + switch_safe_free(line_buf); + + if (fd) { + fclose(fd); + fd = NULL; } end: diff --git a/src/switch_utils.c b/src/switch_utils.c index 3961d89089..090812a45b 100644 --- a/src/switch_utils.c +++ b/src/switch_utils.c @@ -453,6 +453,103 @@ SWITCH_DECLARE(switch_size_t) switch_fd_read_line(int fd, char *buf, switch_size return total; } +#define DLINE_BLOCK_SIZE 1024 +#define DLINE_MAX_SIZE 1048576 +SWITCH_DECLARE(switch_size_t) switch_fd_read_dline(int fd, char **buf, switch_size_t *len) +{ + char c, *p; + int cur; + switch_size_t total = 0; + char *data = *buf; + switch_size_t ilen = *len; + + if (!data) { + *len = ilen = DLINE_BLOCK_SIZE; + data = malloc(ilen); + memset(data, 0, ilen); + } + + p = data; + while ((cur = read(fd, &c, 1)) == 1) { + + if (total + 2 >= ilen) { + if (ilen + DLINE_BLOCK_SIZE > DLINE_MAX_SIZE) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Single line limit reached!\n"); + break; + } + + ilen += DLINE_BLOCK_SIZE; + data = realloc(data, ilen); + switch_assert(data); + p = data + total; + + } + + total += cur; + *p++ = c; + + if (c == '\r' || c == '\n') { + break; + } + } + + *p++ = '\0'; + + *len = ilen; + *buf = data; + + return total; +} + + + +SWITCH_DECLARE(switch_size_t) switch_fp_read_dline(FILE *fd, char **buf, switch_size_t *len) +{ + char c, *p; + switch_size_t total = 0; + char *data = *buf; + switch_size_t ilen = *len; + + if (!data) { + *len = ilen = DLINE_BLOCK_SIZE; + data = malloc(ilen); + memset(data, 0, ilen); + } + + p = data; + //while ((c = fgetc(fd)) != EOF) { + + while (fread(&c, 1, 1, fd) == 1) { + + if (total + 2 >= ilen) { + if (ilen + DLINE_BLOCK_SIZE > DLINE_MAX_SIZE) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Single line limit reached!\n"); + break; + } + + ilen += DLINE_BLOCK_SIZE; + data = realloc(data, ilen); + switch_assert(data); + p = data + total; + + } + + total++; + *p++ = c; + + if (c == '\r' || c == '\n') { + break; + } + } + + *p++ = '\0'; + + *len = ilen; + *buf = data; + + return total; +} + SWITCH_DECLARE(char *) switch_amp_encode(char *s, char *buf, switch_size_t len) { char *p, *q; diff --git a/src/switch_xml.c b/src/switch_xml.c index 95a51c39e8..d4b26e0b9d 100644 --- a/src/switch_xml.c +++ b/src/switch_xml.c @@ -104,7 +104,7 @@ void globfree(glob_t *); /* Use UTF-8 as the general encoding */ static switch_bool_t USE_UTF_8_ENCODING = SWITCH_TRUE; -static int preprocess(const char *cwd, const char *file, int write_fd, int rlevel); +static int preprocess(const char *cwd, const char *file, FILE *write_fd, int rlevel); typedef struct switch_xml_root *switch_xml_root_t; struct switch_xml_root { /* additional data for the root tag */ @@ -1224,12 +1224,12 @@ static char *expand_vars(char *buf, char *ebuf, switch_size_t elen, switch_size_ return ebuf; } -static int preprocess_exec(const char *cwd, const char *command, int write_fd, int rlevel) +static FILE *preprocess_exec(const char *cwd, const char *command, FILE *write_fd, int rlevel) { #ifdef WIN32 char message[] = ""; - if (write(write_fd, message, sizeof(message)) < 0) { + if (fwrite( message, 1, sizeof(message), write_fd) < 0) { goto end; } #else @@ -1249,7 +1249,7 @@ static int preprocess_exec(const char *cwd, const char *command, int write_fd, i int bytes; close(fds[1]); while ((bytes = read(fds[0], buf, sizeof(buf))) > 0) { - if (write(write_fd, buf, bytes) <= 0) { + if (fwrite(buf, 1, bytes, write_fd) <= 0) { break; } } @@ -1271,7 +1271,7 @@ static int preprocess_exec(const char *cwd, const char *command, int write_fd, i } -static int preprocess_glob(const char *cwd, const char *pattern, int write_fd, int rlevel) +static FILE *preprocess_glob(const char *cwd, const char *pattern, FILE *write_fd, int rlevel) { char *full_path = NULL; char *dir_path = NULL, *e = NULL; @@ -1310,28 +1310,43 @@ static int preprocess_glob(const char *cwd, const char *pattern, int write_fd, i return write_fd; } -static int preprocess(const char *cwd, const char *file, int write_fd, int rlevel) +static int preprocess(const char *cwd, const char *file, FILE *write_fd, int rlevel) { - int read_fd = -1; + FILE *read_fd = NULL; switch_size_t cur = 0, ml = 0; - char *q, *cmd, buf[2048], ebuf[8192]; + char *q, *cmd, *buf = NULL, *ebuf = NULL; char *tcmd, *targ; int line = 0; - - if ((read_fd = open(file, O_RDONLY, 0)) < 0) { - const char *reason = strerror(errno); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldnt open %s (%s)\n", file, reason); - return read_fd; - } + switch_size_t len = 0, eblen = 0; if (rlevel > 100) { return -1; } - while ((cur = switch_fd_read_line(read_fd, buf, sizeof(buf))) > 0) { + if (!(read_fd = fopen(file, "r"))) { + const char *reason = strerror(errno); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldnt open %s (%s)\n", file, reason); + return -1; + } + + setvbuf(read_fd, (char *) NULL, _IOFBF, 65536); + + for(;;) { char *arg, *e; const char *err = NULL; - char *bp = expand_vars(buf, ebuf, sizeof(ebuf), &cur, &err); + char *bp; + + switch_safe_free(ebuf); + + if ((cur = switch_fp_read_dline(read_fd, &buf, &len)) <= 0) { + break; + } + + eblen = len *2; + ebuf = malloc(eblen); + memset(ebuf, 0, eblen); + + bp = expand_vars(buf, ebuf, eblen, &cur, &err); line++; if (err) { @@ -1360,7 +1375,7 @@ static int preprocess(const char *cwd, const char *file, int write_fd, int rleve if ((e = strstr(tcmd, "/>"))) { *e += 2; *e = '\0'; - if (write(write_fd, e, (unsigned) strlen(e)) != (int) strlen(e)) { + if (fwrite(e, 1, (unsigned) strlen(e), write_fd) != (int) strlen(e)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Short write!\n"); } } @@ -1431,13 +1446,13 @@ static int preprocess(const char *cwd, const char *file, int write_fd, int rleve } if ((cmd = strstr(bp, ""))) { *e = '\0'; e += 3; - if (write(write_fd, e, (unsigned) strlen(e)) != (int) strlen(e)) { + if (fwrite(e, 1, (unsigned) strlen(e), write_fd) != (int) strlen(e)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Short write!\n"); } } else { @@ -1489,13 +1504,18 @@ static int preprocess(const char *cwd, const char *file, int write_fd, int rleve continue; } - if (write(write_fd, bp, (unsigned) cur) != (int) cur) { + if (fwrite(bp, 1, (unsigned) cur, write_fd) != (int) cur) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Short write!\n"); } + } - close(read_fd); - return write_fd; + switch_safe_free(buf); + switch_safe_free(ebuf); + + fclose(read_fd); + + return 0; } SWITCH_DECLARE(switch_xml_t) switch_xml_parse_file_simple(const char *file) @@ -1527,7 +1547,8 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_parse_file_simple(const char *file) SWITCH_DECLARE(switch_xml_t) switch_xml_parse_file(const char *file) { - int fd = -1, write_fd = -1; + int fd = -1; + FILE *write_fd = NULL; switch_xml_t xml = NULL; char *new_file = NULL; const char *abs, *absw; @@ -1546,13 +1567,15 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_parse_file(const char *file) goto done; } - if ((write_fd = open(new_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) < 0) { + if ((write_fd = fopen(new_file, "w+")) == NULL) { goto done; } + setvbuf(write_fd, (char *) NULL, _IOFBF, 65536); + if (preprocess(SWITCH_GLOBAL_dirs.conf_dir, file, write_fd, 0) > -1) { - close(write_fd); - write_fd = -1; + fclose(write_fd); + write_fd = NULL; if ((fd = open(new_file, O_RDONLY, 0)) > -1) { if ((xml = switch_xml_parse_fd(fd))) { xml->free_path = new_file; @@ -1567,8 +1590,9 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_parse_file(const char *file) switch_mutex_unlock(FILE_LOCK); - if (write_fd > -1) { - close(write_fd); + if (write_fd) { + fclose(write_fd); + write_fd = NULL; } if (fd > -1) { From d80e91d248e30ffaf42841f7b88a488b8011a3e8 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 18 Sep 2012 16:00:19 -0500 Subject: [PATCH 807/822] doh --- src/switch_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/switch_core.c b/src/switch_core.c index 71c30f295e..30f1ef3bae 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -931,7 +931,7 @@ static void load_mime_types(void) { char *cf = "mime.types"; FILE *fd = NULL; - char *line_buf; + char *line_buf = NULL; switch_size_t llen = 0; char *mime_path = NULL; From 016550f218fb0ea54aa6163d6a6eb7e02539da5e Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 18 Sep 2012 18:42:00 -0500 Subject: [PATCH 808/822] FS-4627 --resolve --- libs/sofia-sip/libsofia-sip-ua/msg/msg_mime.c | 103 ++++++++++-------- .../libsofia-sip-ua/msg/msg_parser.c | 2 + .../msg/sofia-sip/msg_parser.h | 28 +++++ .../sofia-sip/libsofia-sip-ua/sip/sip_basic.c | 78 +++++++------ .../libsofia-sip-ua/sip/sip_caller_prefs.c | 60 +++++----- .../sofia-sip/libsofia-sip-ua/sip/sip_extra.c | 66 ++++++----- libs/sofia-sip/libsofia-sip-ua/sip/sip_mime.c | 30 ++--- .../libsofia-sip-ua/sip/sip_reason.c | 27 +++-- .../libsofia-sip-ua/sip/sip_security.c | 24 ++-- 9 files changed, 252 insertions(+), 166 deletions(-) diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime.c b/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime.c index 4fe75a24de..e889ceb633 100644 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime.c +++ b/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime.c @@ -1069,28 +1069,33 @@ MSG_HEADER_CLASS(msg_, accept, "Accept", "", ac_params, apndlist, issize_t msg_accept_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen) { - msg_accept_t *ac = (msg_accept_t *)h; + msg_accept_t *ac; - while (*s == ',') /* Ignore empty entries (comma-whitespace) */ - *s = '\0', s += span_lws(s + 1) + 1; + for(;;) { + ac = (msg_accept_t *)h; - if (*s == '\0') { - /* Empty Accept list is not an error */ - ac->ac_type = ac->ac_subtype = ""; - return 0; - } + while (*s == ',') /* Ignore empty entries (comma-whitespace) */ + *s = '\0', s += span_lws(s + 1) + 1; - /* "Accept:" #(type/subtyp ; *(parameters))) */ - if (msg_mediatype_d(&s, &ac->ac_type) == -1) - return -1; - if (!(ac->ac_subtype = strchr(ac->ac_type, '/'))) - return -1; - ac->ac_subtype++; + if (*s == '\0') { + /* Empty Accept list is not an error */ + ac->ac_type = ac->ac_subtype = ""; + return 0; + } - if (*s == ';' && msg_params_d(home, &s, &ac->ac_params) == -1) - return -1; + /* "Accept:" #(type/subtyp ; *(parameters))) */ + if (msg_mediatype_d(&s, &ac->ac_type) == -1) + return -1; + if (!(ac->ac_subtype = strchr(ac->ac_type, '/'))) + return -1; + ac->ac_subtype++; + + if (*s == ';' && msg_params_d(home, &s, &ac->ac_params) == -1) + return -1; + + msg_parse_next_field_without_recursion(); + } - return msg_parse_next_field(home, h, s, slen); } issize_t msg_accept_e(char b[], isize_t bsiz, msg_header_t const *h, int flags) @@ -1167,22 +1172,26 @@ issize_t msg_accept_any_d(su_home_t *home, char *s, isize_t slen) { /** @relatesalso msg_accept_any_s */ - msg_accept_any_t *aa = (msg_accept_any_t *)h; + msg_accept_any_t *aa; - while (*s == ',') /* Ignore empty entries (comma-whitespace) */ - *s = '\0', s += span_lws(s + 1) + 1; + for(;;) { + aa = (msg_accept_any_t *)h; + while (*s == ',') /* Ignore empty entries (comma-whitespace) */ + *s = '\0', s += span_lws(s + 1) + 1; - if (*s == '\0') - return -2; /* Empty list */ + if (*s == '\0') + return -2; /* Empty list */ - /* "Accept-*:" 1#(token *(SEMI accept-param)) */ - if (msg_token_d(&s, &aa->aa_value) == -1) - return -1; + /* "Accept-*:" 1#(token *(SEMI accept-param)) */ + if (msg_token_d(&s, &aa->aa_value) == -1) + return -1; - if (*s == ';' && msg_params_d(home, &s, &aa->aa_params) == -1) - return -1; + if (*s == ';' && msg_params_d(home, &s, &aa->aa_params) == -1) + return -1; + + msg_parse_next_field_without_recursion(); + } - return msg_parse_next_field(home, h, s, slen); } /** Encode an Accept-* header field. */ @@ -2071,29 +2080,33 @@ MSG_HEADER_CLASS_G(content_transfer_encoding, "Content-Transfer-Encoding", issize_t msg_warning_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen) { - msg_warning_t *w = (msg_warning_t *)h; + msg_warning_t *w; char *text; - while (*s == ',') /* Ignore empty entries (comma-whitespace) */ - *s = '\0', s += span_lws(s + 1) + 1; + for(;;) { + w = (msg_warning_t *)h; + while (*s == ',') /* Ignore empty entries (comma-whitespace) */ + *s = '\0', s += span_lws(s + 1) + 1; - /* Parse protocol */ - if (!IS_DIGIT(*s)) - return -1; - w->w_code = strtoul(s, &s, 10); - skip_lws(&s); + /* Parse protocol */ + if (!IS_DIGIT(*s)) + return -1; + w->w_code = strtoul(s, &s, 10); + skip_lws(&s); - /* Host (and port) */ - if (msg_hostport_d(&s, &w->w_host, &w->w_port) == -1) - return -1; - if (msg_quoted_d(&s, &text) == -1) - return -1; - if (msg_unquote(text, text) == NULL) - return -1; + /* Host (and port) */ + if (msg_hostport_d(&s, &w->w_host, &w->w_port) == -1) + return -1; + if (msg_quoted_d(&s, &text) == -1) + return -1; + if (msg_unquote(text, text) == NULL) + return -1; - w->w_text = text; + w->w_text = text; + + msg_parse_next_field_without_recursion(); + } - return msg_parse_next_field(home, h, s, slen); } issize_t msg_warning_e(char b[], isize_t bsiz, msg_header_t const *h, int f) diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c b/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c index e4bf3debca..d75b975689 100644 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c +++ b/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c @@ -1190,6 +1190,7 @@ msg_header_t *error_header_parse(msg_t *msg, msg_pub_t *mo, return h; } + /** Complete this header field and parse next header field. * * This function completes parsing a multi-field header like @Accept, @@ -1238,6 +1239,7 @@ issize_t msg_parse_next_field(su_home_t *home, msg_header_t *prev, return hc->hc_parse(home, h, s, end - s); } + /** Decode a message header. */ msg_header_t *msg_header_d(su_home_t *home, msg_t const *msg, char const *b) { diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_parser.h b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_parser.h index c2fc31f862..7d784b5a61 100644 --- a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_parser.h +++ b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_parser.h @@ -185,6 +185,34 @@ SOFIAPUBFUN issize_t msg_unquoted_e(char *b, isize_t bsiz, char const *s); SOFIAPUBFUN issize_t msg_parse_next_field(su_home_t *home, msg_header_t *prev, char *s, isize_t slen); +#define msg_parse_next_field_without_recursion() { \ + msg_header_t *prev = h; \ + msg_hclass_t *hc = prev->sh_class; \ + char *end = s + slen; \ + \ + if (*s && *s != ',') \ + return -1; \ + \ + if (msg_header_update_params(prev->sh_common, 0) < 0) \ + return -1; \ + \ + while (*s == ',') \ + *s = '\0', s += span_lws(s + 1) + 1; \ + \ + if (*s == 0) \ + return 0; \ + \ + h = msg_header_alloc(home, hc, 0); \ + if (!h) \ + return -1; \ + \ + prev->sh_succ = h, h->sh_prev = &prev->sh_succ; \ + prev->sh_next = h; \ + slen = end - s; \ + } + + + /** Terminate encoding. @HI */ #define MSG_TERM_E(p, e) ((p) < (e) ? (p)[0] = '\0' : '\0') diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_basic.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_basic.c index b3dd3c396a..d2e1c0875e 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_basic.c +++ b/libs/sofia-sip/libsofia-sip-ua/sip/sip_basic.c @@ -1391,18 +1391,23 @@ issize_t sip_contact_d(su_home_t *home, char *s, isize_t slen) { - sip_contact_t *m = (sip_contact_t *)h; + sip_contact_t *m; assert(h); + for(;;) { - while (*s == ',') /* Ignore empty entries (comma-whitespace) */ - *s = '\0', s += span_lws(s + 1) + 1; + m = (sip_contact_t *)h; - if (sip_name_addr_d(home, &s, &m->m_display, m->m_url, - &m->m_params, &m->m_comment) == -1) - return -1; + while (*s == ',') /* Ignore empty entries (comma-whitespace) */ + *s = '\0', s += span_lws(s + 1) + 1; + + if (sip_name_addr_d(home, &s, &m->m_display, m->m_url, + &m->m_params, &m->m_comment) == -1) + return -1; + + msg_parse_next_field_without_recursion(); + } - return msg_parse_next_field(home, h, s, slen); } @@ -2106,18 +2111,24 @@ issize_t sip_any_route_d(su_home_t *home, char *s, isize_t slen) { - sip_route_t *r = (sip_route_t *)h; + sip_route_t *r; + assert(h); + for (;;) { + r = (sip_route_t *)h; - while (*s == ',') /* Ignore empty entries (comma-whitespace) */ - *s = '\0', s += span_lws(s + 1) + 1; + while (*s == ',') { /* Ignore empty entries (comma-whitespace) */ + *s = '\0', s += span_lws(s + 1) + 1; + } - if (sip_name_addr_d(home, &s, &r->r_display, - r->r_url, &r->r_params, NULL) < 0) - return -1; + if (sip_name_addr_d(home, &s, &r->r_display, r->r_url, &r->r_params, NULL) < 0) { + return -1; + } + + msg_parse_next_field_without_recursion(); + } - return msg_parse_next_field(home, h, s, slen); } issize_t sip_any_route_e(char b[], isize_t bsiz, sip_header_t const *h, int flags) @@ -2534,29 +2545,32 @@ SIP_HEADER_CLASS(via, "Via", "v", v_params, prepend, via); issize_t sip_via_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen) { - sip_via_t *v = (sip_via_t *)h; + sip_via_t *v; assert(h); + for (;;) { + v = (sip_via_t *)h; - while (*s == ',') /* Ignore empty entries (comma-whitespace) */ - *s = '\0', s += span_lws(s + 1) + 1; + while (*s == ',') /* Ignore empty entries (comma-whitespace) */ + *s = '\0', s += span_lws(s + 1) + 1; - /* sent-protocol sent-by *( ";" via-params ) [ comment ] */ + /* sent-protocol sent-by *( ";" via-params ) [ comment ] */ + + /* Parse protocol */ + if (sip_transport_d(&s, &v->v_protocol) == -1) + return -1; + /* Host (and port) */ + if (msg_hostport_d(&s, &v->v_host, &v->v_port) == -1) + return -1; + /* Parameters */ + if (*s == ';' && msg_params_d(home, &s, &v->v_params) == -1) + return -1; + /* Comment */ + if (*s == '(' && msg_comment_d(&s, &v->v_comment) == -1) + return -1; - /* Parse protocol */ - if (sip_transport_d(&s, &v->v_protocol) == -1) - return -1; - /* Host (and port) */ - if (msg_hostport_d(&s, &v->v_host, &v->v_port) == -1) - return -1; - /* Parameters */ - if (*s == ';' && msg_params_d(home, &s, &v->v_params) == -1) - return -1; - /* Comment */ - if (*s == '(' && msg_comment_d(&s, &v->v_comment) == -1) - return -1; - - return msg_parse_next_field(home, h, s, slen); + msg_parse_next_field_without_recursion(); + } } issize_t sip_via_e(char b[], isize_t bsiz, sip_header_t const *h, int flags) diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_caller_prefs.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_caller_prefs.c index 9cbc5ed2ee..b2dc3d8e50 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_caller_prefs.c +++ b/libs/sofia-sip/libsofia-sip-ua/sip/sip_caller_prefs.c @@ -194,39 +194,41 @@ static issize_t sip_caller_prefs_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen) { - sip_caller_prefs_t *cp = (sip_caller_prefs_t *)h; - url_t url[1]; - char const *ignore = NULL; - int kludge = 0; + for(;;) { + sip_caller_prefs_t *cp = (sip_caller_prefs_t *)h; + url_t url[1]; + char const *ignore = NULL; + int kludge = 0; - assert(h); + assert(h); - while (*s == ',') /* Ignore empty entries (comma-whitespace) */ - *s = '\0', s += span_lws(s + 1) + 1; + while (*s == ',') /* Ignore empty entries (comma-whitespace) */ + *s = '\0', s += span_lws(s + 1) + 1; - /* Kludge: support PoC IS spec with a typo... */ - if (su_casenmatch(s, "*,", 2)) - s[1] = ';', kludge = 0; - else if (s[0] != '*' && s[0] != '<') { - /* Kludge: missing URL - */ - size_t n = span_attribute_value(s); - kludge = n > 0 && (s[n] == '\0' || s[n] == ',' || s[n] == ';'); - } + /* Kludge: support PoC IS spec with a typo... */ + if (su_casenmatch(s, "*,", 2)) + s[1] = ';', kludge = 0; + else if (s[0] != '*' && s[0] != '<') { + /* Kludge: missing URL - */ + size_t n = span_attribute_value(s); + kludge = n > 0 && (s[n] == '\0' || s[n] == ',' || s[n] == ';'); + } - if (kludge) { - if (msg_any_list_d(home, &s, (msg_param_t **)&cp->cp_params, - msg_attribute_value_scanner, ';') == -1) - return -1; - } - /* Parse params (and ignore display name and url) */ - else if (sip_name_addr_d(home, &s, &ignore, url, &cp->cp_params, NULL) - == -1) - return -1; - /* Be liberal... */ - /* if (url->url_type != url_any) - return -1; */ - - return msg_parse_next_field(home, h, s, slen); + if (kludge) { + if (msg_any_list_d(home, &s, (msg_param_t **)&cp->cp_params, + msg_attribute_value_scanner, ';') == -1) + return -1; + } + /* Parse params (and ignore display name and url) */ + else if (sip_name_addr_d(home, &s, &ignore, url, &cp->cp_params, NULL) + == -1) + return -1; + /* Be liberal... */ + /* if (url->url_type != url_any) + return -1; */ + msg_parse_next_field_without_recursion(); + } + } static diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra.c index 48cb7a6bbf..8b2913f43b 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra.c +++ b/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra.c @@ -40,15 +40,17 @@ #define MSG_PUB_T struct sip_s #define MSG_HDR_T union sip_header_u + #include "sofia-sip/sip_parser.h" #include "sofia-sip/sip_extra.h" +#include "../su/sofia-sip/su_alloc.h" #include #include #include #include #include - +# #include /* ====================================================================== */ @@ -887,16 +889,19 @@ issize_t sip_info_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen) sip_call_info_t *ci = h->sh_call_info; char *end = s + slen; - assert(h); + for(;;) { + ci = h->sh_call_info; + end = s + slen; - while (*s == ',') - s += span_lws(s + 1) + 1; + while (*s == ',') + s += span_lws(s + 1) + 1; - if (sip_name_addr_d(home, &s, NULL, ci->ci_url, &ci->ci_params, NULL) < 0) - return -1; + if (sip_name_addr_d(home, &s, NULL, ci->ci_url, &ci->ci_params, NULL) < 0) + return -1; - /* Recurse */ - return msg_parse_next_field(home, h, s, end - s); + slen = end - s; + msg_parse_next_field_without_recursion(); + } } isize_t sip_info_dup_xtra(sip_header_t const *h, isize_t offset) @@ -1148,18 +1153,23 @@ SIP_HEADER_CLASS(remote_party_id, "Remote-Party-ID", "", issize_t sip_remote_party_id_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen) { - sip_remote_party_id_t *rpid = (sip_remote_party_id_t *)h; + sip_remote_party_id_t *rpid; - while (*s == ',') /* Ignore empty entries (comma-whitespace) */ - *s = '\0', s += span_lws(s + 1) + 1; + for(;;) { + rpid = (sip_remote_party_id_t *)h; - if (sip_name_addr_d(home, &s, - &rpid->rpid_display, - rpid->rpid_url, - &rpid->rpid_params, NULL) == -1) - return -1; + while (*s == ',') /* Ignore empty entries (comma-whitespace) */ + *s = '\0', s += span_lws(s + 1) + 1; + + if (sip_name_addr_d(home, &s, + &rpid->rpid_display, + rpid->rpid_url, + &rpid->rpid_params, NULL) == -1) + return -1; + + msg_parse_next_field_without_recursion(); + } - return msg_parse_next_field(home, h, s, slen); } issize_t sip_remote_party_id_e(char b[], isize_t bsiz, @@ -1288,18 +1298,22 @@ SIP_HEADER_CLASS(p_asserted_identity, "P-Asserted-Identity", "", issize_t sip_p_asserted_identity_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen) { - sip_p_asserted_identity_t *paid = (sip_p_asserted_identity_t *)h; + sip_p_asserted_identity_t *paid; - while (*s == ',') /* Ignore empty entries (comma-whitespace) */ - *s = '\0', s += span_lws(s + 1) + 1; + for(;;) { + paid = (sip_p_asserted_identity_t *)h; + while (*s == ',') /* Ignore empty entries (comma-whitespace) */ + *s = '\0', s += span_lws(s + 1) + 1; - if (sip_name_addr_d(home, &s, - &paid->paid_display, - paid->paid_url, - NULL, NULL) == -1) - return -1; + if (sip_name_addr_d(home, &s, + &paid->paid_display, + paid->paid_url, + NULL, NULL) == -1) + return -1; + + msg_parse_next_field_without_recursion(); + } - return msg_parse_next_field(home, h, s, slen); } issize_t sip_p_asserted_identity_e(char b[], isize_t bsiz, diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_mime.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_mime.c index 90cce374de..62286bc0fa 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_mime.c +++ b/libs/sofia-sip/libsofia-sip-ua/sip/sip_mime.c @@ -135,24 +135,28 @@ SIP_HEADER_CLASS(accept_disposition, "Accept-Disposition", "", issize_t sip_accept_disposition_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen) { - sip_accept_disposition_t *ad = (sip_accept_disposition_t *)h; + sip_accept_disposition_t *ad; - assert(h); + assert(h); - /* Ignore empty entries (comma-whitespace) */ - while (*s == ',') - s += span_lws(s + 1) + 1; + for(;;) { + ad = (sip_accept_disposition_t *)h; + /* Ignore empty entries (comma-whitespace) */ + while (*s == ',') + s += span_lws(s + 1) + 1; - /* "Accept:" #(type/subtyp ; *(parameters))) */ - if (/* Parse protocol */ - sip_version_d(&s, &ad->ad_type) == -1 || - (ad->ad_subtype = strchr(ad->ad_type, '/')) == NULL || - (*s == ';' && msg_params_d(home, &s, &ad->ad_params) == -1)) - return -1; + /* "Accept:" #(type/subtyp ; *(parameters))) */ + if (/* Parse protocol */ + sip_version_d(&s, &ad->ad_type) == -1 || + (ad->ad_subtype = strchr(ad->ad_type, '/')) == NULL || + (*s == ';' && msg_params_d(home, &s, &ad->ad_params) == -1)) + return -1; - if (ad->ad_subtype) ad->ad_subtype++; + if (ad->ad_subtype) ad->ad_subtype++; + + msg_parse_next_field_without_recursion(); + } - return msg_parse_next_field(home, h, s, slen); } issize_t sip_accept_disposition_e(char b[], isize_t bsiz, sip_header_t const *h, int flags) diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_reason.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_reason.c index bb7dbd068f..995fd8c816 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_reason.c +++ b/libs/sofia-sip/libsofia-sip-ua/sip/sip_reason.c @@ -96,20 +96,25 @@ SIP_HEADER_CLASS(reason, "Reason", "", re_params, append, reason); issize_t sip_reason_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen) { - sip_reason_t *re = (sip_reason_t *)h; - size_t n; + sip_reason_t *re; + size_t n; + for (;;) { + re = (sip_reason_t *)h; - while (*s == ',') /* Ignore empty entries (comma-whitespace) */ - *s = '\0', s += span_lws(s + 1) + 1; + while (*s == ',') /* Ignore empty entries (comma-whitespace) */ + *s = '\0', s += span_lws(s + 1) + 1; + + re->re_protocol = s; + if ((n = span_token(s)) == 0) + return -1; + s += n; while (IS_LWS(*s)) *s++ = '\0'; + if (*s == ';' && msg_params_d(home, &s, &re->re_params) < 0) + return -1; + + msg_parse_next_field_without_recursion(); + } - re->re_protocol = s; - if ((n = span_token(s)) == 0) - return -1; - s += n; while (IS_LWS(*s)) *s++ = '\0'; - if (*s == ';' && msg_params_d(home, &s, &re->re_params) < 0) - return -1; - return msg_parse_next_field(home, h, s, slen); } issize_t sip_reason_e(char b[], isize_t bsiz, sip_header_t const *h, int f) diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_security.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_security.c index 99520b2aac..69cddff252 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_security.c +++ b/libs/sofia-sip/libsofia-sip-ua/sip/sip_security.c @@ -458,20 +458,24 @@ typedef struct sip_security_agree_s sip_security_agree_t; static issize_t sip_security_agree_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen) { - sip_security_agree_t *sa = (sip_security_agree_t *)h; - isize_t n; + for (;;) { + sip_security_agree_t *sa = (sip_security_agree_t *)h; - while (*s == ',') /* Ignore empty entries (comma-whitespace) */ - *s = '\0', s += span_lws(s + 1) + 1; + isize_t n; - if ((n = span_token(s)) == 0) - return -1; - sa->sa_mec = s; s += n; while (IS_LWS(*s)) *s++ = '\0'; - if (*s == ';' && msg_params_d(home, &s, &sa->sa_params) < 0) - return -1; + while (*s == ',') /* Ignore empty entries (comma-whitespace) */ + *s = '\0', s += span_lws(s + 1) + 1; + + if ((n = span_token(s)) == 0) + return -1; + sa->sa_mec = s; s += n; while (IS_LWS(*s)) *s++ = '\0'; + if (*s == ';' && msg_params_d(home, &s, &sa->sa_params) < 0) + return -1; + + msg_parse_next_field_without_recursion(); + } - return msg_parse_next_field(home, h, s, slen); } static From 20bb474c0e96b554febe3de186b4e22c2664f2d8 Mon Sep 17 00:00:00 2001 From: Robert Jongbloed Date: Wed, 29 Aug 2012 12:43:46 +1000 Subject: [PATCH 809/822] Added T.38 fax support to mod_opal --- src/mod/endpoints/mod_opal/mod_opal.cpp | 147 +++++++++++++++++++++--- src/mod/endpoints/mod_opal/mod_opal.h | 13 +++ 2 files changed, 147 insertions(+), 13 deletions(-) diff --git a/src/mod/endpoints/mod_opal/mod_opal.cpp b/src/mod/endpoints/mod_opal/mod_opal.cpp index cf160ba527..a8b4b70561 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.cpp +++ b/src/mod/endpoints/mod_opal/mod_opal.cpp @@ -743,6 +743,29 @@ void FSConnection::SetCodecs() m_switchMediaFormats += switchFormat; } + +#if HAVE_T38 + OpalMediaFormat t38 = OpalT38; + + /* We need to have a T.38 options for TCS, but may be before the + spandsp_mod has set it us. So, if not, we actually give to spandsp_mod. */ + switch_t38_options_t *t38_options = (switch_t38_options_t *)switch_channel_get_private(m_fsChannel, "t38_options"); + if (t38_options == NULL) + SetT38OptionsFromMediaFormat(t38); + else { + t38.SetOptionInteger("T38FaxVersion", t38_options->T38FaxVersion); + t38.SetOptionInteger("T38MaxBitRate", t38_options->T38MaxBitRate); + t38.SetOptionBoolean("T38FaxFillBitRemoval", t38_options->T38FaxFillBitRemoval); + t38.SetOptionBoolean("T38FaxTranscodingMMR", t38_options->T38FaxTranscodingMMR); + t38.SetOptionBoolean("T38FaxTranscodingJBIG", t38_options->T38FaxTranscodingJBIG); + t38.SetOptionValue("T38FaxRateManagement", t38_options->T38FaxRateManagement); + t38.SetOptionInteger("T38Version", t38_options->T38FaxMaxBuffer); + t38.SetOptionInteger("T38Version", t38_options->T38FaxMaxDatagram); + t38.SetOptionValue("T38FaxUdpEC", t38_options->T38FaxUdpEC); + } + + m_switchMediaFormats += t38; +#endif // HAVE_T38 } @@ -952,6 +975,23 @@ switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg ownerCall.Transfer(msg->string_arg, GetOtherPartyConnection()); break; +#if HAVE_T38 + case SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA: + { + PSafePtr other = GetOtherPartyConnection(); + if (other == NULL || !other->SwitchT38(true)) { + PTRACE(1, "mod_opal\tMode change request to T.38 failed"); + } + break; + } + + case SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION: + break; + + case SWITCH_MESSAGE_INDICATE_UDPTL_MODE: + break; +#endif // HAVE_T38 + default: PTRACE(3, "mod_opal\tReceived unhandled message " << msg->message_id << " on connection " << *this); } @@ -977,6 +1017,76 @@ bool FSConnection::WaitForMedia() } +#if HAVE_T38 +void FSConnection::SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFormat) +{ + switch_t38_options_t *t38_options = (switch_t38_options_t *)switch_channel_get_private(m_fsChannel, "t38_options"); + if (t38_options == NULL) + t38_options = (switch_t38_options_t *)switch_core_session_alloc(m_fsSession, sizeof(switch_t38_options_t)); + + PString value; + mediaFormat.GetOptionValue("T38FaxRateManagement", value); + t38_options->T38FaxRateManagement = switch_core_session_strdup(m_fsSession, value); + + mediaFormat.GetOptionValue("T38FaxUdpEC", value); + t38_options->T38FaxUdpEC = switch_core_session_strdup(m_fsSession, value); + + t38_options->T38MaxBitRate = mediaFormat.GetOptionInteger("T38MaxBitRate", 9600); + t38_options->T38FaxMaxBuffer = mediaFormat.GetOptionInteger("T38FaxMaxBuffer", 2000); + t38_options->T38FaxMaxDatagram = mediaFormat.GetOptionInteger("T38FaxMaxDatagram", 528); + + t38_options->T38FaxFillBitRemoval = mediaFormat.GetOptionBoolean("T38FaxFillBitRemoval") ? SWITCH_TRUE : SWITCH_FALSE; + t38_options->T38FaxTranscodingMMR = mediaFormat.GetOptionBoolean("T38FaxTranscodingMMR") ? SWITCH_TRUE : SWITCH_FALSE; + t38_options->T38FaxTranscodingJBIG = mediaFormat.GetOptionBoolean("T38FaxTranscodingJBIG") ? SWITCH_TRUE : SWITCH_FALSE; + + t38_options->T38VendorInfo = switch_core_session_strdup(m_fsSession, mediaFormat.GetOptionString("T38VendorInfo")); + + //t38_options->remote_ip = switch_core_session_strdup(session, mediaFormat.something); + //t38_options->remote_port = mediaFormat.something; + + switch_channel_set_private(m_fsChannel, "t38_options", t38_options); +} + + +void FSConnection::OnSwitchedT38(bool toT38, bool success) +{ + PTRACE(3, "mod_opal\tMode change request to fax succeeded"); + OnSwitchingT38(toT38 && success); +} + + +void FSConnection::OnSwitchingT38(bool toT38) +{ + if (!toT38) { + switch_channel_set_private(m_fsChannel, "t38_options", NULL); + switch_channel_clear_app_flag_key("T38", m_fsChannel, CF_APP_T38); + switch_channel_clear_app_flag_key("T38", m_fsChannel, CF_APP_T38_REQ); + switch_channel_set_app_flag_key("T38", m_fsChannel, CF_APP_T38_FAIL); + return; + } + + PSafePtr other = GetOtherPartyConnection(); + if (other == NULL) + return; + + OpalMediaFormatList otherFormats = other->GetMediaFormats(); + OpalMediaFormatList::const_iterator t38 = otherFormats.FindFormat(OpalT38); + if (t38 == otherFormats.end()) + return; + + SetT38OptionsFromMediaFormat(*t38); + + switch_channel_set_variable(m_fsChannel, "has_t38", "true"); + switch_channel_set_app_flag_key("T38", m_fsChannel, CF_APP_T38); + + switch_channel_execute_on(m_fsChannel, "opal_execute_on_image"); + switch_channel_api_on(m_fsChannel, "opal_api_on_image"); + + return; +} +#endif // HAVE_T38 + + switch_status_t FSConnection::receive_event(switch_event_t *event) { PTRACE(4, "mod_opal\tReceived event " << event->event_id << " on connection " << *this); @@ -1052,11 +1162,19 @@ PBoolean FSMediaStream::Open() return false; bool isAudio; - if (mediaFormat.GetMediaType() == OpalMediaType::Audio()) { + OpalMediaType mediaType = mediaFormat.GetMediaType(); + if (mediaType == OpalMediaType::Audio()) isAudio = true; - } else if (mediaFormat.GetMediaType() == OpalMediaType::Video()) { + else if (mediaType == OpalMediaType::Video()) isAudio = false; - } else { +#if HAVE_T38 + else if (mediaType == OpalMediaType::Fax()) { + m_readFrame.flags = SFF_UDPTL_PACKET; + return true; + } +#endif + else { + PTRACE(1, "mod_opal\tUnsupported media type: " << mediaType); return false; } @@ -1083,13 +1201,13 @@ PBoolean FSMediaStream::Open() switch_core_session_get_pool(fsSession)) != SWITCH_STATUS_SUCCESS) { PTRACE(1, "mod_opal\t" << switch_channel_get_name(fsChannel) << " cannot initialise " << (IsSink()? "read" : "write") << ' ' - << mediaFormat.GetMediaType() << " codec " << mediaFormat << " for connection " << *this); + << mediaType << " codec " << mediaFormat << " for connection " << *this); switch_channel_hangup(fsChannel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); return false; } PTRACE(2, "mod_opal\t" << switch_channel_get_name(fsChannel) << " unsupported ptime of " << ptime << " on " << (IsSink()? "read" : "write") << ' ' - << mediaFormat.GetMediaType() << " codec " << mediaFormat << " for connection " << *this); + << mediaType << " codec " << mediaFormat << " for connection " << *this); } if (IsSink()) { @@ -1102,7 +1220,7 @@ PBoolean FSMediaStream::Open() switch_core_session_get_pool(fsSession)) != SWITCH_STATUS_SUCCESS) { PTRACE(1, "mod_opal\t" << switch_channel_get_name(fsChannel) << " timer init failed on " << (IsSink()? "read" : "write") << ' ' - << mediaFormat.GetMediaType() << " codec " << mediaFormat << " for connection " << *this); + << mediaType << " codec " << mediaFormat << " for connection " << *this); switch_core_codec_destroy(m_switchCodec); m_switchCodec = NULL; return false; @@ -1122,7 +1240,7 @@ PBoolean FSMediaStream::Open() PTRACE(3, "mod_opal\t" << switch_channel_get_name(fsChannel) << " initialised " << (IsSink()? "read" : "write") << ' ' - << mediaFormat.GetMediaType() << " codec " << mediaFormat << " for connection " << *this); + << mediaType << " codec " << mediaFormat << " for connection " << *this); return OpalMediaStream::Open(); } @@ -1207,9 +1325,14 @@ switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag } } + *frame = &m_readFrame; + m_readFrame.packet = m_readRTP.GetPointer(); m_readFrame.packetlen = m_readRTP.GetHeaderSize() + m_readFrame.datalen; + if ((m_readFrame.flags & (SFF_UDPTL_PACKET|SFF_RAW_RTP)) != 0) + return SWITCH_STATUS_SUCCESS; + #if IMPLEMENT_MULTI_FAME_AUDIO // Repackage frames in incoming packet to agree with what FS expects. // Not implmented yet!!!!!!!!! @@ -1228,8 +1351,6 @@ switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag m_readFrame.payload == RTP_DataFrame::CN || m_readFrame.payload == RTP_DataFrame::Cisco_CN ? SFF_CNG : 0; - *frame = &m_readFrame; - return SWITCH_STATUS_SUCCESS; } @@ -1244,7 +1365,7 @@ switch_status_t FSMediaStream::write_frame(const switch_frame_t *frame, switch_i return SWITCH_STATUS_SUCCESS; } - if ((frame->flags & SFF_RAW_RTP) != 0) { + if ((frame->flags & (SFF_UDPTL_PACKET|SFF_RAW_RTP)) != 0) { RTP_DataFrame rtp((const BYTE *)frame->packet, frame->packetlen, false); return mediaPatch->PushFrame(rtp) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; } @@ -1257,11 +1378,11 @@ switch_status_t FSMediaStream::write_frame(const switch_frame_t *frame, switch_i /* Not sure what FS is going to give us! Suspect it depends on the mod on the other side sending it. */ if (frame->timestamp != 0) - timestamp = frame->timestamp; + timestamp = frame->timestamp; else if (frame->samples != 0) - timestamp += frame->samples; + timestamp += frame->samples; else - timestamp += m_switchCodec->implementation->samples_per_packet; + timestamp += m_switchCodec->implementation->samples_per_packet; rtp.SetTimestamp(timestamp); return mediaPatch->PushFrame(rtp) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; diff --git a/src/mod/endpoints/mod_opal/mod_opal.h b/src/mod/endpoints/mod_opal/mod_opal.h index 5edc21f8a0..2b7a553d51 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.h +++ b/src/mod/endpoints/mod_opal/mod_opal.h @@ -77,6 +77,12 @@ #define MODNAME "mod_opal" +#ifndef OPAL_CHECK_VERSION + #define OPAL_CHECK_VERSION(a,b,c) 0 +#endif + +#define HAVE_T38 (OPAL_CHECK_VERSION(3,11,2) && OPAL_T38_CAPABILITY) + class FSEndPoint; class FSManager; @@ -248,6 +254,10 @@ class FSConnection : public OpalLocalConnection virtual void OnPatchMediaStream(PBoolean isSource, OpalMediaPatch & patch); virtual OpalMediaFormatList GetMediaFormats() const; virtual PBoolean SendUserInputTone(char tone, unsigned duration); +#if HAVE_T38 + virtual void OnSwitchedT38(bool toT38, bool success); + virtual void OnSwitchingT38(bool toT38); +#endif DECLARE_CALLBACK0(on_init); DECLARE_CALLBACK0(on_destroy); @@ -294,6 +304,9 @@ class FSConnection : public OpalLocalConnection protected: void SetCodecs(); bool WaitForMedia(); +#if HAVE_T38 + void SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFormat); +#endif switch_status_t read_frame(const OpalMediaType & mediaType, switch_frame_t **frame, switch_io_flag_t flags); switch_status_t write_frame(const OpalMediaType & mediaType, const switch_frame_t *frame, switch_io_flag_t flags); From a580c31122cd83724ce6d26447081ad6f77275ce Mon Sep 17 00:00:00 2001 From: Robert Jongbloed Date: Tue, 4 Sep 2012 15:20:25 +1000 Subject: [PATCH 810/822] Fixed VS2010 issues building mod_opal --- src/mod/endpoints/mod_opal/mod_opal.cpp | 4 ++-- src/mod/endpoints/mod_opal/mod_opal.h | 8 ++++---- src/mod/endpoints/mod_opal/mod_opal_2010.vcxproj | 1 + 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/mod/endpoints/mod_opal/mod_opal.cpp b/src/mod/endpoints/mod_opal/mod_opal.cpp index a8b4b70561..8f72dda4e2 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.cpp +++ b/src/mod/endpoints/mod_opal/mod_opal.cpp @@ -31,7 +31,7 @@ /* FreeSWITCH does not correctly handle an H.323 subtely, that is that a - MAXIMUM audio frames per packet is nototiated, and there is no + MAXIMUM audio frames per packet is negotiated, and there is no requirement for the remote to actually send that many. So, in say GSM, we negotiate up to 3 frames or 60ms of data and the remote actually sends one (20ms) frame per packet. Perfectly legal but blows up the media handling @@ -101,7 +101,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opal_load) /* Prevent the loading of OPAL codecs via "plug ins", this is a directory full of DLLs that will be loaded automatically. */ - putenv((char *)"PTLIBPLUGINDIR=/no/thanks"); + (void)putenv((char *)"PTLIBPLUGINDIR=/no/thanks"); *module_interface = switch_loadable_module_create_module_interface(pool, modname); diff --git a/src/mod/endpoints/mod_opal/mod_opal.h b/src/mod/endpoints/mod_opal/mod_opal.h index 2b7a553d51..25dbef45d6 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.h +++ b/src/mod/endpoints/mod_opal/mod_opal.h @@ -50,11 +50,11 @@ #undef strncasecmp -#if _MSC_VER < 1600 +#ifdef _MSC_VER /*The following insanity is because libteletone_generate.h defines int8_t in - a slightly different manner to most other cases (SDL, PCAP, Java V8, stdint.h - etc) and does not provide a mechanism to prevent it's inclusion. Then, to - cap it off, VS2008 barfs on the difference. VS2010 seems OK with it. + a slightly different manner to most other cases (SDL, PCAP, Java V8, + VS2010's own stdint.h, etc) and does not provide a mechanism to prevent it's + inclusion. Then, to cap it off, MSVC barfs on the difference. Sigh. */ diff --git a/src/mod/endpoints/mod_opal/mod_opal_2010.vcxproj b/src/mod/endpoints/mod_opal/mod_opal_2010.vcxproj index efe610d5f2..bf38e92ae0 100644 --- a/src/mod/endpoints/mod_opal/mod_opal_2010.vcxproj +++ b/src/mod/endpoints/mod_opal/mod_opal_2010.vcxproj @@ -47,6 +47,7 @@ 4100;4101;%(DisableSpecificWarnings) + true /NODEFAULTLIB:LIMBCTD %(AdditionalOptions) From 468739da2910396db2b40cb23262884f702340ed Mon Sep 17 00:00:00 2001 From: Robert Jongbloed Date: Thu, 6 Sep 2012 12:43:17 +1000 Subject: [PATCH 811/822] More T.38 fax support changes for mod_opal. Not quite there yet. --- .../mod_spandsp/mod_spandsp_fax.c | 24 ++-- src/mod/endpoints/mod_opal/mod_opal.cpp | 114 ++++++++++++------ src/mod/endpoints/mod_opal/mod_opal.h | 4 +- 3 files changed, 90 insertions(+), 52 deletions(-) diff --git a/src/mod/applications/mod_spandsp/mod_spandsp_fax.c b/src/mod/applications/mod_spandsp/mod_spandsp_fax.c index 57fb05a439..f48bed8ad5 100644 --- a/src/mod/applications/mod_spandsp/mod_spandsp_fax.c +++ b/src/mod/applications/mod_spandsp/mod_spandsp_fax.c @@ -1109,21 +1109,21 @@ static t38_mode_t request_t38(pvt_t *pvt) if (!(t38_options = switch_channel_get_private(channel, "_preconfigured_t38_options"))) { t38_options = switch_core_session_alloc(session, sizeof(*t38_options)); - switch_channel_set_private(channel, "_preconfigured_t38_options", NULL); + t38_options->T38MaxBitRate = (pvt->disable_v17) ? 9600 : 14400; + t38_options->T38FaxVersion = 0; + t38_options->T38FaxFillBitRemoval = 1; + t38_options->T38FaxTranscodingMMR = 0; + t38_options->T38FaxTranscodingJBIG = 0; + t38_options->T38FaxRateManagement = "transferredTCF"; + t38_options->T38FaxMaxBuffer = 2000; + t38_options->T38FaxMaxDatagram = LOCAL_FAX_MAX_DATAGRAM; + t38_options->T38FaxUdpEC = "t38UDPRedundancy"; + t38_options->T38VendorInfo = "0 0 0"; } - t38_options->T38MaxBitRate = (pvt->disable_v17) ? 9600 : 14400; - t38_options->T38FaxVersion = 0; - t38_options->T38FaxFillBitRemoval = 1; - t38_options->T38FaxTranscodingMMR = 0; - t38_options->T38FaxTranscodingJBIG = 0; - t38_options->T38FaxRateManagement = "transferredTCF"; - t38_options->T38FaxMaxBuffer = 2000; - t38_options->T38FaxMaxDatagram = LOCAL_FAX_MAX_DATAGRAM; - t38_options->T38FaxUdpEC = "t38UDPRedundancy"; - t38_options->T38VendorInfo = "0 0 0"; + switch_channel_set_private(channel, "t38_options", t38_options); + switch_channel_set_private(channel, "_preconfigured_t38_options", NULL); - switch_channel_set_private(channel, "t38_options", t38_options); pvt->t38_mode = T38_MODE_REQUESTED; switch_channel_set_app_flag_key("T38", channel, CF_APP_T38_REQ); diff --git a/src/mod/endpoints/mod_opal/mod_opal.cpp b/src/mod/endpoints/mod_opal/mod_opal.cpp index 8f72dda4e2..a6a6f44dfd 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.cpp +++ b/src/mod/endpoints/mod_opal/mod_opal.cpp @@ -751,7 +751,7 @@ void FSConnection::SetCodecs() spandsp_mod has set it us. So, if not, we actually give to spandsp_mod. */ switch_t38_options_t *t38_options = (switch_t38_options_t *)switch_channel_get_private(m_fsChannel, "t38_options"); if (t38_options == NULL) - SetT38OptionsFromMediaFormat(t38); + SetT38OptionsFromMediaFormat(t38, "_preconfigured_t38_options"); else { t38.SetOptionInteger("T38FaxVersion", t38_options->T38FaxVersion); t38.SetOptionInteger("T38MaxBitRate", t38_options->T38MaxBitRate); @@ -786,18 +786,18 @@ void FSConnection::OnPatchMediaStream(PBoolean isSource, OpalMediaPatch & patch) return; if (switch_channel_direction(m_fsChannel) == SWITCH_CALL_DIRECTION_INBOUND) { - if (isSource) - m_rxAudioOpened.Signal(); - else - m_txAudioOpened.Signal(); + if (isSource) + m_rxAudioOpened.Signal(); + else + m_txAudioOpened.Signal(); } else if (GetMediaStream(OpalMediaType::Audio(), !isSource) != NULL) { - // Have open media in both directions. + // Have open media in both directions. if (IsEstablished()) - switch_channel_mark_answered(m_fsChannel); + switch_channel_mark_answered(m_fsChannel); else if (!IsReleased()) - switch_channel_mark_pre_answered(m_fsChannel); - } + switch_channel_mark_pre_answered(m_fsChannel); + } } @@ -978,17 +978,22 @@ switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg #if HAVE_T38 case SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA: { + PTRACE(2, "mod_opal\tRequesting switch to T.38"); PSafePtr other = GetOtherPartyConnection(); - if (other == NULL || !other->SwitchT38(true)) { + if (other != NULL && other->SwitchT38(true)) + switch_channel_set_flag(m_fsChannel, CF_REQ_MEDIA); + else { PTRACE(1, "mod_opal\tMode change request to T.38 failed"); } break; } case SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION: + PTRACE(2, "mod_opal\tSWITCH_MESSAGE_INDICATE_T38_DESCRIPTION"); break; case SWITCH_MESSAGE_INDICATE_UDPTL_MODE: + PTRACE(2, "mod_opal\tSWITCH_MESSAGE_INDICATE_UDPTL_MODE"); break; #endif // HAVE_T38 @@ -1018,9 +1023,9 @@ bool FSConnection::WaitForMedia() #if HAVE_T38 -void FSConnection::SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFormat) +void FSConnection::SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFormat, const char * varname) { - switch_t38_options_t *t38_options = (switch_t38_options_t *)switch_channel_get_private(m_fsChannel, "t38_options"); + switch_t38_options_t *t38_options = (switch_t38_options_t *)switch_channel_get_private(m_fsChannel, varname); if (t38_options == NULL) t38_options = (switch_t38_options_t *)switch_core_session_alloc(m_fsSession, sizeof(switch_t38_options_t)); @@ -1044,45 +1049,55 @@ void FSConnection::SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFor //t38_options->remote_ip = switch_core_session_strdup(session, mediaFormat.something); //t38_options->remote_port = mediaFormat.something; - switch_channel_set_private(m_fsChannel, "t38_options", t38_options); + switch_channel_set_private(m_fsChannel, varname, t38_options); + PTRACE(3, "mod_opal\tSet " << varname); } void FSConnection::OnSwitchedT38(bool toT38, bool success) { - PTRACE(3, "mod_opal\tMode change request to fax succeeded"); - OnSwitchingT38(toT38 && success); + if (!toT38 || !success || !IndicateSwitchedT38()) + AbortT38(); } void FSConnection::OnSwitchingT38(bool toT38) { - if (!toT38) { - switch_channel_set_private(m_fsChannel, "t38_options", NULL); - switch_channel_clear_app_flag_key("T38", m_fsChannel, CF_APP_T38); - switch_channel_clear_app_flag_key("T38", m_fsChannel, CF_APP_T38_REQ); - switch_channel_set_app_flag_key("T38", m_fsChannel, CF_APP_T38_FAIL); - return; - } + if (!toT38 || !IndicateSwitchedT38()) + AbortT38(); +} + +void FSConnection::AbortT38() +{ + PTRACE(3, "mod_opal\tMode change request to T.38 failed"); + switch_channel_set_private(m_fsChannel, "t38_options", NULL); + switch_channel_clear_app_flag_key("T38", m_fsChannel, CF_APP_T38); + switch_channel_clear_app_flag_key("T38", m_fsChannel, CF_APP_T38_REQ); + switch_channel_set_app_flag_key("T38", m_fsChannel, CF_APP_T38_FAIL); +} + + +bool FSConnection::IndicateSwitchedT38() +{ PSafePtr other = GetOtherPartyConnection(); if (other == NULL) - return; + return false; OpalMediaFormatList otherFormats = other->GetMediaFormats(); OpalMediaFormatList::const_iterator t38 = otherFormats.FindFormat(OpalT38); if (t38 == otherFormats.end()) - return; + return false; - SetT38OptionsFromMediaFormat(*t38); + SetT38OptionsFromMediaFormat(*t38, "t38_options"); switch_channel_set_variable(m_fsChannel, "has_t38", "true"); switch_channel_set_app_flag_key("T38", m_fsChannel, CF_APP_T38); - switch_channel_execute_on(m_fsChannel, "opal_execute_on_image"); - switch_channel_api_on(m_fsChannel, "opal_api_on_image"); - - return; + switch_channel_execute_on(m_fsChannel, "opal_execute_on_t38"); + switch_channel_api_on(m_fsChannel, "opal_api_on_t38"); + PTRACE(3, "mod_opal\tMode change request to T.38 succeeded"); + return true; } #endif // HAVE_T38 @@ -1103,13 +1118,21 @@ switch_status_t FSConnection::state_change() switch_status_t FSConnection::read_audio_frame(switch_frame_t **frame, switch_io_flag_t flags, int stream_id) { - return read_frame(OpalMediaType::Audio(), frame, flags); + // Avoid all the channel closing and re-opening upsetting FS + if (ownerCall.IsSwitchingT38()) + return SWITCH_STATUS_SUCCESS; + + return read_frame((flags&SFF_UDPTL_PACKET) ? OpalMediaType::Fax() : OpalMediaType::Audio(), frame, flags); } switch_status_t FSConnection::write_audio_frame(switch_frame_t *frame, switch_io_flag_t flags, int stream_id) { - return write_frame(OpalMediaType::Audio(), frame, flags); + // Avoid all the channel closing and re-opening upsetting FS + if (ownerCall.IsSwitchingT38()) + return SWITCH_STATUS_SUCCESS; + + return write_frame((flags&SFF_UDPTL_PACKET) ? OpalMediaType::Fax() : OpalMediaType::Audio(), frame, flags); } @@ -1128,14 +1151,22 @@ switch_status_t FSConnection::write_video_frame(switch_frame_t *frame, switch_io switch_status_t FSConnection::read_frame(const OpalMediaType & mediaType, switch_frame_t **frame, switch_io_flag_t flags) { PSafePtr stream = PSafePtrCast (GetMediaStream(mediaType, false)); - return stream != NULL ? stream->read_frame(frame, flags) : SWITCH_STATUS_FALSE; + if (stream != NULL) + return stream->read_frame(frame, flags); + + PTRACE(2, "mod_opal\tNo stream for read of " << mediaType); + return SWITCH_STATUS_SUCCESS; } switch_status_t FSConnection::write_frame(const OpalMediaType & mediaType, const switch_frame_t *frame, switch_io_flag_t flags) { PSafePtr stream = PSafePtrCast(GetMediaStream(mediaType, true)); - return stream != NULL ? stream->write_frame(frame, flags) : SWITCH_STATUS_FALSE; + if (stream != NULL) + return stream->write_frame(frame, flags); + + PTRACE(2, "mod_opal\tNo stream for write of " << mediaType); + return SWITCH_STATUS_SUCCESS; } @@ -1266,17 +1297,17 @@ PBoolean FSMediaStream::RequiresPatchThread(OpalMediaStream *) const int FSMediaStream::StartReadWrite(PatchPtr & mediaPatch) const { if (!IsOpen()) { - PTRACE(2, "mod_opal\tNot open!"); + PTRACE(1, "mod_opal\tNot open!"); return -1; } if (!m_switchCodec) { - PTRACE(2, "mod_opal\tNo codec!"); + PTRACE(1, "mod_opal\tNo codec!"); return -1; } if (!m_connection.IsChannelReady()) { - PTRACE(2, "mod_opal\tChannel not ready!"); + PTRACE(1, "mod_opal\tChannel not ready!"); return -1; } @@ -1285,7 +1316,7 @@ int FSMediaStream::StartReadWrite(PatchPtr & mediaPatch) const if (mediaPatch == NULL) { /*There is a race here... sometimes we make it here and m_mediaPatch is NULL if we wait it shows up in 1ms, maybe there is a better way to wait. */ - PTRACE(3, "mod_opal\tPatch not ready!"); + PTRACE(2, "mod_opal\tPatch not ready!"); return 1; } @@ -1310,6 +1341,7 @@ switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag m_readRTP.SetTimestamp(m_readFrame.timestamp + m_switchCodec->implementation->samples_per_packet); if (!mediaPatch->GetSource().ReadPacket(m_readRTP)) { + PTRACE(1, "mod_opal\tread_frame: no source data!"); return SWITCH_STATUS_FALSE; } } @@ -1320,7 +1352,7 @@ switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag if (m_switchCodec != NULL) { if (!switch_core_codec_ready(m_switchCodec)) { - PTRACE(2, "mod_opal\tread_frame: codec not ready!"); + PTRACE(1, "mod_opal\tread_frame: codec not ready!"); return SWITCH_STATUS_FALSE; } } @@ -1385,7 +1417,11 @@ switch_status_t FSMediaStream::write_frame(const switch_frame_t *frame, switch_i timestamp += m_switchCodec->implementation->samples_per_packet; rtp.SetTimestamp(timestamp); - return mediaPatch->PushFrame(rtp) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; + if (mediaPatch->PushFrame(rtp)) + return SWITCH_STATUS_SUCCESS; + + PTRACE(1, "mod_opal\tread_frame: push failed!"); + return SWITCH_STATUS_FALSE; } diff --git a/src/mod/endpoints/mod_opal/mod_opal.h b/src/mod/endpoints/mod_opal/mod_opal.h index 25dbef45d6..2dd627a822 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.h +++ b/src/mod/endpoints/mod_opal/mod_opal.h @@ -305,7 +305,9 @@ class FSConnection : public OpalLocalConnection void SetCodecs(); bool WaitForMedia(); #if HAVE_T38 - void SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFormat); + void SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFormat, const char * varname); + bool IndicateSwitchedT38(); + void AbortT38(); #endif switch_status_t read_frame(const OpalMediaType & mediaType, switch_frame_t **frame, switch_io_flag_t flags); From f8143eedd4abd7f745dabb7eb8189c74069403e1 Mon Sep 17 00:00:00 2001 From: Robert Jongbloed Date: Thu, 6 Sep 2012 12:45:25 +1000 Subject: [PATCH 812/822] Fixed outbound H.323 calls correctly marking call as answered when fast connect used. Fixed correct media "frames/packet" for G.711, default to 20ms worth. --- src/mod/endpoints/mod_opal/mod_opal.cpp | 35 +++++++++++++++++++++---- src/mod/endpoints/mod_opal/mod_opal.h | 1 + 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/mod/endpoints/mod_opal/mod_opal.cpp b/src/mod/endpoints/mod_opal/mod_opal.cpp index a6a6f44dfd..e9beeb93fe 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.cpp +++ b/src/mod/endpoints/mod_opal/mod_opal.cpp @@ -310,9 +310,12 @@ bool FSManager::Initialise(switch_loadable_module_interface_t *iface) OpalMediaFormatList allCodecs = OpalMediaFormat::GetAllRegisteredMediaFormats(); for (OpalMediaFormatList::iterator it = allCodecs.begin(); it != allCodecs.end(); ++it) { if (it->GetMediaType() == OpalMediaType::Audio()) { - it->SetOptionInteger(OpalAudioFormat::RxFramesPerPacketOption(), 1); - it->SetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption(), 1); + int ms_per_frame = it->GetFrameTime()/it->GetTimeUnits(); + int frames_in_20_ms = (ms_per_frame+19)/ms_per_frame; + it->SetOptionInteger(OpalAudioFormat::RxFramesPerPacketOption(), frames_in_20_ms); + it->SetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption(), frames_in_20_ms); OpalMediaFormat::SetRegisteredMediaFormat(*it); + PTRACE(4, "mod_opal\tSet " << *it << " to " << frames_in_20_ms << "frames/packet"); } } #endif // IMPLEMENT_MULTI_FAME_AUDIO @@ -602,6 +605,20 @@ bool FSConnection::OnIncoming() } +void FSConnection::OnEstablished() +{ + OpalLocalConnection::OnEstablished(); + + if (switch_channel_direction(m_fsChannel) == SWITCH_CALL_DIRECTION_OUTBOUND) { + PTRACE(4, "mod_opal\tOnEstablished for outbound call, checking for media"); + if (GetMediaStream(OpalMediaType::Audio(), true) != NULL && GetMediaStream(OpalMediaType::Audio(), false) != NULL) { + PTRACE(3, "mod_opal\tOnEstablished for outbound call, making call answered"); + switch_channel_mark_answered(m_fsChannel); + } + } +} + + void FSConnection::OnReleased() { m_rxAudioOpened.Signal(); // Just in case @@ -786,18 +803,26 @@ void FSConnection::OnPatchMediaStream(PBoolean isSource, OpalMediaPatch & patch) return; if (switch_channel_direction(m_fsChannel) == SWITCH_CALL_DIRECTION_INBOUND) { + PTRACE(4, "mod_opal\tOnPatchMediaStream for inbound call, flagging media opened"); if (isSource) m_rxAudioOpened.Signal(); else m_txAudioOpened.Signal(); } - else if (GetMediaStream(OpalMediaType::Audio(), !isSource) != NULL) { + else { + PTRACE(4, "mod_opal\tOnPatchMediaStream for outbound call, checking media"); + if (GetMediaStream(OpalMediaType::Audio(), !isSource) != NULL) { // Have open media in both directions. - if (IsEstablished()) + if (IsEstablished()) { + PTRACE(3, "mod_opal\tOnPatchMediaStream for outbound call, making call answered"); switch_channel_mark_answered(m_fsChannel); - else if (!IsReleased()) + } + else if (!IsReleased()) { + PTRACE(3, "mod_opal\tOnPatchMediaStream for outbound call, making call pre-answered"); switch_channel_mark_pre_answered(m_fsChannel); } + } + } } diff --git a/src/mod/endpoints/mod_opal/mod_opal.h b/src/mod/endpoints/mod_opal/mod_opal.h index 2dd627a822..db66c32381 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.h +++ b/src/mod/endpoints/mod_opal/mod_opal.h @@ -248,6 +248,7 @@ class FSConnection : public OpalLocalConnection virtual bool OnOutgoingSetUp(); virtual bool OnIncoming(); + virtual void OnEstablished(); virtual void OnReleased(); virtual PBoolean SetAlerting(const PString & calleeName, PBoolean withMedia); virtual OpalMediaStream *CreateMediaStream(const OpalMediaFormat &, unsigned, PBoolean); From 7ffa4eece455e2a4df93eff7e5899897019998ae Mon Sep 17 00:00:00 2001 From: Robert Jongbloed Date: Thu, 6 Sep 2012 14:25:24 +1000 Subject: [PATCH 813/822] Allow SVN trunk to be used in buildopal.sh script. --- build/buildopal.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/build/buildopal.sh b/build/buildopal.sh index a838d9c339..6009f1048d 100755 --- a/build/buildopal.sh +++ b/build/buildopal.sh @@ -22,14 +22,17 @@ export PKG_CONFIG_PATH=$INSTALLDIR/lib/pkgconfig # Version and patch for PTLib and OPAL. These are almost always in lock -# step so shoud be the same unless you really know ehat you are doing! +# step so should be the same unless you really know what you are doing! # The PATCH should be set to a specific"snapshot release" when things -# are nice and stable. +# are nice and stable. But right now comment them out for using trunk. -VERSION=10 -#PATCH=6 +#VERSION=10 +#PATCH=7 -if [ -z "$PATCH" ]; then +if [ -z "$VERSION" ]; then + PTLIB_VERSION=trunk + OPAL_VERSION=trunk +elif [ -z "$PATCH" ]; then PTLIB_VERSION=branches/v2_$VERSION OPAL_VERSION=branches/v3_$VERSION else From 45609f89867467696def92fa52fc6fcb12326dd7 Mon Sep 17 00:00:00 2001 From: Robert Jongbloed Date: Thu, 6 Sep 2012 14:26:19 +1000 Subject: [PATCH 814/822] Fix direction flag for outbound H.323 calls, all sorts of consequences there. --- src/mod/endpoints/mod_opal/mod_opal.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_opal/mod_opal.cpp b/src/mod/endpoints/mod_opal/mod_opal.cpp index e9beeb93fe..15d86f6106 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.cpp +++ b/src/mod/endpoints/mod_opal/mod_opal.cpp @@ -494,7 +494,7 @@ FSConnection::FSConnection(OpalCall & call, params->fail_cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; if ((m_fsSession = switch_core_session_request(endpoint.GetManager().GetSwitchInterface(), - SWITCH_CALL_DIRECTION_INBOUND, params->flags, params->pool)) == NULL) { + SWITCH_CALL_DIRECTION_OUTBOUND, params->flags, params->pool)) == NULL) { PTRACE(1, "mod_opal\tCannot create session for outgoing call."); return; } From 75c3e360093386e600868bbf240968a7134f3559 Mon Sep 17 00:00:00 2001 From: Robert Jongbloed Date: Tue, 11 Sep 2012 10:37:05 +1000 Subject: [PATCH 815/822] Added XML config for H.323 User Input Indication (DTMF) mode --- conf/curl/autoload_configs/opal.conf.xml | 30 +++++++++------- conf/insideout/autoload_configs/opal.conf.xml | 30 +++++++++------- conf/vanilla/autoload_configs/opal.conf.xml | 35 ++++++++++--------- src/mod/endpoints/mod_opal/mod_opal.cpp | 11 ++++++ 4 files changed, 65 insertions(+), 41 deletions(-) diff --git a/conf/curl/autoload_configs/opal.conf.xml b/conf/curl/autoload_configs/opal.conf.xml index c0844214a3..280b69304e 100644 --- a/conf/curl/autoload_configs/opal.conf.xml +++ b/conf/curl/autoload_configs/opal.conf.xml @@ -1,15 +1,21 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/conf/insideout/autoload_configs/opal.conf.xml b/conf/insideout/autoload_configs/opal.conf.xml index c0844214a3..280b69304e 100644 --- a/conf/insideout/autoload_configs/opal.conf.xml +++ b/conf/insideout/autoload_configs/opal.conf.xml @@ -1,15 +1,21 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/conf/vanilla/autoload_configs/opal.conf.xml b/conf/vanilla/autoload_configs/opal.conf.xml index 2378d1d6e0..280b69304e 100644 --- a/conf/vanilla/autoload_configs/opal.conf.xml +++ b/conf/vanilla/autoload_configs/opal.conf.xml @@ -1,20 +1,21 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/src/mod/endpoints/mod_opal/mod_opal.cpp b/src/mod/endpoints/mod_opal/mod_opal.cpp index 15d86f6106..1becc0dcc2 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.cpp +++ b/src/mod/endpoints/mod_opal/mod_opal.cpp @@ -364,6 +364,15 @@ switch_status_t FSManager::ReadConfig(int reload) m_codecPrefs = val; } else if (var == "disable-transcoding") { m_disableTranscoding = switch_true(val); + } else if (var == "dtmf-type") { + if (val == "string") + m_h323ep->SetSendUserInputMode(OpalConnection::SendUserInputAsString); + else if (val == "signal") + m_h323ep->SetSendUserInputMode(OpalConnection::SendUserInputAsTone); + else if (val == "rfc2833") + m_h323ep->SetSendUserInputMode(OpalConnection::SendUserInputAsRFC2833); + else if (val == "in-band") + m_h323ep->SetSendUserInputMode(OpalConnection::SendUserInputInBand); } else if (var == "jitter-size") { SetAudioJitterDelay(val.AsUnsigned(), val.Mid(val.Find(',')+1).AsUnsigned()); // In milliseconds } else if (var == "gk-address") { @@ -649,6 +658,7 @@ PBoolean FSConnection::SendUserInputTone(char tone, unsigned duration) return false; switch_dtmf_t dtmf = { tone, duration }; + PTRACE(4, "mod_opal\tSending DTMF to FS: tone=" << tone << ", duration=" << duration); return switch_channel_queue_dtmf(m_fsChannel, &dtmf) == SWITCH_STATUS_SUCCESS; } @@ -925,6 +935,7 @@ switch_status_t FSConnection::kill_channel(int sig) switch_status_t FSConnection::send_dtmf(const switch_dtmf_t *dtmf) { + PTRACE(4, "mod_opal\tReceived DTMF from FS: tone=" << dtmf->digit << ", duration=" << dtmf->duration); OnUserInputTone(dtmf->digit, dtmf->duration); return SWITCH_STATUS_SUCCESS; } From babe1cdb89f052f8a0ad9f959e2b8b65d009f848 Mon Sep 17 00:00:00 2001 From: Robert Jongbloed Date: Thu, 13 Sep 2012 14:55:04 +1000 Subject: [PATCH 816/822] Fixed numerous issues with T.38 support on mod_opal, now WORKS! Added tracing for error conditions in mod_spandsp --- .../mod_spandsp/mod_spandsp_fax.c | 15 +- src/mod/endpoints/mod_opal/mod_opal.cpp | 169 +++++++++++------- src/mod/endpoints/mod_opal/mod_opal.h | 3 + 3 files changed, 122 insertions(+), 65 deletions(-) diff --git a/src/mod/applications/mod_spandsp/mod_spandsp_fax.c b/src/mod/applications/mod_spandsp/mod_spandsp_fax.c index f48bed8ad5..7e07a4e7db 100644 --- a/src/mod/applications/mod_spandsp/mod_spandsp_fax.c +++ b/src/mod/applications/mod_spandsp/mod_spandsp_fax.c @@ -1590,21 +1590,29 @@ static switch_status_t t38_gateway_on_soft_execute(switch_core_session_t *sessio while (switch_channel_ready(channel) && switch_channel_up(other_channel) && !switch_channel_test_app_flag_key("T38", channel, CF_APP_T38)) { status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0); - if (!SWITCH_READ_ACCEPTABLE(status) || pvt->done) { + if (pvt->done) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Premature exit while negotiating\n", switch_channel_get_name(channel)); /* Our duty is over */ goto end_unlock; } + if (!SWITCH_READ_ACCEPTABLE(status)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Read failed, status=%u\n", switch_channel_get_name(channel), status); + goto end_unlock; + } + if (switch_test_flag(read_frame, SFF_CNG)) { continue; } if (switch_core_session_write_frame(other_session, read_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Write failed\n", switch_channel_get_name(channel)); goto end_unlock; } } if (!(switch_channel_ready(channel) && switch_channel_up(other_channel))) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Channel not ready\n", switch_channel_get_name(channel)); goto end_unlock; } @@ -1645,6 +1653,7 @@ static switch_status_t t38_gateway_on_soft_execute(switch_core_session_t *sessio status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0); if (!SWITCH_READ_ACCEPTABLE(status) || pvt->done) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Premature exit while negotiating\n", switch_channel_get_name(channel), status); /* Our duty is over */ goto end_unlock; } @@ -1654,7 +1663,9 @@ static switch_status_t t38_gateway_on_soft_execute(switch_core_session_t *sessio } if (switch_test_flag(read_frame, SFF_UDPTL_PACKET)) { - udptl_rx_packet(pvt->udptl_state, read_frame->packet, read_frame->packetlen); + if (udptl_rx_packet(pvt->udptl_state, read_frame->packet, read_frame->packetlen) < 0) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Error decoding UDPTL (%u bytes)\n", switch_channel_get_name(channel), read_frame->packetlen); + } } } diff --git a/src/mod/endpoints/mod_opal/mod_opal.cpp b/src/mod/endpoints/mod_opal/mod_opal.cpp index 1becc0dcc2..fa7b64229d 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.cpp +++ b/src/mod/endpoints/mod_opal/mod_opal.cpp @@ -26,6 +26,9 @@ #include "mod_opal.h" #include #include +#if PTLIB_CHECK_VERSION(2,11,1) +#include +#endif #include #include @@ -57,6 +60,7 @@ static FSProcess *opal_process = NULL; static PConstString const ModuleName("opal"); static char const ConfigFile[] = "opal.conf"; +#define FS_PREFIX "fs" static switch_io_routines_t opalfs_io_routines = { @@ -287,9 +291,9 @@ bool FSManager::Initialise(switch_loadable_module_interface_t *iface) } } - AddRouteEntry("h323:.* = local:"); // config option for direct routing - AddRouteEntry("iax2:.* = local:"); // config option for direct routing - AddRouteEntry("local:.* = h323:"); // config option for direct routing + AddRouteEntry("h323:.* = "FS_PREFIX":"); // config option for direct routing + AddRouteEntry("iax2:.* = "FS_PREFIX":"); // config option for direct routing + AddRouteEntry(FS_PREFIX":.* = h323:"); // config option for direct routing // Make sure all known codecs are instantiated, // these are ones we know how to translate into H.323 capabilities @@ -320,6 +324,10 @@ bool FSManager::Initialise(switch_loadable_module_interface_t *iface) } #endif // IMPLEMENT_MULTI_FAME_AUDIO + OpalMediaFormat t38 = OpalT38; + t38.SetOptionBoolean("UDPTL-Raw-Mode", true); + OpalMediaFormat::SetRegisteredMediaFormat(t38); + if (!m_gkAddress.IsEmpty()) { if (m_h323ep->UseGatekeeper(m_gkAddress, m_gkIdentifer, m_gkInterface)) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Started gatekeeper: %s\n", @@ -453,7 +461,7 @@ static switch_call_cause_t create_outgoing_channel(switch_core_session_t *sess params.cancel_cause = cancel_cause; params.fail_cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT; - if (opal_process->GetManager().SetUpCall("local:", outbound_profile->destination_number, ¶ms) != NULL) + if (opal_process->GetManager().SetUpCall(FS_PREFIX":", outbound_profile->destination_number, ¶ms) != NULL) return SWITCH_CAUSE_SUCCESS; if (*new_session != NULL) @@ -465,7 +473,7 @@ static switch_call_cause_t create_outgoing_channel(switch_core_session_t *sess /////////////////////////////////////////////////////////////////////// FSEndPoint::FSEndPoint(FSManager & manager) - : OpalLocalEndPoint(manager) + : OpalLocalEndPoint(manager, FS_PREFIX) , m_manager(manager) { PTRACE(4, "mod_opal\tFSEndPoint created."); @@ -490,6 +498,7 @@ FSConnection::FSConnection(OpalCall & call, , m_fsSession(NULL) , m_fsChannel(NULL) , m_flushAudio(false) + , m_udptl(false) { memset(&m_read_timer, 0, sizeof(m_read_timer)); memset(&m_read_codec, 0, sizeof(m_read_codec)); @@ -497,6 +506,8 @@ FSConnection::FSConnection(OpalCall & call, memset(&m_vid_read_timer, 0, sizeof(m_vid_read_timer)); memset(&m_vid_read_codec, 0, sizeof(m_vid_read_codec)); memset(&m_vid_write_codec, 0, sizeof(m_vid_write_codec)); + memset(&m_dummy_frame, 0, sizeof(m_dummy_frame)); + m_dummy_frame.flags = SFF_CNG; if (params != NULL) { // If we fail, this is the cause @@ -871,7 +882,7 @@ switch_status_t FSConnection::on_destroy() { PTRACE(3, "mod_opal\tFS on_destroy for connection " << *this); - m_fsChannel = NULL; // Will be destoyed by FS, so don't use it any more. + m_fsChannel = NULL; // Will be destroyed by FS, so don't use it any more. switch_core_codec_destroy(&m_read_codec); switch_core_codec_destroy(&m_write_codec); @@ -909,7 +920,7 @@ switch_status_t FSConnection::on_exchange_media() switch_status_t FSConnection::on_soft_execute() { - PTRACE(4, "mod_opal\tTransmit on connection " << *this); + PTRACE(4, "mod_opal\tSoft execute on connection " << *this); return SWITCH_STATUS_SUCCESS; } @@ -920,12 +931,15 @@ switch_status_t FSConnection::kill_channel(int sig) case SWITCH_SIG_KILL: m_rxAudioOpened.Signal(); m_txAudioOpened.Signal(); - PTRACE(4, "mod_opal\tSignal channel KILL on connection " << *this); + PTRACE(4, "mod_opal\tSignal KILL received on connection " << *this); break; - case SWITCH_SIG_XFER: + case SWITCH_SIG_BREAK: + PTRACE(4, "mod_opal\tSignal BREAK received on connection " << *this); + break; + default: - PTRACE(4, "mod_opal\tSignal channel " << sig << " on connection " << *this); + PTRACE(4, "mod_opal\tSignal " << sig << " received on connection " << *this); break; } @@ -1030,6 +1044,7 @@ switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg case SWITCH_MESSAGE_INDICATE_UDPTL_MODE: PTRACE(2, "mod_opal\tSWITCH_MESSAGE_INDICATE_UDPTL_MODE"); + m_udptl = true; break; #endif // HAVE_T38 @@ -1092,15 +1107,23 @@ void FSConnection::SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFor void FSConnection::OnSwitchedT38(bool toT38, bool success) { - if (!toT38 || !success || !IndicateSwitchedT38()) - AbortT38(); + if (toT38 && success && IndicateSwitchedT38()) { + PTRACE(3, "mod_opal\tMode change request to T.38 succeeded"); + } + else { + AbortT38(); + } } void FSConnection::OnSwitchingT38(bool toT38) { - if (!toT38 || !IndicateSwitchedT38()) + if (toT38 && IndicateSwitchedT38()) { + PTRACE(3, "mod_opal\tMode change request to T.38 started"); + } + else { AbortT38(); + } } @@ -1117,13 +1140,17 @@ void FSConnection::AbortT38() bool FSConnection::IndicateSwitchedT38() { PSafePtr other = GetOtherPartyConnection(); - if (other == NULL) + if (other == NULL) { + PTRACE(3, "mod_opal\tCan't change to T.38, no other connection"); return false; + } OpalMediaFormatList otherFormats = other->GetMediaFormats(); OpalMediaFormatList::const_iterator t38 = otherFormats.FindFormat(OpalT38); - if (t38 == otherFormats.end()) + if (t38 == otherFormats.end()) { + PTRACE(3, "mod_opal\tCan't change to T.38, no remote capability"); return false; + } SetT38OptionsFromMediaFormat(*t38, "t38_options"); @@ -1132,7 +1159,6 @@ bool FSConnection::IndicateSwitchedT38() switch_channel_execute_on(m_fsChannel, "opal_execute_on_t38"); switch_channel_api_on(m_fsChannel, "opal_api_on_t38"); - PTRACE(3, "mod_opal\tMode change request to T.38 succeeded"); return true; } #endif // HAVE_T38 @@ -1154,21 +1180,13 @@ switch_status_t FSConnection::state_change() switch_status_t FSConnection::read_audio_frame(switch_frame_t **frame, switch_io_flag_t flags, int stream_id) { - // Avoid all the channel closing and re-opening upsetting FS - if (ownerCall.IsSwitchingT38()) - return SWITCH_STATUS_SUCCESS; - - return read_frame((flags&SFF_UDPTL_PACKET) ? OpalMediaType::Fax() : OpalMediaType::Audio(), frame, flags); + return read_frame(m_udptl ? OpalMediaType::Fax() : OpalMediaType::Audio(), frame, flags); } switch_status_t FSConnection::write_audio_frame(switch_frame_t *frame, switch_io_flag_t flags, int stream_id) { - // Avoid all the channel closing and re-opening upsetting FS - if (ownerCall.IsSwitchingT38()) - return SWITCH_STATUS_SUCCESS; - - return write_frame((flags&SFF_UDPTL_PACKET) ? OpalMediaType::Fax() : OpalMediaType::Audio(), frame, flags); + return write_frame(m_udptl ? OpalMediaType::Fax() : OpalMediaType::Audio(), frame, flags); } @@ -1186,17 +1204,26 @@ switch_status_t FSConnection::write_video_frame(switch_frame_t *frame, switch_io switch_status_t FSConnection::read_frame(const OpalMediaType & mediaType, switch_frame_t **frame, switch_io_flag_t flags) { - PSafePtr stream = PSafePtrCast (GetMediaStream(mediaType, false)); - if (stream != NULL) - return stream->read_frame(frame, flags); + if (!ownerCall.IsSwitchingT38()) { + PSafePtr stream = PSafePtrCast (GetMediaStream(mediaType, false)); + if (stream != NULL) + return stream->read_frame(frame, flags); - PTRACE(2, "mod_opal\tNo stream for read of " << mediaType); + PTRACE(2, "mod_opal\tNo stream for read of " << mediaType); + } + + // Avoid all the channel closing and re-opening, especially with faxa switching, upsetting FS + *frame = &m_dummy_frame; return SWITCH_STATUS_SUCCESS; } switch_status_t FSConnection::write_frame(const OpalMediaType & mediaType, const switch_frame_t *frame, switch_io_flag_t flags) { + // Avoid all the channel closing and re-opening, especially with faxa switching, upsetting FS + if (ownerCall.IsSwitchingT38()) + return SWITCH_STATUS_SUCCESS; + PSafePtr stream = PSafePtrCast(GetMediaStream(mediaType, true)); if (stream != NULL) return stream->write_frame(frame, flags); @@ -1211,6 +1238,8 @@ switch_status_t FSConnection::write_frame(const OpalMediaType & mediaType, const FSMediaStream::FSMediaStream(FSConnection & conn, const OpalMediaFormat & mediaFormat, unsigned sessionID, bool isSource) : OpalMediaStream(conn, mediaFormat, sessionID, isSource) , m_connection(conn) + , m_switchTimer(NULL) + , m_switchCodec(NULL) , m_readRTP(0, SWITCH_RECOMMENDED_BUFFER_SIZE) { memset(&m_readFrame, 0, sizeof(m_readFrame)); @@ -1236,8 +1265,8 @@ PBoolean FSMediaStream::Open() isAudio = false; #if HAVE_T38 else if (mediaType == OpalMediaType::Fax()) { - m_readFrame.flags = SFF_UDPTL_PACKET; - return true; + m_readFrame.flags = SFF_UDPTL_PACKET|SFF_PROXY_PACKET; + return OpalMediaStream::Open(); } #endif else { @@ -1337,11 +1366,6 @@ int FSMediaStream::StartReadWrite(PatchPtr & mediaPatch) const return -1; } - if (!m_switchCodec) { - PTRACE(1, "mod_opal\tNo codec!"); - return -1; - } - if (!m_connection.IsChannelReady()) { PTRACE(1, "mod_opal\tChannel not ready!"); return -1; @@ -1362,6 +1386,9 @@ int FSMediaStream::StartReadWrite(PatchPtr & mediaPatch) const switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag_t flags) { + *frame = &m_readFrame; + m_readFrame.flags |= SFF_CNG; + PatchPtr mediaPatch; switch (StartReadWrite(mediaPatch)) { case -1 : @@ -1374,7 +1401,9 @@ switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag mediaPatch->GetSource().EnableJitterBuffer(); // This flushes data and resets jitter buffer m_readRTP.SetPayloadSize(0); } else { - m_readRTP.SetTimestamp(m_readFrame.timestamp + m_switchCodec->implementation->samples_per_packet); + if (m_switchCodec != NULL) { + m_readRTP.SetTimestamp(m_readFrame.timestamp + m_switchCodec->implementation->samples_per_packet); + } if (!mediaPatch->GetSource().ReadPacket(m_readRTP)) { PTRACE(1, "mod_opal\tread_frame: no source data!"); @@ -1393,13 +1422,19 @@ switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag } } - *frame = &m_readFrame; - - m_readFrame.packet = m_readRTP.GetPointer(); - m_readFrame.packetlen = m_readRTP.GetHeaderSize() + m_readFrame.datalen; - - if ((m_readFrame.flags & (SFF_UDPTL_PACKET|SFF_RAW_RTP)) != 0) + if (switch_test_flag(&m_readFrame, SFF_UDPTL_PACKET)) { + m_readFrame.flags &= ~SFF_CNG; + m_readFrame.packet = m_readRTP.GetPayloadPtr(); + m_readFrame.packetlen = m_readRTP.GetPayloadSize(); return SWITCH_STATUS_SUCCESS; + } + + if (switch_test_flag(&m_readFrame, SFF_RAW_RTP)) { + m_readFrame.flags &= ~SFF_CNG; + m_readFrame.packet = m_readRTP.GetPointer(); + m_readFrame.packetlen = m_readRTP.GetHeaderSize() + m_readRTP.GetPayloadSize(); + return SWITCH_STATUS_SUCCESS; + } #if IMPLEMENT_MULTI_FAME_AUDIO // Repackage frames in incoming packet to agree with what FS expects. @@ -1415,9 +1450,12 @@ switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag m_readFrame.ssrc = m_readRTP.GetSyncSource(); m_readFrame.m = m_readRTP.GetMarker() ? SWITCH_TRUE : SWITCH_FALSE; m_readFrame.payload = (switch_payload_t)m_readRTP.GetPayloadType(); - m_readFrame.flags = m_readFrame.datalen == 0 || - m_readFrame.payload == RTP_DataFrame::CN || - m_readFrame.payload == RTP_DataFrame::Cisco_CN ? SFF_CNG : 0; + + if (m_readFrame.datalen > 0 && + m_readFrame.payload != RTP_DataFrame::CN && + m_readFrame.payload != RTP_DataFrame::Cisco_CN) { + m_readFrame.flags &= ~SFF_CNG; + } return SWITCH_STATUS_SUCCESS; } @@ -1433,25 +1471,30 @@ switch_status_t FSMediaStream::write_frame(const switch_frame_t *frame, switch_i return SWITCH_STATUS_SUCCESS; } - if ((frame->flags & (SFF_UDPTL_PACKET|SFF_RAW_RTP)) != 0) { - RTP_DataFrame rtp((const BYTE *)frame->packet, frame->packetlen, false); - return mediaPatch->PushFrame(rtp) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; + RTP_DataFrame rtp; + if (switch_test_flag(frame, SFF_RAW_RTP)) { + rtp = RTP_DataFrame((const BYTE *)frame->packet, frame->packetlen, false); } + else if (switch_test_flag(frame, SFF_UDPTL_PACKET)) { + rtp.SetPayloadSize(frame->packetlen); + memcpy(rtp.GetPayloadPtr(), frame->packet, frame->packetlen); + } + else { + rtp.SetPayloadSize(frame->datalen); + memcpy(rtp.GetPayloadPtr(), frame->data, frame->datalen); - RTP_DataFrame rtp(frame->datalen); - memcpy(rtp.GetPayloadPtr(), frame->data, frame->datalen); + rtp.SetPayloadType(mediaFormat.GetPayloadType()); - rtp.SetPayloadType(mediaFormat.GetPayloadType()); - - /* Not sure what FS is going to give us! - Suspect it depends on the mod on the other side sending it. */ - if (frame->timestamp != 0) - timestamp = frame->timestamp; - else if (frame->samples != 0) - timestamp += frame->samples; - else - timestamp += m_switchCodec->implementation->samples_per_packet; - rtp.SetTimestamp(timestamp); + /* Not sure what FS is going to give us! + Suspect it depends on the mod on the other side sending it. */ + if (frame->timestamp != 0) + timestamp = frame->timestamp; + else if (frame->samples != 0) + timestamp += frame->samples; + else if (m_switchCodec != NULL) + timestamp += m_switchCodec->implementation->samples_per_packet; + rtp.SetTimestamp(timestamp); + } if (mediaPatch->PushFrame(rtp)) return SWITCH_STATUS_SUCCESS; diff --git a/src/mod/endpoints/mod_opal/mod_opal.h b/src/mod/endpoints/mod_opal/mod_opal.h index db66c32381..da2ea1fa5b 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.h +++ b/src/mod/endpoints/mod_opal/mod_opal.h @@ -331,7 +331,10 @@ class FSConnection : public OpalLocalConnection switch_codec_t m_vid_read_codec; switch_codec_t m_vid_write_codec; + switch_frame_t m_dummy_frame; + bool m_flushAudio; + bool m_udptl; friend PBoolean FSMediaStream::Open(); }; From c979f1b8f3b6e52739429ac8c00ed775cc388b03 Mon Sep 17 00:00:00 2001 From: Robert Jongbloed Date: Tue, 18 Sep 2012 13:39:13 +1000 Subject: [PATCH 817/822] Small tweak for media I/O in proxy mode, don't silence frame just because no codec. Needed for H.323 fax. --- src/switch_core_io.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/switch_core_io.c b/src/switch_core_io.c index 0a3db343ed..8978306adb 100644 --- a/src/switch_core_io.c +++ b/src/switch_core_io.c @@ -729,7 +729,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi even_more_done: - if (!*frame || !(*frame)->codec || !(*frame)->codec->implementation || !switch_core_codec_ready((*frame)->codec)) { + if (!*frame || + (!switch_test_flag(*frame, SFF_PROXY_PACKET) && + (!(*frame)->codec || !(*frame)->codec->implementation || !switch_core_codec_ready((*frame)->codec)))) { *frame = &runtime.dummy_cng_frame; } From 96da5216340a3b2660d01be40b2c0260be63b099 Mon Sep 17 00:00:00 2001 From: Robert Jongbloed Date: Wed, 19 Sep 2012 10:37:06 +1000 Subject: [PATCH 818/822] Fixed mod_opal shut down of media streams (in particular UDPTL) on KILL from fs core. --- src/mod/endpoints/mod_opal/mod_opal.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_opal/mod_opal.cpp b/src/mod/endpoints/mod_opal/mod_opal.cpp index fa7b64229d..53c504b059 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.cpp +++ b/src/mod/endpoints/mod_opal/mod_opal.cpp @@ -929,9 +929,10 @@ switch_status_t FSConnection::kill_channel(int sig) { switch (sig) { case SWITCH_SIG_KILL: + PTRACE(4, "mod_opal\tSignal KILL received on connection " << *this); m_rxAudioOpened.Signal(); m_txAudioOpened.Signal(); - PTRACE(4, "mod_opal\tSignal KILL received on connection " << *this); + CloseMediaStreams(); break; case SWITCH_SIG_BREAK: From b39232c7ffa83ce7bfb211bd1d7636263ee46ad7 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Tue, 18 Sep 2012 22:10:47 -0500 Subject: [PATCH 819/822] trivial compiler warning --- src/switch_xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/switch_xml.c b/src/switch_xml.c index d4b26e0b9d..a4da3ca6cf 100644 --- a/src/switch_xml.c +++ b/src/switch_xml.c @@ -1446,7 +1446,7 @@ static int preprocess(const char *cwd, const char *file, FILE *write_fd, int rle } if ((cmd = strstr(bp, ""))) { From 2aa5b78514d13f5ac28a7a32bed907803853cc1c Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 18 Sep 2012 23:11:05 -0400 Subject: [PATCH 820/822] freetdm: Fix for DL re-establishment on NFAS --- .../ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c | 4 ++-- .../ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h | 5 ++++- .../ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c | 4 ++++ .../ftmod_sangoma_isdn_stack_out.c | 10 +++++++--- .../ftmod_sangoma_isdn_support.c | 14 ++++++++++++++ 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c index 2483c01094..a3b640f90a 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c @@ -1,3 +1,4 @@ + /* * Copyright (c) 2010, Sangoma Technologies * David Yat Sin @@ -40,7 +41,6 @@ #include #endif - static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj); static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span); static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span); @@ -696,7 +696,7 @@ static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdm ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Requesting Q.921 Line activation\n"); sngisdn_set_flag(sngisdn_info, FLAG_ACTIVATING); - sngisdn_snd_info_req(ftdmchan); + sngisdn_snd_dl_req(ftdmchan); ftdm_sched_timer(signal_data->sched, "timer_t3", signal_data->timer_t3*1000, sngisdn_t3_timeout, (void*) sngisdn_info, NULL); } else { sngisdn_snd_setup(ftdmchan); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h index cc4d1108f6..47efd941ec 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h @@ -289,6 +289,8 @@ typedef struct sngisdn_span_data { uint8_t cid_name_method; uint8_t send_cid_name; uint8_t send_connect_ack; + uint8_t dl_request_pending; /* Whether we have a DL request pending */ + int32_t timer_t301; int32_t timer_t302; @@ -441,7 +443,7 @@ void sngisdn_snd_release(ftdm_channel_t *ftdmchan, uint8_t glare); void sngisdn_snd_reset(ftdm_channel_t *ftdmchan); void sngisdn_snd_con_complete(ftdm_channel_t *ftdmchan); void sngisdn_snd_fac_req(ftdm_channel_t *ftdmchan); -void sngisdn_snd_info_req(ftdm_channel_t *ftdmchan); +void sngisdn_snd_dl_req(ftdm_channel_t *ftdmchan); void sngisdn_snd_status_enq(ftdm_channel_t *ftdmchan); void sngisdn_snd_restart(ftdm_channel_t *ftdmchan); void sngisdn_snd_data(ftdm_channel_t *dchan, uint8_t *data, ftdm_size_t len); @@ -581,6 +583,7 @@ void sngisdn_delayed_disconnect(void* p_sngisdn_info); void sngisdn_facility_timeout(void* p_sngisdn_info); void sngisdn_t3_timeout(void* p_sngisdn_info); void sngisdn_restart_timeout(void* p_signal_data); +void sngisdn_delayed_dl_req(void* p_signal_data); /* Stack management functions */ ftdm_status_t sngisdn_start_gen_cfg(void); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c index 754aff1187..9cd1a2f42c 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c @@ -70,6 +70,10 @@ void sngisdn_set_span_sig_status(ftdm_span_t *span, ftdm_signaling_status_t stat ((sngisdn_span_data_t*)span->signal_data)->sigstatus = status; + if (status == FTDM_SIG_STATE_UP) { + ((sngisdn_span_data_t*)span->signal_data)->dl_request_pending = 0; + } + chaniter = ftdm_span_get_chan_iterator(span, NULL); for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { sngisdn_set_chan_sig_status(((ftdm_channel_t*)ftdm_iterator_current(curr)), status); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c index 9055f7006b..02b1ce0be8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c @@ -307,7 +307,7 @@ void sngisdn_snd_fac_req(ftdm_channel_t *ftdmchan) } /* This is used to request Q.921 to initiate link establishment */ -void sngisdn_snd_info_req(ftdm_channel_t *ftdmchan) +void sngisdn_snd_dl_req(ftdm_channel_t *ftdmchan) { CnStEvnt cnStEvnt; @@ -482,6 +482,9 @@ void sngisdn_snd_data(ftdm_channel_t *dchan, uint8_t *data, ftdm_size_t len) len, sizeof(l1_frame.data)); return; } + if (len <= 2) { + return; + } memset(&l1_frame, 0, sizeof(l1_frame)); l1_frame.len = len; @@ -545,8 +548,9 @@ void sngisdn_snd_event(sngisdn_span_data_t *signal_data, ftdm_oob_event_t event) case FTDM_OOB_ALARM_CLEAR: l1_event.type = SNG_L1EVENT_ALARM_OFF; sng_isdn_event_ind(signal_data->link_id, &l1_event); - - sngisdn_snd_info_req(signal_data->ftdm_span->channels[1]); + + ftdm_sched_timer(signal_data->sched, "delayed_dl_req", 8000, sngisdn_delayed_dl_req, (void*) signal_data, NULL); + signal_data->dl_request_pending = 1; break; case FTDM_OOB_ALARM_TRAP: l1_event.type = SNG_L1EVENT_ALARM_ON; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c index 8232d1969f..246c3190ee 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c @@ -1211,6 +1211,20 @@ void sngisdn_t3_timeout(void *p_sngisdn_info) ftdm_mutex_unlock(ftdmchan->mutex); } + +void sngisdn_delayed_dl_req(void *p_signal_data) +{ + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t *)p_signal_data; + ftdm_span_t *span = signal_data->ftdm_span; + + if (!signal_data->dl_request_pending) { + return; + } + signal_data->dl_request_pending = 0; + sngisdn_snd_dl_req(span->channels[1]); + return; +} + void sngisdn_restart_timeout(void *p_signal_data) { sngisdn_span_data_t *signal_data = (sngisdn_span_data_t *)p_signal_data; From aa8f48c7e30ebff345bef14cbde6afb6827453a6 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 18 Sep 2012 23:14:27 -0400 Subject: [PATCH 821/822] Fix for compile warning --- .../src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c index 8356932ce6..801febda14 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c @@ -333,7 +333,7 @@ done: ftdm_safe_free(name); ftdm_safe_free(dchan_span); ftdm_safe_free(backup_span); - return FTDM_SUCCESS; + return ret; } static ftdm_status_t parse_early_media(const char* opt, ftdm_span_t *span) From 2123927af751148381fce4091007a640c47d0cf1 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Wed, 19 Sep 2012 08:52:58 -0500 Subject: [PATCH 822/822] spandsp fix argument issue on irc --- src/mod/applications/mod_spandsp/mod_spandsp_fax.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/applications/mod_spandsp/mod_spandsp_fax.c b/src/mod/applications/mod_spandsp/mod_spandsp_fax.c index 7e07a4e7db..51dcc6ba57 100644 --- a/src/mod/applications/mod_spandsp/mod_spandsp_fax.c +++ b/src/mod/applications/mod_spandsp/mod_spandsp_fax.c @@ -1653,7 +1653,7 @@ static switch_status_t t38_gateway_on_soft_execute(switch_core_session_t *sessio status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0); if (!SWITCH_READ_ACCEPTABLE(status) || pvt->done) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Premature exit while negotiating\n", switch_channel_get_name(channel), status); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Premature exit while negotiating (%i)\n", switch_channel_get_name(channel), status); /* Our duty is over */ goto end_unlock; }

    16S{hm;p%a1-l`Z9M&#S}_}N_J@X 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�Us24I@gs#1dizgqDU8B`8Xa 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 Ma^;vT8}G>f0{`7vfB*mh literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test95.ans b/libs/libtpl-1.5/tests/test95.ans new file mode 100755 index 0000000000..9ce47203a9 --- /dev/null +++ b/libs/libtpl-1.5/tests/test95.ans @@ -0,0 +1,3 @@ +s1 NULL +s2 +s3 hello diff --git a/libs/libtpl-1.5/tests/test95.c b/libs/libtpl-1.5/tests/test95.c new file mode 100755 index 0000000000..d7b0f6dfb8 --- /dev/null +++ b/libs/libtpl-1.5/tests/test95.c @@ -0,0 +1,23 @@ +#include "tpl.h" +#include + +const char *filename="/tmp/test95.tpl"; +int main() { + tpl_node *tn; + char *s1 = NULL, *s2 = "", *s3 = "hello"; + tn = tpl_map("sss", &s1, &s2, &s3); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,filename); + tpl_free(tn); + + s1 = s2 = s3 = (char*)0x1; /* overwritten below */ + tn = tpl_map("sss", &s1, &s2, &s3); + tpl_load(tn,TPL_FILE,filename); + tpl_unpack(tn,0); + tpl_free(tn); + printf("s1 %s\n", s1?s1:"NULL"); + printf("s2 %s\n", s2?s2:"NULL"); + printf("s3 %s\n", s3?s3:"NULL"); + return(0); +} + diff --git a/libs/libtpl-1.5/tests/test95.out b/libs/libtpl-1.5/tests/test95.out new file mode 100644 index 0000000000..9ce47203a9 --- /dev/null +++ b/libs/libtpl-1.5/tests/test95.out @@ -0,0 +1,3 @@ +s1 NULL +s2 +s3 hello diff --git a/libs/libtpl-1.5/tests/test96 b/libs/libtpl-1.5/tests/test96 new file mode 100755 index 0000000000000000000000000000000000000000..b336b843d0239ecfc97de23d021db332222b1d4b GIT binary patch literal 128320 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

    9`qb%s#zsC>gImD!^pHhUcH|21A_;vzpyll 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�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 +#include +#include + +#define S1_LEN 6 +#define S2_LEN 4 + +struct has_strings { + char a; + char s1[S1_LEN]; + char s2[S2_LEN]; +}; + +int main(int argc,char*argv[]) { + tpl_node *tn; + struct has_strings hs; + + tn = tpl_map("c#c#", hs.s1, S1_LEN, hs.s2, S2_LEN); + tpl_load(tn,TPL_FILE,"/tmp/test57.tpl"); + tpl_unpack(tn,0); + tpl_free(tn); + + printf("hs.s1 length: %d\n", (int)strlen(hs.s1)); + printf("hs.s1: %s\n", hs.s1); + printf("hs.s2 length: %d\n", (int)strlen(hs.s2)); + printf("hs.s2: %s\n", hs.s2); + + return(0); +} diff --git a/libs/libtpl-1.5/tests/test58.out b/libs/libtpl-1.5/tests/test58.out new file mode 100644 index 0000000000..f235fc6acf --- /dev/null +++ b/libs/libtpl-1.5/tests/test58.out @@ -0,0 +1,4 @@ +hs.s1 length: 5 +hs.s1: draco +hs.s2 length: 2 +hs.s2: po diff --git a/libs/libtpl-1.5/tests/test59 b/libs/libtpl-1.5/tests/test59 new file mode 100755 index 0000000000000000000000000000000000000000..4cd0109de8a922de503d042251909053e7a3136c GIT binary patch literal 128791 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test59.ans b/libs/libtpl-1.5/tests/test59.ans new file mode 100755 index 0000000000..11e5c1cc54 --- /dev/null +++ b/libs/libtpl-1.5/tests/test59.ans @@ -0,0 +1,6 @@ +hs2.a: t +hs2.s1 length: 5 +hs2.s1: draco +hs2.b: h +hs2.s2 length: 2 +hs2.s2: po diff --git a/libs/libtpl-1.5/tests/test59.c b/libs/libtpl-1.5/tests/test59.c new file mode 100755 index 0000000000..bd394f1ed0 --- /dev/null +++ b/libs/libtpl-1.5/tests/test59.c @@ -0,0 +1,47 @@ +#include "tpl.h" +#include +#include +#include + +#define S1_LEN 6 +#define S2_LEN 4 + +struct has_strings { + char a; + char s1[S1_LEN]; + char b; + char s2[S2_LEN]; +}; + +int main(int argc,char*argv[]) { + tpl_node *tn; + struct has_strings hs,hs2; + void *img; + size_t sz; + + strncpy(hs.s1, "draco",S1_LEN); + strncpy(hs.s2, "po",S2_LEN); + hs.a = 't'; + hs.b = 'h'; + + tn = tpl_map("cc#cc#", &hs.a, hs.s1, S1_LEN, &hs.b, hs.s2, S2_LEN); + tpl_pack(tn,0); + tpl_dump(tn,TPL_MEM,&img,&sz); + tpl_free(tn); + + /* unpack */ + + tn = tpl_map("cc#cc#", &hs2.a, hs2.s1, S1_LEN, &hs2.b, hs2.s2, S2_LEN); + tpl_load(tn,TPL_MEM,img,sz); + tpl_unpack(tn,0); + tpl_free(tn); + free(img); + + printf("hs2.a: %c\n", hs2.a); + printf("hs2.s1 length: %d\n", (int)strlen(hs2.s1)); + printf("hs2.s1: %s\n", hs2.s1); + printf("hs2.b: %c\n", hs2.b); + printf("hs2.s2 length: %d\n", (int)strlen(hs2.s2)); + printf("hs2.s2: %s\n", hs2.s2); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test59.out b/libs/libtpl-1.5/tests/test59.out new file mode 100644 index 0000000000..11e5c1cc54 --- /dev/null +++ b/libs/libtpl-1.5/tests/test59.out @@ -0,0 +1,6 @@ +hs2.a: t +hs2.s1 length: 5 +hs2.s1: draco +hs2.b: h +hs2.s2 length: 2 +hs2.s2: po diff --git a/libs/libtpl-1.5/tests/test6 b/libs/libtpl-1.5/tests/test6 new file mode 100755 index 0000000000000000000000000000000000000000..0760800d62cbad441fd26773e579afd460dcabd8 GIT binary patch literal 127790 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 +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + char *s,*t; + void *addr; + int sz; + + tn = tpl_map("s",&s); + s = "hello, world!"; + tpl_pack(tn,0); + tpl_dump(tn,TPL_MEM,&addr,&sz); + tpl_free(tn); + + tn = tpl_map("s",&t); + tpl_load(tn,TPL_MEM,addr,sz); + tpl_unpack(tn,0); + printf("t is %s\n", t); + free(t); + tpl_free(tn); + free(addr); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test6.out b/libs/libtpl-1.5/tests/test6.out new file mode 100644 index 0000000000..e972e9fa3c --- /dev/null +++ b/libs/libtpl-1.5/tests/test6.out @@ -0,0 +1 @@ +t is hello, world! diff --git a/libs/libtpl-1.5/tests/test60 b/libs/libtpl-1.5/tests/test60 new file mode 100755 index 0000000000000000000000000000000000000000..dac0a361e571893bdbf734fbc0c801ed493e57ac GIT binary patch literal 127551 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%0Ak)-< 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 +#include "tpl.h" + +int main() { + tpl_node *tn; + int i; + + tn = tpl_map("A(i)",&i); + for(i=0;i<10;i++) tpl_pack(tn,1); + tpl_dump(tn,TPL_FILE,"/tmp/test60.tpl"); + + /* test load-after-pack: implicit free via tpl_free_keep_map() */ + tpl_load(tn,TPL_FILE,"/tmp/test60.tpl"); + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test60.out b/libs/libtpl-1.5/tests/test60.out new file mode 100644 index 0000000000..903c08cf1f --- /dev/null +++ b/libs/libtpl-1.5/tests/test60.out @@ -0,0 +1,10 @@ +i is 0 +i is 1 +i is 2 +i is 3 +i is 4 +i is 5 +i is 6 +i is 7 +i is 8 +i is 9 diff --git a/libs/libtpl-1.5/tests/test61 b/libs/libtpl-1.5/tests/test61 new file mode 100755 index 0000000000000000000000000000000000000000..a0683bbb1ebe7e682fbb086df04be159854d72d8 GIT binary patch literal 127511 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%0An42 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 +#include "tpl.h" + +int main() { + tpl_node *tn; + int i; + + tn = tpl_map("A(i)",&i); + tpl_load(tn,TPL_FILE,"test61_0.tpl"); + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + + /* test load-then-load: implicit free via tpl_free_keep_map */ + tpl_load(tn, TPL_FILE,"test61_1.tpl"); + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test61.out b/libs/libtpl-1.5/tests/test61.out new file mode 100644 index 0000000000..71580ae9a7 --- /dev/null +++ b/libs/libtpl-1.5/tests/test61.out @@ -0,0 +1,20 @@ +i is 0 +i is 1 +i is 2 +i is 3 +i is 4 +i is 5 +i is 6 +i is 7 +i is 8 +i is 9 +i is 10 +i is 11 +i is 12 +i is 13 +i is 14 +i is 15 +i is 16 +i is 17 +i is 18 +i is 19 diff --git a/libs/libtpl-1.5/tests/test61_0.tpl b/libs/libtpl-1.5/tests/test61_0.tpl new file mode 100755 index 0000000000000000000000000000000000000000..d928efa399903c22fe4ecff4dd6d8ccf129971a1 GIT binary patch literal 57 ucmXRZ$YEq)V6b%5$kYVV3|t@r2ta~NK+FupEI`Z(#B4y!4#XTl%n1O8Rsy{M literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test61_1.tpl b/libs/libtpl-1.5/tests/test61_1.tpl new file mode 100755 index 0000000000000000000000000000000000000000..0ee24de064d4c34defe08ae32c6799160496aaff GIT binary patch literal 57 tcmXRZ$YEq)V6b%5$kYVV3|vsm4WxO1m=}oofS4bM1%Ox(h=qVy7yypK10eta literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test62 b/libs/libtpl-1.5/tests/test62 new file mode 100755 index 0000000000000000000000000000000000000000..4e07a1c99e91646effc408a6243e37c00eafa7f8 GIT binary patch literal 127759 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 DMUH~k literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test62.ans b/libs/libtpl-1.5/tests/test62.ans new file mode 100755 index 0000000000..61287c2b8e --- /dev/null +++ b/libs/libtpl-1.5/tests/test62.ans @@ -0,0 +1,20 @@ +i is 0 +i is 1 +i is 2 +i is 3 +i is 4 +i is 5 +i is 6 +i is 7 +i is 8 +i is 9 +i is 0 +i is -1 +i is -2 +i is -3 +i is -4 +i is -5 +i is -6 +i is -7 +i is -8 +i is -9 diff --git a/libs/libtpl-1.5/tests/test62.c b/libs/libtpl-1.5/tests/test62.c new file mode 100755 index 0000000000..18797ee1ef --- /dev/null +++ b/libs/libtpl-1.5/tests/test62.c @@ -0,0 +1,20 @@ +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + int i; + + tn = tpl_map("A(i)",&i); + tpl_load(tn,TPL_FILE,"test62_0.tpl"); + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + + /* test load-then-pack (then load): implicit free via tpl_free_keep_map */ + for(i=0;i>-10;i--) tpl_pack(tn,1); + tpl_dump(tn, TPL_FILE,"/tmp/test62_1.tpl"); + tpl_load(tn,TPL_FILE,"/tmp/test62_1.tpl"); + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test62.out b/libs/libtpl-1.5/tests/test62.out new file mode 100644 index 0000000000..61287c2b8e --- /dev/null +++ b/libs/libtpl-1.5/tests/test62.out @@ -0,0 +1,20 @@ +i is 0 +i is 1 +i is 2 +i is 3 +i is 4 +i is 5 +i is 6 +i is 7 +i is 8 +i is 9 +i is 0 +i is -1 +i is -2 +i is -3 +i is -4 +i is -5 +i is -6 +i is -7 +i is -8 +i is -9 diff --git a/libs/libtpl-1.5/tests/test62_0.tpl b/libs/libtpl-1.5/tests/test62_0.tpl new file mode 100755 index 0000000000000000000000000000000000000000..d928efa399903c22fe4ecff4dd6d8ccf129971a1 GIT binary patch literal 57 ucmXRZ$YEq)V6b%5$kYVV3|t@r2ta~NK+FupEI`Z(#B4y!4#XTl%n1O8Rsy{M literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test63 b/libs/libtpl-1.5/tests/test63 new file mode 100755 index 0000000000000000000000000000000000000000..4f1ab3897a61fbb9b3ea4512d9094d7e42c4d6c7 GIT binary patch literal 127575 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 +#include "tpl.h" + +int main() { + tpl_node *tn; + int i; + + tn = tpl_map("A(i)",&i); + for(i=0;i<10;i++) tpl_pack(tn,1); + + /* test pack-then-unpack without dump/load; implicit dump/load*/ + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + + /* implicit conversion back to output tpl (discards previous data in tpl */ + for(i=0;i>-10;i--) tpl_pack(tn,1); + + /* one more implicit conversion */ + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test63.out b/libs/libtpl-1.5/tests/test63.out new file mode 100644 index 0000000000..61287c2b8e --- /dev/null +++ b/libs/libtpl-1.5/tests/test63.out @@ -0,0 +1,20 @@ +i is 0 +i is 1 +i is 2 +i is 3 +i is 4 +i is 5 +i is 6 +i is 7 +i is 8 +i is 9 +i is 0 +i is -1 +i is -2 +i is -3 +i is -4 +i is -5 +i is -6 +i is -7 +i is -8 +i is -9 diff --git a/libs/libtpl-1.5/tests/test64 b/libs/libtpl-1.5/tests/test64 new file mode 100755 index 0000000000000000000000000000000000000000..b6f9024c34332dc23abe3c9532c1a25634d81be1 GIT binary patch literal 129327 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⪼FXTQa0_tgGke+dYFTvlOfUY`=ca;s%Ng zoc(3^Q?w(#2rn@n)UKWf%~-sxkGr3~%o35GZeLhCpY5d7OO=T|nAf1U=2GS_Yvhg{VHK@@6X2DkbKox{zq0tBSLf zuENyR&6#(qFamQrVQ2+&7B8N2i!>-0*TM#jXeB;H&9YiFI>(a~Li7TIV2ygi!uhpx zLXC^7QYxiNe5xG(ZWxWV_2{L)uxpQKG*(%bJx!?qYgUY=F@zSvz<~2CTr_8X70tb} zYF<@?r|c@eM~WZPSI@I2(ww=Lwa&f8GpD}ZQ;Dzt&lUPrYU^r;)z>w^0G3pF@CE5Q7 zIt}g=LTk9K=_K`Wn)0L(U>wBI%vm&F$jmB~n=?Z6(6e9;+$p?Bb@jr^g;mhB<;@_o zZ9ZM6gKZAvW7z?RcP{?5hnqQdEz?es@bq-F=h|UHxZ3(g4jAd+IRC4mbe&?-Lnr+~ z%D4-w$1MK0v7;V1r~bq2!9PXO5R$e}JEv~o+By23xmBoGW#t!!8mell-MBf!(DCw^_$EyF^Go&8G z1pH}}LXZ(?W@N%XII5q3_CPt)yQ+$l~9WfBJNz#4nI(@fqmO zRKHE~KWnhXfA)E&PY=uTVp+c7ztEqFPsIp}f1yl&U0}go(__Oee49+WmjC|+UOP<*rgm-oncDkr_%oH;eE+wpGUW9AxB0gfTjfuT zK7Be{;wxlYd09u6))@df)XHpF3|nefpalEc_)hee1u_cja@lq*uE9ESB&>q&Qwv8f99E zRK+j9&8Fekk6-?bw-TiqDe(cBPLt_PNFDg)zk9|sAHV!r*jU+69hi0#@u@%lDFxmk zt9SHUL}k-Uif^n*lVY`UTh#T!iPkk;S} zhX;|4{Sx>LMR^tJJfyv4=ha)UR@7x~^{j3g+Ils^P5c1-9{fcjalWKsa(a42@uH0M zvmd~xKdEScjyvqQBFE>v!ja>iki)Uz59^oWcP;d{i-<`%yGYKu*W=d*eQrPs{C?GO zf3jW>sO9)=L%A@F@j33h9A!CqcRI)Ccv@WJa|+g_mF5(#N%!XzhckjXO@8O!)vTQ2 z2|0!SoC45{&&flb@i|%`8+<75tN5*dFp=QP{mSKG*Ba;KoF~+E4#(209Bm@0Fpl{B z8ovu3N+fP4ooE-l?sS$V+w~{gEzPNLJcU+)IbExYG7l_D!RLP12Oq~-{5tzl#(oHX zrR+y(PLt}m>a+}vY-f-iocM1|l|gjs>M^uafy0ycso+kzJN1<+_j=WNCE5ME#y-@@@)=k(`z*0@S@3c?&O$BkJz1;F_2(JAfJ zdkyL};pp=HQ}up2`3>m(K?nnmUGzSwli%~;=f=~CTckX9Im9@2@)PzW^d5xa=AGVr z48f3g+zs>9hvyr#Tl;4yGG5@<0`HgYtaFs+ZU@xvx!2h0EKf-Up8>)^)r&W(7 zCv7bPe)q$_Un2S4Njq+#A6&ob&xWP5MaucaAG`dUlZiUQvmHMC?fkcQ7o=G*hlD@(JA6!(Eb$ky zj1<(i-#m%Wm8qRzYKot=x6Br)t&0sZLp|{aOSkyxD^o4QCvrA^Z@LBBau-UvOqts4 zpG;W&*(mAp&`I>q*6U#j*T`~N{r`Ak|9iq+8~Q|!>rt7eXZZw4ADNyf(~D&~QKr*n zS}oHhGF>CnpUU(RnLaJkoicq(rk}|4s7%wdW&1KcPo@{kbfQeB%d}diOJur6razTw z*Zy{e+jOfv``=mh$$Iv`$9lNS{FpRh!e~zc{x#wuo>9Xu8D69e1xL%4G{Jj=WFUgJ zuB`#K=r78&r-0qS?5j^h3{(*)C4aRVR;2F5pIdEnI!ztNo3MGup0Ox$Y8ex)grDAb zIx-Fda=FrQII5&+Hv&knWVxEocl4dA_6QSK#uXNFqo|a|+g(mAtr|!nh;!WqG>VGVcMxb#gNPI`WmQ9)z6gZw07jtt9A@pgZep z)N`dtFfZ#G)OV#z(38cDgDXRV1z9B|)+AV%HHxK~5-iSofMAvceOYuGu5J=EvP#Lh zy96t;90YSDI5X>B61&wGfOX{0&N_#zda5r9a6uL)wX3&k^{758kHmQr3}rpX(*9}- z5=Z{BtVal*qh5~0nct*ly+rDP>M{YZR56n#F&Kz~xmx5b#aS$HHz?PwMf+8jQa4Z zuCYRTXMUTSHHPJvsUIV8=5JS(?5iozgIYT(T18g_i3H#N30y4zXJOq|E;{>*s;`k8lrCs<#5QvY!80pvk$cZ*b z0iAxG#aGGv8D>WM^;Ci*U(1{Xg7h0K$emN$xJXIA(W1=D?9Z}UMS{|k`Ac${O@@yA zg3L_xBYlnq6=seAjSUrNt|K(pD)T{BuA~l5^Ylt)wWY|q)2p|El_kx5t9>P>;Z`Mm z0eb||6bI?j7ycY%+EZveOHGd>pMxixikiVJCWWPh?*IrTWGcEk74_8~?1b%9zVGe> zWc{cUA&EOwtEfGhG`T8S_z_`SVWEnkWN(#m7e=j3ZLv+ctjTd0yP-} zg1xL+)JvV5>C|OQO3&{l<+GstI!USY%@*pT@ zpF)YQOp=9}nToQ~ZtGlI#NLx-aXyNBULyg@`*4zx(z8zDDer4GkMkuDq0kESTpg|S z{IR5@Ry&d$q*k9yDdha>R2<~oDGRC9k*5?|S{-JK-19X_NhvQ+QYt;;5>F{Z7CzH? zS}7H2XH@O4k{l>y*S4}GB~|;}DU=ZTELlj^?zbBpcZyn+p81l9((+5jR;QJoqa>cv zo{ca}7-@NG<=INlt0fWDIocxXG}1*Wg)_Pqu9AgR=c-c*tu9`lRHrE^Dd5kNluFM> zC7uFqvGAGBt^&RwiKxj~vT~;;JDYh`Qc{y?_&sItKa_>kB;OJf%BZzP?A;-YX{5PF zBtUtkGQn^?=6;{u3RdflbknNZhu>_;_`L=6RTtAMHVUVrQk!|d1#Lg2uR0TH`cknt zs8m+oME;>yLgAAvyu~VHd!2>-l>X`u$a9IRvh$(@HFPwdeydf3T}`dgSDnNf%dArN zwX;+?OYM;jfp1c+Qg$_uvh`C2s28A`_Nl6>c@I%8Asi584@h$&VVyplVD+Y2AtWM5-je{fHONwg1+tyIJ3J+(CE&9GrPM4E4nk_%+8VE z%TP9-5GFZ_f%czwIhE)_d0^TRjWt!-5GFZ=SeWsodIWdf3+0}0?zJ_ z5Ijd+fP?{OcLto<16A^H=C4+}4`#VX%>r)*oZT64W_#8C0$!_jC!g$L>dS(Dz1p1t zXZFP^hr*eEzuKJvXZ9r$-k^48z?oev;f-o{2AtU?5`IGMK8o;Yb(pBX8TDah*<*$D z3^=teF3u5-~E$t}UCn(AOgQXlzOAvb8(hUPn zzFVB8(I|wmvR~2^(=?igz!uurUP?w7%-44tuES2XJ}|p(g*+_d6!;B9?RL?x1f*$u zG5}rrlz`mY*(|&4_X5h(4uNqu-&z3;(0JI>%}+CQ&Elp$Z(lquXO{2(Z8ijMP`J9;)C<9$qjGSxV z1x6c1{?}P!sc77VY4I-*5EV&iYLvlC}}NG z)>+jQF=Xm`ximl&w&`H|>e@C+#hU89#AeW6=Bf9sL%vt_JVm|VHiEH~{AX5Unszmz z2P_$}Zn2j7^XX*pQ)GSWuZ|(F-Afhx+UD?A*4e-Us^=0yzhOJ*Sg-0uAw_-AlCVHq z1cOr_Di<9q)TXf04_RD_A^o2zGMiB!zK<>9x*=kq-;F?}UX_ZvQLLF#jlZ|5xv;Ri z65!K2PknnK2(?|Pr0%skplAo!;5#g!XqQv8f7qQ%(>_E+$E7e6_1%j>l6yDnW;#{U ztNe!|`e5go=_J@^A#-fB?@fxDC31P9?hQ4v6Dqg?zJRb?h=km^+KM$X!v&5M3nV~4pz9RN~QlGG^ut^S5^KC zC6uyzI;HG)frTfwFAXdwy$#ts5hz=Ea?u5G-+4 z_QfL5kLC!7?e^i6MPBF?jOJN6h*%{8zP?MD6J5@|nboGHTbkJdM%3>#(Gw~_=Gdoc zqEG$mtO_K}<43F1>FM+*ed*cM8A9Z|VoGM^shF9TVuV!Jh@R#>LkgKcjwQg(3vF0< zp^a;WHqc}0C--UU>U}wk-%?m8?0pye%yvEy!h|ED!W`F@K8N)K&-M$ zRLQ%YWv@%ZYoT>@oYNxQK|*wYoMokRFx$pCg;7uwOJL)EL7F#%>KQKx zEcHxqQazR_lsbheh~Y1Dis2V#F;Vaq9iHU0hu^SfgV0F8$^I+-ugB=C6CJ8Lsk=2& z6CE_rymzV2Ne*^7?<#i0u<~b9nt-68j8-o19bzxHD7sMxR-QH|b9AX!IN0V{eZ`qn zl|z_|k~@cH+)t{hj#5BP{Y2lz)aWl1f(_VedVx1pE28^32>Y239vBMQZzF_6o_Gu{ z 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 Q6}(xd7pxqU)#4rbU;beR +#include +#include +#include "tpl.h" + +struct str_holder { + char str[10]; +}; + + +/* the real purpose of this test is to be run under dbx "check -all" + * mode to ensure the level-0 data are freed when replaced (i.e. the + * level 0 nodes are packed more than once, this is an edge case but + * the required behavior is to free the previously-packed data when + * packing the new replacement data). Do the test for s,S,and B types. + */ +int main() { + tpl_node *tn; + char *s; + struct str_holder sh; + tpl_bin bin; + + /* test a replacement pack (s type) of the level 0 node */ + tn = tpl_map("s", &s); + s = "alpha"; + tpl_pack(tn,0); /* copies alpha */ + s = "beta"; + tpl_pack(tn,0); /* should free alpha, copy beta */ + tpl_dump(tn,TPL_FILE,"/tmp/test64_0.tpl"); + tpl_free(tn); + + /* print out dumped tpl */ + s = ""; + tn = tpl_map("s", &s); + tpl_load(tn,TPL_FILE,"/tmp/test64_0.tpl"); + tpl_unpack(tn,0); + printf("s is %s\n", s); + free(s); + tpl_free(tn); + + /* test replacement pack (S type) of the level 0 node */ + tn = tpl_map("c#", sh.str, 10); + strncpy(sh.str, "gamma", 10); + tpl_pack(tn,0); /* copies gamma */ + strncpy(sh.str, "delta", 10); + tpl_pack(tn,0); /* should free gamma, copy delta */ + tpl_dump(tn,TPL_FILE,"/tmp/test64_1.tpl"); + tpl_free(tn); + + /* print out dumped tpl */ + sh.str[0] = '\0'; + tn = tpl_map("c#", sh.str, 10); + tpl_load(tn,TPL_FILE,"/tmp/test64_1.tpl"); + tpl_unpack(tn,0); + printf("sh.str is %s\n", sh.str); + tpl_free(tn); + + /* test replacement pack (B type) of the level 0 node */ + tn = tpl_map("B", &bin); + bin.addr = "epsilon"; + bin.sz = strlen("epsilon")+1; + tpl_pack(tn,0); /* copies epsilon */ + bin.addr = "zeta"; + bin.sz = strlen("zeta")+1; + tpl_pack(tn,0); /* should free epsilon, copy zeta */ + tpl_dump(tn,TPL_FILE,"/tmp/test64_2.tpl"); + tpl_free(tn); + + /* print out dumped tpl */ + bin.addr = ""; + bin.sz = 1; + tn = tpl_map("B", &bin); + tpl_load(tn,TPL_FILE,"/tmp/test64_2.tpl"); + tpl_unpack(tn,0); + printf("bin.addr is %s, size %d\n", (char*)(bin.addr), bin.sz); + free(bin.addr); + tpl_free(tn); + return(0); + +} diff --git a/libs/libtpl-1.5/tests/test64.out b/libs/libtpl-1.5/tests/test64.out new file mode 100644 index 0000000000..c9162af499 --- /dev/null +++ b/libs/libtpl-1.5/tests/test64.out @@ -0,0 +1,3 @@ +s is beta +sh.str is delta +bin.addr is zeta, size 5 diff --git a/libs/libtpl-1.5/tests/test65 b/libs/libtpl-1.5/tests/test65 new file mode 100755 index 0000000000000000000000000000000000000000..d7405b16b7a0a83be214f84c5e2f655626b25606 GIT binary patch literal 127219 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

    j(CIee7%c12nzVPxF1oj?hMusj< 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 +#include "tpl.h" + +int main() { + tpl_node *tn; + int j; + + tn = tpl_map("A(A(i))",&j); + tpl_load(tn,TPL_FILE, "/tmp/test37.tpl"); + + while (tpl_unpack(tn,1) > 0) { + printf("unpacking index 1:\n"); + while (tpl_unpack(tn,2) > 0) { + printf(" unpacking index 2: j is %d\n", j); + } + } + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test38.out b/libs/libtpl-1.5/tests/test38.out new file mode 100644 index 0000000000..157e8cf278 --- /dev/null +++ b/libs/libtpl-1.5/tests/test38.out @@ -0,0 +1,9 @@ +unpacking index 1: + unpacking index 2: j is 2 + unpacking index 2: j is 4 + unpacking index 2: j is 8 + unpacking index 2: j is 16 +unpacking index 1: + unpacking index 2: j is 3 + unpacking index 2: j is 9 + unpacking index 2: j is 27 diff --git a/libs/libtpl-1.5/tests/test39 b/libs/libtpl-1.5/tests/test39 new file mode 100755 index 0000000000000000000000000000000000000000..bac2966b50f49c428ce1065b7805b64f62ae1ff7 GIT binary patch literal 127639 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 +#include "tpl.h" + +extern tpl_hook_t tpl_hook; + +int main() { + tpl_node *tn; + int i, rc; + + tpl_hook.oops = printf; + + tn = tpl_map("A(i)",&i); + rc = tpl_load(tn,TPL_FILE,"test39.tpl"); + printf("load %s (rc=%d)\n", (rc >= 0 ? "ok" : "failed"), rc); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test39.out b/libs/libtpl-1.5/tests/test39.out new file mode 100644 index 0000000000..b2035d820c --- /dev/null +++ b/libs/libtpl-1.5/tests/test39.out @@ -0,0 +1,2 @@ +test39.tpl: not a valid tpl file +load failed (rc=-1) diff --git a/libs/libtpl-1.5/tests/test39.tpl b/libs/libtpl-1.5/tests/test39.tpl new file mode 100755 index 0000000000000000000000000000000000000000..37d246ccf5180e82d20b4c4dcc7f6f92a25d01a8 GIT binary patch literal 57 ucmXRZ$YEt*V6b%5$kYVV3|t@r2pEBw35c12m<5PIir9dd9f&!Am=geqE&{;- literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test4 b/libs/libtpl-1.5/tests/test4 new file mode 100755 index 0000000000000000000000000000000000000000..1699276b8536313196985675ef13978032756a5a GIT binary patch literal 127830 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“veZV1x>2s%99e*^PCY5aQyeWssQWDLHZH&vwM9i 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test4.ans b/libs/libtpl-1.5/tests/test4.ans new file mode 100755 index 0000000000..c35e4ea80e --- /dev/null +++ b/libs/libtpl-1.5/tests/test4.ans @@ -0,0 +1,10 @@ +j is 0 +j is 1 +j is 2 +j is 3 +j is 4 +j is 5 +j is 6 +j is 7 +j is 8 +j is 9 diff --git a/libs/libtpl-1.5/tests/test4.c b/libs/libtpl-1.5/tests/test4.c new file mode 100755 index 0000000000..9972d13f9c --- /dev/null +++ b/libs/libtpl-1.5/tests/test4.c @@ -0,0 +1,22 @@ +#include +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + int i,j=-1; + void *addr; + int sz; + + tn = tpl_map("A(i)",&i); + for(i=0;i<10;i++) tpl_pack(tn,1); + tpl_dump(tn,TPL_MEM,&addr,&sz); + tpl_free(tn); + + tn = tpl_map("A(i)",&j); + tpl_load(tn,TPL_MEM,addr,sz); + while (tpl_unpack(tn,1) > 0) printf("j is %d\n", j); + tpl_free(tn); + free(addr); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test4.out b/libs/libtpl-1.5/tests/test4.out new file mode 100644 index 0000000000..c35e4ea80e --- /dev/null +++ b/libs/libtpl-1.5/tests/test4.out @@ -0,0 +1,10 @@ +j is 0 +j is 1 +j is 2 +j is 3 +j is 4 +j is 5 +j is 6 +j is 7 +j is 8 +j is 9 diff --git a/libs/libtpl-1.5/tests/test40 b/libs/libtpl-1.5/tests/test40 new file mode 100755 index 0000000000000000000000000000000000000000..62dcb1a51ee6d98fc614e0999d6c27c98a88ee08 GIT binary patch literal 126507 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test40.ans b/libs/libtpl-1.5/tests/test40.ans new file mode 100755 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test40.c b/libs/libtpl-1.5/tests/test40.c new file mode 100755 index 0000000000..4c0992ba8b --- /dev/null +++ b/libs/libtpl-1.5/tests/test40.c @@ -0,0 +1,18 @@ +#include "tpl.h" + +int main() { + char c; + tpl_node *tn; + + tn = tpl_map("A(A(c))", &c); + + for(c='a'; c<'c'; c++) tpl_pack(tn,2); + tpl_pack(tn, 1); + + for(c='1'; c<'4'; c++) tpl_pack(tn,2); + tpl_pack(tn, 1); + + tpl_dump(tn, TPL_FILE, "/tmp/test40.tpl"); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test40.out b/libs/libtpl-1.5/tests/test40.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test41 b/libs/libtpl-1.5/tests/test41 new file mode 100755 index 0000000000000000000000000000000000000000..7613162f7463de69ba21f23056fb929567480eab GIT binary patch literal 127668 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

    5;|s#a+$k`6kQnjRu=#qIAUa33-_oVdAx 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 +#include +#include +#include +#include +#include +#include "tpl.h" + +#define DEBUG 0 + +int num_tpls = 0, sum_tpls = 0; + +int tpl_cb(void *tpl, size_t tpllen, void*data) { + int i; + tpl_node *tn; + + if (DEBUG) printf("obtained tpl of length %d\n", (int)tpllen); + tn = tpl_map("A(i)", &i); + tpl_load(tn, TPL_MEM, tpl, tpllen); + num_tpls++; + while (tpl_unpack(tn,1) > 0) sum_tpls += i; + tpl_free(tn); + return 0; + +} + +int main() { + FILE *f1,*f2; + int fdflags,fd,fd1,fd2; + int selrc, maxfd; + tpl_gather_t *gs1=NULL,*gs2=NULL,**gs; + + struct timeval tv; + fd_set rset; + + f1 = popen("cat test26_0.tpl;sleep 1; cat test26_1.tpl", "r"); + fd1 = fileno(f1); + fdflags = fcntl(fd1, F_GETFL, 0); + fcntl( fd1, F_SETFL, fdflags | O_NONBLOCK); + + f2 = popen("cat test26_2.tpl;sleep 1; cat test26_3.tpl", "r"); + fd2 = fileno(f2); + fdflags = fcntl(fd2, F_GETFL, 0); + fcntl( fd2, F_SETFL, fdflags | O_NONBLOCK); + + while (1) { + FD_ZERO( &rset ); + if (fd1 >= 0) FD_SET( fd1, &rset ); + if (fd2 >= 0) FD_SET( fd2, &rset ); + + if (fd1 == -1 && fd2 == -1) { + printf("%d tpls gathered.\n",num_tpls); + printf("%d is their sum.\n",sum_tpls); + return(0); + } + + maxfd=0; + if (fd1>maxfd) maxfd = fd1; + if (fd2>maxfd) maxfd = fd2; + + tv.tv_sec = 5; + tv.tv_usec = 0; + + selrc = select(maxfd+1, &rset, NULL, NULL, &tv ); + if (selrc == -1) { + perror("select()"); + } else if (selrc) { + for(fd=0;fd0\n"); + } + } + } + } else { + if (DEBUG) printf("timeout\n"); + } + } + return(0); +} diff --git a/libs/libtpl-1.5/tests/test26.out b/libs/libtpl-1.5/tests/test26.out new file mode 100644 index 0000000000..bf8028a425 --- /dev/null +++ b/libs/libtpl-1.5/tests/test26.out @@ -0,0 +1,2 @@ +3 tpls gathered. +999045 is their sum. diff --git a/libs/libtpl-1.5/tests/test26_0.tpl b/libs/libtpl-1.5/tests/test26_0.tpl new file mode 100755 index 0000000000000000000000000000000000000000..a811f623c7fedbaa51321b3789b96174f6ca0d44 GIT binary patch literal 57 ucmXRZ$YHQ#U|?|6$kb%u0y02=5r~<9m>Gy!fS47C*?^cGh&h0m6Nmwba00vl literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test26_1.tpl b/libs/libtpl-1.5/tests/test26_1.tpl new file mode 100755 index 0000000000000000000000000000000000000000..85ae076aa787b733208636b51b59a603f8bb37bb GIT binary patch literal 4017 zcmW;OQ_vWQ4hGP_wr$(CZQHhO+qP}nwrzX2-L1L3r#F-H&EzGoN!N~T12#nn2q=`Y zRjPoOK?43?fn;F*j6n%Ta6%B0P=qE7VF^cg>lxi$tXrMhOvxeJQJA6 zBqlS3sZ3)!GnmONW;2Jm%ws+aSjZw4vxKEAV>v5W$tqT}hPA9?Jsa4_CN{H$t!!gE zJJ`uCcC&}Q>|;L%ILILmbA+QD<2WZc$tg~AhO?aGJQujgB`$M?t6bwcH@L|yZgYpb z+~YnEc*r9j^Mt27<2f&Q$tzy-hQIimx4h#Y{^dO%_{b+d^M$W`<2yh2$uIunHvxe( zfeAuTf)Sh$gd`N92}4-I5uOM{BodK{LR6v=ofyO<7O{y#T;dU*1SBL8iAh3Il98Mg zq$CxoNkdxFk)8}>Bomp*LRPYoogCyO7rDtpUhrl%y1;DMMMx zQJxA^q!N{>LRG3!of_1n7PYBEUFuPv1~jA*jcGztn$esVw4@cSX+vAu(Vh-;q!XR# zLRY%cogVb07rp62U;5FX0SsgigBik5hB2HGjARs}8N*n{F`fxbWD=8^!c?X)of*tz z7PFbdT;?&K1uSF{i&?@_ma&`_tYj6dS;Jb^v7QZVWD}d&!dAAiogM6C7rWWRUiPt{ z103WKhdIJgj&Yn5oa7XzIm21bah?lYUG8z82R!5vk9opV zp7ER)yyO+HdBb1)&0F5_5C8I>4}9bkpZUU9zVV$O{Nxw^@tZ$~KM;WlLQsMcoDhU0 z6rl-2Si%vW2t*_jk%>Z7q7j`K#3UB6i9=lC5uXGkBoT>8LQ;~EoD`%a6{$%>TGEl8 z3}hq|naM&{vXPw}F`or2 zWD$#5!cvy8oE5BO6{}gpTGp|i4Qyl+o7uuvwy~WZ>|__a*~4D;v7ZARh2uUbH6Na#aBRmm^ zNF*W?g{VX$Ix&bzEMgOfxWpqq2}npH5|f0aBqKQ~NJ%PElZLdUBRv_&NG39qg{)*F zJ2}WnE^?EHyyPQ41t>@%3R8rl6r(sLC`l}a>$Rs8+g{e$qIy0EbEM_x@xy)le3s}e^7PEw-V?7(#$R;+kg{^F3J3H9PE_Snrz3gK@2RO(f4s(Q~9OF1AILRqabB42= p<2)C*$R#dwg{xfSIybn;fX**A`zJ=L?s&j1Y!`ASi~j{afwHK5|EHYBqj+-Nk(!~ zkdjoSCJkvxM|v_4Ohz)1nJi=_8`;T0PI8f(Jme)G`6)m_3Q?FM6r~u&DM3j}QJON8 zr5xp{Kt(E1nJQGJ8r7*mO=?k_I@F~e^=Uvu8qt_0G^H8MX+cX`(V8~2r5)|*Ku0>! znJ#pt8{O$aPkPatKJ=v@{TaYO1~Hf+3}qO@8NoeG#AU83dBtnq@RoPH=K~-4#Am+nmGAhTANY}<_?ch$mEZWCKlqcs_?v(DMj%KC zMQFkhmT-h80uhNsWTFt2XhbIlF^NTN;t-d3#3um>Nkn3jkd$O3Cj}`P^DMC?-QJfN#q!gtoLs`mEo(fc?5|yb! zRjN^)8q}l~wW&j0>QSEtG^7!YX+l$)(VP~vq!q1cLtEO>o(^=R6P@WoSGv)i9`vLa zz3D?=`q7^O3}g_48NyJ8F`N;MWE7(r!&t^Ko(W835|f$2RHiYV8O&rBvzfzO<}sfI zEMyUjS;A75v78mGWEHDf!&=s{o(*hd6Pww>R<^O75O%PWUF>ELd)dc+4seh|9Oei| zImU5LaFSD;<_u>!$9XPrkxN|W3Rk(tb#8EzTioUjce%%X9`KMyJmv{cdB$^I@RC=& V<_&Lo$9q2TkxzW)3txi*{{l=6^ltzF literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test26_3.tpl b/libs/libtpl-1.5/tests/test26_3.tpl new file mode 100755 index 0000000000000000000000000000000000000000..bb209fcd20380c224dfc2e9e2faa5d0d7bb5c287 GIT binary patch literal 2017 zcmWO5LjoKK006M5ZQHhO+qP}nwr$(CZQJd7Yb%F5A%WLH0)aQYy8VCd-D8UF$2tpEy(1al@;RsIzA`*$nL?J5Ch)xV*5{uZxAujQVPXZE> zh{PlzDalAq3R04a)TALT=}1ooGLnhRWFafr$W9J&l8fBrAusvJPXP*2h{6=1D8(pF z2})9m(v+brs7?)PQj6Nup)U2PPXij#h{iObDa~k33tG~O*0iB5 z?PyO2I?{>GbfGKV=uQuM(u>~op)dXD&j1E8h`|hDD8m@e2u3oB(Trg%;~38bCNhc1 zOkpb1n9dAlGK<;FVJ`ES&jJ>*h{Y^nDa%;S3Rbd;)vRGH>sZeQHnNG$Y+)*>T;VF$xXul3a*NyC;V$>M z&jTLvh{rtPDbIM$3tsYyKlqcs_?v(Dm;d;m*Sz5^?|9D#KJtmreBmqK_|6Z0@{2$) z{|QPkf)j#}gd#Ly2unD^6M=|CA~I2kN;IMqgP6o3HgSkcJmQmpgd`#{Nk~dEl9Pgz zq#`wGNJ~1>lYxw6A~RXYN;a~SgPi0dH+jfQKJrt5f)t`KMJP%!ic^A;l%h0cC`&oY zQ-O+9qB2#eN;RregPPQ$Hg%{=J?hhdhBTrvO=wCpn$v=ow4ya_XiGcV(}9k3qBC9S zN;kUGgP!!FH+|?!Kl(F(fed0WLm0|1hBJbZjAArn7|S@uGl7XrVlq>h$~2}kgPF`? zHglNEJm#~2g)Cw*OIXS>ma~GDtYS55Sj#%rvw@9lVl!LV$~LyMgPrVRH+$I2KK65f zgB;>8M>xtcj&p*OoZ>WRILkTCbAgLo;xbpb$~CTYgPYvqHg~woJ?`^>hdkmjPk72R Kp7Vm2yy7>;S^RAP literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test27 b/libs/libtpl-1.5/tests/test27 new file mode 100755 index 0000000000000000000000000000000000000000..ec6951b78f4c36cb717f67fd7a5cec44f275526c GIT binary patch literal 128554 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
    &#yMX|t8%y1987S`0!j>+c$nZZa>aHLgj7u@ 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 +#include +#include "tpl.h" +#include +#include +#include +#include +#include +#include + +int main() { + tpl_node *tn; + unsigned i,perms; + char *file = "/tmp/test27.tpl"; + int fd; + + perms = S_IRUSR|S_IWUSR; + if ( (fd=open( file,O_RDWR|O_CREAT|O_TRUNC,perms)) == -1) { + printf("failed to open %s: %s", file, strerror(errno)); + exit(-1); + } + + tn = tpl_map("A(u)",&i); + for(i=0;i<10;i++) tpl_pack(tn,1); + tpl_dump(tn,TPL_FD, fd); + tpl_free(tn); + + lseek(fd,0,SEEK_SET); /* re-position fd to start of file */ + + tn = tpl_map("A(u)",&i); + tpl_load(tn, TPL_FD, fd); + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test27.out b/libs/libtpl-1.5/tests/test27.out new file mode 100644 index 0000000000..903c08cf1f --- /dev/null +++ b/libs/libtpl-1.5/tests/test27.out @@ -0,0 +1,10 @@ +i is 0 +i is 1 +i is 2 +i is 3 +i is 4 +i is 5 +i is 6 +i is 7 +i is 8 +i is 9 diff --git a/libs/libtpl-1.5/tests/test28 b/libs/libtpl-1.5/tests/test28 new file mode 100755 index 0000000000000000000000000000000000000000..4ce901af212d8fd447b0400c09ed622ce1234c2d GIT binary patch literal 129004 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%0A#vWTE_EajP|Pt4`nQ48&LfsZu1q&~hDB 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 Y7s$9JC7{dPUo3B|EwT)cXxDQ80~$ppYXATM literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test28.ans b/libs/libtpl-1.5/tests/test28.ans new file mode 100755 index 0000000000..494c321c46 --- /dev/null +++ b/libs/libtpl-1.5/tests/test28.ans @@ -0,0 +1 @@ +sum is 49995000 diff --git a/libs/libtpl-1.5/tests/test28.c b/libs/libtpl-1.5/tests/test28.c new file mode 100755 index 0000000000..ae177890e1 --- /dev/null +++ b/libs/libtpl-1.5/tests/test28.c @@ -0,0 +1,38 @@ +#include +#include "tpl.h" +#include +#include +#include +#include +#include +#include +#include + +int main() { + tpl_node *tn; + unsigned i, sum=0; + int fd[2], pid; + + pipe(fd); + if ( (pid = fork()) == 0) { /* child */ + + tn = tpl_map("A(u)",&i); + tpl_load(tn, TPL_FD, fd[0]); + while (tpl_unpack(tn,1) > 0) sum += i; + tpl_free(tn); + printf("sum is %d\n", sum); + + } else if (pid > 0) { /* parent */ + + tn = tpl_map("A(u)",&i); + for(i=0;i<10000;i++) tpl_pack(tn,1); + tpl_dump(tn,TPL_FD, fd[1] ); + tpl_free(tn); + + waitpid(pid,NULL,0); + + } else if (pid == -1) { + perror("fork error"); + } + return(0); +} diff --git a/libs/libtpl-1.5/tests/test28.out b/libs/libtpl-1.5/tests/test28.out new file mode 100644 index 0000000000..494c321c46 --- /dev/null +++ b/libs/libtpl-1.5/tests/test28.out @@ -0,0 +1 @@ +sum is 49995000 diff --git a/libs/libtpl-1.5/tests/test29 b/libs/libtpl-1.5/tests/test29 new file mode 100755 index 0000000000000000000000000000000000000000..2c6f04aedc4cb495724b1d24ab413db2e140355c GIT binary patch literal 129801 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test29.ans b/libs/libtpl-1.5/tests/test29.ans new file mode 100755 index 0000000000..db001dcf71 --- /dev/null +++ b/libs/libtpl-1.5/tests/test29.ans @@ -0,0 +1,2 @@ +sum is 49995000 +abcdefghijklmnopqrstuvwxyz diff --git a/libs/libtpl-1.5/tests/test29.c b/libs/libtpl-1.5/tests/test29.c new file mode 100755 index 0000000000..5ed6228235 --- /dev/null +++ b/libs/libtpl-1.5/tests/test29.c @@ -0,0 +1,50 @@ +#include +#include "tpl.h" +#include +#include +#include +#include +#include +#include +#include + +int main() { + tpl_node *tn; + unsigned i, sum=0; + int fd[2], pid; + char c; + + pipe(fd); + if ( (pid = fork()) == 0) { /* child */ + + tn = tpl_map("A(u)",&i); + tpl_load(tn, TPL_FD, fd[0]); + while (tpl_unpack(tn,1) > 0) sum += i; + tpl_free(tn); + printf("sum is %d\n", sum); + + tn = tpl_map("A(c)",&c); + tpl_load(tn, TPL_FD, fd[0]); + while (tpl_unpack(tn,1) > 0) printf("%c",c); + tpl_free(tn); + printf("\n"); + + } else if (pid > 0) { /* parent */ + + tn = tpl_map("A(u)",&i); + for(i=0;i<10000;i++) tpl_pack(tn,1); + tpl_dump(tn,TPL_FD, fd[1] ); + tpl_free(tn); + + tn = tpl_map("A(c)",&c); + for(c='a';c<='z';c++) tpl_pack(tn,1); + tpl_dump(tn,TPL_FD, fd[1] ); + tpl_free(tn); + + waitpid(pid,NULL,0); + + } else if (pid == -1) { + perror("fork error"); + } + return(0); +} diff --git a/libs/libtpl-1.5/tests/test29.out b/libs/libtpl-1.5/tests/test29.out new file mode 100644 index 0000000000..db001dcf71 --- /dev/null +++ b/libs/libtpl-1.5/tests/test29.out @@ -0,0 +1,2 @@ +sum is 49995000 +abcdefghijklmnopqrstuvwxyz diff --git a/libs/libtpl-1.5/tests/test3 b/libs/libtpl-1.5/tests/test3 new file mode 100755 index 0000000000000000000000000000000000000000..baa0e8484872720dd5de5a0be8a3ba63bef43a7b GIT binary patch literal 127734 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 +#include "tpl.h" + +int main() { + tpl_node *tn; + int i,j=-1; + + tn = tpl_map("A(i)",&i); + for(i=0;i<10;i++) tpl_pack(tn,1); + tpl_dump(tn,TPL_FILE,"/tmp/test3.tpl"); + tpl_free(tn); + + tn = tpl_map("A(i)",&j); + tpl_load(tn,TPL_FILE,"/tmp/test3.tpl"); + while (tpl_unpack(tn,1) > 0) printf("j is %d\n", j); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test3.out b/libs/libtpl-1.5/tests/test3.out new file mode 100644 index 0000000000..c35e4ea80e --- /dev/null +++ b/libs/libtpl-1.5/tests/test3.out @@ -0,0 +1,10 @@ +j is 0 +j is 1 +j is 2 +j is 3 +j is 4 +j is 5 +j is 6 +j is 7 +j is 8 +j is 9 diff --git a/libs/libtpl-1.5/tests/test30 b/libs/libtpl-1.5/tests/test30 new file mode 100755 index 0000000000000000000000000000000000000000..15039ab4282ea634fb2b6a2f237a7d56c1d4ce93 GIT binary patch literal 128508 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test30.ans b/libs/libtpl-1.5/tests/test30.ans new file mode 100755 index 0000000000..1115af876e --- /dev/null +++ b/libs/libtpl-1.5/tests/test30.ans @@ -0,0 +1,2 @@ +buffer length: 4 +good diff --git a/libs/libtpl-1.5/tests/test30.c b/libs/libtpl-1.5/tests/test30.c new file mode 100755 index 0000000000..f54f0bba4d --- /dev/null +++ b/libs/libtpl-1.5/tests/test30.c @@ -0,0 +1,40 @@ +#include "tpl.h" +#include +#include +#include + +int main(int argc, char*argv[]) { + tpl_bin bin; + tpl_node *tn; + int i; + char *file = "/tmp/test30.tpl"; + char str[10]; + + strcpy(str,"good egg"); + bin.addr = str; + bin.sz = 4; /* just going to pack 'good' (no NUL) */ + + tn = tpl_map("B", &bin); + tpl_pack(tn,0); + memset(str,0,10); /* just to test that buf was copied */ + tpl_dump(tn,TPL_FILE,file); + tpl_free(tn); + + bin.addr = NULL; + bin.sz = 0; + + tn = tpl_map("B", &bin); + tpl_load(tn,TPL_FILE,file); + tpl_unpack(tn,0); + tpl_free(tn); + + /* print the buffer char-by-char ; its not a nul-termd string */ + printf("buffer length: %u\n", bin.sz); + for(i=0; i < bin.sz; i++) printf("%c", ((char*)bin.addr)[i]); + printf("\n"); + + if (bin.sz > 0) + free(bin.addr); /* malloc'd for us by tpl_unpack, we must free */ + return(0); +} + diff --git a/libs/libtpl-1.5/tests/test30.out b/libs/libtpl-1.5/tests/test30.out new file mode 100644 index 0000000000..1115af876e --- /dev/null +++ b/libs/libtpl-1.5/tests/test30.out @@ -0,0 +1,2 @@ +buffer length: 4 +good diff --git a/libs/libtpl-1.5/tests/test31 b/libs/libtpl-1.5/tests/test31 new file mode 100755 index 0000000000000000000000000000000000000000..7565901fbe58ef719de7db1171c009bbb6a934c4 GIT binary patch literal 128412 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 literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test31.ans b/libs/libtpl-1.5/tests/test31.ans new file mode 100755 index 0000000000..ab23e54dbc --- /dev/null +++ b/libs/libtpl-1.5/tests/test31.ans @@ -0,0 +1,2 @@ +buffer length: 0 + diff --git a/libs/libtpl-1.5/tests/test31.c b/libs/libtpl-1.5/tests/test31.c new file mode 100755 index 0000000000..ae3c908da2 --- /dev/null +++ b/libs/libtpl-1.5/tests/test31.c @@ -0,0 +1,38 @@ +#include "tpl.h" +#include +#include + +int main(int argc, char*argv[]) { + tpl_bin bin; + tpl_node *tn; + int i; + char *file = "/tmp/test31.tpl"; + + bin.addr = NULL; + bin.sz = 0; + + tn = tpl_map("B", &bin); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,file); + tpl_free(tn); + + /* load these two fields with bogus values to test that tpl_unpack + * sets them back to NULL, and 0 respectively. */ + bin.addr = file; + bin.sz = 4; + + tn = tpl_map("B", &bin); + tpl_load(tn,TPL_FILE,file); + tpl_unpack(tn,0); + tpl_free(tn); + + /* print the buffer char-by-char ; its not a nul-termd string */ + printf("buffer length: %u\n", bin.sz); + for(i=0; i < bin.sz; i++) printf("%c", ((char*)bin.addr)[i]); + printf("\n"); + + if (bin.sz > 0) + free(bin.addr); /* malloc'd for us by tpl_unpack, we must free */ + return(0); +} + diff --git a/libs/libtpl-1.5/tests/test31.out b/libs/libtpl-1.5/tests/test31.out new file mode 100644 index 0000000000..ab23e54dbc --- /dev/null +++ b/libs/libtpl-1.5/tests/test31.out @@ -0,0 +1,2 @@ +buffer length: 0 + diff --git a/libs/libtpl-1.5/tests/test32 b/libs/libtpl-1.5/tests/test32 new file mode 100755 index 0000000000000000000000000000000000000000..91bcd967f5beea0b443be730c0180fbb1bfb3ada GIT binary patch literal 128812 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 +#include +#include + +int main(int argc, char*argv[]) { + tpl_bin bin; + tpl_node *tn; + int i; + char *file = "/tmp/test32.tpl"; + char str[10]; + + strcpy(str,"good egg"); + bin.addr = str; + bin.sz = 4; /* just going to pack 'good' (no NUL) */ + + tn = tpl_map("A(B)", &bin); + for(i=0; i < 5; i++) { + tpl_pack(tn,1); + bin.addr = (char*)(bin.addr) + 1; + } + memset(str,0,10); /* just to test that buf was copied */ + tpl_dump(tn,TPL_FILE,file); + tpl_free(tn); + + bin.addr = NULL; + bin.sz = 0; + + tn = tpl_map("A(B)", &bin); + tpl_load(tn,TPL_FILE,file); + while (tpl_unpack(tn,1) > 0) { + /* print the buffer char-by-char ; its not a nul-termd string */ + printf("buffer length: %u\n", bin.sz); + for(i=0; i < bin.sz; i++) printf("%c", ((char*)bin.addr)[i]); + printf("\n"); + + if (bin.sz > 0) + free(bin.addr); /* malloc'd for us by tpl_unpack, we must free */ + } + tpl_free(tn); + return(0); + +} + diff --git a/libs/libtpl-1.5/tests/test32.out b/libs/libtpl-1.5/tests/test32.out new file mode 100644 index 0000000000..bda4a86032 --- /dev/null +++ b/libs/libtpl-1.5/tests/test32.out @@ -0,0 +1,10 @@ +buffer length: 4 +good +buffer length: 4 +ood +buffer length: 4 +od e +buffer length: 4 +d eg +buffer length: 4 + egg diff --git a/libs/libtpl-1.5/tests/test33 b/libs/libtpl-1.5/tests/test33 new file mode 100755 index 0000000000000000000000000000000000000000..f47bbec0e348fd0da368505c4d03e9a152e0307c GIT binary patch literal 127735 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 +#include "tpl.h" + +int main() { + tpl_node *tn; + double x,y; + + printf("sizeof(double) is %d\n", (int)sizeof(double)); + + tn = tpl_map("f",&x); + x=1.0; + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,"/tmp/test33.tpl"); + tpl_free(tn); + + tn = tpl_map("f",&y); + tpl_load(tn,TPL_FILE,"/tmp/test33.tpl"); + tpl_unpack(tn,0); + printf("y is %.6f\n", y); + tpl_free(tn); + + return(0); +} diff --git a/libs/libtpl-1.5/tests/test33.out b/libs/libtpl-1.5/tests/test33.out new file mode 100644 index 0000000000..8805eb3396 --- /dev/null +++ b/libs/libtpl-1.5/tests/test33.out @@ -0,0 +1,2 @@ +sizeof(double) is 8 +y is 1.000000 diff --git a/libs/libtpl-1.5/tests/test34 b/libs/libtpl-1.5/tests/test34 new file mode 100755 index 0000000000000000000000000000000000000000..59db46b7c19f02b20c912d3decd0ae5d2e37d809 GIT binary patch literal 127871 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 NX2HraSuMel{{;uIWZ(b* literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test34.ans b/libs/libtpl-1.5/tests/test34.ans new file mode 100755 index 0000000000..6b28190d83 --- /dev/null +++ b/libs/libtpl-1.5/tests/test34.ans @@ -0,0 +1,15 @@ +sizeof(double) is 8 +y is 1.000000 +y is 1.666667 +y is 2.333333 +y is 3.000000 +y is 3.666667 +y is 4.333333 +y is 5.000000 +y is 5.666667 +y is 6.333333 +y is 7.000000 +y is 7.666667 +y is 8.333333 +y is 9.000000 +y is 9.666667 diff --git a/libs/libtpl-1.5/tests/test34.c b/libs/libtpl-1.5/tests/test34.c new file mode 100755 index 0000000000..a4dd8bf75a --- /dev/null +++ b/libs/libtpl-1.5/tests/test34.c @@ -0,0 +1,21 @@ +#include +#include "tpl.h" + +int main() { + tpl_node *tn; + double x,y; + + printf("sizeof(double) is %d\n", (int)sizeof(double)); + + tn = tpl_map("A(f)",&x); + for( x=1.0; x < 10.0; x += 2/3.0) tpl_pack(tn,1); + tpl_dump(tn,TPL_FILE,"/tmp/test34.tpl"); + tpl_free(tn); + + tn = tpl_map("A(f)",&y); + tpl_load(tn,TPL_FILE,"/tmp/test34.tpl"); + while (tpl_unpack(tn,1) > 0) printf("y is %.6f\n", y); + tpl_free(tn); + + return(0); +} diff --git a/libs/libtpl-1.5/tests/test34.out b/libs/libtpl-1.5/tests/test34.out new file mode 100644 index 0000000000..6b28190d83 --- /dev/null +++ b/libs/libtpl-1.5/tests/test34.out @@ -0,0 +1,15 @@ +sizeof(double) is 8 +y is 1.000000 +y is 1.666667 +y is 2.333333 +y is 3.000000 +y is 3.666667 +y is 4.333333 +y is 5.000000 +y is 5.666667 +y is 6.333333 +y is 7.000000 +y is 7.666667 +y is 8.333333 +y is 9.000000 +y is 9.666667 diff --git a/libs/libtpl-1.5/tests/test35 b/libs/libtpl-1.5/tests/test35 new file mode 100755 index 0000000000000000000000000000000000000000..fb842626fb857efd3493eaf2b6386861fdf45866 GIT binary patch literal 126755 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 +#include +#include "tpl.h" + +int main(int argc, char *argv[]) { + tpl_node *tn; + int id; + char *name; + + tn = tpl_map("A(is)", &id, &name); + tpl_load(tn, TPL_FILE, "/tmp/test35.tpl"); + + while ( tpl_unpack(tn,1) > 0 ) { + printf("id %d, user %s\n", id, name); + free(name); + } + + tpl_free(tn); + return(0); +} + + diff --git a/libs/libtpl-1.5/tests/test36.out b/libs/libtpl-1.5/tests/test36.out new file mode 100644 index 0000000000..0b21bfe31e --- /dev/null +++ b/libs/libtpl-1.5/tests/test36.out @@ -0,0 +1,3 @@ +id 0, user joe +id 1, user bob +id 2, user cary diff --git a/libs/libtpl-1.5/tests/test37 b/libs/libtpl-1.5/tests/test37 new file mode 100755 index 0000000000000000000000000000000000000000..b68ae4ac80eb2792ba355c83148f2899b26ecccf GIT binary patch literal 126587 zcmdSC3wTsTwm-UecPBKDWVb>fC~89*4ag$_#6(cLA%Wf6(I8KsJVGKUk4(}5RD?)( zlx-75#~D2{b4ErT#nB_ojN_o=kRXrvnh{VGpP(b!+lb-|5tY8bUsdf+gD`XM{qFyM z-)*I<)~Z#jR;^mKYE|vpo#o|`aV}lgoR3SpKqK^N*PuYjZ)9KVpb2UvnpX>I{k48t zHj1+F&!G#doRhYyYEJ3}EkADj^DyJ$7e1~azVLAc@ug{}i0_WnX`LzC>-Yp!R;GO# zBI9rDg83h2Sq3R zT#k~Hk5hWa3Gj_+Oj=|JVuedrp9-4IQuDjVHhtJ9y>a0E$l%-{iBt zb5Ov}*KNoUzqd=!L5cJZe4hl%u3R!hz|MTqrcb|i{=x;*>!UO4qSL2qm|j(!Pb0PJ zC3B-%eY9>t)%;qmCR*39plW8cTC1y`Id9&=DwfpOF3{%BpINKTufJh|z|5-#rh0yT zbrgK7>*^LPoDSNV(YXs3u;OeMlHH>E1+{f^7es3WqV@)DzQc4jYH9Nu7Le`q=`~9r zS5&K-x3IoiTUZP3Xtrujok+k35a<`yfs}%)Ud*34cY(IJZZ4!p*Dv92+}eKRiEB7zZfEj8#6o<$ zi)Vf} z=_@nvnd{fI41A{lo{@p4tj=dn20m?bD6GxELqX}!k_>#8G*;6ZGw@wA@GCR$-7@g2 zGw?YX`1>;Oxf%F18F(WDzcvH!j4_MXXW%o(aYF_^bDpU8TdmP`1}mK8T-_0CbF95`!%zvHJX(i4y!X` zTfCbyh>%U4QwNe%|0uqVGlIwwo&@i!e>qZWZtqglVGodI4WX zn5Jp35%5KXX_EG80goX}Q?wfed>&z%pj|8AVT5UV_6z|JButaDD+Sz-Fip)43iuSl zG%>qKz$X*#M%XXlE`(`Pwokw=!ZamY6Y$}AfN4VZfg?cl|B^6G$KEU8PYBaw?Ck>n zfG|zPZWZubglP))dI9ew+=K8M0l!F?Lu{`W@Nzl7=52beeY@51l%*9q7gw* z+?re|xPG48i(bH_e8sI-ULCq>^XlULVQa@VruBgt`|v>Jq;Om7cGNQ4HU&k}HUn#7 z@+JuV_3HFz!&EGAlg+{Or)KO>u4(OC?7DjM2Fgmq{rc(_7NzzYXEYMGfsjML>5v=r zruCe;>5~gheYcS(Yc}mn*Z)A(Z#;j~^?tbdlP05Pav28v>TOw10HuGm znf7nS&R;SI1kqE|BAhh2rKkbYS^HAkueNVO6?+lBWEad^J~g4Yc&lkW8Mu#)TK5Fj zh;&t8Ez*b;53CpIssLF=gT{b(pcOe|z^cG@k=_&7E7IQt4v6%j0OMI>z~cd*NS_S& zMfz-@2&vf|4^%R>4x7!9fY)qZ8t`wNjhby`0WW8cX_W40Sb7R1>qQ4YqFYu;y#7vw&9L<`|lLB5x zXryU5A$(cD&u-)=KY_%>t>!ITDA(rD)bip~Xi8{uXj0hv8s<*V!$I&PL8YLzG%$!_ z=TmIK!kZup-3>mYfhuW#pGrlll9(5v*pDeA{wQ==-n8F{Z^qmRCp-bzoe`f7pe#`f zCz{hZ*RPf9pP5ZBR8$>|Krg;%=WyvijobbL8Z!adOq8VZLLfs`@HOH!4l6bruG(c* zE%BQA=gGgL?QmjrAeDD2s3VDa0bjVy6F?szeYrQRV+tk1rCW`ATaBk$VgD019>QQn ztTxkn^Q(uArpG}UO4NEn2ZL@Mq7+37ji<^2MaEN;0>f99;U7kfm||jv0W%DkVhCAO z(LAE4qV${k(dA7kW94v27(qkvCUn07ncF_(Jum3KUN|eM>9wQ!rT(MNwzd>#- z`l6XQZQZqgE&0}ASa^ySZf%2ozseD{+UZLk5ySKVh~yC5$DC@j{q}I_e&g01kS1bz z0xdr9Oy$*p0yV?dwlI(pa5CZ%>TAGOQbnkuF%C_(EYC+d+l*MBMBtASC1uteZ*mL7 zmdb5<5MtYNL_-*Uvw2=1Xr}-w-AADg)%?dbs(H5i86+~TLg?Qox>V`43s9@280zIb z-U(uRB{0Qrhhw7ynh}2z4Yl~HWbw~Y%zE~>z(T6OA%WiS5oj9Z?aVnNkT@p+u%)Ns zJq3VWjT&M+!7-IL7O2eeyqMK7o@P@jnw`oUO;B za1yW;i4j80_OG0hRNi;hO7bJXnbuVSOx<~b1E%#=#F`yARD2NAe=U?#jB)xQ`Pd;C z#i0}yJ$LjvtVPzg77U1%ta9+trJS-wWeInA@e9SNr(Gz0h9ss{?@P}67HyzDX0d6F z^+uP%^(1~H{F<3~TzL3M;-SDA(%-U$&B8Rx!2i{Qv`ZM_K!}^1jMgI7M_8I#CP^K> zY9-tMQnNZSDj7x-$%h>B?`MPj%ntH}9ptxyxDSaJJH-Da@pnKe-nXZT?J3Z)afTL} z8k!Qej?h0&o`^6YKa!|HC=d;JE1Etu;&($}A#X)uP#~PRD&P$#hP0nvGsKx+Ex(g2 z^I~WU{LIAsBC~0Kbi7$ruEh>@Tl}8&Tq>|DSQC_d%tX1*tg6U26O}$Q_MC2(?l7%N zpKKCZAnP383g`wBSSrh3S2!b3A!?F1wOiu{gwpI-MPiBaLi zh03`0RKb2MjMHW>>>hwUS@a&`U?zr}%{LdaD0u+(Vvmw~Nlebi!qK$TxMLs?9rBoo zQDoW~_76Uw3dP!V)((}vvGfD`N3an3N_e(0^`?plA-!Du9QB+H0@<)Y=bw9E)<<;5SS z^14zCEX~d1QcVX@!@vAo5tk%b*}{qq1(_WRg7r1BeG!|1LAu(qe}ofP!+E{k(9PP` zo^;07ta4)%7Zs+*`PZ|c^Td@HKqG!oKhvQfG1_azXp43dH{~~_mi;qQCG~Mp zb0kaSTDW2}gos#si+4r_yx-olCf#212t8bS&{**x%4r|XgY<~rT6(x)U)b8x-ee}m z!hSCPsr|f!DQPCAdF`sB$E$g=CtUh^-PCa6QeUE6OLT^ge2x3Oavk&;PelUVvFdeS z83_O=3!FsE$-tZp%t`2=&)RxP^X&c}Q{NRX{mh7^FmN6HrFJ)<#ne$M4q|nlSQtTk zfoRCym?ip}N*bsNUtz@OAY+1ek*RMD>s#!{$Wz+Q#raJy7ZA$uTHht~|@+4wTW`t4E92g*bTfg2u74idj-ol^#=V#FGQpL9s7&5>ZQ*c z@ueur)W5N!JKJs0tZy>3v(x^O>*vAp;@09+dtc5wrT@3EgdJV~RZx~CCTpSQF{x1O zu#Tv2TwB-}msA>cG``V(6qM+i&;A9N&_Ac0^R!4}Ih->GE*i+MNG$Y+6ASahu^+w0 zt;^sSo^eBL5db1&N>2D9l|p3Nv;ZXs%iX%sG!+J8JXP*q`-9Om3)r=;P@+>qcH_&w zkku(M+0!47Q8dWY2l22!8lWDb%t=bKz$wj6QktCv%_6LW!N$9B`ZZ7XUesJRn2w3D zxYx8^HAi91Fyb$xxXgHJczOJw(Zp>}II$eNh1Vm^^?Gu{0VyaqE1^vvx+2yAb3n49 z>cfb>mm%VcRu&}2mtYPTG1fi|>%8FBvsVKT{141hp>XvC4Q#S2?LdM2}EsgNprqv^m{O#wUM2Mci#y5U4TE)J( z@koJj54`GTJ%pLtM@)~P7P`ft^6dYHna~a(o__-dG8HNP#E5?YZ2KzVmz$$fPNPH4 zNa?}orI68j4)!{H(le6Py7!( z7lUsfy-+Y>eUT`_tdl5$ z<`7Aw>`my*2JA~x_FtJ3!P@^Y2UN;tw7LQRQuco__YHG*GKZKXWj8U0;3Z{qU(fhs za@hJ&EPUT^;lrwaM#619cgqJlrs^$+`EA7KLG!V_{bGmu8Sw{^H|0td?T7ft4Z%<0 z5;YjBB7>1s-k~e8Bm&=%tXUm~|7n8>pi*p$SB^N=KrI#6>bo|mtrqJ^!pE(DZ!>Wo z*Y+-{yeGgxl&GqSu~_e5cswRBtoel70;M=2#&=vC(tJ_1E$A0%;>toh038WCnwVd_AM=TkNCR+E-qD2=G%uBx zr36h(%s1OSY?8+?2uQXfAbD-+4v-7Uo5rDTVtCU*BmM~#Z(6&}L@Cxr)+nxk4(eSA_EY4%NXIMfm-{p0(hHA{OP9a~}E5xqSOleA|+ zTOIL4I58q10#fTOmL@;ta9Eq|(V${~%M#@XO!t>JwJta9vjnn{qaLxoO>X}rm1;J1 zt1DZKeWx$#f$cV$i&!{?I2_TxPcA^aWE+ZY)yqcB&o`Ps1b=R#Dw+;9{H=}a2PVp9 zPy3r{JTl@~oPiX#q9f5W#8wrXl|9MRz|gFktU)Scoo5$AUh_Wo46e}v>(!2tr{}v` z&#?7Eu)Av_c4ZsuMWdYi2znE93b9R22GAGmt90vnPfeRUTHCvI+gR5;lzh8Aw%4_C ztQ%5#lkeHo&Q_Sa9>q~0Hqf6@s@qUGEF7TTZdT2~E~~c4+_cZdjY(IKk*10b=(x>yFni}#2CcQ4FFjlkc>evV+f<m|n3Kku*ydaYx; zaibU{#=!}g!wi^MwRBdot+2BXX`P9phVvu(KKlaNma=csws_rYaDYvR0HjW6Ap zv2JXBq-rl%L^nrpD2q|J0QzlzO4{AUuscLLFufO+kF#kv#AAP!oR*Y!R{_)6nqhdK zW7jDR@5kgfAfeG=S@xEdUY~E=!F7Vp?2-gdnwmarc&e?O{SqwNUrUdNnHU2{IY#W6 zpdurFJ?q6j)6@F&npIR}w|@xZGuG`ejdib^13I+&j(x5Wwvp^HEyC9J=!LMg!l$ud zLsv^mn#X+?JLFnC+^p&ayf-qSH9baC^Y!h`WqJzB@!>PR{mxjo$-FPDw??d1xsNxi z4ko&N!=~FeQ6D^J`~f@Z#B|?J*Rf5o31=Pq5P4yI81U$TbbmY6vzybVSUB0QwSOeX zQJQrEr-N7kde^`oO~;=0$Rt0vZm{cy&m4-vRNluxhp|`ol_jQ@lsD~MW|)cPMX9`3 z9DFKo3$j;UjZwsQdIR#ItGI>6DjL{o&JpY5O|Y|0Si++DaA(|sze%lGZK=GKpvN-d zOXV#Sx$Ci*>^I{7CCc}t^5y`G<=3>@m8U`+frY9VuJ9%wq-kSZpYVK6=6wXmk%G@y zpIpw8U?du7F6WA-mu_FWz5VW^?KwG$AzETA7DTMiOJMKxmR!#qx|@9Vl^uSvEOBZ% z6kcQ|t`9<8sl3e-(FsU+zMw&KIGJ5XoSb0x$qH}1Tij|FlfSb#&iqI&j)S;3KC}-d z$1aY2gpG3{yc!(s9DvEUKjcDaCI$}!DtR?{bS#9aUG0Ca5ufz=O2&FGojz%32?9Wf0ed6PkA!KVN{dt)WGaJ`RNimN z6{~8#U_Az*%Tzo8TZ^4u+cP9In&zRU;K4SR(R8ECd5osj$XPpzTQ}M6gU@-sG9Qa} zY3oF`W~|L~@Htnsa}8lYuGj~9)V-|}8iCwA&MBg32==sO7br-!jlBh8)>fSVj`15C zi-XuZ#7}c!+E{OxZDoO4!5SHA0$nN#%wPsyiup?Bkzen0hH)E(x55|sB{oh z(4ch$&EeN$p}9e+j|J-TyB(yt#Mui zY-KGJIh8lDQuSvXtjHzolLCVExL~XV2U^c`QSER7H)D8lG>FGX`yl%Sz>lzP&rO3o30e|Ep1VWX};vM?_+G5m*}ay7cYe%!lo^F zi^LeXwQ2AgZyRxgQqcyJcaWN+Y&KWI*!LvQ{{UN+0buKlABL+Cf;Jt%-VS;kl<1B{ zKX$kXIx93{i?T2Swwvy;zSwhKt2>rrbOe@B#>s~?ASNN^YNdTD#s>Z`*m$JMh(FvJ zv#IgOTs$q1xd!YRW$rp7Zpz#u#O}})=)y)^$LJt8*@&Mib2U$Msu|@GJkr8HN8U2@ z81{u-@&%As*;vaZYD~5n@o`{ThMpASUl98Jw}ytb-?24kD1@b1xkmg?sHv>%uMpU= zGP7z@AV@1OGph!Pz-QDTVRvEU(tn0<+>&W?yHJrfw~?LPa$$1P{+b%07X)BFQ=fywZP+`9cL|Up zZmO^rBOcvfVJ%7gX3*3*h{tX)iX!P<0_S{TlL0)03TMp=lR7m+1bVRP5*% zHg%MW+p;l>H6!*mV)Ua;OiVP+x>Vjrk&Irx$WdrRrH;wg^mDo@b~YCD`s^k^PMojo zI=@5q|8kf?_8(wej$~BQf9eH2*wL;CGXt(@KRUq)-7&Fi#pHH~Tj)bmd8f;!5u_UN zXJHFsnTS{o=uf#YQ1SSHp&^~dTFDeAW0Ntd5%^hi@b5arjgnYx#b3BMLphg$jnvJt z>m^|6$kkezc2u{Z3l-M4az=}p+b`?>l~Ci&sX`;Z16kPa9EzvI zTtGHQN6q%LI`kb7vhysa3_KKDjuzuDdbkKYpzv}FL1gD)WN_Xg$0=Sb>j|cgV`+bp z=N;05tCt7kryEn1>Xp|>s$0N{G=dhSq%cN#ywFk%Gz&t_5q2pf~{#y^xAP8h&g)hj#iBo z`!H(|(WOb?nK@(ZsnC*`=hpMFy+2~V866V)u2XbC>^oO9K<5)ndVyV(FY{fP?}p(H zBHY=J)3DX>!3EHv5ogHBAYd9ai5O(R)MfizM-DM=(UY*a6k_)>DjFDM#LuTiC6)&< z_I6jX$Q&i4eMZOpL>nRN-E!;8aMjibm@J7{-&@g{@vt{U?HDTQTkECeET$XK#WVc$`eS8kP8O7>I)g` zaP*DuMcDHlOy&JBUiA!yV#K$hTDYo503o2&rUDhvB9O)R6mGYZ?QinHV>ULOrC%HI zzp$$^5^1<6lmJP>^s&v@C%UX?Rvj?b^$gG@?88XOmR z=^s?!9Kqo0rk^goEMX#6T2eH&Ihvy(RzkyNnCD(|(?_mU-fI|E(fB4V_Ff~N5HkXr z!BrL!4OwQ9aYqxJOqrG3lyo)sXk!1cp2hn>R$P5?8@HZ}T)66sw8uzAnmvCkK8X2Q z6EYThMj(XzDr7A8AZ*{}D?PN>4(U5WrMryyVDPP|djFzk&+pW}tm;KP-Ak-m)rdx5 zEU{J(2$v^qHz>hRohc56*kVI#_jl$;(08;G=2GUhUlvn7h@}y}i2<0^-R_0ygBi)k zWSadI&Sb%tFjjxf{+EOiza1{B$B{s0&_>rF1{NWU7)YBZ-@+bQADYwb2W5R{G4 zlfF&U{&b<(bj1?_Tc&9pJE~7yDDoKb8&TA8ek3XNi4^RA(o{iT#!6<0VL10V*w`5H ztLO(3Qwv3C6iJLJX|DV(cG$J3Q$p@}!d18v6Fh1^gE?3!&U!kjP%>q#YeOgr*IEnz z%&Alcbq#`0!ZF%c;4y|8t=q<;D~~})1uq7SdF-=)m8qziq#EX6Qh5^`s!uQ~+;sWU z8XSotF;CeypFIhNtXTJPD)ocrs362Kn%(p34E29EhLz#w?Ncx*NP|ESgXRoTD(?+Y z2>DD9D8`$C6E4TDhGOw7MP9vmT%dUppmt35PD%@|wP32*?_*jP@3j45rGh>Fe{mlW zcjUYfKwMo!dfZ!pTRwx7>JA`IRDN=vB2VdJpU&akzo6LiGQ_ClmBnd1h)&=cI~Ms} zZmgtACp;`fWTF2_aOXP!iM;~1CNo%$H} za@TwBtKwu!TuelV#l5GH)%rAOuiLUH4Gi11m5kS>-2LJIXZaEgQrS3asA-}zdR;tGvezpE)ffwK0;0Z3P*|& z>&NyULf-Iz_wbYhPj`&?A4UByP3yBVs5Z78@>T6_dVBdhvF}q2?dt1 za=6y`dyv_8g9&=ta+~O;DoL<}#{tQ{5JEh{Tmn?`LG)j0WrQHdLri-l$qxThkxd}k z(lptnX|kiPVO~uB7ofw*O`;;yp3jP7QPH&C%eWD^OGspY3f+nedg;}|3woYfdF|8D zm*fqO0NY1{&-aj8@sYRxASj0aYY??RQL{REv1;|S2T1)7P`8{8N!4XoOjXYHML?rc z3uwh%cHmm_XLG=nma0+Nz6_G3&#SE;Ct@u~Lggl0k{^S{o9?XwzDL~i<_-7_gsoM9 z=S5l;SYjQDSaEU9y+3IqDBF#+P2NpMPCLI9UnUUu5yFT0H6kaxSS?pXw$+H#h{rm? zlYAF@Ux#B48clrvRfbR%C@>R}Yy;;OY^RnfHg9I)3OrE0(P!D|bKThcJXb4>o)$Ya z)VS^MS>U=U){0BoI~XCD37k?RcDZFATearlPIbI9ni9l(o2A+GTH7Lt5yN8N4FzGX zaoc>fA8W<2(~D#Pa}Gul{cvWB`WjD99Pk#iC4A62 z05#qqgu|)ud4A_ngTn9eL+ik@+kHz|#i6;YVP@3EbR$?)lh@}S7Ju9>t5rs#X|+mXa|Ub`JLT=><|@)FQpvIaiI zXnGwJN1W7O(j5J}W<2GBrNzblyJ(;m=1m0`qM{ai-(?QK^Lt+M&c{7J94qb;9gZC- zGGd)!I;*WOO}8A;*f#IzdPMM;s{`>M1cjsPjJOYNjmEiqfN4X`Y9rp4Ih@ItF%22< zxlG64&L-0uBYrJYoWKh_&fl*mj8ppgOmRlPkZFMt{~6Naw_!TG&UQ9~FMYSP+!Y7V zxM{rwFUp7PZ=&xQp6IAD>+q&e&M4Cl?>LO7qk}@t<5P@Rtj}?!qIpuDZtBU^##3J7 zsa`7$?gv+5@RE9@^o<5PtiQ+Ow-9dkabCvv!4*T%wN%84L$o$*2$qblH=FAa)(qtO zvBYTlUKBu?5oc1Zm<-WEiJp)LleSWNk4pNAiSQK@;VS@?1tt)488DXtGXbnC8>r!38v5ijE*8jac8AXLFP124I$AcVn!0pCrOXoH

    =yX`N)(XoO&daNXoI|pcJ3c6af+9t(rgH?O3Ra531=>?(z9Q|Z$-d!h%kYO8Bczy+VSo$+q!>&VRWyw#swh2DH>SKXp{*Sb z4nycD+KAy-Aak1w8GZC3pIeK*jK!%NhZ4Cz!&)$(LrLo&C6gHLWS^Jp#6rHj#IAtR zR@@4DE3$)4FmqwfE|off<3BfolS@ur{s!SCwKcoIO~`QhT0Eec$Xx>rvUAyvA~e6(u$6hq}Y{-PRFwHA=#w}X)} zK1GW@iH=%ctg@>AjB2(szXlXs{S^u1{-gj?As=PVo`Ki}kD=J|s-(RP1#>=Ha6XTL zVj{N+pw#)ip3O0zdSfD-p2(fSqNMg$tl)%s4!I$-iQEaOq_E7_Z5Rho3}{7cgb=fN zzg?5a?IS1y`vhRRF~f(YyU2G~H@*xR^L)pOk7D_6fN+X2Pv6BagMJ7vXgI^y!3P;T zS}-9>+-bwZE4gHg%3{v);+KjO&p1%~EKzi$&J+LcDEdHqtYY05=MJxg>4`lc?3x~X zTv+%}>>=NJ;@|oLyM=0&fqoSl#!8@sm(GV09{HMj^f6sy_8c(*uNm?7zf?EJM#oKH z#z)xbXApfy2YNvV`WhfVN8}6}`SW=|{&@%TxFoVU6*7iD4@?V84H_qCAE$_zBNVIl z(3ZO^8b8vaKLNvn--_5EUobYq=MKh(w4YTy#9m)5S6L);A4FH6r^gl->5T`&6ZEQb zC339m^7oAA6TUtBtNj)oJy!0~t19yJSfxit%%Yd>(v3=ww&p`hD7L_j#`W7e=!c9? zDvZw(xnn@S0!Fv74t(pd(2S1H1(0z@$GT7Y{ZMRlFm{Plu0$2|$G|*ob3^Y@FsF#o zV;=O_aJ}i~0#?NjLto6%mRw>}^58fccWZZ?2S5iudTca_W$@5|+T-^8>Qzq6;}NaVBW7E_ma{GTiQSafn7HMip(;xrmo|mc6#Bx|+rUJ~*k8OmRQP^- zF9fwwvIVa;LJgK4)mA@<0`;S5kQ!23OOMwd2pTW6H|nu*(4WhGs6T(llGJ0<-DcIv z^VKxP6)b(Dc3LoYg(p_7#4;fxPs0JX1aTt#MEF)SzEmi_5Vws zpcy%)F8@U_0=M@2g&dOWq#0CcSDGeL4%+G%X)3W|NB~yKYfYnw;*Zh8`jk&=yag1f00(T^hGVY5_qZd*H&}?5vx~>BPr6^ zZGKPxd9=K^wK&m!HrJh$|G(hEPHz7iFw0_7lt9ziL?CipMbtOGEvSu;ONrVN-(o%j zObpFq{tQHDpOeOUdMLIE#+efr_T^Q?mU@G+rFp@~_ik;?EwBsEI>ELG01-09|9v=- zKxEpu1T{y?ovPM24GN<@RqovIoz^%P&<&12ETcZX;T2E7$cRmG4dn49`00mu*cPKIO=)P*a^6pDr2YW+kxoBS*+MtQW>Bsy+&-`xzpxZe>MmLJ8Jz5o7KC zC?l@v*W{;#ZlqVm)*zCm7rxcr!&*nd$PS?|(JxUMh^3DmT~?d`PetJan-N+;QD2yz zvSgF?C!lRP+TvY;1#I;6#fKaMCPMUBPXtum(Q9#Qpy5Qmb~mi*HZ_2i+fOVHzY@4r zqwvgMLQSX#V9&c56PXB=eyT-30JMFbu**$hi%+eC&rs>n@D0CZR>NAP#E6ojqz9LHuvus^Urv|J3nJ+wmpkn!(W5f&$8-WFdA z0l*A}mjNd)SonF!iA@LM-7^sF*PcO&+_}-x4GD*5{SHjfMh!Y zlGj)60=nS5aXi|_hBqG7qMt(Wy0KS}`Tg*h^y6CNQ-H-v8WZ)V`FB>w>byEUcl@k_ zmZtb)H+kZ7K0{60ILWIuT=U03mr?p}uCjz?_7QyEl!yHgK<4E@iHFzzbz=k;BdxbsPcfH|YK}l@ zHk9YQ_P*A-NX9E!=#TzG#-*2>9GB)T@c);%bhOYnJ1&L3us>@`UB3DTXcbNlQg@zm zT?4NS;cS_4K1_uRp{pJ%3TI)H#{;r8kVZ&t4?-o)xsX;zJQ0kI@QHxb_!n#ApK&^j zZRQwYalB=*as;La%W>4Eo97B(17|&Cd>xxu0)x(gXNg*YBk zzm4ahUy=<(wyR~M7w2hBAAvqMQ5B6x>;KwD|AB?F&DH*v9lv$Nu{Z-MZpA>t{l!)l zo0Wa>zoARLYKj7`w2iJk40-kYI5L<<1Eia6B~Pw*>CdqBLa@7M5_V-<>O`kp`v`ht z3ktAJjz4LFFoFW(dRKLuGhEZBb;mfzBGi1nGqT^YcAOJjy5mcTg`F3M6UI>>Hqf7w zt8>9sP#8e9U9VbzT~D?=T?V~FqyyD^Y1Md>dP6w&XYu$amflrBb+)G{-XZL0h2ni5{}~8T>EM>#Wu@2W zX?M_1(3o8w!%0))NA*v&m2+HzMEmQ>`OsryVJOFnJrhKvMXzVO$meQOo^HL0g6#Sa zp?uoLUAngM4ZW~Ks_&Si1hWk!k7W@wc7`v3t`$53hYeY+C}|r1P2`wk`Eb3eH{kA2 zVQX@Zrsb(So66J#-0|`LUw@-*+^XLfR9izvtF@2UtB%IH9%0w*TPY77Gk%AibZnOA zhkk5piXZz3d7*rm@Ni*rydD1R=AQ@l$1$JRVrY8}JrARIuSYS^P$*wdZ`4A6mI z*MDwf6eMyp01jfW>?w;)D=BZ>eT$~YRuv_34^5WvMD9n(UOf}Di0$-V;X^$zxvKVJFLCXOu(WMSARdKg5;D{csWn0S+$`IOq;1v#%0n zEijXhEy$>T?E9j7C_85GTI6yw)_L`SH{244wK z{ChO(aD<6H?SHNopXB*Uia#{I#KF~OA>5U|q81&wL~c*A%J>4IoEF`J=VY+B)a&F) zLyI2;gc#5_!n{bB7Ra@_`z5?#MtV z;G4%eMPv=Zo)W+RL&}(aV{d_&wH4>TW4+pzVn6l{(KE4a2^w$eZDqb1K^hrK0z)eE z&1MExiup?BkuH!abdN3n0gxCvQopS7$#f7?X;+%YzdL5qvWYE^BS_(4<3kfE5u5|I zY?F|m2*^r2ad6X~f}Rx_i4ooU0w?OEAUaCw*nYKQX;m(?{YM$leemY>zm*d@j%39V zvKGA$&-@^pf?(TtHyb1MFb%Yg7t@Kdmt~}4OpOWTiU_GNZt(}&(kW0adMq7wZ>6tH z)uL&jNV)2Il^Pi%j;J!wLs?L}{GT|;5?Fi?qHEDhfQmzh0yxhSy{eZU8}HW7hg_4U zacZ9WeAC#R$nzOm@cGF8V>st>qCRMhcOzgcYaz>t+`39Rp7GEkhtN+l2-4&IkrEte zJ=;b0!v)-g>BZ3?9v>YHH7$mzo{FWyVr@~#s420Br){ZMsSb@(u%yaj^L&HKaa!4U zwODUSjfze8#6$06Zkkr8iQG@G03$-L3|NcUSeUixuo`b`QH@+t2jgcEo3pGpRYKYK z#oqT5m7%}t}fD;Ynfg(+2^O0m+4i5MBp=ekkGrJcEvvfIBrSR zxjkq|o!de#=$X;Z53d}FXTU+zH)|7)oUDbGgHD$Y`h>P|M~WVnLDXg9@zG}$a>!J} za-njT{xvp0E(pLpy1D>|+t7DT?+O4#+*DyKM?8A4!dRA6K65sd)Rr%#=EM0%<9=+2 zA?gB3`gP=`r0eZ&A!!E&7whrgL~P3!I(3qW+tRU$6)o~MV)T<$Oe{36xM@>jp`haN0YgI?jSUu2oQzGu zqDJ6nEWqD&h#M_rxfM4rljEUqt^^rNHl6(?%9bIQzA|a3Zp9EPjIXT~Emm^-kD4Qk ze1oXMgK(<*4$f5q4L2tWwCFBmp}Pyno(gpV+5#0V+t2Ngw@>iSvzRi_kYqVqjK65% zLa>0s$}I(wnTwghd51Mm(Hg6rAZi z$Tu0`!pJv{u#d(k5_bc-EYHe!VZJM-+mCSPAWp-YVT1D_LoLdXlR?0AND?u~K}(kH z3vE8cyoI~LxfEdcGCJ%Vq(v{HM#Wb7G52Pca55(`Y4-0}pXeiCyjyO35vfgBBf4Hl1xP;>*kd0hC=4Lxa8qor_p|7r1u;K*lJ zlzv>l*gO*h5c3kOa`|E-EQf)idIH);9DU<^8TNcf6S@6tHlQe4bO)LRt9tqn0vc^H zPysH2NqkS`b~_$>iw7R_u<0!QN{jx5L$xB2`nv-$pu}_!`;2_5S`GE8!`jB4VuvSo z>l5APBC#c~;yJwvN>XOL!O`N${X`JB0oyH~;20FX5?n5u0QnOG_DVMb;B*aS5woz1 zj{@&?@^)x1&n<*ssz1xZhph&h#SL+AT;QgCkb!duldtMtn)I@mj#z0$(YU5?wt`p* z9hYI9yY;OfI}*8HVOmA!Tj}iGS~MnB1SEs2EFu~*^djw!Mi`kgBfd56XzJO>`G-G? z_5-iD`r_2qbVn{&_3xy`NQ9bPe=I(V^;sRzmbykDg#0p~t#To3-{C1ew%iP;y8@+q zwCG^at*Cnc(k9n$Rg#Z4zLK~J73R)B4>p*08E>%;Fk z*$C5>xy@I^lJ~j==&}s&ub3ZNWyEjCi|TMBkQ%hn zG>C~s$RZ}voo0pj2YD$RD(S-FL&lxm6fnGM0c7?i2=SU~}g+5B&7?y@MG zQJ`fD(vB3&e^OO}U&cmyfMGcIIM~=|(HXP@v1tV&Gz!JWmNZp<6FKf!mJze|Ji#j5 ziSeJbpTQce6lXmdGL%ec8`}^{!nD@FK65FRL0p3{VZtz)SK%>+oUMn)VJMG*Nm;%Z zWvpY5d4H;)ZY9<*8O5}b$R`RCwyo?@NS zMLt`=yMKPMh?6fW;k$^#b$-j^uep?7{)?vzDd7!-zx1w)k&%NyG=yyLd!# zDE@@q_$k0Z>~rAY1bo3s4_Ji#lE-sc#1&29be97n1OtDasDDRT$oBU{zsY+& z<8ZGBZ93vMY(|pj)O&GHhug~k8|Tz}>)$b3#ICaeQdTf^h!S|WgQnBVS>){CF%O<9 z;l#DyC0^^8s7;G*!n}kGNcsdNeLs#RL&o>*Jq5qP!uRl$15bCf=pRM$)V~|w{VES8aX&J=3%4c1ui%Js8>)M2CVNHj&2g_B&c?1jBztEQf22+ks~O1Vk{>7XMrhQ`S7j8XgD4|M*V| z2#+xD11LTY^0TCJa1PP&5YrqmvSR;kKoAs46+p$^pf790Qfw$a+_yiEb&a6fx}}!=NBDx#@UQw`tJr(`xDj8 z@wflMQQ;oq^Tb{Z?3OoyCojWdsdBCN0vL^Ep^>=D4p__1RQWZcv3VspOP*I7-%o-s zh(qK$Op+Iq#+&Y~qI|cw=gk}Nn^`v2`Cb%hnQw)0j2GZ{qByV>Um?`(McQWFO-D|- zs1;v20Qa$k5A*9qPFS%TdPMfsfK-b{GGIx*iM+4Eu=}+}zMpG_P!*`qV;0(Gt}W>jCy^ zEW(}YXePQ6$b5UINp~ANLa`CUBHs)JVvTm&V)P$r#j(@NBmi~xhhhV8W{dU;Pfx5{ z-Z)Ky=z@_1uK4ikL+TZueeoPj9*?UG)Zlu}_0HJ!t}??!|Ff+Tms$6tX7d(L6>gGL zt(}Zp__)_Ihmg5|%mri)Zhg%b)(^M8IASlE&>DY@Z@uXJ<7GU^wAQuu z6z=?MjYo*VYkEdkA3dp#XS#afznCrIgVsW{c#|a@PA$C9Yd@;+ibwW(tSg@6#~>Y^ zzIt^7k50S#;tO9vwAYB`%-WS08P|FVc=#K+($&K{Zozo8$iGqIc?hqr4Ao=L35DQe zu>pGQN#A;fyB1^#G%pz@Pt}wgQ7hd_et7Ii+X(E;WKalN!MkV=sO?6uZuC zwqu10yE?|Y1oXU$1O1@drkBF5?$jC&&~?}XG-qKscI^NC;`!-EJoOnww5BHoKYZFf z6%Lp4cnoav`Y=^H1b){e6?eTM^eFNe1TFw!ya-#qwq%ZFpUBNA^;+J*h06(;2^s_3 z00%W5j+d1i7mM@pLr%fFLFq&hteA|)(FpVeUN33~9e+A_D zZg8w^Q6tAD)qBML6Y;iH4u2InRuDcEIaV0{l=Fxn1C#jrOB6CnxV5>(y~MA?hrLYe z`T==^0|1kyJGIpVIbh?}_4?}ysGfrTSZ>Mw5!{|!$}9MH6=xPKS+)j+)| z-~u#MBJVr&LOj3cCGR}k^TV;?9x>p^i6SkM3Ds#fzR;c4j7E02$J8N$$67rP4?<8m zrdEr3(AOB8yZe~dS2t_Xvzf!0d>PY#7G216EbeSFt=6K~GQ|nJfaCoAdX{lYznCe` z=$A6h*P=g0TKqOthu7K8XYi%&wKRA2VRWt=|AH0eL-rdmc1%xrbeVB{>!4Z(v=M>eI-hL2226lRW#k=YTR96oY10=VV+6GXHJ}BT+N)=B~N6I2Xy8HEs zgt6ulPKFmRjUdCcDwq>D!PkAZox@dU*JHc<>#XN-l*WaD@j{u z9svoV8s;Hb@Ra=^?;OT5@ceaTa5RVw2CsTA}=P|-$s2hUcybNZ^2AS zOly3p{vup+!+rJeM4W{PJ_dmg+%qV6WCXoEVoCzl?c&`7f#xXUn=_JC- zgH?DG*Hzwwn!d>1*W$FrQ&BYmmc15MX$S7`AJ&ap+=I%3`s=Y9@vc__``Xwr-8d%v zM-?KU8h7$x@=150f~9Ts@8P`&bXb3C-3ff+;5LhHvgiwsV!Z4#*fzmSuFR?ITg-DHHZ70d=V0UR zRkdP&A@$N;mAJExY(F-$U&De>aH@jw7kS0g6-b9sQX}3mbos)lwHUWUQ^8a8TM*#Q zF5bs0FI|e8U3@1FBX(EBuEjbUkr!0o!L`kBqX=0>_~OrOg{|0%_yPW)pBB9ii;jV% z2otfh9gE&ETR{U8#_nNXNCvSW-(ttBgo4ZXxaVOqz@J;(+`-_i^$_bRpB1d)qk?I9 z!Ps&f2r@f`PQ0C*m(=@gP;=a82ALq;IIe1H8!yzq z-Y4cyuPPGv+Em>1sv2QEe!#u9ptf(!sbMX88PcHB=oB{ z)fM3Wv#0oAyqE_{W!L6Ocr1JIY+2<|+(4iM5AV+c8A+hG)ss^V-)X>z-j9?^Dx`iPz?C{cI-& z@_*_b=)<6mEvt$hA)^4ST2~R}#>JX^@7WWck9rT`e2LEZ7$t6IA$L#w>9;TtX#jbj zSv($#-wKCmU4|7egW)azeY_KE>@&8d|3kuV(%Qjk%qxz_lMUO z(WUGU*RWaP1uDAEi;qd^x)ngH>vVJ-GTxWHGnPW{bCSJ3{YK~Blj}S3i6>musr!!J z#b{r`Q#5O|;fYpv_u{A?n^9w*{c{FK#l2w;G<2%2$`qw#`&|0a;)99Ym(It09}?>B zSN?{1$LdM0=M?{a>u21yMG_8%P&Im!b&SDx)@L)wT)_Ajk8PvA2B7g^V=Yq5rZ~dq zZ0c-SsYR#56+{wFE!u{;iX_zVc_OsZs~K921~+hqx4yv6e&`ReNySFh!|iHq9*KK_ z7T_HU%l}hhintA{`m*p}*jez2;*R+5pW`V$JYaCA`kL4Mshz4Q(8&PJ=!#hQV z|I0f?#P{m43#Omvg74hbu;gNo> z>dTsyb47T<(v0nmg9eY7S_fP6@=}}vIHu)^Y?meLWYnrpv5aZ`9WSCF_Fvo7AD&r2a?y_U6yzR`*&jMw-y z*NtcAW_M^MBx@b&gdkNJC%b#og?^-)E+YZ9 z;lwY14VLghfD_jKL{i{=1Zcj6%3nv|x{iPO6qhR=Z)j28)e}Dm@g_1@z%LHO0o~5^(|%31s_8 z0+lOqP7>i9Ak=radcF+M;?`!fJ7DpVf_aX^3}HYi`&av?O}?9A9GN6;h&N->u-i^L zp;nZo6FQCm5mAHD;eXbm1>A>+x0n#`F`SCKU=FZ!JYS2S$J83{hJoPA0Q3__x8WN2 zV`y}A8#Xfc1C>u7z3dc^82Lm6NJ@OyF>%Ow$4`iW0NE?n?v?@U&G-ZXKoN!p$HoEJ zj%}O&=nhBy0DOaTyJ(2@3q#MRVCFSqavOjTf^uEwp&$-gah@sO0fABF4g%xznu94k zYah(P2nLMzA|K;T`A_gO1lYa8h9TpPM_&-kMi&V$aa@Z&j!et=Dr@rY$+y*l)4_QO z!q8%e^ffQO#BYNgfpu&2f??x5&_)mOVHU;4CqYPv@)_RYZBzJ)BQ4O;v3y1ME7*LV zS7}dO>5k&=%@AN0ztmxmntrS{9M9Lv{)s&x&YnHd-Swa8RWIpVaTMA#!>tB!h~SdCN|m?)MpZ6emKt=)|d^b1mMd#W5lVFxlq-zyX(`VijWuPM0}d$TZ4ng)FAn@6o>{-=qH|-nK;^ z>z@!zm3v}63|#2IjPj|yJB+(i<#?GN|Labid#!~uE76zkSX=2>i~CX>W78y;?wo-$ zNX)kRF|3WH7x+a7J}=$_fFx*az4d(sON6i7H~s}IHNF%sEq=*9Uvpvy31&EnXbQ z4sollzR2H`;9(@^QyvtU`BpiI%Mk@Z{KAtb{u?NqIUW9k`U$2dLyz#jtg(YLu=R8N z0>B8Lu|vFN{5jt;#%W;K=Mb~dc|@sv{>`M5OYXP-13g3(E{i5Q`Z{ug8d|~;@3myJ z&0GRXmfQ`unT7)P)0oA`hu&u#VsSXIIJD@y7(|;g0Qo--Fn6NRA zTiWMZd=wQo2)o=u!?g0adeh)1ii<+5sRs%S&rzvvmhj%6GP}x zi~~WO{re-_$ija_K3iemet}Wn4w09~G+g_~`6%9$Xce}r<9PJ!$hT^EjCCa0Rp>3x zBVS87ABDW_6Vf^891-v!be}NW&^PtcIv*9*Is6*VMqx(1jD4>`PcY+=V`*%n5<9vP z+z5nFY)L_TAJJd(oH8HOu^uX5-}sK|jNnPXKU1)nCb|MwJEy?N|5zMRif48|#u4R{ zw7Ib#yF;a)^V&l<-8h_-5ARzdJTD5B#_PWf;@2Nw{vHxc@B}dWJ=lcC4#Ju43fpJl z*Qa=(5Qv?H-|K*dp+zd7xhtZ%`%gc*1!P__`T+d!_Y3&55-%Z~a95~!gA~Ujw(5!>&)JTnzxg=&y9Kq@*n45@*phMV=W*B=dszI~ z*l=0|Aqo8ASXlhp*f4^Mxr00Uf+sAWAr*y;FLCjRa=`ur_s&61cyai1ynEQMpO>*} z(AY{xqeZ`kij)_>9XYNpJEyGaDlDs4v9frZ3%(ss+ORs~o+o%@h+GKK2WAx;u5mkD zeUwmBxQEj`4{FI%>{xgBD=k_8f`Qo0`1Km?j)!4Z%H$Cs-o+1A?M&(i&fU-tjuH3j zRc{BKGja5?FaGc!KnnV2w<&{}{TvVWcI-OQc=VRx0UY-g@2;rAgX6scJV?ir`>uW0 zy87}#dih#6PXkNeSal$k0=lHMgX$X;^eV&b36{jefwlm{H~chPT#F`P_jKG9hMVZ7 zfBi49zEbtqd=Ch`-tXlDHS4r3PkRcN&Jb}#U(%xYV9>?8*{-QpZTJRp#v4|gfm+5H zyY;OfI3O;MYOhN3dXSW&LEs8uQyBQsqpF?p^^aR(=r}wDTwI!(iberruYH)C$gSur zrc*bziepAR?gb~D`w)JtQA{OIPpkv#xDL7uATf_P0yFtrD`KLPJAmGxCgzyBVIH8U z5RlGhKw4Scx&_M%`vIJAHS!2t*dwiRB&d++Z0bd&j7k&n2XM2J_UI@qFCRNqCUXDS z2Szjl=$8E&53Xvw=23c%KU7&3`yQg)C@3PJWG9>>UbBwj#aAu*5)FT>#tWSug!wW& z;>^-Z5}Tx{o7jkGC_#zTM zBHtOpQ@1#`frqIC$N0D@RCpj@;11tWee3s5JU+)|t6LvIKQN(vIX>~KKQ59d0*RjQ z;EW$HxVP8iIX`~Yh4%$81@mygfSi{PWD9trPy}OGVxJd&xvjaG&)CF6FUWwu>l`Sk zFI0wx7uO68&#wy)8$Kjlvq-6)vvAS;dEW3+FMp5PJFxCT{3#2)3+ucC=XFtlGV9to z;RW++y%r{`1=u@(Mb-TI^Xj~d=dAGJhqA8?FAy!3)`z`ItG)PT?4`9gSeP}n^Q#xG z@Ge}kY|f&EAUbYo{i1nG&IKO3tOf(J-;^r;Q1;1HX+2j*VHVn4PzA5 zOKTUSS=E9$wR5V%^J}{(_)+fpwM*tK@`~Tp1`A$}sBV5OIPRjPkQ6`BZ4EA!;?f%a z*td6JRhJY=)y%1_Bg=rz0N^51mE)LuM8&oip!bW(4F^%uxI0)Yi_qK`IoKYhfK`vi8slg}%MV&`PrLpSp;GaXc*29Hf zs6lukR0}Zg!o_p0o$rOBSIwU{zs_5J1>f()hxpa=>?Jg3uBE4QZ}85ksqt3fSK{Xi z$tp{hE*V_2v<_3hY`z!2^j<4|WZqk~w0=ogOtGM*C{;_Bgcn|0zqG#2o1a{PQ1^LN z(1m&4MGF@%46|pUOBaf{6RN_ltOWuAQW7YDH;YN&pDYfmAy&z(rFAz_gUMd)Qb>OZ zx?v-Zi-a%q&aJPmhII%pUFyYDEm}0ly98!|x-<6%*csWwmnlS$wVFnN7$y z*MbS#KUq*0mRe6er)*%< zIs4wZ^U-j=m0uXHo4=?U{8#q$lPrF*`_yTHgnMKf|1bER=`=|El3o`5n$x7~d&~Z1 zdiXSWr)%FT@!#%e(YfHvQ>U9Gyi%r~)8L)1y$z3_WzjG4o;qzsEWpotnJ$p&>F_(l z^CZ6aY>SR(z^T&`2|p(BUi>fko#|9c{KxVw`iFg|P8%frMVS_z2Jdw3ZTSAd7X4P4 z4n5Z@cTU&J`pW-;*SX#Q-^zJ|tnpQzf9i4mH-4K7|DUxx9bJDXdjD_JKV82z{B-^O zH~8u5ZMy$!+T2OsY`S(@Im(i^zx34U;SvkJU#2h0^mO>0;SG|0!FWkWKXn?PV8Lr- zy7Rx_@9#usy2L*`#iFxe+No2ogm0Q^)i03g>F_(ly%K-tRaX16W}Z4No?*e;uC~%@ znVt^6GyGdgU+MIzmF0y6hMW)vw<$iaW zO!JZQv#`FZt~xm7I>J*wfk_3v!m-I(fv%q69K9Dveet*Gmx%;_`(XC3@Xs-z9Qt)4 zF&X84>k|q7OyhG%*D-x4k$4B`JHJaLTwq|v!@xtj^07qXIhJu2GsX#eIK5nnH1wxL z;uWN?Jef%Fed9rYNhC%fUHNn(!G9oa5U$ofiS!kuud|F-QG98jkNX>8q%*Lce*kH} zcN2-vnC`=oO}e5yfH#WnM*0qZ`R*&EkN+F+4BXKE0{kNFDF?6Kc%`DQ@Tg~W&2TrX z86LuUIc^@td!EE$a%z0=gF52-AF$-21adrU9C}V(#95Y8F_U0rFjs6!873ncw-*Mc$ zA(42O0`B0uLtd$TH>=LeN$!W7Uz#O`bgF)CL4zL(n4%klE=Qo>Jm@`N2x9+DoUe7x zK#q5ft1PD=!ufJs(kbpfqWgT)4qg@?h`uby#RVE zu>Nk4{M_jf^VmU8=#P+lD97*2JGJ`gf*{vJPpsPwSjRJvw?AADg8)AactG~E&QX?= zw}#`6xExPlMPQADq=r$yW&q#w=S1Q$o@oB(dAc;`uOcWOb16+-@Lw-mh0@jEWo)AB!#`aB_Ly~DZQ zaY{WKN5OJkE&{#TyRhDnSITlcj_FvBWm(hkEv<-U5AFuuX5c+{x^Z;q_k^4p=b5J# zn>C-4(bY$wR{(o@TI4iFe7@Fqb9YCWpZ_D*-|{pXAJn; zxffR)V24jHA7Qs(4OPeDQ;Nsple)H!)@7z&h<_h-w#c0!%eJ4Pujl7QSCndt};qy#H&tGRNY>{&zb4lAitVc{X%fHxtHrp`rQswM4brMnC;D@) zTg>c7L~3Fd)QV9^bEmt1ZV~tkiW$6sx!3hQUu$&70C$}bB=VKaZY(*~pCWPOyEB)w z=#oWG=I3bVN|VLB%o%9!N|!}%=37M0ki~*b{vw#mEsI5&BUqa$izS&qVX=!W`ZM{i zrmL$g>X{dla<(j1W`4)o99f*6c|VID^${RB@@HqBMN-|>jiR_9lWW}7Q?*7^li7#J zd9oPJ{4;C&s$nFK{1utMV(~2XQY6m&1~u~qV)s|4i}GqUb0F)zD*sh4XMRM@d9DoPv*(B)5FK{2lIMU`=r6TuG;Mk=Sca){MR-GSQeGIM~WGJnQS?GNL1+0xZNHldC zU}`2iwb#1+kD&vks5hY}Pk4!OU7%E~gl21Qaao|Lud!6658+8Yw>AXUggyq1tOzcZ_tQtR(*>$x5Z? zatU9CMm=wlh1*fc{fR8FH_;RSbxD3OsuamU6P81JdcBOA^bJ&cRqe$K=;@DGh2H84 zl+xLv}LMF zxr-XKxDc?6Us^3F#yqYfL5`hqpO|)|Rm(A@(mO*<&jQESsa7>5C>pa}1$$ayRZvPD z?Ua7%YpBc|rbYo*)7{lz`Aqe4bmacIDr~1}jYfG5=FOor1KVx+r%NF-`X}45@gL>n zrx#$tH@WtdpeTKl?RYGwl;*xfR0%I67hEUrrKY+q$80Y7M$&V1gLO+=GoD%gLyKv* ziR>@If7)7s@HTWW?REiun7AcN3ECcKm~VJt#1_ zBT3sJvOi;APl@cs?BE$@)7)o(mQziqhjiQvl=Q_3z%%-RpeJL+RDj)Ifr*S8-vQW> zuefiAnajAT3-R;aWFUZwOp;lQzb<>&8g%PW$Z}MoCwIXrJc?r)=~stABh7sP-(AUv<63-mDLR60 z%jsu*-wKfkr=N9#6NhnRcSD-xRCC!N-n@&F~ zLlz6N>GZSQvRIT&r=OK6izV4~`dM9M(VtDHpVd_s^=vx*tZZ4V%%;=N%8|wC*>w6@ z9`yv+cjV8`rqj>ruDUR4NB)9rI{mDksx_jTY&!j{JXs89|CzOY@pd|qS7g)aXPu=k zKtiXVO{bsLUnLD^{%SRQAnUzq7tp5D&!*GQ@~M4Ad99jFr=K-geOcf)tJ!q=StC_W zg){#?HJeU9Ym_XnSF`E#vr1%ngPKjJpH(W$o78MN{j3Ys!J_?UHJeU9YmDHYPCuJY zKkH)EEBXhsIduA2(&=Yyph$$%&w9j?j^*^T9<_vHIsL3BEZKOV9(?UG%}u2c%F1y` zRZMeJJp{DKhW1c0YOr>iyAIKyr*3-Lu0=er;1ak8taiPC0;NiBg@Sgy=t)uXxHDOI z@gt&?=l%?YyZYCPQa|_KK&ortr=sL_&tSW87K3;J5yRooSU8xZh-d*Ks&d2PKm$ znD5;SA>d!C?*qoOhl@2>fZnrj6jp~nwc@%*SdF1r_&Jwdh9;Vrr5VV1_JK+_#bH7| zIiYJs9W`P(>o~QFBNr5MDpn_}?qwBmWIcZoE$8yz0@_`D!md*sBf(D270(Fp4uZK* zyD1sZg14faiRU75$MBVNC9|BB-sEr6U{P|r`2#FDlZT6v$2|y*bEcGvQl5JeW+i7T zJrLus1CUG3G%}0$3o7DAZ)t9hF3rtxq`Ap*nw!iy*nQ4)GGs-9Iaj?6h=>GpuD0e< z5s_fd433fd!ALM?rd9IvU?iAxjfH7Nf;qFSzO6_wXEq7ikzmdot7JujcFBqabLLug ze(+YwHkbn?r;6E(CXC6GQ{5AZ#m%)=|4NU#8M7U_WW zSh)CFC1Ma)Eiima9Rji<#80*?4E?5$Cu(8^}Y{p!SuRx7-Ln5T8il2?Z%yUd?qa{Rl zkGXRdbbl^!)lT#J=;Rx?FRnc6H}16X07 z4)(9EZ6#N1soqU!h8ud8r{22``5ugo@3WPlkevVA>dfuFgr)l}9^tpxO8v!D65t`H zU;WiFTfL$3*0|~>Z=b{h=CQk{p9XJ zi%JQ&{|i}WH|j(8vd5WNT5k1WuICAgOew}ktY$7ab{Ey6XP)}zLLj=gqmjDT z8i3;7#SY(M1z8(K*8XJ=F3tTu8ahTpP1LtX0ws41+h#gd;;Z}({a)C0WI9>wg)K*> zlb!ay4m%N%%M%07a&qKK?htUV7F&*5eVt7(iN&I^lFQ$fQb#&f4qg3TR*n>veS{cB zI$5RUP9TdbUBYmwKJe2U9pCI4kGkHF!7VO|Qt8X1N;NxORr!xMkjw0Ja@nW11t+vO z6)Y#c71=!QNM)W>G=bcE-ZDk?q;ux;__H@^xAYxEE+Mbo(@7)m7zfoOot@@ggbvi6 z=@eh@8fZ{%`YY@P{PjwwU@(Jzbf4zFOnh@qr@5D+QQu~YxXP`nz2OA65%Be1&YT!>?lcZPKRvc~28V=D(*HWnM_b$_r^+C8U87Q$D%B zrL5kS)A%)+g}~l*QP%9|Ju!`Wv@hyDmk?g=`)sn)B?1rC3j@R^J4KT`p^&>I;uVm( zdWq9Q+)hLc{}M|}=U}y6;uK0jNnGL-JyH|=PHF->4+zw}aTL#3fnbSeoRi|QRH4i% zR6$ICxl>HPP>b<`wixgPr#=0;wHky(f=-TK>Fehtk9Vl*gluc3#ydEOytgRM2@Vc9 zuZ#oHt$ZfA2?`wYXyx*@6MCtI!Br;n)Hw^47G2bE7Mai8-HSQzD zw3J*xOnt=I#nR|21cHs(Qd)u6RV$+V1rYlz2J?WB$v(dXlgJZ}$z|NtPrVE+oV{FD zO!yW_&ze<72&0TXXP`CmVu-UbW@nyjFdC!XG`1Tc+nt$Xw;N!!%V4_!qFtYE9r-*# z!)Mc|B8?%E#^NN6At^M5q|lK0H4r;mb?{VV(aSxbQaxaiQ|~4@NdJI~rj}CvSTs>` zzomWXDTVnm(E14V=_%Bw4v;)L|Hl;F$-gfDTc_RiHl8~!z@s|}i>oF&}D z60ySf0@$tpoEk-4>gHz4dDrHfy-$!rjhnd6yLR4u_J|xmMX9)_;-&?F1Jo&m55NhI zd)@$bqVr32$^i9BwpH@SOXTY<#7yVov#r)ZXDh{LGgJg}AmzwR$oRS$O+>(1r3}0c z5?8+!+F;`!mXv)o2#0}tju^gU4rjY5^zOZ-D_+7s7Zn_5;4+KpA@^jKp$U#9ALnLcc82Y-gT z!Ta$wq%+3QV}R}j!J!VAQ2zKzQCDOX3v-)x*V>j< z>C}cUidV_MQ{rAL@KD=~TIK9NOYmJFafe+c8@g{+++LsCdybM{CAs~r)eBG8idRWk z+Fkd7REwyYn0D8C(#`*ato)bNAk)d8FA$&nzsai4J7^6%B4K|58^d~avrt=6C>|gS zIGH=AyBK1ob90i`Tv=OcRjGa@e~koHSRe;BX=gt!VI1Xr0iQ^C{`(TXqN90^)VZHp zpiJkd$<7ALsweEK7pv?sT_>wvva4QAwz^qXePmZ1OSWo~RmZFoqQaFaG4gojK&22)OdlJ6IzIh>lBY5-{5%>`td+fK9n&Bt6YpJuD(#bfmtO z?(V55qwWCwRWum28ksccwQsP*dJ9tn?$u&iv1Q0kbnuYp>|9y@9qI>y1P#UEn`K_^llrIIpJNqwC{sw7=XA6$v~9CtDq%p~^}rHqR` z616GUVtO=SYWH3c@EGKpU?wgchD`c#e*b!?j_>UN4xNO|*Rfki zriDnCEFZC;j#W?wuY?Vduw?~f$T$~$wZGse~-+S%=`(Nwa5tjp4D4&CR4Q`-G#ao``#Ht*!L|YMEl+)FKORL(qAZf z7QISj)phA*C(*jN0Z`F?Fq(<>FLksR{Op$PkIPh@mwxw2G=_A>5cF>EBk8??jPy78 zdvYyaHiCedn~xWelSuujElpYFVC)2cC? zBWS&%T=2Y;!?m^!_GCBpv-jB8?^& z{cpvYD4)d;;|@{(7|O!ETgBmLp;~M&tn!^Kiyf&|KDR&0V%vU)s{-uZ#quj1H z9zv5l#YSb4mnCdGtl~x#&%c|zHH(O{>i|@XNU2$DfNo(Kk%m<}Js(s4CC#Z-d;WLq z<}MMa{sndCiw&Js?&gz9H>j^AnM#?ezjNIHA*Co?XACjPSE0R7n%^TMC;5_17~e)T z&Kp9OpAjAB{gR@z^1l0IC-bIpK4Gk3j0U|9E}xMVTWv13xIP1+QHN3Y5_%ZY8Da3p zsDY88o{5uT)C8Q*D-%e}0zLZ~8fCF&-Lw;cKW(KhE!8 zr{?|d0;0Nx9%1#l5P%AkTgXfnGWRjl8<`OW$mApQ95aKF`4X9ciBBq$U1j{GJKZo zNsvlLOv*((L0B*AZuVNeufcHC16bjs#-MiZdB{varrY_LfMLkMS>pTGL$Ad5J^+W# zM5cNWGS?#W05f&S9A{<~GSdem6GP@EW*$W5kIX!Q%qPt7$B@q&g3P_hOh#rTcbJb# zu4*Xkkh2F2(x^WHF8KL9GBIFYya~1AwxHy~8e_A%{?;It%T%4?oM|_G0WC(c>0xAs zbjBP-G6h31*%kvfg~McEu9Fr~poD-TI9bXJ$^8Tw-|ezPhR|GJj7>xkZBaWQtN9#B zz0P^S=IJjsk?)bYxDvIZliDKkAx89X*)m;Dk9xgx6eox5J_rkf;_f zlO0@$6B$5Q6fc(5*V+`Xa?+p+isuwdia};baS<}UNheXXM#u2a9%KFyIbDx}P$zwT zQVxJCc&AnESOxn^p5f(g!nCUSmX~XgEPOM-k17OO;7k1} zEIz$lzVLGI55sch#TAr40m|UvsO3>ZzOd4Fpm@GGG1Gg|m8Bss$#(y+`?|pOFxpzJzKFxMh>vJ> z&L}X^xxqx_n9PYZW=)}B5FcVP$UT# zA(8|U6-fdZNC=5QjsX&gKoUs8O-L{SYrQ6TZB-85Z>ZR+Rj}5!TEVKNtpaMT)MB;1 zts-9PrM~^vnpw}Dlf93=zTf|n-!ErBvu4ejwbrazGy8VV(7_Y=Kr3oe4J0mRK`ik~ zNPL)pbC#nhtTQP-^+nSQbZGycYIKIK8a$DB9A_dixigZUWMM3$$9U1|0s<2nsa6~I z9F;_siw93+>|8QPQeMYH{zTeFyx@f%*ZZF1`qD<8Fke|auHLjdi&)cW z5ughSnm_GH#wTe0wC7U@pQy2OE+;)Fb0U4v%NTNutn%Cn+Cz@JhbmXI>wZGuQ3lTt z=$B96MFPtSWbY;L0E2f39ANMvfgcu-yz}&fQ10Ck_ac#e`^gizBj*=X?GBV0lpV!y=M-!9T z#!V7~wzA?6NA4j;y^Sj;j!_p#rQXKPm4e>JZIXiC#$6``y^V`WLGP)%Z{wa6C;pN; z>Ao!H4G~4%eWs2t_d1!4Lj5m8*Y ztJV{B)xdLTBsx=w@oXKN$DT`Nev(kif1&bebhF9S{_8xdeX)mM`_%bV*3ob3>!wh7 z39rYKw6u2$P0XC5yKXO{+RM4Ml&4Zz&m&X5X&TKRey&gI(_`#~bG4r;PshoBfn_}wIXR@YK z+zm7`s;jeY_;fB8YFYOXFHaj&dXY|fqWK-C~(_@1lzF$XejF#ee9X7V)_cHVrt%QWzQ$e5vN_%T zqJjV?z%LnaN*rBDfRp4B0uyq`6FMEcVpJTx3aN31rv(fy&Pc_mTiQ8>(pM&Ph ziDkmGEP}m~GKVzpd75E;ka*yg#owj*W@(U`LbBJogHIF9e@W7`=3g^l&Ci%Cnl})b zzz@b~&F`j?)_fNO*1UP1uleHPMjbsz-*sDAI{W-4VwrG&MX=_dP${!XSZjy}nqTv6 znscBGIo-(4;UN0heFL&vsz~+*B5K(Osg#*5tiOzteeQS3{vg}P-ovt=aL3YVrq+8+ zlw_xRBKv(RWqu{BClC+xe(wy^JQRlU+T+(VV2^wA9s0{W?Uadpbnb&H6P=8EgvMKqUl}^xTx+EZyqI-w z87kd)tTxS^%;^&U{F;ll;nz|{8yM3%qe57C(I05olITt$$!!^C#EdXhH`mGdR7kAE z`Cw)xG6tV&n7O99Tg_;x;T_kdrbeICiUOJcmcYG1>Q<5i-jNu(&(Nsr%m-xXcM55W zlldPZ{Z3la1&YiEvWy;w42>>2Ei?q)va#qFg`qcHGSDuWA`DLEv>d~FqN#GHI2p+! z4e7thtTQ#4?&xix8-Gs5?QvCQ-KsKwI?A+aKp%bz%iJPCb49qS@(k1J?r>F|R6QH6 zYLlur!&TQx)#u@=2c+t#Eb)TX@HweEJzUjutkLlNaMcM?H9u4}dW=*BCQ-7-&pr2~ z9h=ihjr9HRo=%~DDBm4x_7WFK(@*6%oaTr76>*!r#8|zcuO_0ol|RnKJ@AwG4USyB z%(^8*{vpkI3qx^W?t~9GT9L3Tlzy(lZKNGDKeBO!d1Qljm{%Ia3$#GK0&tan*uXrU zBv?PqbamV#EZ68qSoC8n*ZPmGbn3@eoB{n)sMqcCV9{>s^*DXYZ@a$br=Mrot{(+D zZZ@m8J%w4)^iy+>>IaRE)9kS=xf>80E7P@Gx=XTGY8GY_>6*BZX2t!k~M<$o+^Q&WC{%a72~ zKUj78#Z-Qp{bK4{s63X#VT>5M$D_KpRU=)}8P|ujd7c<1q*CwM$53hi5(4Q2 zHY_DDoWO1dW0`Rofk^~X>j_LJa0Y`52`phyLtr<7%z4sN5p|&h+CQ@!HQ-F+Wln*k zYsQ;`=GnT?6v)40Ines%nsN#I<)AuqG^zU|qW_b67SEXt9tHe zzLQJ0b1U@O2j9=lsF4;Y(Vpi_(?VBr6K7N`&lsW4V;+)%zT5k>6o`41Y1aL2ZxgkC zFTV9>@vW03Sm~*j>9(XT^uz zwD_=_D+LO>(_S4$^$`dD3J#)jgAs1piNc`I(+tl-2UXB$MFx zv<~N&)!dJC{S{4=WAz$n|5#t~eviuf0=OxDy@slvXLeJ5^AcGR4(qGfzg$PvTX?xK<)svI zX}PSODVsB5ga1OoGMpdnc0bXV=?_sD4u6F$HRZAmRQ@%mU{hX2<&*dx;-^Xc+=uEq z)M{=Yf2Iw6mf7hGK^@nWU$~Ssqm}D3eQADV2i58u;h*cyuH~{mUH?3Zhk)Nw9sXk; ztk094qjF>um7Ca3Q$F%CoJMyf@0no6@AT(r&3mK36yBDjdwlXc<7jo*OLgZ_qpTo9 z_5rEM`G5c|nta#yu(Td1qTQ2{N9D%f`OOM)=)1rt{D9UOep;fAfZPSvw=mxoIedxS z-IRO>$UQmGQvO8Ks7j9M zXVREI$1zZp%ukM{?T*8*SX|7{yapRnn-OJ1A2EeL^7$i&KC*&*ITsO?{?1A#?=AOx zoEF!kVBMp^Ls~_}n<{h$N$UDyJv|vnx5xP>k+;j}V&3&|hRM)V0= ziIDw6Lc7S3GIqBL^FBGc>yy8t2IKxgyifj+zyShp637a2>M{Ips?lRO_zD92L?iQx z?3_sx89Nn|Ch~!viBB#XPs*@t^OR(eL(4pmMR8no5sE*kjp{ETp+a%!LGF&}Y()Xqf${pln+$$A)?)fiM zNskZk`Rb1)Ecp?=WAcn}y%6%WcQW6Q>eEeCQkyesh?B8YhL?AElck1-*vYs>YM!Kl zU#e^9^i~i43~!y&hrV9qKLeeNn`8u8olfagKR-chGq2E;dNc2sWIT7DsZZ(ZY)#3e z?b~xg=e93NTkQ?~oR41JGrPq5@0faHYUVf@i*F1y?zzRxnNpROuRRc7b+J^PiK?pk zMlo3oGcOm0GB7wbhJjAPrK$y0>*Ct3CnKL1hE6c#_-*${)jg)l*f9Faw3ABc1!UFCH3$<&EgQTC@3 zz=*DMOUAD4N$>ec>q9gh+@zH2sr|SciO$U9t|GuPCZzYKpnZT!XY)?onaV9QrDX}# zQ4hM+#b~vaz=RD{lg$nGQYo98kGYy!)8FWM(pX!|zo%jTiu8Nw?gz%gPGOo_Z0awj z*6xT&#=;M@6;EGdEc`%Qc;U6i!v8WBRt;~8PzzH!qLUUgKGikF*;E{^pSk~sKIz=b z)qGy|PknB>sf()hy=7D0$z^>*{6qcHOUhk==si@{?!R43+|Ew?G^PJp;(oS7yPpl5a43QMACZLJ#{F-R zSlz1s_0;Mjs?qK*q>^_3y#)AA-{s6df1)l-l%qSW$2{(y?E7)uIrYDxdllFsTRb?Zo_;cdL38PkLB_zk&{$|rOA zj2=Aj=TliLf7TS@q`!0I=$_kSAW^jPcM_BCayNmjAgAuqy@?x-`hm3OY?pbD6nGv| zSoZGPMi;>(uZ?u$4N1wkU)cCMUJ~)J zq^49!WuwoRDHKrI$^2NtDAzRUsqUR`3~(~fm~2ofs{9K9nO{g%t*LS+I+>j^_-mza zx>Pyp-*H~cJSb+~A`G+?Wb_cF+4QG`ZXR9W+Njj>qi=7cl{SeU;^If!^m39crhR2N z;xqgJsTx3`)7|pX!xK9sS--+j=)RRq&b}&HUt=l})}m>~AK#F>-G%4kq~oe&igoAq zAK|3q>SS}$(J5Dzu1V%dKK;j(5cKUqQ@()9oNum8=IcJU=xWLrom$#6T;z*JruY{w z>Pt>t$$SawAGc7Mum5dMuIowf;NFUz^-q$APc=$rd?{M<6~QCUVf)MYG5Cxlg@IR! z;hHXc4!$0eA(g+QPNsLOr0XX7$&Czjz*p02eHJI9S(K0j&0{l((? zd#+n0J#o+d@k71qIJ$+Ad;OEo=w!SX*XyToy?zrpgRdN!~RxYu4XkZk3cZj}>Z z<eJaYQ- z=RKZ&hw^J~bFVj#qJv)zyH7J8%cE{!TDl^J`}NZA3>eCV**$ecx^vDWQ92-I_vGj@ z?|shhIf5eb7=D#$c29nl>6iud8q@5a{2G&ar)+l5_lV6jV+()Ip zV4bF4NfNAIN4ii;H%iUv$&W(Q$@!BMe(qXhcZvAs`BLMSyC^K(14Wo8Yqfo!--dZ| ziM*A@=b+@Pb-MbK}B}a2K}a26BWnuy#7oKnMk?Sz1%CFLfQIiqI2)#E+y~| zagJL_Ani`x<`CPoo2jI_4zy<9MPNFSvmYk#AcLm}OuUOy0H3CAm_E_rzx(Cr{@iY55e;p^XG)|-lz;bxT1;z?}mODMZFjortYT9BcP@cZo2%`%;HKwUE z>YJHyLQasN(d|x^0=3%{YL_`pYX1vW{0pY~FLSzEw+p#0hAo+eHuP2sN&xi z)_VAK5mKSFB)c=V2#x(xt?9-ePYZpW;f>#c zyed^Ug{nrsCsp0!lwA3|q@O>a%@nbRMo2&UG%7>P;x}dK-S{L5#N%Y`Sz1hKpH54T z^LS^#PcRKMh?W(D%**M=>t#i+HiLBLHLva)%*&A=esK2$olMj2QPj_gI`Nvjg9hun zfG2tU1P|Su>lq=YpP7x*9+^BnE}W=`6;~P4bb`X?h+e`sAN*IwxXw3c2w~DrKhp+H z9)kh`OCBRIg~0U336v4Ijlo3({>b3pB7Q7?c>(%A#QhKUeleB$@7afL6+c1!r_-Qj z_ovc2D#@H*Q*IRAB1d(KFBbewsl_~kZKt&%DlK)r6{2*ZRg>b{@;Y?8Fnk4u zo&km@g<$~Y932P$HQ$VdlleQT%0bmB(0O!3(v@z}33X_*JI$qNxu%ESf~N`-zC7@h zC#mj;Sthq#(}R=m>Zi=LscU+iJA&H9?jIX|Z|r|s){a1Q(r70o3TQ-1du zD(h5!eUA}T@BM>-*>hbmrno)cm@fKpxm!xL?l5$%K)#~er`nuFDMADZMCrRV2-1wRvy5W0NsT=0} ziW(lE8r^0MmGrf&eFXSV=d;ywChEdgIl6m#WY6rDAA=k^kM;ev+2?uoJk@GB*;LYUN*QqO=6V`MUYL%kGO{+X ztZh9iSQal#D_O*L7QqYCC%Qpqn~d5T;?i>k*Ksko-x3D?eoDeH056sr@dp^Bz3*d8&*eLz#Fr#bd7$1Bcm>ko>r!n&`X7>Z4_g< zRgSLJ^vqj?&d(#0+VmC#?r!XgYcW5r#ovX#-n59@0A}=!8jtd|hC56X{x$*nu9B^7 zI`409b27#V6X*SBjSS-r&ik1cOYNJG&Ogek|1uwvs?Sliy;iD5|6Z!Ju5JMa2OH#aQ4z)>QI2{ROf;eMUn8{Os?|ZZtXJyoQuHO*C~0`BhL3% z5T(y-)c*kWJ)H|0DVw-|zm==}n}vN=aj_@miATZN$GPB-$;A1=Z#3uDWyYXBw^MP( zi)41M`}mt4U3W%?ONINT&_XhL>FgCAAt~;1YF2|OZV80#DndL@UKTgiB%UcOkw~Qsd#+{Yx@3uX9lzs}{E!E#@ zn@Znm%U60_{&oxKbU$?!=@gy#*(lQ$Yn-aTU}?7gV&0=}GgpoHxhP{Oa~$Q&c88Fs z`(Qm2|!I$i?D&0e* zSn9Q=Yg=KyK9jy(&OP~v{=L-^#~(2(yDqyH7{t`q6iHHj*YrV58E=+qZHbk1vApVf!o#y-~eJG4(>|9stLTC!I0xHR(j zz<35zeY{UfwrvJwIWWKw>5Ha=d^~)1JlM+r&1kUK^mzP_qXD1yg3tLSC#R2beBbV4 zb%Y(OBL}#wx^}wpz)|dheoST}eMw9FkR9FMwE;08i{gWZQ+p&`$H+0shMj_f{4ArW z3u!V6x^Nt^>6Xk!-i8<>-%<+^sz(ZeHAbs{`KXvQ%6zP>F3->xydgUT@GtBCWb~l>nrU#l~J-0h8PFpGt zkJFZlr=LLa%-vS>u1sdtMkG5N;90#Xtoo6ovd2)F<>WA+FS9bLUpJ{2bC05uOo`E^ zf^KZ+5TX2jMp#9efMdDWneK#evqZOvDPr1q%|_Pe8MYgY#rf>z zk^S`~EwGKGvkASaBYN7153KV z^pJ?5$4a#xx^9Lon5;E3p1=WC+Fcuyr^@1qhBV8NIDE%Y{$nSWhZEOqzo8Cv!&hO6 zKbUxg$#LAi($Wo)QwBLN;{2ZTo%=OqdRo$m;?TdF-O{uoduiSL>_rO}WUtO08y!1l zL`(gW`i52YBbL_Hx2ztqsJWt!Q4ju%9(wz(>HsS`=z&`=O3NjA(FArj0Zgm1o7|4elwqx(fB9@BdEUn7J2 z&+#(U#^qZgL;6L=9lhbKr@Vc0)CWgy$r-Q4ZBvC6JG?Wz4%KIi>eacsxTzqogNHCB zD@FC}^se(--u+=q9#guCy)%ku7prGlvnneK3+Z3|%5A^-=9?5fJ;W`xrKq`Hg*Ui` zOE0LFExR?jIi+iA`689ouC}&$+dkRqwOnwj>Q&JdQxmpqj${t--YdSg_(FBT;n~ct z(ziV9ttwDuht+Z~U9HV}Xt(O!d3NcdSce+ob^0Q;=+2Zy9V&H;ccxn7b*k$w@$$XQ z;j4z9l@w9!EBBJHj$Q`|f76n$an_hh@1)|&!j>`FYFXrDmt1pk3w@OEhq}LYi|Xz5 zQ!PcRPsP6CN;Ul8XR5TQQXTKr7Ebkw)%+rreXt-;O{-O7J9oaO=5!Y9D=1XQ9#-$B zd`i@ zLanV(sre5TtNIGne}@|1{#!MvNY!_${(Du=!!0W6ZBZF}Ur-n2lf*Npsgo^>0)uh$y7rZ7IEh?Pq)w<%UnL(@AFe6#c6X?Ty$=^wZdYr)!*uLYZ>#+5 z!b`LBii_3V>pG`?H0R9XscL1X>YcAz@;3%J?poKWjy|k@(RTR75!6I&O7chl-bqMs`#fL`zn9d)So77k9y!K-C168D^?NFn=yZ{9o{b(=0Qr+K!%xz-bUte9M?(0#Z_S3Nsjr7tYbu^8@L3N;K zh1$BZf{t70Sk!T0p_v0kDRT<5S>U1Bs&0!~yM;bucc_dlJX^k5yXz}&<1@uw#cFhg zntD*Z>{ixw4kbZk`fc74)Ox#)n( z+V%2_N#hZ+S#@@a!P;oJju!Eq#sT^O#aGJ z%@yj})*|(d+rD9%dUt)kx;avz-d~@kZjVs3=M$_bpr5%cQg5%XP}lXP$oOzYg}Nh> zuQpJ#4OH>g`l3(N-9*Se{F$0u)S(7>`DDX1@^K`Evq&UmD}TPmA5Ax?%6v89pt^vD z@}>3L)DtA(x9e$|JwXy)Twj~5L9cD<550=i!!1P*sfG&myY*f=wRY805l_dIw^A3M zU%!oy1-kHb#DvSQ*SB-Ii$C(HMTM8qp`Kq~(V||B9MnM&@g`7Zgfk$0<%fE7jaPK+ zxU)x2n^mm(w&%4xn6s}^t?7)Ze?@B7d7Gc9WJ#YClSg-}fh;@n34avx$HJFl`~J3g zL~MlmNn7ovosX!2yVOy&FLH}#_(PTN`lOiV=R9)tNt8EssF(W|sh_SWs`P$DS!82z zmnz&wG2N_w*SbXq%!f2o*R&l}?X8guZHwCA(#UnR6;b;R^(6_r zye+FkeeM*sEb>NeI)9ql+?KEY%c)Q|v{lrpBii%29?aRP-gKHba#tSpKho-|cS+k@+ww{8zc@t&i@ecuW_crNeif;Gr0@NtuO7G} z)s#O$^~zT(i|DhG22s7>G;i)A^>?ce9X)O-UU~}6mV-Oh9j!amU)U#iv}S3ayy3R1 zdt386)IPU}7rRJEZM~GSMeZX0(Ca6;X16z8-PpQ=)`P#1h#Onk#p*qRx3ILo8fk7y zZHo8ELwN;t<;5lqdHqtnhjsqY-LIhdIB{F$Ll3d&lpQI&YCT;!UOh#6zTy_CpU`Cc zse7168)@i@c28R|V$O=Gs+ZS~b&Z_dpAY+{T}k)V$T5d#j<0Grvh-v~*;ni>o^qj% zWc6qI;UTrL&C_GZEBuk(j#zBx&$w&Vb4SXq6cXTV(VDcUc*kja;XyS$GTxmsRsFuT z-TSOVJwhh_v9*G&y^oA6UX)k7_`(eZn{_i2Cf>u|8ZTq^=J6LUQmZ4G?!L{1#Wde~ zd-)r>il5p)e(EBxc=PPyn)ml_nzG5u$SZiLGLJ^Nm6mam5>YXiRz50bx&*aI%D)Fy zK1JK|E$T=;r0PnFm)VCuRs9chn-pyn*>thDOJy_3Rf}|u`ohu2FV#O=57V~guzJxU zL1QB&u3AFihBk_Z<04~;-^hT|2fAGGdOU($CM{-8Bq2VT$i z)p=b{<){x_ujtGx>3#MdFX!B#*u12&IpASY6si)BLu!UFsl(y%z90 zGuzYvs`v|cdT2dO*Qy4uyPTQg$OZK)!GW&1$_C2JYS-XQ8 zyz6eGXv$J8?W%XX{ybc%nzK}&c3Rhd_-LuO`jd;_rA=nzE_Gyn@dav0mKxB>3xiph z+#M+!bt;!-O4sOBK~M94amVNJhfZ6o84c%;O{y2|3Z~HZG{1t9oZ6kzi4EJ&*0ifx z?P_@EA{vMb)ad-&8y=lLS*>kXJ=+)U%d33P8?alw;&>(WK^Flb^6{5r_7&3L#9e<)j*1fMMdhk+754ZhdRZp=%C3{>=jU2+(v2q zRi|j=Wc5&6t@v(q-F_&dgbuQ5rgIi-bGjm447V`F&*F)yQX zqn3X|+d)2hdKA1|o)OJ7X^OlD)xNcR)&0qlA+G9jn|FH!G`A~gnnq^0+7tgyDay{P zp>1M;dSgw|WVKwoT}|Ky*YQrh>7aM)*EgzTD%8Tm>UC!?iO^jxt5DCmkx{O?a&6Hf z_3z{?wQ+4l_HM66eUaR`dpnid)#u6ib1N5>(=yVo?pW>hTh!4N$vjHE-=lN4x^eYE z_0JypkE&()YCzVMoJDG*+xeOLidF}8faZSj46{G-a;Uoq_ZcbVj|cgq=|i9q^|RdR&FJ44)&TWrN}E3yZbY<~%=T=ewWe zb-YVW4tiz<(L1gbb=hjKBBdhbA@x-cogY)Sq^MkPTgPlYS!jWyZA`oDuO4PQ^h}z@ z=zRY0@)YI2emnCz7EyB1%Zomj`Y4IE3+g%YXlm9Y6Q;07Ty@K8oe9|~?tcCl&mR*O zPd$C=?v>kHrWF^e1(YBDW>ldw7PAu>C;9bUN}SiM_R=ZO)T)n?yo$&$I!_+hQAkhC zKAhLmMPW+um6xrKt5A!{T|Ymw_#vSd6E(GhPE>0vpB`Vp#O#>YKQH?tI@iiq)y?Xp zEOqfg^_S$sswXAHRrwdG)w{f#>2&;9s-J&QWoFTN3Y|p_E>h7fb@C2coV&ciHdv+bIwSNpdHd8whv&9VEu30Bd9K>! zR_OEiO4W0lIe~wAp;}n0PRNoo_`k3B#oiQYzxfJpD4oJjD5tac&W9JhrY@%?iB{+0 zsa@)Q_u%eNC@I!&QRJbntxX*-s=-@!fAVezovCE0QM)#K?-i({wy70cyw}Z%{Mn^6 zbx6JDZ`9MR-Y!zEC8iec+O3YDvnMbAA$97O-7&g2FeavMX=_(MU+ZnTN3G7H|NN+; z1UJLW;Nde{suZ=hNcGEq#ydtG)vo$>ZuUN**lbs4AFhijI$`UT{}HvxJGZ#7Qe__A zx}msh_jNC-MSH!=h^R(h)oHwGlIFDv)$81$| z&>KQwQaGV}0-XhTm7|N*n!T!-2KVwy$UiqGlM-)64y*fDZ&4p6dFkh?5n1MBw3yE5 z3ec{=C##AgKIf}wXF0#TgnDjjue?-mB6-%llSCVj_BBMlA=3Pk>b2$FTj(rtH=T|a zIQ64?@)@lwFhUi#}u8E@)_Zwl?OXIcGJ>)bI;Cq z)%$c>sBY|;uRd6rPsfTeYVkoeFkdaqSA*J@QI&T5=4-vob$J=SUKAR=F zs-%Kct5qwC6rDA%Xy2-ZU7>}|=E3+^YiDK4Icg1`G8RzQ*KyLG5;^7Q*_En7XNh-H z^kylNqOV5kWT{gNXQv3~w}`sa-9fwegX&FpM`2~la!vbltKRSBa)B>7L~?1DA^FMJ zsjgkQSH*hL#(!-QCBc2_spL-eo3#{CPtuZ>yUUBwyzZY@@UYHs>d44YS3TKAKRtL# zf6pv^pHVJXD|V^-Xk+JXE!<4qxG9|}>dv)hcdh=D+#JcEi=@$LLv3xenJ?8w>l^4o zaJ2A(=!%-^h0#WOkSV%gaW%b47j0VHu%emYa%fypvr@BAAv(Xhsm58_P`@Z$f3(y$ z)h(*8S(wg056y}p2D*>zkOXr#>{a##j zLBrCPW%XL(!j@%?PPAd^Le{#ehU5|Rvg#E}YF6m0p~Qs?)LgS_MO|}^F{FvL*Jh-5 z(=*!GV7hFoURh%-iY{#+y`#0P%_tVz&|>VVT~SlxG}W!G;p?%s|Cl^jV&!L}!Pd`U~3!Yh*RX3We>~v|Juh$c8#K^2Ove^bw%GlN9ELdE( zbRl_&F5QZQX;jEw9uw{B=*s5m`AchjpG5VgTJFBOxvqhf{?aAvR0GLnWO}rTDWvd#xS1musb3gfSlwJLw@9*yGiw2b z;p*ln$4xZ4ux2GG#{z1JZK<=Qrlyg`rlFDUeK<5HmQpX#X!U{xHI2=qHQ)R-6alNq zIpl{?QSScisHQnJtLw;?rbSLQQyZ(JMnf9K`nu*dY@qQabx0TSX;An^j-GPW%d~@A z=pmyxTbkK7D@a34)J;~@koKf3g~?KiAnjqnjy9twTxsyc^1c+ysn z(!%wfB#kbn2~@LsK}}Orv|$OXtEVy1wF??oI;%xvGFQ(-?o5XQ#cyLvvrgGg3q>k< zPa;`Yb6h#(gsAwDoTH~zbO9>@%qawTv{TDB#E3$1O7{UtTGLu>4);k@qRBC%Kt`{u zSxS6$^$pC#zMDV4xw>vCSx`+WgOWKnS=`XT8Mb;UEj&CIY@N^}o{LM5?9mx)9aVnggYl0;rzGo0d|} zq&d#Yrus&@&(>T^1bSnlVP(yV+NBMvqI6e}{%fkW3=V3e60Nrj=F`1a>sd)8wX3!B zSO=Xu&A@Pw(oNkZ6gBK;irtnK+_g#3PA&TknX7s=2SEJ-T14sC=&Yi6B*ZDoq1XW>Xp^;3b@ZnOEFX-%vlFmuw~*PN!C<_xhHl+!OcA?0PVDUgRvWjGW3- zGs=q(kJ*BT`sO+^L}xitbwy26%hG12VL@|4GcDP4pPXF2kd{ejS<{;O1)RmT6Pi~> z>zl~gw8dIbLuq1>(@4_IYE)lSv#^PGM3h;gdTFqFTVK_(yICi4X7!3VXK4ShOHBn2 zzMfGnwd7s4tZ@y80jEoj9KD+IgdaVMe9S%ZTC&mvDo;60)2o?wLyHa>z1A?Z&gmwA zsKl9wr0CJ0ZZrduI89!=;%X)9^b*I)(99=YIO2J-M@^86Ix=AXXpyR9bj?zeEW3xx z;uX$f zo{1|coJetEHT;Fh{*!NG*W9-SLnqgn5o~s}^m~l$9}rf$PC5EtX}JKcYQ=Srm9?Qpr2TxS;GPkqu1K!{3m=o`;t-2_kpwfm%kl>ly_XD;}U zlsG`&!)yxt12O!^j0V|H2rCdCQVg)hCzSz0QewqWyCSYX;8m8E3cSYB(tt0qv~=J$ zOB)8f!P0Voud=jU;5qsM68`m@RU3Zkpj0JP@<=Xl)Y5W*t1WF9@B&Lq2d=TSG~h*+ zmI};2^}v5T62Oi03=IDn4Gp%R@abJ*8;uX3ZOFgaX`2`nZditfu*7xd0`f1+@*fXu zSqvrgK#Zo^eul-*fOxb@a`q!PgEd{X&G0%0cgV7juOMWW(7U)6HJdY@Dg5mit0 zwXd=w4B8>1KFM!24`TyEU1wg$w~r5C&U%DB^tIR8nz`G)arBb6CCe4Re*>M8g=@;T6hiJ80y(Fr0B^|QLfbaBaBV)i1`m|B8pezg+cxWO7S)k07l3O_6_?Vu? zp-(qR$z_(i3FyPxP zEeDu?z?%Q4-(28XvN_^Ck%L0H5SbBpwx#6&S6bRI;5n9-4m{7&(tx9umI}Ps(mde4 zvLVt68vX4jJo;0y%yr5DZ9DoYTHC^)yM=$ObV%_H$S;ZUA5E8hfiR6%VR?6^f`|hFX=P75{jJv7;35G9f9aX>|;RTPz>o)_6V?ti_?z zfF;6zr7tR!{(mi1FZ(R?(qQ*LY|~HiS!RAC(DqHQ<97cGw<-y@3T5B>MDP=G9 zxuto){A07ef+)NpL{<>^O-suGe#_E^0l#f&>A-)nv^3zqT3Rab`C%YD);K$wsq z)L}rGuf$A1L;-E9!>Z1Ns>h06#5Gai=GyU3%EXRWPvdX5ob&c7=c2X0Y2t;Fc%QX zgt!0^LZm++qKUWwKee&|k#dL&(1u0mf>44fzCF>L+@5HP)0bfc{&FSCu&~n^Jt7KA zDUmSVReEKXfRU28E$~-9Urr48Xg^Fx#(?1wZW|arC#V~3 zGd76W>*Pol0p8^IxY7asxz9EW5DL=rvAOM2sqf)OZV4cN(EEBIWgcBK5b+Sc&$$hJ7c!gfhWOOB7*tXzWI-L@xWs&EfsjIrKJJq zT3R~rnU*#Tc)X?M08g;AT;Qwv8eM1?-|3=owGere41A5HuvPC*nd6e24KJjc>IOG^b_Y-t|wJwnqS zMB#qRm<#-XrR4x`v$SEr4_jI~@ODc}1OADnr2;=`X&!LjBjY@1p#4NlUM#Uea~SYV zkwsHyLmLY33X%8#t$gCMk`03VMZWwpK!_yymnV>4mO%dHA^Cq2x%>_4{6`zM%O#3# zk|U803jBv0smso`Po?m0%V%WRPiRlyoTC3Y(*mQLh%+*Vt{{r}fM4*3WMmBZOP`h# z1BM$}p4GshH0gh+uWCt=h^X`jq~vmeU6!O|>^(VtM^-u{9%S9W7Cgl7Z!S!H)sg^V zDYt}Lm~FHp`Ms!v@g@==Z0D9in+v3)v;7WB0850VoW`~o3iE~7!)eRCK5672e*k(( z|9(ZVCy2es?`b9=ghrgU9GL0(?wtvUE|@JSy+fqJffRdN+t2{+(!_-#7*V2$7(s-G zCI#SUKR2g`}L7Dux1PA`z2fC?L3K zE&|dQ)961s{Q$(2qFo=xf9MM;1&ovZs?@%3xlI4|6C*NR1oG^eDHtj+4LUp?#|I2$coPTQAYF1>U}(mC zz}8#g%@B0@|5A^ji&$Ul9fM96TPDWYR4aI$9BF?SY<5swh32#*2YXAf^Ozz6XZnIe zxBTEcNTWSLYV2Ra4~J@EP$m9KUH%(vW7Gp4Vri+sr&wAV@GwhD2R_x(h5?^uX*s~7 zEG-xKRiWuS)hO(bV+4NP(sF>`w6tNsZ&_M8@Y|M_2K*OGO9g)4(mddA`WdHb1r4;H z@aS36kZz>|qFv%AD9|v=Z#ZMJKp0F@AMhQYs|4_0KB@E=(Qup`sUcv#PbvYd^GT)c z0`Ik?`vtydNgoM>K_uQfz#ynT)mN$v@D(9ZZgzn8_-rMB7C- zQoqNUw+Y0MB+5 zWCo>68N6|`6tJ(TMj3kD|JVoLDG7G*jd%-sB-mYp1%Z~p4Pb#f31&575|I;ca4w*eHPMtp}rGV?>oq+=8fO1;a#n4e)jsnEQNa#s)3gy|8kcEbcyt`a9LT*fOmp{xB zIx7JSOd{_B!aBN|7%X!N`K;1K*dSjR#obQh2Zy9&@yjN9*jf4hrLhNS)*Y=UQ40@OVob2Apqc z>A({#Ee&|0rKJK-u`~~O4Sg#n|7iscjQbRehRTsf7w{&ZG#3z}%;P6&X!hDITC4wz$+~Yu+t}%0N(49%AwUemh`p2lYOPi;WT(5!RBU& zm<}JZdB8LLu?{WdFb{K%@)yjrot1WTBo#gufnWN9X9Aw$8&Wbx46uSi-M<=* zq}6)qxbxc;01KvWf*lN4Zt$g)8e{Dzk`odU?NauiY^%E=@WxGFKs2XIu;DEm+JPz2 zred)KEqD@~Cxltbx~WHnFiYsh#U0X-O(mi2!7U+{P)A{wP)A6YHbu@IAhQs2DS?q# z0MIIaJc27hd|l8JkQ0|40Y4Y>^jM*Q1xN2F(NSC?1%&De2O6D1c^+uULc>IZ|AA=q zwHy=dD8nqFVFL?HqDcz~>k{lJH^`XW;AhBLfPWHF;ynl&-sU$f1H4N}luLTVQ21?} zw6YjV=p(`GMF(5`4rTzp;FBrbafe9x&Ezb2x=J#nw4^ek5o2Xk1zCNiX?fRq>TfCIz&Y;0Du>V4|{GXex=4N33 zl{8Cn8l4r+i7}L|?xB?xidvSLZ-^B5g?42@^9~5hJ94D$xCi_Z#c$C zw+`C(Q-?%qPtPg!&1x5k>exkoMBAjUu^>`c&V&N&~ zvyu&hIdB#81T{_ca0zti8`od1;7M{!a4oG+%&7FeH|s)yi+oZk;1ZuSE2wu_xK)tl zXi+2M+tq=G5N5PrOpQ4*FW@#q3`oxrrcrhhdB9^VEfsjIrKJJqT3R~rnU*#Tc)X?M z0H14VxxoKC&L~Oe*N0pbJ`^Hf0092T(sF=5wzOfupIBNt@Mo5m2K+BeO9gi57ee`u zGac}o!wgL;XrTRsN2iNrlyU%VyRK(jZ3~0YuGDW=2KX1zi{=&J7eeB^R2D<2;dmp9 z7y+LYl3_&YnRK5Ka7G45QNWRdK`I5D<&&a-_lh^DQ^4N{$#jYm%ukRWVEpa=2;{_0 z6V0pTNLT-#Zhh?}Q7PRVHSstpOo%6bEcTor8f(rIPBG2e<;ZEG|4>6aU5-qfF8CEW z>c+6+Re$(NA=B1=eosptYkf(~>O06Z=InHmSob?QGVSPeQ$IwGtR8Tj!H>006^1IG zabyf5Strh5fdz8nGgppG`$jPR)S3Qc+V}O;udaeq}b2z>6JaLjpB_5PcV(i z@q1bmn7gO-igd&Aj2vmV0tl;ho|wonF>&0_ zdE?yT??HXA-E@qLp2{F3gPr^ z8?B%s!P!YS<->C`in$5Z=t>%99kx(J!Y=A5f25;;m_(%O`+g$E08>-I3+?9d{Z?$4 zzL6wNeAq9+Tq40@JAtC%2^7U_LCU3u!Gues@N9{Or$#h9528W0exLEBhd+WtNu()5 zjI5J=qpM&nEd92z4F)br3kG9?2Ts~#w660s1D%}3l8_E5qtY=Vu&p+p;tL*MH(3N~XKN6y;c ziUKxrw2cIe^UeN5zS-~l2KzWI5e4kzNFrd|rfz>CAMQ`&!~NgOhtvx)2GRx3s{|h0 zpU8vzLmnI?Yt3+fA?iBRiUJlSy6A|BjaW}`9Wv)66Ov=)NJ$^?d7tEOCW`z_QI1TB zG)c=b65e5dms$?^rB5mWL{3bwj=v$P`CtCp8@k4QvE;5xq!LWwA#!fS zOPat_eNyO3IAkyL1(gA!yF^bJydqicOFz4nA1Ubwxr%H>{=xE-!2IwwrV85_Br`st zfTTj-OI3hY_=UlY6P6S{!MaThe@%`Yt;fpHBc^Ee4rVxJ3wBo}BH%bWs|ZRbQc%+W z{kg}6w%|fX6MsY7_g&Y5r=PlU(5AU*hB9A{6jgxehuYoe=Z4d8S->d)j5{B{FEqUe z1{MI?E#OQV>l~4=Woh*1WHgxNi3;wg{`SVvOz*fusI2?HZ+8S{_K$ z@<3>$gDv^iaY0ijYu5(O(&GtX(8gX(%xurF*{UI-0 zEt3IP`iS&rA>le7kuVu>MUO}bA9$Zg;fpTO;F3*TLB+2XrEZWTO$tD4F(~-LdRB$? ztP1N{1wG%fGXT)4UKLioDy(`{Q1#&MNC$gRRKgjMpyh$q1TDieAVJGLiCXRn&7EM& z#3L58F-B&O8Ocf048s`rYm5`2cB%1`DKN3Qf93 zy48=e)ityYg07Y&G^O7csa+=;Uyz@0-vm1dB4NLejVh6FhC0pPDTRXlOOgE_Ia06# z+U}~t-BqDG&+ZEWtp-(L4MH({mss_ylYHy2+dbbdjF|g<{aF+JnLsQlWH9!xSS*MX z44=oPyPdu>O8{|6f@U`~z&b~yum)Ao;2B@35AuUO!7EL~g;Uwh-#+LYq`NEqeP;=v)u1Y@K~-3TDrivccUJ<4t0CmPuu>r(EEKDd z=5(40UOh>eyArfK(3+rSICr7t)xJkd0HH>Np4kb?qDc}AD@Z~!8i;VKP%y5Nez9q# zOOHXpmkG;*avbWc{+9K8HLvHZ{hWjb4@<)oN@kpsP_})Bj6t84C6rIQ8wNbV($aw^T3QYp@PVv21;5RszZT1AC;*QYS#%8o@EjqT(Lw1CryHrn2>6yyng#g75k42-H9lz; z;4Ysu7tj;^O{Xa33za$roZO8OrAEsLcuhA(l;EcX*IW>Ha1A{<3HaJ+Fl!zl{9+!s zKxwk?l6ipemSIHcpwCza_?1tZ2Y8k^%Ctpkj_QUgV9e0g+1ZhXbqYd6ogrc0OG4zzFyWTKZT^^*b_%p(Rth*o z+`}z_VFhg$0MGEfSUO(d<8dv4F~-X2`JWgH7-b4Mz_WdK=fr?9%(^WKn0bjV@WD`+ zLfbW{Yv)F2yH+Y{Bdw5;^+Nig9BD?Oe>+`5w|tKhZUh*GP8uQ%A;dJ`Ksd=2JR1u; zWaUCa{_YhFLBJ_#Rt#}qUGY6vFl0xpQM6_NVysLLC?O^O|FT^DPF#WvOA!Q1G5AFK zK%yH1K_ra-1^$SZV!V+Xi3`R*V!2?Zovo!9)7Sj05lY+{k~vTH*U*`Ok)x4lcr#>6|}_o(#;6K8Dapx6d2ZgMo{xa?+!MK0?;i{+QVc(jL@4*pN z6EzH)^00LCvh5Dgc2^$mt{m2#XuAU(=99{yl+_@#hy4~81- z#888lV&1(YZTV~#_@Jew0{_j@(tzK$v~=LVTiP(-e^^=$@F$j*3w+&3qa~egZ;haE zy%70?6Zi&8%K^U0(uM*5$kNh*Z?UvA;M*)M6?m(qdBB^-#VPo09vz!wYA9C#ZV_2# zQ78S2>0t3E4tW9>-J0l0if_`CEIOeb2S>c&+;u&TIt{!bv5UD}m zFl(LI`n(*472e4eBbgN#rV1;Hu$)-~mOC*0k8!30!*srR4!dDMyfM(8`G7IB%m@66 zj6Cxl77TNk1`Kl&nZ|to8@n)!EDIQR^`#*lHPHLdz?@U*!#5Gb$xVPUw1FnyXNUt$ z5;-V1)PW}7$1i~<{~H%QoNa=F?FELbX!*g&KO@o2Y`}02u?1a0q@bxpf++*zq8Av$ zPHaK-iS%uO`*xi6z!+eUKA%Q?cA_a9ACIUwJf=U3b2Bi@6lAnc3 z0IlrMX$CUP191ZdjDe!ln(rDWc!Ssgp_cX*3UCqe0VW(c_)9kqdQ21HKA21r0b#1< zLjf_&F$0WIr?x?VW6ibGtQ7EZNyPelE>QTDzg*7*{H;$a0o>=4W&r-xm$tkuhQi-0 zAD|tGa?F$8%Y3JE1;Dq2M8C1r7DEB4k@&DUtoHW;<$#w8iM)1S>$OtYYWW@zh}l3_ zGXTf>L0JVj!zV=n5d*Y84~{*N!ZW2RIPS!?Ik4oC62Va?F61dBsRWlY5%X{>hXn#0 z5zMs9WX`W1VT8Md)JY-4#avRPQz$Z`ZWf|%KYQ4A}wXfO}( z(|(LaVK@Sd*}|(uG-xGVLxmEUQQQ(3qd;sJ2I{)pfH3JZ15bUNY#DT{|MxVNOSN)#XaB-7aB5)Fn7OA9BQXgJ}t zwZ)KKFhU`Al16wL^i93|O66H$O$xHT|hUNfTb zsNLZK!a14`1vrQW0+&e6(2OV`jF=JFdX)@B;kzaf_Bn_$x(R|c&MH4X^aE&IyC$LTvgB>G)P7($5=m^F{qUi^{ zpc1nILp@>xjL7t6HsBV2%Fl)FP@CB>`j`(S4c1`QWj0_KM{L0%B@#^jt^tMRZk*-7 z*7BDT94v6g~?daf)2H94!mB2VFBsRc!p9K>Nv3-}%;0YPYeHq#VV--PXagAh_8Mi$0Uc|5Q@PK@PMHPhu|t%HLsT=M-T9=K5b+S z_#U4&DhB+pPa7Qre!{1n5d(h4r;UvP|Hh|{ivhpl({f|LdwtrOG2lP@wDB?EzxlMh z7%=t~5hp)(m&}rT;%3XUf?x1y^t%Uw;YI#w4S4cPpKr9k5}hK8PQ*DQ20X&2jg0}1 z^J(K^z-Rlk+!%1NPdhUPJjK-bPvDnzzRz-Ez&Ly6OSHhqT#0^G zrAcJ`K#p_)0q{y+{K|E}5S8HieWz?WuJ^AhuJVBYVQHzrhb+wl?vZO;OSf=Rfjvv} zfcsinYH%>1$7>>=R0aH}kjy;^lpyRoZ2FTgs|*mWSyovLB`d2esMnn$V~>^ff7NPM zxYev+Uk^$j+vUh{4g9oE8yN$B!PjZVZv|R4L*WkTmZbzbec}r$3F?$8W7f}(od>=V7ZVC zBTCCHBOsJBjNhgmzS)`{7zMmUv@>%DB`8XafY8z~qV%d*LX3dW(lDX~MTrqGUgz-l zkKZkdjhCUIiwcDT(K(SIYrF4~(E0tBu+SGYD@ouepHz}0hRpH}`qo(kkMK+ewpx}$ z%V&Mzz@Yj~~TY=WRa=__g9(Nh^DAVAED||PUZxLucQw|8nbIV|; zL_`VbN5Kf8keFb1dO&<^9a`~Ko)LYV@6ZZB_*gls!{3%&A-?*X@4mS`MAXT0)L&2y zA$R-o=Z3v77dpdqIuQ$6j6i$EmrlPVgTkvqq@^DaV?yVy+uP73B{;-w+Vo(wc#-Bm~KLY_jLNuV?<4nZ>W%>@B0SMnRThN%r5+G~k z$U*eF;P>R1;Er0hD78?Ilm~)=Or&6E;a0Q4txAKfMoS;La%2^Or}(syG2l7APBWqc zt(u`F7t$?DNm!>)@_0-<@23LiaL@CCic1;1aTx><&FPzZR)^*;+JPz2JFmg{t!Rj2 z2qw%HO$;iBmT^f85XnMo6&992RR}{%RyEi#k@}xVgr)fNG88iiOdE`IKbKas{Z?}^ z!7&RcF<|0hf+xroJ4FyuHJt!&ZwrkBxZ-juEpUpjh2zSao$a_0{u2R5X`lJ#-EIbL4)*j*hgB_O9j2<|z|M;ubOpN?Vd4ts4?B z8QN$l4+9|>XafmJF)0s+6zG4>`Mz^@&%FzF<<4|xwEuU$`@hbA9{28D?e6W4t0ms! zxEkW0g403#DZw!+q6Bi0OZa_I=K7PZ*PSBad;~CxY%K;W9toL=QS?*kgy-+r2$2cg zi$mKW)rUe}1O6|^)on!VPDrKahx>Qvb9`d9hA+VU&umvB8J!I;Oj@0ni2nx1^4~(-R86ixoSk~K^$e`QW!s}5vV*4 zskbTMCmdHx{FLMBi1#}#LHvy4>WQCqTqE&|j$1&yDrvHmH9Jzp#$_NS!3D%A$2AhK zaa=udi{lc+mpiVG_zK6>61O_8hIq-+KtFVX2D)cf^rEEUWD6j?*itQo>p+=ZfvqoD z#kGXLTWH)FMYh&0GOPq4+`70_k*%FzMUn6iWr}RQ?-U6O7ngcu>yN>TM?%&mev4~Q z8aK>cmIzbX?Sd9@5lLS$3yBq828U`rvT}E!Oo}5Owp`N?@$HDH^oYM>vq%v#i?}79 zMfecz90WVv=8+;~KKRUIJ=>h! z5@PS*F4T;ZNzQu-j-yReDcS}SrPr9m_YTg35<8$nvB8N?4{WpQTDelanY_&K8@$xz zl_N7}6-A4w(0k0%n1$NSv{QLQ3ebhy;8#j+%tym*U^sRv=0z}!V3sMY1{64zTy z*J#BJQ7uX0r|lAKrl(z4cXAr!5_HZZFEMVy%6SM<&Xiw*PwpZ@ae3cw!=)JR%Qjpp zz)C;XuK3h!z%w0nF5qVzsvHO~Q8hO43sYzzc z0vXaz2Z1L;s`?WrEY~zde1_%b4*9N*!7=K@T$qe@H{gV}i~aw>%4eTGe04H&4yvp> zj_ZdkMf!Hj{PL)y!`VXUXw+vTI^t$6y9^-)kZG2T)V|0bEygk1^S-$4dEcPF zJ&Q3b$3>wd`_nRm-E*@$0}(P~*-n@*&xb-09<l-3lFLY3E+cXCd}J^taP({8o<#{>g;ZrCe%EqMLl$Fh#J!`>u^nUQPh>z- zIG?S7R4*urTO3zQe7WQ5h_7^9f_Q`D>WMoY*GPQ&GE;eZZML_Hje3xhOe66bj;kmB zwBr)QXF0Bp_-x135;r=ohWP2vmn6f+vmjM6#Lqddp7?pkC5T^eTpjU?j;kep)p0e% zUt3X%O&@~V!Ig^=k_$o`oZdTd>b3WzNs^A=memynvVWoyGFCL>WKyvkB* z3GcYnY7y?S)LOz%qoXQez(z~0C1g27t5Pxk))u3MFk$=HOvvu54z&!ibt1Yc+chCO zW)#^f+HN)zejI%=ifq-}o;DM9mnpLKyi+8cg8mziY^}CcX(sG1Q)J84Dsp<_#9=km z_QD$6ZI?vj5b=*~0aH%^zF(q7Ji(SPuR~ z?@En$xh+wO#rU$LDovbw?8ekMM9c!o_ush+*n5L1aK_xE=ix*rN5EsGndl5xBbi>h8c`jJxQUDxQj! z!2R<`wo+~=Q*FK1F9qasiP`=(AtFyi@?xB0$+aj{)c57|-Dbl@Zi3S{9Z3cE4*IS% z={wV;UuzbJ?$o~~`rZ^rXY94&d|z|05uXpKrZw?O%SG*WFE^eZg;aLG1%4Y+J`ytn zE*M5AW;$rSHxB(1@IFXU8;^3jQC#Ea&a(1)Le4rIvRO8TX2Ln3HQjT zoXw$mIv@)o0az2(UMO~Gk28D_@GVD;i}a_N)BxcrOd1nXLHQ$ z6NWqwuGFMl4$LqzwR}%X&9Bt&VKxr4Lg^6Cuw2s+F=tua3yAmNi#joxUj>)fS=aL- zDfv1d;-+ZbG!7A8W4WdwVizuYyDICYB=-~iBKa3uvb1W4{EI40`j$I!uKEi|^@54` zuN+rPe52#)h;MdWg7_B4)f3<9xJKeT9Jhe@xs@hMc@Z^S#m3J;N`ecBpLbj%@e7Wt zCw|d!3F4O>S4aFGj;kg9rQ>RdTd^{Af|V+IA9^OQM+oUt{?n3>F4d*++99^KVuVGJ z@J}tZmXK+P)<-AN!Xz$5hh!xaUW+}$T%WV`Bv?@-WHLsPt;cL?&4jOmGKy?ngu01G zLiWKZ`rTlH|7LUEz!EV_x!&}%6Uxs+C_kc5ez;o@=DRjr3*k>Jl}e#5E`!LH%e<)~ z=YSpC{WLY{C#p$5RZaTIa^)tGnYySTX1&DlzX$z_X_A>SDP>K}an*`!Fj1vQ%yHF< zY)r)n)L*DU_z5Qq*tgiOPo+x;}Yf;D)j-6d8N?gcd= zxLUr_U4CYzCh^H3rkk;IZ#7{zD7i|j8e)S(Qs%@@Vml(at!fS9&|a>&d@G(7IGobI z-P^x~*~iLj@-Qrix8EAI9FCNWF*!6Pry}lL=6vAKPQ$V{oRk$$Q2v09@@&MknWLO{ znINkt6oayMF=uDrk(%tjC&l@$6z7k^k8qiB&|YpdPsBvv*+A;URmf!~)JHoCqmII; zqsX<#Pm#&bAXV1H&sk2sj}7=0NV%?k4bXK4)5#@E?@lGfG^g3shc)D^4&l(alAWBm z&T>sd#0kqqugBkmFY3fx{$B(0o2{GZs|a7`L)`p{b<;RRyvuS;L&PpzH0$fUlww{* zyh)cOXUQ?ZCs?j&h?U{xVJ)c1f&6UMsnvI8lX@sWL7w~C ziSiYD+*C{T+`t>eP_&Dg{#0RzxV3f?(wc8GUgt;p1`gc>IZ53oknc$!H>YmgoUucs zAF>`&ggo8qkK?f6wz$X{GG@Lo_?_^s`fx8W!^l8z6X2;WuB*EzBz4zrm}sQm&)beM z%=aLNA@76q^>-X+m^&fggshw3Ynt|v>eoy%cE>|bgRFz}qs*LanDZddhr9@KwEEw! zH6EUTd6dU_-@EMAcv2V z{yEc3oCT1dg}e}QDdciUKg)2sVcH$oX&W3D+^zDBE zyO$u3w*HT1n22vc26d)A8`95bIrswPR><2R6Q48|3m}iSJ%2=#zesuR$4rC`kRjw| zNdDv&e_+qg=V<%84RP;)X~FTe3;-u!$ ztnpXL{NGpe_^iqJNl1Pix%GU*k3a?&nD!pX5lFwkZ-Qr@{Nyb^Q#)Gy{-p81 z|KI07%pb!4o^M-Xj`N@1{dl9b=f6Mi!2e1PLo%)(?@0Ce4(|xwQsuuFK7;nFkgb=P zNMDAm!@KV(NWO{e=X1FJ8}a7oJjl_;DJ6!#1(f`{aABX%6~W@py}px7lh}8V%lKI}z=ZA$d=hw;=wn{rR^&KPo>zpV8X$b`kGb9f#X2 zyfx&+vEL^nw ztYUf-TAOnH4Q>71JsoFtcLWWp)s^n+3K}{Fa^la(V!<5Qk}33c=W}I^P>vNcJ!xeC z)Z0@G8oG1c@?6Ypljlxp$gzA!x|j|cGF@S3A)U>HT^(Y}maz!ag+hA3SP);;E^6XE zo$YRy(0OqvPYpVX@z~ba7c{izv)N2e4t8YP`ZtMjI=3k!ylHmlI`hQowzfiM3tK(i zxeT$?i?Amz!Hg|D`2+O7XrC-LRq{86wque8fxt^u9@VsdpE)Ketss~Q zBB5LEX{>`9HOX_S{RLx^n!f<{r|On_^6k~9HQxT>*;Za7x<6Xnmhzg{?16NC%)j894{5UEAr&p(xG>Er9tD77Df{Rr$w zyn^EvX+U{{XU}`myVazS#}h3^@|kvQ-z1%Rl` zJ6eU5$GzUY<%DM4(;k7P_VaQ{eQ;jR==|IW`|QX6dpS~SUz<;A-P*h{xtjxHns)rq z4E73`EPrYZsK?&^R!A)(`W%0AGzcCOaJ>A{ejn`j^&g)7eo<5T(|!c@BZq1Kyx6KP z(tbbe_rsp^hh<>?oCm-3;_unoDvZqEty)yzC~h1gQKQNkGybxA^T*rK=v4 zH3Epu5%WA7@mott!M^T{3ij8)eyjJ^v2Q=8g8d;ivE;FZ18COYh3))>&E^bp17dz#|IrNs#SJl zl96N8vRm^yr}SX8WWwv0a(=8_k0eVejjQFVWLGRdPOcx~^p6dAeNgJGTB^eHemOrr z;Q73qKTgiiasDUR^KZHS#DM43a(+_4^JO_dIpBG)oIgI``K_F<4S3!v=cfcbAC>b{ z?Rlo0pBC`^QO-{fcwQ*yPYAf*m-8pe{@q$iXU3x4%F3n^idtmjFQ4s2Y92xJ6av!4S)#$agQ<0>L5{ppB>@V`WYL%p|<_9hgz3$ zyxJe)c-5n-AUZB*2tOv66zrXt6yzQk3RL_-k6#VGaZ=JL3)&=qRl!L?9nNPeZ}r$B ze^o(rp4=+D@}Khj{I%AP&bNKS$Mx%9;b#Z@j7VEO)agX~pPW?9V7Gn_f)_>Vet{RK z`f-T-)TC~of)0!msq|~78~$qWCyT6-E2-UC!*^+`AUF;BJ5Mlt0{-WNA3n+O&tnr_ z1V0H}M{@g5(a%hyKOXws;CIi0A8D({Aov}Lq;3yD|9bGlry2gPT75XUQFxVq4dNbW z=%CX4xku|y2_EP-exM%wQ1j7w^{DVcFg3D2JgfDi`+zz9M92MYtsmV7CQARN%DD8l zntae*{W^H6L_RRy@B;Ot0s6uGq;9w3JT+hQMyK?7Z3X@+;S;5bz+csTbYJ>&?PpTZ zIwz?$7fM?_ZqmHLrO)>YKSlPp1Gui_b;=Ja=>LoGwX#3>``!~3^k30@^nCH#3i?%Y zvR8FZU7FNszANLQ9^*A{aOv~O75K9&@QW+(S61M2nwNTBkknznjSG~m74*MRfxoQ+ zKU{(TSq1)O;cH{gM+YnDkCpu(QCcwIX~It#Qy1*RxKl;#A8J1Pk8_m1tY4nrrKul_ zw7%?DS0;6P1oM0)_yeKgzpjr4!3NDsP7@3dT0Tw|ANOnYzr^TY4TGJ+t9h8f{!c&O zgueejXSaZFJp|4*ci;o8-}Tx`&IxinZd|4dpMXxOsIQ=ZVFf-VyqXVwf7e&=zeW3*6pS<{ zb=djn*Y*njzp44?_2j>seZ{%w2xu=9`-=UYodUz~lErJn z70a7j!Z7H_6f&E-`{ZtOSj>j)J^7s6f{mfVup=LC>dCjId%})lzR(w@`?m#h3%9o? zQ_OTUoHu{&eDNHk6snua=GJg1w|ff%fw`I7(Vxu@h)GE+R9Tm)7JGYCFM4~zPPrA` zqftKJ+o!>%bg@hF&gFA$a`Sg{cW#rWv)Od71ntQfyFw-tri%l;4c&c(bi+BCl%{l3 zx$VmodNMh4Y@T7#lEi?q%@)Jr4CO~e zyS=MW&c$WaSuFJDqzqm%GM;^zV!62rrUo>S_0#9+OSryXFS$Y{-BIoVW29>()2rJv zkf71Rhb84zor;W1xG9^@nfmKl)zOy^yVAK185!lUcfjS)G*5nv;xf_g=+1@xeVGnD zQTubf>GsW~6G%&5Aj{FZTk=R%O literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test23.ans b/libs/libtpl-1.5/tests/test23.ans new file mode 100755 index 0000000000..903c08cf1f --- /dev/null +++ b/libs/libtpl-1.5/tests/test23.ans @@ -0,0 +1,10 @@ +i is 0 +i is 1 +i is 2 +i is 3 +i is 4 +i is 5 +i is 6 +i is 7 +i is 8 +i is 9 diff --git a/libs/libtpl-1.5/tests/test23.c b/libs/libtpl-1.5/tests/test23.c new file mode 100755 index 0000000000..52193df5a6 --- /dev/null +++ b/libs/libtpl-1.5/tests/test23.c @@ -0,0 +1,29 @@ +#include +#include "tpl.h" +#include +#include +#include +#include +#include + +int main() { + tpl_node *tn; + unsigned i; + char *file = "/tmp/test23.tpl"; + int fd; + + tn = tpl_map("A(u)",&i); + for(i=0;i<10;i++) tpl_pack(tn,1); + tpl_dump(tn,TPL_FILE, file); + tpl_free(tn); + + if ( (fd=open( file,O_RDONLY)) == -1) { + printf("failed to open %s: %s", file, strerror(errno)); + } + + tn = tpl_map("A(u)",&i); + tpl_load(tn, TPL_FD, fd); + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test23.out b/libs/libtpl-1.5/tests/test23.out new file mode 100644 index 0000000000..903c08cf1f --- /dev/null +++ b/libs/libtpl-1.5/tests/test23.out @@ -0,0 +1,10 @@ +i is 0 +i is 1 +i is 2 +i is 3 +i is 4 +i is 5 +i is 6 +i is 7 +i is 8 +i is 9 diff --git a/libs/libtpl-1.5/tests/test24 b/libs/libtpl-1.5/tests/test24 new file mode 100755 index 0000000000000000000000000000000000000000..a6bbe6845c8504d3628c8599ead05e3cc8514ebe GIT binary patch literal 127991 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 B$c6v_ literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test24.ans b/libs/libtpl-1.5/tests/test24.ans new file mode 100755 index 0000000000..903c08cf1f --- /dev/null +++ b/libs/libtpl-1.5/tests/test24.ans @@ -0,0 +1,10 @@ +i is 0 +i is 1 +i is 2 +i is 3 +i is 4 +i is 5 +i is 6 +i is 7 +i is 8 +i is 9 diff --git a/libs/libtpl-1.5/tests/test24.c b/libs/libtpl-1.5/tests/test24.c new file mode 100755 index 0000000000..6cc57972d3 --- /dev/null +++ b/libs/libtpl-1.5/tests/test24.c @@ -0,0 +1,26 @@ +#include +#include +#include "tpl.h" +#include +#include +#include +#include +#include + +int main() { + tpl_node *tn; + unsigned i; + char *file = "test24.tpl"; + int fd; + + if ( (fd=open( file,O_RDONLY)) == -1) { + printf("failed to open %s: %s", file, strerror(errno)); + exit(-1); + } + + tn = tpl_map("A(u)",&i); + tpl_load(tn, TPL_FD, fd); + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test24.out b/libs/libtpl-1.5/tests/test24.out new file mode 100644 index 0000000000..903c08cf1f --- /dev/null +++ b/libs/libtpl-1.5/tests/test24.out @@ -0,0 +1,10 @@ +i is 0 +i is 1 +i is 2 +i is 3 +i is 4 +i is 5 +i is 6 +i is 7 +i is 8 +i is 9 diff --git a/libs/libtpl-1.5/tests/test24.tpl b/libs/libtpl-1.5/tests/test24.tpl new file mode 100755 index 0000000000000000000000000000000000000000..1b03586065bbf754f255034ebd46f39cedd35dbf GIT binary patch literal 58 wcmXRZ$YHQ#U|?|6DAi=(0y02=5r~<9m>Gy!fS47C*?^cGh&h0m6Nnc80FDd;XaE2J literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test25 b/libs/libtpl-1.5/tests/test25 new file mode 100755 index 0000000000000000000000000000000000000000..daa4c560a44add4432779ffdbd280277a30d441b GIT binary patch literal 127887 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%0DA4ZpJ@A`cBO8+GQhuxUNo-& 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 TIAkFef>~x3tQ?co5*+y-h1Ycc literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test25.ans b/libs/libtpl-1.5/tests/test25.ans new file mode 100755 index 0000000000..9383cfbdd8 --- /dev/null +++ b/libs/libtpl-1.5/tests/test25.ans @@ -0,0 +1 @@ +test25.tpl: not a valid tpl file diff --git a/libs/libtpl-1.5/tests/test25.c b/libs/libtpl-1.5/tests/test25.c new file mode 100755 index 0000000000..7c5ffb0bae --- /dev/null +++ b/libs/libtpl-1.5/tests/test25.c @@ -0,0 +1,27 @@ +#include +#include +#include "tpl.h" +#include +#include +#include +#include +#include + +extern tpl_hook_t tpl_hook; + +int main() { + tpl_node *tn; + unsigned i; + char *file = "test25.tpl"; + + tpl_hook.oops = printf; + + tn = tpl_map("A(u)",&i); + if (tpl_load(tn, TPL_FILE, file) < 0 ) { + tpl_free(tn); + exit(-1); + } + while (tpl_unpack(tn,1) > 0) printf("i is %d\n", i); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test25.out b/libs/libtpl-1.5/tests/test25.out new file mode 100644 index 0000000000..9383cfbdd8 --- /dev/null +++ b/libs/libtpl-1.5/tests/test25.out @@ -0,0 +1 @@ +test25.tpl: not a valid tpl file diff --git a/libs/libtpl-1.5/tests/test25.tpl b/libs/libtpl-1.5/tests/test25.tpl new file mode 100755 index 0000000000000000000000000000000000000000..1b03586065bbf754f255034ebd46f39cedd35dbf GIT binary patch literal 58 wcmXRZ$YHQ#U|?|6DAi=(0y02=5r~<9m>Gy!fS47C*?^cGh&h0m6Nnc80FDd;XaE2J literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test26 b/libs/libtpl-1.5/tests/test26 new file mode 100755 index 0000000000000000000000000000000000000000..9ef5356e1efa75ac8bc0c7c6d9e5135c2f3b0e36 GIT binary patch literal 132198 zcmd443wTu3)i-|5%p^G>Bxkq;0wRnsXi&fe5EDV2feD<^i4Ag*dIJmzpj=`yK~w}} zCdzS$jjdH%eOs#5dTX(LEk)}~!ZqI70*c}t?{kPK^@51Xe81n`=S&79ZNKmNzt8g@ znAv-;z4qE`uf6u#YhTXE%8JM&m#Qkx$EBR7F!i7w5Fq)hC^M6tI02`EldxVZ_BBd|Uzi;NuG5M^XBV-_FpfogwS%`~>W%413=o zlTN58J^^4k@>*o)7u_&hz@2az8N#Q<4xMsjkL612awT>-C){Z>=7diB*fxF#*zFtO z3LwRFfPoSczn!6w1z=SlM&~jTTd*e%yG5?0@pC+H` z@Gtqz-t~Kx$EN(_w!QP8VxA9Q(qOqbBZ~KQAAV0^6rc8jedpeC@UG?Ke_x(o{&`}6 zgr4|!5x_l9kTs|a_-$Rl|K0`sP#5qYcLAT(1$jF-DcA|E@(FOc`8@{u90I|+b76eB+C3%5PAY%98OZXGV;olEf52c^da?@cdimMw@X4bl3=)r;zs+Gu^_;_5lk8l|qLzJ5u) z(onOoraG$B*UVYCa7ndNx1_FSF|ix!7AuPu&8brsHC(^AnvjLaSX8s9p(d)#nuWrP zm&`(mInf167PI(VX0nQ<4U6mQ7c7p}3P9cU$|6a+AvzbOltqn;Np{w(+GXH1s?;t3 z;U!94^};0$HLRz4e!Ws#y*Rp1BtQ@_$?L3HY?a-_MROJ`R<5gGfTk?1wJWTxuc=Wc zN5T^(&KfncbWA!rYUEjzlIuVENBj4$Fr~az;Lw)x%g>#6+y!&!R=S}-32W@XAeS{3 za$xYYe6|Q^GihU;kJFEw1BW<3ggzTT2k}!f;KdnmhcvTGGT_b>On6xaoVMHf1Tx^x zoWndL1D-iAS7pH22In&~15RF@&+H6%T1SyNKLZW{r9X8U@NQ|SqAbgR=VicGWx%^< zz}IBJ^E2Qr8SsJ(_&phLJp;Zj1Mc)OvmefY_sGD1A_Jaj7dB?Vdu8CaWxzA_;n@s$ zVFv!r40xXm_}&b7-wgP^4EW#-crpWClmS1O0rzFV4`;ypWxy5N{;wJpQ)E3Q3R%3J+v2EJc3?xKT zXYB_{YUn5U)dvL-V|qT3tbHkbhQ7x%hnBTdq+e&6L&|Cs>D^3oC|OU4^z%$}2wCey zdJEGWI#!EFKg~3UjI~On|HL%KX4Q%GqfB#%ShGd?ex^AztSXWICDR-dRzReG$~1?9 zRU*>2G0h=h`9yj((^P%SE7CVGO_jG4k*;T&s%{-T3c%2-nWl2sK-%37;LdKA-CRjW>1yWza)7b=o)6bVS4<@Z&7LKZnHgTwr`@=l(r?G1>IFIYMZDuAv0xe0qjY@WKDIb zDS4JdA>`MR8`C7VJ0zNpA@P|YaV=miPm!O9`LUV&?hE6wil)@Eej)S7M(T6O{ATl! zY~!VUM)htZH}rBzMbiQ1?zeNTV{?PC?^AlbJ4#lRe^z1c51OA==#{TVnnQkH#QdnD zX*XN#qoy-bj8Li2!=INvSGqgcyh2U(0Nb&{pg~bJwdrx{cj+6o`k;`an0w9FHXqJ5 z?lBV6wv`w!9f`fCMo$lxzY`s0G*9yvRg|`swmsG24JhW@tsH&H&x540VuCCm+o}f3 z-@a+1l}AaTgtxOq$UG{Gw2C4tUosNo{lQisrjpNmhdwQTtFhHcEca`q@;?Ippn$)v zH&-KRZ2;@Cp4Jj}#|DVj`VD|B!B{G#H|<9>an_i{KBYAe`RKoCD4#fMARz-KWC9?@ z&D+@c(zeU42won%B6wwR*4CDm(gR_0*Oi9(o)P=tVAZs6d)vY40ED=Cwg}p*@=;|2 zihtSCvhi*hyy?aW`UyttaDicdc%AEtt)wap-IrIiGAp%DAGC_FjZ8WCn-9BzZXd)aF2CyBDT{n?UwTYO$>a(MWBK!+f|RC4yW)SyrH0-5cJ z`il*7n!m&_BmS}oNCqN^8PT)#VIhB&J}ly&tq+^#uhWO!=U;^~`mhH@h2(pkNIxlB zt`B=gw3iI+1Kco=8i{kKqFRn4&0!j0nolr~q0VL$C7(WmQQQX2CSO~FmsFIdq+w(? zPyH)x96P~>0EGhPa{q9$T|~A82@NA}IGY=IS^-w_dWaxWoixnt(&Rh>S;92w@vTsa zaKhuqgs#VDArVT{VUo{ZcePKcP(L-Ao~x`r6oFj4(cEzP-}PJn3>+hYw2>%F70v+~ zih`~luXRYV+HmzAqk5TUsGlV(QFj>DAyqgI*pb9Szc<|O@uLmkzCsJD7^=x|`F8#8 zHhn`I9E+)&-a%(YXxv}>;vv21abN}$b)Mj%fLjGCCDCGiL&#sEZdNfy19)~m~@mH9-RH|?|la3^A-p1}U_hwizr~c#%hhX^1VkwUv_k*ukD(|o0 zTZukzBu@SZ=GEk*hoRxWqK2D0px-aCN6ij8X}=TQv;|1A3pO%l*V%Dfxcq>A%Pw#e z!8F?H15DAzeHKcoUbLP zeGQ2U;Wj-0wypW1B6PpeywD%8Qb^jek3t-F^*Ih{*83@?Zx%!TUeTl~%^HGItvk_F zj^oegp{v#aQu;&AI9`@fORa@N;?f~&tGfZU%HU@GLJj5$4!IO{Pa zTmL*)7G8>kRf7`j&m<_O3abIi?9XeErdW-pR5UwPcsY|cwZCF&Nm-|o8#0?JoQzBg z%X-;?u>qxkRwl*>FfVweryaqxY;yqu&DL$BF#v7dGurYk>S*C-R6ivNZ!T z)(0uUOM)}P=277|a_%dNBx*7LMg3Z3(+7I|r(js{TbUT{4<|17YvIJmj)Ao!o$=Kg zk|YZsKvke;Bo>tzO$VZrjp_;|cDVa>Z<||E{yqDy4oEsiqQYxbR~8wGDz6dSq8jD9 z4719s-|{{sl$fufaO2ia`fwF1%}-K=<3YX>Mz^T}d<)+QtEtlf#PnL!IquVbMkFyV zoH*ZBuGC!UkBNTTszL9Ou%?UFhgjukqxq&{W+e|oU#xLbE{W-I@ls8@_1jMeppzdX zF^)uYq5q%*tYEBNW$9q~tIOZBz6S{*uY_m&gV&nn=jL#kV?_eBo8r~plcV!b5O z!AruXn4iMt9{BEt`8W20VI(GdBPOQjNTRMN;;!>G9g0R`N3-1K{kiPl>B&Z+F!_|n|R(_=M!?3xn zqsd52g#KLkL;ZOHL()jh)GRv4o%|Th(>>wxSL!bbCw}BjR49pD$jH0uLru2c-t)l7~Dx3YoWNRCquueibjO$oZ#U!pCq4bbn4w>q!DGF3* zn0r{~N1T&lThcu1tKUKXe^MuC#ty63-CGLBt>c$M4(V~y0;;qt%~L1`eRYB~l|(5d z04wE_-RNVd4M8J@pwo~D`A;EaFd%~gIfVlRTn3-d>Rzn3Q8B;Dkj`%Fd(NMSxU@@koWgNu%l~yQt}^;hU;Pp=Ly751uz5l% z7(1fE>zmXb)+Z%xi8>PBWIX~*G|g-M97JfJ)5dvbB(W04nH?AP7gZ*f_`-=LMd8@@ zntsa)*oCL*+zJN}E>rT|Pg5y)rcH~HbEv|t>P?qGVe}0Z?uWnAo2~-%VOKDb)0n;L zMQ_l|Nlf<)<#s*z832FS7xhz)5au*nvVhr=on}jR8YBz14hk#Q;b^dSL33yX4HJEF z%`jgw#$nFT<1eD-kiKDbMf{N7#AQ!7u@b9=S0c>~YSOS7o~X67Ex79F z5dBVARV>XhatDav5m16R>lB{#Ur-b30oe0xL`S9~<@@#cdw_PV6?VBfD*4nq`HYkw ziv9>Znp>c+qc`s_S_7Zl+#-hNeh$sjU?NnI0(4Y4TkwKa4#KiL+p!TVo*&pBS}r=@ zURt3*#QbNX1cMVYZ%?j)0APlqOMz1q9`-tNDfYE z%G!*^Y{b$pW&MRQ;jI0hF@RDQy;W`qrL12t2HzuP{e&@iI4P@%F*w{Q>qf-re@qXX z-;0UwD^7e^J`GB^%`G>-r(&qye1yMxd?6$s+c!9Nc(5LS0C7XkRMElkkKACqKc}b> zm=)=aqza3!z?2AhW3sj-4Exg#6+ofbHcj?8=0GLo-~I$x+?SfJ=U3vC%%!Cu&J7){?(NTU(2fOch2+ ziHp36UOoO2KsH7A_>PG~SR{(J2Yez-TvlxPAtRwjQ;SLuU_8+iX#`C2JHD8V7N!b^ z+KeWq78&gxR;dJI+u)FFhePu6@?Ag|oHtEE*~I9kLwcNhLx#E6NCX0yFFB9vP25jP zlr^OqE$anlCmMVPX71$34yh@D#EstMl>NwQpJ?+cn`>PQblXe+&1F((RzJb#jYU`w z0c2eSlw`M$F=q$133Z`D}_?7K1WZ1jrOFeW*6WO$Qn&~nUOVLk< z408+yBdxa>PYI8oY7R$fHk9Y|j{b67r2UmV)W`Y5_Djz{)-Nqu82C4S={TWpj$aCW zVSTboJ^sd3&?@X4WUf5zaSgl>+}V(M226zquB(wKiRNLE$9?Q>kV{HS<_w z>>G7yZ!EV_UBtvL#F2>lZSp8ENH!STu7<`fD$<)j0DUf^Dw_^9{|M!34s>!c%m-8;g;T?Ms~{cI$r!XIsbKY9VyGn=uV`MY6Wfc4Bop*I(3 zM)?cT9ftX=El;D`o9Hd%q_3|k;!d}Ug-{|;Vw7)fe9tgnpkMv7PJN)&I?fue5}icr zlz=+ShKkilV-?#DJ^O&#nJ8&IH==%Mok!i0{*+^<%>BuGV6q`KaUNr@Q)tHY^%ILC z)%!pqx;28$U-ZJ?Kf=7VLF(Ow&^vfKP`&3?PO_*sgkyb{eD*`Bca>0`?HP*q8CJAH z@xD(sfe@7r)3O#SzotmPo$~~Z*+mKLG&OzDxS_p*?Ghw9UQYLik(dBOIYF$MAR;|} z4a>zoRnzj+jA{z9``?7}>FakH`ubOlVVzQa(>hx)yNcv7EW+l_==spK;-@fSLsrYm znkRh|JM6k{v{Bs`a4j;dE!{_#6sbF#Ln;nIHXj-E^*8$Z&Bi@pwJl<{$#uL@eJIiW zD^}gHneqruqh?Pv60^KNoX0jpC!Bfg1H^^$p~IuY((Ub>&u&VqqA|m#bbKWHQL1$U zyMvej`qjc7&BB^?ATU4&dfoV`gHfC+%mFxz-Ar#NaY-2tL{{iVVr5CH@U!VQJXQDs zqL*EPUc_>GFXF+=xrD|n>ffG(l7s$@(6by&VbLO(Gp@j2qtwjyRN=$GXMU>iS0Z)| zCX)kt{1+nsomAl(Kr#IqW`}L5LU7wSpRo|QX%}|c^BIW`5EN$!IupHeI!l6(sGzxm zGn!hybNSAWpB}5v$#I_vJ;H>D`FR=ioz}ARe1uh5mv!37P~xNt2)x8dToZt}QibnN zLnFZ9xdI2(VQ2OqgvkMB^|ayUTcvGQDd{_tV~-Ey=G!i2&1}HfKG&(23)Siz2t`(p3{z}GtXnui>tBpdq%l##-24bng-ei^j z1zb5jz6s~5u(;Ig^iD%-013Dl&^N+-2pAUIVTm0E7)s|PRk&%Y4+7w(I7v@{>vBl} zmJ3+vwLeWny=ft83LI*8=}kAtm`87FLCoA$+P2wpAKK!<@m{oBdk)DOv3Ad)Ev{&8 zEz?N3c$((kk%LOWH@9<2$QqnIC3(ZUlrihZ+5$dn8}@%E`1DPs0jwS3Cu7+XHecn5 zUY#I~2ql3gh5WM_ft6ysigASV?GU=hl79n8G#z2U&hp#gaE7*BX`b}f_^C^$wBA)C zw$}2{^D@^B#pcw6oxR^K1p;Z(moq5+SHT+M09ASxgrp3&!#~2 z_~C4ro#picHk#aSRYBe@qY*FQ)hEQ0)=ig zn4}qJK(1-iIHO42(mbIcwk1aoZ;9ZOpnFK9z3H>C? zAU!D%E5nA?)3`ez>fr!xM)zWC5XVOcBF&3ns%K!RFj-#`G3&~l=INUnRjNbNbPTCb zVy=I91$HZ&E)(M|tx<`Y-sJFi&^OJ?)KuaADlj7S%AANsO@LXO39Ipj9@ohgbufAK zZR#F+*=VkUvcHr38;V=QK-TF$bXPGLZQ|KHpJ zTQsv5reZV%ni1mQL+BTS5M#BgWQT7RXp5){HWCwH`NQ zY$<$q$O?F2J+7j65Sy;YPm;0Pr*cq-UJ=2O7QPO@A+#9!g;nx-;Mmr&cYb8|$qqd} z2_!>kNin_w$oF3=8s>hW2wii!LTH*in}2dL#Cqk6b-e8vqI zdKcDz^!FgPTQYTS4+>HjHjxX?%qSPYtQ&^xN1t3|H<@Z!AyiK4U(+hc1rC_kQ0HTF8~V=fT?U|B_nOziA3acME=?<+H5*Fm z$QM%cWB;RR9~Q(AbulIVGUB$R8=Yz)X%`xo==JYJ?8p~7b&QDHvoVSlJ@y8C^kY>_ z3^b0qRAIJL9b5T4d!ZeLItN?R&uFUH*jPaGT1`kfe!i{OMV-7qRcVV1ynhGfayX-q z{#`3*!HzXW+ym9)2ha!(=+1#%CkD5J+)5joDm+hC4JTEPKLcG5(?rBcy_N@RN}Zbj_&P&gNZjFips^Ci;KklS-*+ECq$CRCbV z%MmR`a>tKbVhjDlslvl?kK|44s{~iwlq%NayAXx$&L?{+)CFksRg~;FtyA89!8`Y2 zLZD%jW#j07(ZWSw0fm)Y0wk*tJ%jxY*-!C0Sxyjj3`@uJ-0zSY9RCpz(9>nO>;jgC zC9oM6@|Wp%Zo%H(LSZ4AG+3ibGZ|@q(7y`R0#lr8MPR*W^4NM=rMbPre5KOd7dGDs zn=f~at8FoNhTW5C-GXM{L~+xB6~SQayWEiZ{&iP`;i646hp)rVSV&+071o(5s#b>R zP3NPcV4^Qny1o?*;s!#M7B(-@NML1aDZFWJvwzy^osR{s`F^T!#)a@iK{tZtdY3)~ zJ1J0F%YeY6zp=;{c^$Vo>wv^WLDn#*YE~Q@Vvd}9p;mqMhZr^R=+Y>#%p5V+C6JOB z=jOAqecxlf866q>CMP;9_Khp*r}2p;H9(gZ$#^%$yQ8}UaCZ)1H>?FVcnD;u$LVs? z3782Ij-| zRhXZLtG7o$WLd=g*4Vty6~VkUlU+L#z=h%F`8Wl_bpi-HgpT&wX6Vzft@=ASA3**8 zftrsW!(!|K=wk~I7TaN_LxH(QsW4~2qrKN5$fV01fM&bxr~ntvBz|Xbxt+Z6Rc?69#iFzPOFjN)HdT5ejdunUKuH*0)*0Kc z%7RAqL4AF1vBDFp^(mUQP%H`J6pvz5LrFsBD{L)J?x%pj^;mBC1;?Q9rQmX@0r?XH z_R27W;Pe*AA|bI$4*~CG^7hUv+_w<(QsY304_gg1$qjL^U7*oE*p71qov#``n)Fb@ zfUmTyWMXqPUxBZLibELZnz8vKSE}&K$>4yMZ{}pL>G6aZ5s(b7vIuX;G)nZ_n_y%@ zW^!}V)!e&@?ZbQ)9{^r)^~J5<(i5?8^*_@VBNb`({IT>9#%FC%U*Z`97xIgszS0A? zeTTRF@O4&D-4!g~qsK>pZe{hm7c_f*W3S(;pU3H5V(r>hs07LqYx4kcWzup36ZGso z#Y(U(7PQt-XM6;_#~NWyWt#P(81ey3jj&C0z|3A&Uko3NNFI|Z))&~51zo1QG5x+w z!+$$c(ts_2Os9>eL3Au!7SWLwcfN%_vOIUmtOsOyXEN2SGHi8oJ>F?#I-aa;sf7PP z=fN5*ER7=OC3BJ2nkUnwhxtLVrb>EtyQgCmiY~TBd@lILqDkGMD1SO%EV|+e0Szfi z=Zb2-3t1jLegm>P_mAWPEVdt8sqG%?O6G}n(7qe|nY|Hx3iJ9;>l54>Xc5h}Gyf^_ zt#iPcV2hUbnF^m`eGX})A&(L=17*{YdkA?L;$RD^tPbSK*n&(-^~Czbf#6;Y($sm3 zprF@k`KRnVagq3J&~gOncna3vsj9#av5*m@8_qQj7B+hPa@v8!CB?!uiXWu~BRCe|nik}AB`!P<{r;iAi%mf#FziE+xdc`aVvv`LS5 z3Jr$js5}~#rw?v@qzm^Gg<l32y;z z!=(cGAMO|LJ>hOr5UyHhajBBY+KZ)q339vxKqug6M1#e> zr=Z#P6maDkGfote@BIT3#xY`;Xtx3lKx`T3?G$D8_&Ndl99#0-BlciR{%H@&i^GV| z%&p1QC@(HUJb>CIG`Yzsya6x}dt218ZT>L_EW&=-+jAJimCey?j};fwLjWS2=#!9o zK;SP=E#lD`@1n6t^TpT=n6E{em+w(J2BE)_d7_FoPgva%DgWM}D_2J3*mig@n6Fcf zZwd?9@wTWpeXnOC?)9Kdr{9*jPrVoSbhxbizu2eV+xVu{DpsAVASDG|2QPtlJ7_w6 zPVeBD2d7HdaUBrw$!(%`J^lpxC1OI-M=9xFVyiu3e&5ks@EacXHcmNkx}(Sc2x34p z%uhoQ?H7Lof7N@N-dOo&?Aui1Tgm$Y;6=&2=q}urjJ}91%Jt`Ci}E%ID8zG>Ev*H$ z!u{UEyDZf}7f(dU`J}bQcFpfa8S6Ee0|`evT+wha_Mu0#BYJ71ybcz=&dV10z>&Us zy~F;;$+vNmfbH8{(V44|3x;t&F?r}kR7Qygzuv9@J&GX;sg%CK={I7QSg%sr*za+u zLQc3$1~>J~^Mssm&Is>N(8D6q9Nlqy>ukaBU*XH)TH|)0Sw964w6yhf(M&t%G3IbP zAbB&G5J#Bz0F-R_J6IJ`d9{X8!6BwKmS~qcXx9=gl1BSHjdsj6%xg&hJTy3YiYN%N zm$6_k6g14YGj0U#5gb{cK(^w7UfSRn1E0HAnl%t@Nxt@i&F8^$LFWbbv!o+$|AA3- ze;k!{{Gqlb`Ix}QJ;W`<{x4v+ZU(3JWmp`zajc&TFbe$$g~Z)?z*^ff<=2G5*2Ul~ zyhU<^}kjNDghoPXu|K zPuk_(bi|Z%+wfxma1T@XFuqR2gcYmfjL5oHA=Kls99WWXV(+Rj>;b)r&&Nv_suCGS zLZWS?<%90jF~s7{NL-2ouua{Kez^U`7W>GA-t=qy8qF8tQqP!ixD9ET z&*LCdj%$4b=6Jp7D`N1Pp4r{cnbg3Ut}*O&M$356It(RVWeS^93JqY9rmvNsal zagv{abh!KKGfW(vcK0WLj7C*9VK_5)Ia&Y{=2OaoHMBr4AJ(| zHzJ9vHLC+7T-ep|@)FP%6&w0twcRL(UEQfSeaNZ95uh~-!?APy9}wrKA8^-aIMJG) z6#VeCd&Wz$9}j~~ULU4vN5JnogyOC@gdRs6jlcyUv=?s6*HY#f_Nl^xb9{0(@ZfR+ zdV;vUi9*wGR_mJ8Ks!F=bIJsR7gjc4nmMQ zzFv=eQP+6vyZae7*0$*JQy9aZe28ICk1t?2L67qp%ki~(d>%vWzzaC`->+dByY!0~ zVvl|a!y$V7T7;!3!>Rze2s}G`b!+af9l!xpK&~|iBbQ~Up+q{2JNIkOa z2u??b2b(9S=&zWc;YvmGv_jQTlP&rNP2bRWjn4Jp8gyP#jg-IIXoc0cx&0Qz?LLmn z_=hmX5Of^{vHCEz4f{UJ#y1$v^>AxW=lrouZ{o9m90|n{XHc!44%UK+KHvv~wn|!$ zD%y&vuoY8bE075Jrx0>6AQuBN1*EH1E%%oxjX5v{ELYjQ!qc?7(mbliA45OE1T_B$ z4S`D!@Y8>ZuHgf5=EGZNoNZ^#t|-PLW6$>ZbHrV5aChyrEp%7<9DP| z6Lxq;V|d`0rcwp`3i;%y)K}3?3`H0vSnv{>o@GWed@~r?W!7C-?>Kl7W?YL5h{75# zwhuz=v5w!Dwso!-BGq!m7&5=LMnhcUS;P)&BRW^c=VqK5%xRH~Z zwS+OTn5$u|8)26*CRWK)7~=+=H5swv#`&vjs@&q%Z<+b(=Kb={ZZPFs%yu#G2wP8QGRUAWJ|mfoRO5ST!28xI0j|ltt1F`w5D~K2%!| z+AiWu-c2A=>) z+d}IrkPxb2eFh7ju^!}|!$c0wU&l5b5*HYw6 zg<8nyU@z42{47l8^Jen5u34=5YcqL5cb8YmCaYQo)V0AB#FT z3M#|BPh21R66~N177b^F%xZgy7cB%8%yLbifp&X&NR&0jS13<2EHKQdVog>1((UuZ7><&PZKwH(6~68q9l6TX9X*HRB%aA zIB^}ea(5>^KxbbJgZ={Mwb${$fzDR%wfg} zey(wG-X^;PdyfNfU15?>zvWYE1)A181!Q&#op>YNFPZn*pys&G3^HL(Q$qTy+*J;d6MCZaZ+CC@DCSewp!ig}a76dS;OKV0^^ z`IDV!$p6-!=RwfMl2yfukX`^rt*3-?<6uoc_w0?s7>V-o|E`Nm^aZWvh@7Yv$B-(&Zqy2W81iY70|e`u?8V} zQ*7b0Hw_l7(&IBR6~t0*J>HJKily-03E^6mT}{_&9Js+`c=I+^_QUxQi&QLByIRXhGhgkn=wkri9C|>Mw@9j+F&Z6n7-=dYZfVm;u8()tAJA*~6;8%~|QeMe`S8 zhZTKo9v~Y*Mv1PDeXHqBC&T4{*IyFFJP6ML(b77-=}j3OwNP)`h3FwX(4ullHYQ}w z#WO|2{*z~li0?BJXU#mr2fOw$Cy!jC{HVVAO-#>W^E}*lMGm?+j2TIfuR=YvNhQ4b zXL{{6R~eu|6F&of)NpHfD{ZoduXL*?(+zevACZ@Lso;pJO*qnDEj zICTji=IQY^q+^G1#P%0v)H8#wzj-=b|GAK0Ya4t)d*ck5&=X!yv-!b@sbYVKp$j9& z?MXb`$qVmjYoM5Y5A%j`g-2xBINbX}b0gKWftp{5Ix5vK@k#+c!>sXr0x#;fK8h|8 zYkhHRwFhvVQNBXtfDTvN-1HUi6L=^2J@_&bH$jg&hS8+s!3x}xVXwjt!;?|pDcv15 z_Xfp#TsS}7jhDaR*_f%$YXxvn$kz&dhyt0f6%fzii3h~^93Gz-6VKt{0WtX;9-kPq zpTooRb2xkdxB-_Q^);uE&vLBZgZj_6M|i)x8jwmi6 zt`@Pg8Zt_!pPwHKpnQm`7f68zuNeD-h?~K~X@bN}=ymZ7eNhG}`B>H-&W+NaFkj+n zu7>~Iz$32 z!;YViv1P-D15Q}SAJX%4KLM(ds8OJDTqn0a$>ECQ4L#1gdg6r;uOfm0{OqY1zz?AM z%mEx0eY+i5awy*>dd(?Sb;z-~`4xbC;>=n|&bQanU|*d^oJ>RlS$?WO zrV;|v3`H%4$0<2zP!w~T$1$qmN!|)Og2GKcFl@dJ+NdEpN>Xfk5`=^(pW+?fc7=~P(gGctz(;hygw5xE zmA>I(Esnc4BY|D|T&F#1zE)jzWQZR6JJx{Md-le6H-2JNKWA*lR%r9(ni|F??g^h~ za)V|1>nDCcLmL+I(oS^seg{iHPy7L_UYxZ;WA1B*4+1vU@ z1ydE?L@yH;I?$s$wb!D!J5_;)`SIUyW8Z5Hq*;Z!4A+_}*BacHVjG*MdJOmF*n>oG zTOYyNNWSq#2c8%20l+3`Zoc_l1w(|7+&BFhEHynBEiZk}*`|rnC-ZsjK-n~ zH7x>fiIAOd0wg$^FtK2t^l&=2b+&dr15N%SkvOcajXzG z8|t%sp9D7}*`M}Cfi*;?!?+w#9L5`-yvg4{;jEdMKd7HzdK&Zy&&!%S*aMqC#Tx*| z_{|;SDdSK1lreS#qkfm@h2vY4$>;xAoaEB$?SDZJ9)(BJL`7f6j#5L**y6oXHe0R5 zpd{sPYE~8!SWlxDWAFQ(a*4s=!r;*3Z=n(G%3#F*IM~{WM5jDkZ?uQxkW(YK7 zbJpiTX`N(e?DsiibsdZ{-qtq9&e)aCxD^@F%HKr0Jrk2HP4p9Kgj#@OhmT;xUXQPb z3d9b76TPl=xJ_sc@OU2t_QZZ}_RxBvpwX-NXiz^Sj(;>r)~16jk5a#=l@*?!u8{kc zt$S>6aT@$K!Ct%C9sqaTn%w_;>4%O`kxsse$}+Z~_gFVzFtx6-TlDrI2#Nc|5PBT# zfD`Aue}oHJ%pb8&mN~ayVAQum`qKN9LqHwlp%V6u&!}D=KIZ*1#n;kASK?~tbQt+-#TKPFv%3~sluy#; zCa%>Y<)8A}Ll46|n3fOkTf#jriIgWBzX;>)4={fZ3MRM%82=t@LSu(xPj{I!XW<=s z+)xN62I74kurRbp#WZ&%GU{-D!QoxEcBsWl$V)c7D3@(m__D>n`d~$>i~pVTo0R4fk%7A z6X@{QR}Qi66K00OtiV&m+pulb9WT$>j;+5MZ2hf3u55cBv>i(_w*7QA8*Pt@myM04 zMG%s}8^@yJZDXSdD&-39&^B+>K0_*rm|x)H5#@mO2kxDNoS4NipX1rX0Vn(DtA@?Z zoWu3_w@{Ia(l=s9)TO6}nlHt$`Ugf9Z*yU8$4MJTXHt2bTZV{5;C-N1vEZ7x!_!ZR zG)H^6t<#~F+{I4x#C)a4i$O4$xCw8s(Qp49%u2}K0>rcU;p&}f{lLB(>cKYRUZeVr zu=@&Zy}XmW`!SG${yAkrFteZHU~k8+qfLiaj1FSEuXJ~1H4cvV262#%ll$)d*LeE# zAiZLZ#@)d3S5|(QNdZ+-+F|t-3VNk!^#)7gaG*U%_YJRROX~3y?4E(U!k8v{7+=3G z##g5PT5kh^*ZX}uP?NiDMfwI@I)ld%e@>6zg+`a|X1V5ib=5cUGhUH?26E|V>^3&P z=YqJrsxvCBYe3Q#4IEbpo5H|LkE(YjTOO5S=-fO7TwI!(fkHuZud|t(Dy%$7bSJJS zi)}_6_kt7leFQIu6kW;P6S+a1ECXFSkmyHjfmwXlisydi*&W{zRP*Iz1fyWqQS)rH>@m z*`|6bNfZDg=SSSJ*a51Wtw^UK9um{gCTi|30I6#QHvvL-Wve2zW%kGlEmM zB$t5)sRW04+!Pu1VbH`KzC*_5@7*{)$7QQ2ze7DRq5auD@u)v8lBa^H-fv=$9}l>9 zG~%2eZ*}2)0d&D!Y%n0^cIFGb@Rt&O%go#qDy>y)qT1|zm-qr=w*XRdBzs(!L0qDXAg8%C%Rri3h~jgquc0tyE+JPh ziHaJI7x537S-51*++&#$kP|UOEtpeZKj(T|si0sB8qlNFc%?S;7NgQRzBCh}73c)n z>kSL$EuIr?tgp!^l*#e2eEd)`8W-20mBEtZTSTRidAwpEJ`{i)8Rt+Lq6?s4fcX|I znlrD)2X(KmnOoD~tN0P0C&h>OwR4@pH0LU*tyf*|n^RYZp}KJ4RYJbX;w6hm)GcX% z0xYfZ;g2QMi$B=lt6tK$I4U|?P{X)ivN*b6UgMI+2H%kMScKBgt%gR-^(|bmXhD=U z3ynHQ^q^1}RwaiC#7KD{0p8N>I#wvMAjZn9B@H)FkI7#B67<1hRKr4S7YU!^yQ;Ca zwx%BHvc!iDTextzZ!ru6HR!7AVWI3Ard35|O_~|0xM-?x&f>W~CPTq#!K#Xi3w?_k zqm3wdJ=?Reu>lh3RJdahWp~TrWXt0O`DrCUKZvfGvuK{+nMKGqM}%mhZ~mMH^l<}P zu%LQD4J0is8hCcp=lJ2^r~~OpJz)1j;Q4Sna|6=su&wn&TZQZAyQ#LT~?0w%=H7Hmk;|rpg zm}>1lCSB*Vvu{8|lSL;EAGYBwb~wKayspYCHvYzblK#OiLf=Vt{rzQFXNO(k9}f@M z_?P))`9F6NmYgEeBw~C;f5VP@o(_EqBFZx(hu0-`qO3l_)xR+cb1$u z|9JfWzozdwQ}Vxa$gf zcj)gtN9MPUKXF)R!)M!}(FI;t<&|-g?!#dj&W@ZooPVK&AG|<@Rd(1F{_*g=HvPIE z%kssSoj6=~sf3rDsiSlv(?o_;mq znV;a)V*juS>0E)Xp5z|44@f8BJK)|_icfde{Z}gW9nzQoDwX2);EMkqT z$FEDJK4AD@Dm4ZST>e{>L-^)Hz(e>Q_7Hlzk;d*R&$2$jzUj*dU;JY#r9ggx}$KkZ+HD9GA7bXCWWA*@q*1{BNn$a)g)T9?6Rc-$eK&!u#IDmQgmsw^OP6 z5DvhTO`jmV9B)31!6%skF`Jz@unF|v4fle{>j>mtJUS~Th(((+k z9if6%s_RE5BxvNhBW&QLA5>KV)|Z2{2ZG&)&6>B;{U-Q6uHS6FTU7T&B=P0@`<{c+SAz&PTAPHbnh3+-I%4i@-sfu0q|vZ!oVb}J|bB?55nIDJws>@0_NP?pG49lM>eq?d zc>%}QBPZ@Bp93&Ojqp?c1h^>DjITemnp6^WiL+W|#1Dk1N1H=_Y>hH!y8R9sMn`;e~eS1Q@#F zqb;8;LPr)Qb_V6d4_pHA>1&72<^)8{f!|}N9llF!yj(kU>OY#2?U`@mw{MWQQ~Cu+|Qj+TksBc$XbMWQQB-OX<6~OF(0A`&HOphlEJH057^#M|@rNmpy zCb`BCshLqwGYFZ%%sWNq3WD!qG)v3Y)-$DMPeuvXK*T*IoAH~|A3uAuzF&)C+I5I$ z9j(Q$YlxD|g-DiLeMBU++=rOyv6J51KcGNXmYpoh6GWz3THoat)cC z%g0-@da88VT|?&Q&SJ8+DqB>S`w){wb~2jFL-MTtY7`_~Lzd-!LsA3P3lO-6tWtBI zA@(43rbw?=b9ua+NtXonEKrrkF0X(+{h;*{rYJPCudM<}-bcS}MwKRC6DMu4RoE+`EUgskwaTO4fPm zC!&6IR=2NM;QpKh;6+&vQzTjoEPmD_QaXw@m?a*S!qGG?EVBL}W#d({wV$Ctwze77 z06{BE00K>42x>V={21D$ z*%(k_A*fv@+oEX0ASvx~3f?tD)80fG?FyOl>Wdo}fg6cgq-|i{EQ;7Q#HVqot<5Gu z*N|fE4#-ZMBU2^XKIYk}GVN)U(5{ks0Z8IT&~cF=t(wuC(+9ElO z6dh+3indtR4?z%7ThbSJUNs1!YQE@T$8LR};ZUe$S@`SZIC20ITeA({o_C2dY=9TF z_hegTF1HzaEl|_~QPmw)y`zg2RVRs`Bd759HsPJHb8n&cKI-&bH~)krKYi3`F4%&? z?KYAHq->M~lBZm^I6xUKjFLo^l;zu@OPA>k=_A!X1O5e}zOg}Ou1yIwvqtYVv zO4O#FL>3*(e7_z*N>N?_mw0>(Yx3GsMIFGHhQ{@-9c8DcA=NKNtdm)Ot;n2fr?$ux zN{YG7++;=>&qW_)fQFSm?*L_FZ3gN*8v$2J+mKB`I`UY@N$f#0i+A~ra zq_YTkq9geCaQT6#bKU$4x#Cm!a~pRCaBq>g?(39nrSM@pV+k@Ikr}R)EUk`~9i

    fajEgpgU*Tbbz&7h%@KbHvo1NDcY}Kq;hWSM*Jd; z33Mpo>MJkgCZ@TE<4X9i|%~7?7S>l^yJfJ=Vi;HH=iy$FGm)O^XanlG+8Xk zr_0XEmBq4ry6n7evgpsJ%g*aAi$*?Oc3!?LR_D`Y=M~7}jC{K6Jhyrr>^q8P<g!Z;Z;Ra2DOC=F?^8T`0@z z)O@<^yfRr{ujbQb=atLyMm3)s+grwJp{BQ1?{Ee zM6q^SyARi)r&?dAUH1~6HE;<$1XjCWK!MV?y#fX8e(|HC%G&CtHj()D&}o_3J^-NfNQ9h6+IV7?PBS#ZSzfc8`$PSq)n%fU{;l}`xp4uZK*dnh^o0B z{SsdVS24?38A|@93=<_yJD1%~9VJR`Z8RDeOe+^9kG2%EQZW5eQSxfXAeVxx$tPOKHLn9A;<$oq?YXq$xPt3AM(PLSxPt5L zlDikPOK9J|gB-m2LKbASkp*_;P3 zCU-$?ZzLkBEV$9`U+L9wt5PtJ^G@sSAYQ@zgKY9S*mM^xFaYT_f8mWv!9v?KD!p*O zLMf=TSwesS$aT%F$SFCTLyvm<2GnWY!J@jt<{OR${i-Wj zK{+u}O_jJ{NzB26hx(2YqJ{{~|UDHmk*iyZh&>Y%J zkNT6f$oHz9tEl&-lwce=|Eb-Xrd`F-&ukvyx7bSk`E(NaF|vO3mq(G;)=~t&N>SkN zW~u8~LGfJ3(y!SM2G*-~VMI|MusJN&>Y)1SZ>q$=O0+2)^lxk`W#Im=WSQNl5B`Kb z;({Gwpx=)`qh1K~*9)I1#rOxinG23x#N@p_>Z|jCsQn9#)V=lq6zzR>_!=w7+GS+z zU#Y=mX>Wr8$3&=!`uZ546#krTbDb*jRsP<69|Z2XP8R!M_mJykr+sh2K11X@V&HjB zj$A36Kv|dCj#_=0O)!b2qOnq#$DYSHRSsSKMpljymHmVm#yDA}6kbEbw;mc)nEe8~0e^k6 zDHzP4ALv=y<>H%bI!jxGM*V+I5r;KZ?F%Q+uP14SHTK(wOBQ({R}h+O=fGl(2>ALg zWljvaZ~>c5%eE!68H6a`X<{T4fXs1B)5Mti@i*g;C#r|Py`xUgrakFP%cfo}SoQ?S znVqL#X4rxeTzyZB)blhkWZs#P7t*ldLK@cyX<)>ZPa%~@eN#^37i1O!d(*`+v!A!b zGpZyuu@FveP9357i3;#3nmM6VD3P?UIPNk*TPcI&H-5M8xnfwY79MR@K=sU^c*Y9^TRan-6pyV66;7cFV)`qcV)}(zOcb=mfG0Uq z({I?TK}aO%K(Gs2 zMJw>KYDaWG2V%cfU>*=M+3yiBi9F$$T*h4k)Em&k*~ewags+kG%$W^@Fv{q6E?Ofm zhS&(EogUXPG)B9d*lv()cVb)cf=^t>>)KbdtizZ580eV$?OJP0-w0=T;dJFaG z$H)P-A7GGuI3c}lB{;Kz@H$OR?OapmyxhyHO}e6-CEP=uSmBKGdJLRhuc(VOZnm8F zY`We11S!;O#C6`Y^Y*i+7WmN?W_~(uMF2QRoksW|b*e*~J4l`E{8XJbNWF?}l_ETt z5y&^&h`G*JX4wFsvz6jYF;oI_AmzwS%J{k!O+>&MRtEo!WB*EMLki!m+l097R1X99 z95IluIRE@X#~$Z$9ADeRSii!TE%7TwKT~ZkCp+(1zXG8`Ar-q*6CI=oyL;Ike9R6e z_M)U<4LXH+oB)}ebt8_AIyKfTXEBTw-l<)M;_E055fjoWOl)sx>_A+jRn&vp4Ai^s z!S8vU$G`~yE|n@EoQE5tsWN}A@Vv#)f{#RR0oa7|Z|5}FEW|@}5upk2Ts8*F78CRu0{bRaE4*$8@<&)$?+F*xU{~h`M3>@iqKpj1flx?S{Ta zIAB7jBU92H8AUn!YAMh<2(%hRFnQVc{Hbl_y)Mjc);(+5R%TNhx+z|zXoJMPQQ)Dr z6}8IQFG=t{AaQr9N;cGPS2V9r^PZy=MJ2Zn*u6NG;ANU$Nm$lB_kmQKsF|E~&pOgA z`iHFim)#)O$)6e!pQ1Nq)uAq0BMW=jwU2;}kz-_`9fi{IvVfztb9#y)<~m=K8mttp zlC|Y_mFicDekVayHpqcZ+SxBi7)Mzn;FAe2QhVCnF6(MOT!MaNgL0kxv2gJzs*+U? zr>YX+RMlOw>e*D);WUfCkX7%csyuU3t^O>lj@ng}YSC*F)~lBsY*+su%c|kusv4Ek z%ccnp$lw^JIt1J-joXAQZ3@1{zIi@?qj~g`9H?AS$%Vbkjwn(KZdh-d+%0IK4!{G= zA>w#(mk5Dg2k@+ga5B5HS;Z*ayNyJ4XVWpjrmPr4PjiXn$%~HE*Rpv}=)$`JSFzGB zT!qYq$oQ%x)@zs=aIcoqiY-BQvV(^_XI~)ezefFFkf4EDj&Gjuo*j{u{jXM(%k4_F z1WifhDs|)_96XjNBmXS1gmV2&7KCy=Cks$6({7&Y94_aZd@P4HzAAApM;{~K$Rzb) zCaEvGNWGjQ6+DTQONv#H%9RDdRbN>kS7qnO0=N?M$saf7M{ zvXEA^XCKIR9BSL}chN|EWgp}BuSOX7{sMm^rr>J|jL3+Y$e7H`N2ZM#UX`yzJT+o1 zGV_?Z51BYK42*NRweATD{Fe-~-AxafaZ zvOJ25<8D#^Cd$IS+r^qQQ7yI?c6kfSVn=G1zjqeOV%vVVs|xIGW%=zca%T?&IfN!Z z5F3?dQNqTNW-qZYY_GXNt#o;_WT}D0`(pd zsD6OD^TmeFE>9?uN*C&HOQv3?>Tg}QKu8%%cQS^UK4~fOm7$am$+4_=ePMJ%daDoii337VKX?Ij)v4Sx{#^4&fU@v(5EW6*b!DulN8hO!6sLejc?_Xu+{ci%I zx<-7C1gt3|RG7VMnaM-uIcEAIQ+qBlMaUdtW*9Pqi*Z}mLaRaJ_n&EZ=8&B(!ipJD z4xDR&qm1Els+3iJ2wT0E@tQ-|IEy9ka?Gxhmq+w3>p4#aWykPL1r~FW4Ob7PI6UGVTYW( zU~w*d1aQI6?~wUBFfZAN+6kLcLSQwN&3-h{9>h;%s?K&^pK5vpEiPo!LBp}wPR6{D zWUfJtWFST1Fd3NRe27$tvH~cAlV3AKa@&yc{ZV$v5Sr_Yv55$x?croe;d&jQc9Zi! zil+}!L`ICjaH>%&I(ZN!Iieo2-Fxf$!@c#%xC+X|UvWhEs zr(Nw>0s{f}ri`O1F?{hUvWEl0YEA>s@N&0fTGb-k%dL|L{fhjkLZAh{)E~iY(#sVI zFV|}%yd1Bcp!@+)W}Qvju z4HhnOJ!;RxVTWCMfh8WEog;d3j>i63_^fk<&r+{He=QhL&lMi+A=J`?6$>ukVW|!~ zf4k_p07agZ4sr3QY&MGLi$k*W1k-IO59LAOQ*!*271dvRFlyZ1+*BuM1qiM_aqqCy&A&i;rkE1FeRi z+~9;Y`H7^`<7~fZrjBtXz0fXd@E_4y=-WHYP~WmHgf`?#)Xdd166x-^Ns309>wiE)@a6|6g10a;2!SjDZX`hs zBxGU9V}K-}kVKL|Ku9ov#XV7Qsmg=zSN$z*foH=vOnKNhRZqIWc1ieNe-Os5z?U&6y(kT!Up5f6eiW@al z^cqbpT3jgu)@wO|VKatK;-(h#GAD_vh@vf>GISC_dOCjSBtFoJ8dn2}KZnF$LE-@d z)@hcauuh}+)E7<9)1j>hP4izLbPfc_f=tGKUXc0c^5T5s}H5yu?@^K>u61*|O z>#Of}+}ZkS{XM!gbfmsqf3Ic@=bIF0N}H%OQeU>ePqUs(#*fsO?oIh}Ds!$irDwTT z-$lDW#COrY;qokUscp(rCRx^$ZNun4ecqDeIGX+@Y=5V(_1AE<-p0)ngSIG=@KES( zV$|EX4aAYvAeDL>w@M0n8+Vr!^fvAnQqbGDUrRynse5kY_Pb8>FN-;6h@$pBQh*|g zFZWt$okIPGA@a#y>X$;}4PT!V5q{>(pX$e)D*fxQBr6B*3z21Uwz)%jCbcke7^ew? z=mtl;M%IY&wBXp24C5Y=a`8C!lx00TiRxCS(|GH3ZIX`aBd1WAuUb#iRnw?A@{R;z zoUCKB;B+b<74Mb@oI!&?H=9iDNoP{+UwgT=|2T`vI{Hoh&1X}24X?*jw6r4&Ow63F zyMByHBX8x_QZAyho=2vImM4$YQ_&P>oI`@i4W@M8xg_Ww z4kuGCJ&(%zmar+;7E^f`8+E1@HfuV!CLfsMEilyk>^ac#{7PaX-nnk%dAH5cIl;7zZ2HaqGT@{`vbB$9p;ZPl?Pe&)%HS`&FStllBN^j$O;0F z5~YR#C&^n0)1}>jT6CuWa}+%^#HpNeLu-r9Jdy(fo6grZpcmTQsj@z?$DiAfF$M(VFk0lGglN z2CVtrb6m|gj5L~evh?@tHkQsl-%Tv}2UrAae!^VR{5oN+As%S{&<|u;iDFZeOpy)%vMJuLf|_BcAJ)OtTa((;oWk$rTS zWFIZ8#}W_p?lsOd55ytI%D<)KViIEy4sB%F94il#H0|-fGvHWBJD&i1dXs_nz?jylt-`{K{?Udlj_wqa+)X1)<57lcXIrU9o@7X@#MxkGB~qtE z)l~PWDUll9ab03+^hvEKkTyi(Ws}q`BL{?JobNR>>N@R3A?*;-R4eWHQAV3TN=v#x zk@jM`p&c|dy6CjP5O~YRqCXObK6DbVhn0U2UVqY-NCX^bs_dy&>ItJw<^Pbu6EvCb z=&hj}e^%;mqN+-JRHeO=Wm+|$5BEw*+D-|Y%Y#)bPBpFW3RYbvRnG*gB2x8cu<5Bzw32_joBvv%>YzS5kx zFcb&oPWZs%6$!gs>E|l!M%pp+BO8~SM>gmr`wD}2ffmSD0It*z8UEnuShSmZ9jtHpZPT~>^z#hc^rJw7=dpU*5||}f zKQ;G=e$Z$T-*A%PZrqs(|`LFrPuKkv3pIfao@Y_zMZF;-Vj3ISzBKq<51g<6!VbDQ<-JQRM4Y-R+-w`?E5ds%95O|uvKMAB3 zh&aA=`*)+4$*`*Tln`C%P`w|st<-wq;(NHqWNGdB9mMlWhR&wx{{k%S-;LPM(FdHm!+WZ_P!+rVqR{V^}O5LM6G*CNb1%DrJ!4%AO*TA z_&8cGs5X7Ey3{)L6yf0$s+V2OtgKU`rJf!w^*l&zvf|0zdRV>|saEPNspYe^G*c~S z`E7Jzpjv9VH)_bs2`=`X(i$deh5+vkUp-+Tv6yiI9(|OQRM+r}u6zV_Lm}4$yn5#U* zla((#dT7d|pogYL3gm%e(>PI`InNuK)zrfh;pwQLyV}x2JJFvNI%{{S(9Ojc*6WR^ zR-3(6X-6W+ghsq+IYN8c&=OTArdQfbsrm#})jhS#3PT=Em8>OF(6+6T0)^cvlp%G1 z92V7@yqWQL3;)uo&_S`(Ok4U! z0Q)9R#UGnDbdcsxIMXyKZKS%Lbh*VO_>cAF=esXLg8wAWB=|jTBaccT&QEpy(@QDG z>N~im{6rI#f6jT;l&@)~vR)7l>dSbKwov)$II1`0Msn21N4)ZcK<2kIIDVsB5g9lKs zjNHm~pXN?nFZXbWC4L!u{t9hj~ zAY4PuIVS;~|*1mdX$FV0{($9F@neqjC$|Y08t= z<1~70{K0%Pey2P~Yu>kcrtlv*+Q-DdGoDt5y;QfH8m0RgG7d;h=0^nRN-00x&|gGO zl%suod{%b!o!@jnhrV%r-leq8@Y51E6Ts6Fdm z-#lEz&%F8@Q=3txL?1Pk|K;+(O!}AZ=gT~wsPs84g}ir>+v7P=Jqp%68a!;XsCYw# z&LDAJU$3So1L^koh&&0HNhJ;X|VK`Qv%^IxWt9v|TI)$J0N{D|IBIZ+EC zPkSrvTd6+9RK>MhS;MT>dno@1rvr~)*?=|%aU7c+SX|#Ro7CN_mN!n^}(EV6h-P0bC zN%W4XH>ReQ%UFDGs8JWx(w0h9a;~g+-jZ~=R82rt`#hrN&3hE6aPyKN6j)!nAb*f1thmNdOAZx?C&tR?5tc>U;a0X>350c@L7 zt4wL|pd43GVA)&q%&Cv9U%ZIBf=YCi)7B?b#Z;pGw;j@TcJa8CiIkhH)U}1 zS_1qTvsxN!Yx%b?%%@PlOm2Tl@;q z=$BryyO^EdkN8xd*51eEd5g%q2lY!oeXgZ4->Uvhzs9nXiX-*AF^9CG`>Cwm{~IxJ z8$0ofgaN0C``Hrhel{@wAl3Ta|3_(=*_T>=WZZxFb<*lg0{Q1tjduUVRMPH$odAFI zUCudYPtt|+nu<893>jZAUC {Id#SJC8*##Elj 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�Us24I@ggiY3Gd2rUgGN>G#-0i$&ee*gGgqS!2;@cb} zda&!z3PAW+S*^iu%dQY#z3;kjPA?I4f*kc1R71#JuKYPcFU*0?Fr7}s{1zk7{@_Zd zUy?!LRUy*S4~Q|LbJuO{=o0cZ(ceRxn6l0_sTk0+vgArJ#51S_(%ao(Ee6D(#2AdX z0s%iA0Y6GKpx@(6!T_bY4xA1M-!hxun1vD`E9J;R^t#{=|D z+wO9e0RF}$6$4`7iIKGS2=|}m$d9%Gzv9u7fM4}!$-r-Vv=rb+^NnHp`&dzUT!_?3 z3h*yIS~BpH9xVy@8IR@wXPy?-2?}F`$ejR>^=Qe!<2+gt@Fb7s0N*S$Z3zmSJ;oH^ zh)4TB&0Py{T-A9#wu~`ggKYBMZ|tj;w6cVyUCnA` z>;keO%%n6O;-<`$0AWRV#1lws2-A|5rfzt|Fig=<2nIqigc3KT#5BAUp#M4N`_9=t z_b%X(Gt-^X{@?lT|2qG9+`D(RyA8y*d#;{%i{~a0KLO4J38w_dsDu*8MK0k_K-ue0 zwtnXo2~R-)tH{O}43?XNm zI3r~7#Tg-!*O?Ljjdw=KStZU0zwfmOIfB|*SkULuU1ltvLY0kBxxrV4@E%9Ceh9dq zk59-&C%a8Qj;{Awgj_YE^$?CSaVbog)F@P*hBVt0@H3vPC;o-!8i;pzE=Byj=NgG$ z@LV(TE1sKAygY5Qlr=j#j*as`N`mu=GoEWEUg^0;;x^Bvh%fM51Mx+kt0!*v+$7>f zitmx@!%gGi%c&4M;2rmX@cLlbtbc*K_{_g_o&MLBX@fnttAcR*etW;!c zGgwh1{6m!@TOWHx!XmEgY-qOr0<3r>WL=WCxK4D6xyuq^DkDBh;LV-Gee|j(Dr%TFS(?Bcj$LzT0JyA!HUwOTHiBBe<8heCXYGarM8TKMHdu;fwhiBensGA8c`wCrbZKfu*Fd85 znvnRm;ki&^2TUk7IPvL$ZC2eV*Qz&@ml=Lzkh;8bWag}*XfYLfPgoi=QM(y#DzC}_ z`f#hlO397+c(_#z$4(`@2<8&lvk4csx`18cdQ0dUt+*lTB}x38TY|0hbQ9K{oCdiB zz4O>hjGM7?9)^@N<(2TsT|_7@?+0AC48vXJ!ezM9_jM~iGYjwpPn`_-RZoQz;4QYJpmadXO{ zt9@{cItdphW8Donq1|Htf3Wh|r%zv<%$$QN>yG34DNB*Q{W8BG?&$MuA#^n6vk@I} zvzA?kkV(o!+dj-RD@JO2Y>yV>gzb5I()PT4INYAan3dzAFph`anHp1L%)@n6Q&AM#pE zD(z0-7cr@_ryd7<&QoEY_ao1jUGdyW#fPhT(r1_St`bi?!vb?nXf>9R>1r-aYB7>w z5#@C*AxBhZ!h>!OGL9kHU{En;wHVvzF@cJ?_26)rN#bVCURUHYnv~0E(mWp>P6!*P;SqOUS&%mhe@iW^LJ8b&kzQ6bUbP)cJ&Woa?j*w>av2!Y`wvI$^+ON1ac| za)?%~V*J<@qm3}-`q)ay?&}V7?`tw*+2xT>@g4pk|#`8NiP#)QAso z<;#SH(h*pbqg_`s?EQeJHUa($9|?bu_V04YZ3Zx$8MW&gxD`RsgDk? z$2c$eGh{dk65Q<^zB=x1=Wv3%_?Idkg_Xelb5FKXZYa}Sy)Rn~$mNo-{jEVn zo`~edILDG}QK-1@3+TJUg^S$;r*Arv3T_(?T^TZTX2`JCEDqi2e@zU%X^zg=Yt4ne zW@95h6;e-Y;$@DD+l?%-o*swPcK-wXE~I=U<}kQm7@?Tyu=Czr{#W4bkfOF9%IQaO zWtcn5%IgU^>u|_sx)fRoXM>WDyG$sv@e8l_8^DP!ht`7uSr7@pny~glu|r$D;X{D$ zcxqy-Kdl@eKXYOy8g`N4WIpUpnmN0NLuW=atk@Pz^2gkXW@WrXu{y`CGI6Wen=G8A zjff>5uboh4<5HJEhOph~$q(1F!Tw8`StZWqgxe98%j=x$xv`W&olkL7a&DT-#Md~krA+L@#cx;j z2Pw(@gs@2Ag_bO>`f_+tWysKSGtO1tfz&UUi2v4e^~B%xTm$hfo=Xwm>bXYZ?|H77 z_zus_Cw_66%~D=OZ5_wPFF{Iz^NC;bTr=^@o@*q2#d9g*UwN*9_`f_?PyD*)CK0z| zWts$QRrG%JOkR%=(x?2VB_UnvOXKs)Y+Zp77Dd9pa@6^ROhdFjJBc>2j@oULcUiXtJCv5IUx=~8PY{2eH($kyqon|LH-AFN{74JP;>F6UJ&5wn!*%`iKm z!aRfuBMKFUyA@%6;KH>LKI*7U26gcn#I{`KO%*u@Y}y#6X~-~9Lx!muGE9~$H;v5n zMFlbIC5C?-4l8CzX2ztnH8IE4D6+vswIVUc)hMzt4TG!|i4SoDzk+a%TSJl}8|=8Y zCFTqA+_29jM`E+&10{`8{wg)!aE~*?-#Fx z*UKQ~d@u|1{{*)*GK6P2YUPE1osP;7_BiTd7UEo2#0+7^Q2@R^@#)bVn;!C-C7c{W zacXQwVRW&=sUd3diP0RJ7@`)R7R_#2aM(qSke$^*i8%vA&G*luS5R_4h_NfTgtfRi zX)SKvm@ut3Zw!-=X}Eb~n8r7-2Jdvc#0tV~pbk)1%U8O~&#X*J9aCnyIXCxK5cYzS ztF&=tHaH|zPQoNMB9h;#Rx%Fl<(ezB;%R}yDg7JS_*#>&N* z9GZ$#5qB(ekku24L0P+mvvcT3PxjE0=0aDR z3rFE+xXjq?E;m{yVSIIEV>2CF54SB2gacE-2PEOq5xRx?;%5m}Q@sHq(ItiEm*TDQ1 z=O+FtBGma5H{Wt@n#;sDIj*Hl?8C*gzAi{9;Z?-jbXjqh91nbm<66qZGaVNX_W^uS zCn4NBFrVZ$!HWp%K^>^%XRD5?d!#>YhVo0~xvw26U$MtcwNlRyyhRK}yM*aa6^2M! zYlkDPQ(VRuhmrmghi-c|0U)3qN@wleJJZTnc}N03_~?}rTaH|=kkJ0ahOY&am) zwCz3BpESkV9RxWYvH>!TGUGtY%!51?@^r|t>fcpwJv;;X9^~OuL(jH-JoqNaIgoQ9 zzY2LOWawqA_V2;(hmapZPMH=)vh5uBUdTHjx9%nVuS~ab=0koB^3Na_LoR^~vy2Y5 zOb28SWIyB&ARmMb?MK1?0dmSAR^tnhvml!xL;L@P-K&s$TmNT=*@$mJss`Jh1sUeE z1bh+l3dq|aQ^#0~`H*|to`0ioE|2gEZA%6q;F62LA9&w(B zRomPC_@i{Ue91-{fqV#(zx>9Zc?EdP6|&+q-<$EY{Ww;6u}vi<9}-3b}?XRP+&N6SAe-k$1j`kKx7Sx9~y zx&2hjk3y=`Y-vxknQK#NLN8N;NABOB;Q01^ZC5~oAKu8 zT*$G;$lZ|dLx%CjY9GEs9KJam#^WtY-e#*`W;J+^ z?NGFjfaE<{-h%j3`wMS-epY^AK4Z1#?IPZ>+8?)Bcxxz(x2O6yz#ne_&0lFf@}5oT ze^2#Q)8K~wQno{6sc2;nQE$GKD-Nipe4&(UT5!ga6HD1OXsyW)HFXU2_H~`u+ohUx zt0z0yqnf%l|4vE##{jksK@L`m)*pXrQm8ntJoS@?6TTm*;M2$gx6K zwv<&(xt^%InC;I+JzZkUmbHko#bS1YwIIH{Q`E$Jw!gPiLKnoLJT;jp)?>%upla$Y z^!MlTa)7h+&F6@vUW9!G31)5KDIB0ZZXY2Q zqL9p&@i8XuM?j3J^Q4krBn|BPS8dbkDzJZYy6}l|GtT7qur+i%7Ygc%%5>6*NV=^ z74}BlR_SEw^_+& z+Od7JfXetcwx`XZ8{3UgNW(VdIm~}VIBn1RkHCJUT}XM{7u;D+8P-2-5m;&8mQS05 zZF#HnODo)S82=ySNTq#qA#HS<3)bXT4vcNO@k3K>6L6sX={2AqqeJbGM#S_v{`RO+ zPYO6l{%F4g_B)0?pZyL|)A`eWC+v5APWzX{R(Fy1yI{Wy_MAT~1M}xRcs+>!;1%t{ zDD~hKM%3&-{k$P+mHBUj{WjRYZ{4_O+EKn8+OKany4%)UlZ+MaIpvTAABxbv*#G(s z?dCxJ1|!@$u`R!T+5SX;&cB%iB<*p7-yPMu`awBK0I@w{pJyR{dnGA2)IF?*{WY*( z7`$;D+Rv_G|A?Mg^2l=FZ8H|XrH1{{FI$5n4uxS2`>(@3tY7*aYcLP{5WO&e%Cl?4 zUx!Qw9;Ky~v?JSE!~XS0t>(^P07H9ym~)3dwS4S3tC-{w;{`@zs{ZDw}f_@kubfT!!*^N)fj@8L-&Fh@XgLRS#uV1S9335G> zuA~gEldF=O68VX8{g9-;uj2JVrL#Jz3eWr1{C!~+ zDT?RIYW_gQ^I$c9kmC8Rny*(pZ&mYC70*Z2{4{r-sph9EoM+Iqx$$kk_zkVD8{jG(8CHKk=wA+g+f4Y8 zwtj2`KaxtD_6F#G8~o_emcOUo99B0Auk&w2-2E-BYR#XmMt`c>K4kqsUH#PX@p<)x z@JhUe`@@SyKfVvV27O-7(*Ju#KfVu4k^W7SaoOCSHmc~ZI@0h;?cC4u^m7vQQ>R$I z9p|a}(5D{d1vU7!!l$TIA-`$(_`dWV<7bN6G&^my7f4$_ZZW*YmCyGJKUMa(o!H-a zo$}8$^#5J>df6Yseec;C`nwDtKVQ6ALw~%S>~)<7&P|&%KQ!Z{)c%IA%-rG`HTdQl z{FycQOKb22!%IC+v-#YG3zYRW^uJYuFW2DjtHF=f;9nEIKH+@yRt^1qWIss7%cc$% ze(LxJwLLhm%@SU($?!2(>r32G=%Wnk>xTE|eQBDb8v19~;4cwg&y%pf-8KAgGJdA0-K}X8^%V5$`WpVrhL2yD-X;80IlnV5 z=bO^^c$+#^DK}VZnKMUFXR$O`8tU#A7)9qSTp2B0(%Ke9sw-E_t?3<1SJ?5^V{{9VOQqhWZ+EuEhfj-@hfxf6)?ojs`R45D#8n7l?>XE$jg?xwH6JFb! zUt{S0{_KDR?aNuaVlEeDOB)87dIyWyrmq-Mn$k_}b}(1$%jNB{xt7UF5*w^-e<|wh z$ri0@xAwF)mm7#AfVG%s)TAc^6(LUcWT_DK=lV@sC$%nX4@p-Ba=EopVJ+N8(c+a0 zmMw}FEk9Gn#10T~RZY57bmqm&7c5({P_!zJ43@IRl8Vk+dfpiemPY3-UfjBY$)0`%suc+pV#e5->a%M~NenPdH+=I_| z_77B((UP`hk)K6v%NFW6)Ryg#`s?=qBAc2SLJ6$a4dw@m@~%gBwHtlBr%+g{t|<1F zg7l)Cc{8DZa6`Vc+RAoF@{%#EKBE0yE^kQa$xwYnv^#r>)m&0W-KFACUdj+8BjY)k zD^;88V0u86te?R^U&0Lz1j!Y1*{*627$Z|FnO?ntfdq{gKB_3M?o@1KqBZ@6ysf{P zRb7LHs3)86l9AC42R8T|TIMRfV&t8iocvhDd1BPnn~#PDb6sY}4&?{3oog#+lAe32 zKielW#e30nNfz{a=|)0@7Knc(TY$`AKPO~(WV=c9BkvtSv41EZ8%A9ulbhWI3^Yl0 zX8Ss2UgY|^qHLGEk5w25=SFnSx@aYKy@h?*!9m#z)^#V%f!zAupd(QvGo0&GPkru{ dRTE!Nh`vI$OUby%iYf%t&8%EGCd(!`@_*dXfy4j+ literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test122.ans b/libs/libtpl-1.5/tests/test122.ans new file mode 100755 index 0000000000..e4c3c1b72c --- /dev/null +++ b/libs/libtpl-1.5/tests/test122.ans @@ -0,0 +1 @@ +1 abc 3.140000 a 1 diff --git a/libs/libtpl-1.5/tests/test122.c b/libs/libtpl-1.5/tests/test122.c new file mode 100755 index 0000000000..9a3d38c7fd --- /dev/null +++ b/libs/libtpl-1.5/tests/test122.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include "tpl.h" + +const char *filename = "/tmp/test122.tpl"; + +typedef struct { + char c; + int i; +} inner_t; + +typedef struct { + int i; + char c[3]; + double f; + inner_t inner; +} outer; + +int main() { + tpl_node *tn; + outer ms = {1, {'a','b','c'}, 3.14, {'a',1}}; + outer os; + + tn = tpl_map( "S(ic#f$(ci))", &ms, 3); + tpl_pack( tn, 0 ); + tpl_dump( tn, TPL_FILE, filename ); + tpl_free( tn ); + + memset(&os, 0, sizeof(outer)); + tn = tpl_map( "S(ic#f$(ci))", &os, 3); + tpl_load( tn, TPL_FILE, filename ); + tpl_unpack( tn, 0 ); + tpl_free( tn ); + + printf("%d %c%c%c %f %c %d\n", os.i, os.c[0],os.c[1],os.c[2],os.f, + os.inner.c, os.inner.i); + + return(0); +} diff --git a/libs/libtpl-1.5/tests/test122.out b/libs/libtpl-1.5/tests/test122.out new file mode 100644 index 0000000000..e4c3c1b72c --- /dev/null +++ b/libs/libtpl-1.5/tests/test122.out @@ -0,0 +1 @@ +1 abc 3.140000 a 1 diff --git a/libs/libtpl-1.5/tests/test123 b/libs/libtpl-1.5/tests/test123 new file mode 100755 index 0000000000000000000000000000000000000000..a4de2c3a0e60c38c56910798cf1e47acbd8d07b2 GIT binary patch literal 129055 zcmd443wTu3)i-|5%p^IG%Nc<{K$MXT8W1Ew#6(bMU;<}!qCu`zkxNJb4Ixb?h>8-K z3356_W9wU~ZQoLF#cIX2mg1!(h!AhD1r^0RUeGy4k$OSI%6z}yK6@qulD6;j{J-z{ zk7oAXYp=cb+H0@9*4q2*Gps5PO?IfNlKeQ73lx^t<@f~1{#KNIZ*}ANlu|`ge9ACo zsFDe+4E!bWd@`3zJ7lwDssWcDC;nW_IQWH+!-p??96o$0${_LGohEx{%Ko}PKAE-C zb<6EyGF23h0I(f-ZIktF%jXGrGMz_;@R==`V$Q=a!5-Ufl9 z{tcGn8|?6*#Ilcx5)j|rX|mhO{o#eoe^qBAd{yTYnPmE*4OWtAvfWg)BcK22C&}mN z+9eA{*Df4YyQHpZ#i$jf<3^1edsgGJv&MiBX}j^qAx^nu2EM!H;X$7D{qRT8vEKd7 zE3rpgp6b%?{N&!ZPT#lY=}`~g#=61yOUgeg65AbC@ zz~AZt9_|6&+5`NB9^jmA5B`q-{1*Txn#Vu(0RMdt@Edx7ck}@Nss}jj&58JVxd-?- z3E!3NL$3StJ+h=TueYxoh}^I6NBASh;ok$;NyVv>9V@Hjp6wX z;kk1aEYm8k%W+EeiX~yCG2BpBwX|NT2{$y=Rm~4qEA>s`Mx~*8er@ftDpohv*C|Vv z&aYRNHeOdJAhp$iR4;9;4l8r#RyQ=%Et?D6`QatY>ez50D@n62+mkuGnnt8Z9R z7p_s}q75NLsJ~8Gn(SmDs3=RD>e$WPxiu@mY*?wPUDjBwEUQOvV54ergGkUCCEzb> z04hf#hqiS7k~-zuh9wxn@*3G+O+$6HG9?t8IBD*fvr5LMvSZFVhthHU2mjG3ofyxS zuZmjQHvaK*$L&9d`9vEiEMZN9mh@szxx!v4%8C{9h$ehUUy+kva^C2ZXoHfU^%6e| zfTW#c-G(%{BrTe3OoJy~A}bzAgVUBKKU>n^Ngu$vjx>0>pL`|_p6(}hrNPN-^0PM$ zp3+HF?n{G1K&ekW4cTq^nuBbFAaWb5{T4DgXgEgE7RcVj&F7vynh=0 zyfpZLH2C5)ctIMxJ`D~lllrVkgAYnU6{R^1esUVzhEHN60(VN#sDQTY%IR@AwJ|-UQ8rwUjm}GJJa6-Sf;93kBIV5S*D6v8$|ghEK`N7Hc?*9GF8NC7Uk<%rfOLAqTIkT zRl=Gl%2%^YRj?{Wc>&8*0m~=Km$S^Nw~9siGM1^DmPeE?Vwon*a-&SWX!pPf8l4%n zsAOda$#@0~DikTiZM)oxU72_$3;A1!Vcz@(mPrhB4|O5+iar&oK92 z>zK2B3-}X?`qi9vRwef7Lz)TO!cr1{+hHg04f82u+b0(q>Mq0FY3x4Qg!YdU*Jybu zoNWKTY~OtT?phDr!$~vHGJX>VI%j9bR)Ewmw^QGZ$oa++AcRj&v2fCi_6^Iyow+}; zYmRjTnpn&6We>o(`P04VD%xR~VQ-OPPWKiYX2@F_G6P;;2stBsu0A~At<;Byyz}(o z)4lcj@LzeG(MBJBueVL44|z9;^il64B7M@^fz)V?diOCkj~cP_`+`TKb-GvU40tsz z2c$X0qB`Jp8?6Da$3UM2@gv_S5?jGvLQHG?c@&evMhbonEMD^asCT_+euwDYFxPoE zq8u`#f{PH!6hYXh5046d^x^Bgy8zLL-y!(oI1Y;Pyk;Xb-eRO2 zM#Us~OXta01Fn@F2mY`OKBx zkyM)ks*RXJEk+QA>w8=QR{Td0L8vNjm^=KD?-P3T0m!nv@F$Qp7t_4*r`FOBwhkj>=zPSUAW!l!w zn5>Z5X_&8ndB5KB5HS6*dYAu@iy;&73^Ip8hUH&6GTy*7Y9tQbN{2pI#&7(hzE zWN}67*y4(^uNx#818hhhwQ{c-h#w#zu8&R0eUNPgRPUb6yp`(T3FLOrCE;{MoiD~)*NcI%OnUj5X{UliS znZ9N>xCxmqZ@U{b6ZxBgftEpYXAr;;DCyA<7wRqrLNK^>7DjUmLmaaEbCaamFL&aGSp@mJ#gHmB zs}QZ)e}|!R9S;SvwHA<)H-nK0UPX^SijLaXF0`vZsNt|(Uh5k`!POH;AomXimI# z>{=iu7qqRJkg+~Q@z3(l44Ox2A7@NMFj5eT)wtW=N#?)2&;v}Y_oc-~%V*&!Mpd~IIh=FtJLXdf@16~dd^Q~;R_->c zDhiBPrQ3)+r5a_s4YSg%ulWEy8L`D08aHk4rXMmtt}s7MBltF8p&3oj z0uZrKLHD{(#VMiK_+acpsa&Ih7cwzV+coGt3f2rUdd!0nJKJczv4~aigU}aiye*g5 zi~=~0mY4KfM*z^xj}aSBqP?L1RUQRc{z#|F*8Z~BR=#h24-!ING1rcTbr|!e@&aSM zp>DT65H$$Hd^8n`^|D>|&kCBtKLyP_m;%H6AI^ed#HP4ICL)bctiB-RtoO7W3Wp*` zGxX?}&_67yGKjsrPa>obAbkKi2?KPSJ1%KmILu|JdxB*L^hg2|*F9cJ zcMEz<93x^Myz{i85aJ6&qt@08G1f#}M^o4eJ-Qef1GI|`bw^Nr+Io;QZN0g;pygTp zR+=*dtXCjl6a3#9ghs>^bLY(;DNvw8PiuPAhatBd+6v+@-gn@;>(sW$P8HIPUVdDA zef2c(i1C}99PGBw3w&!=VrZS);_jMlpKAb~L`WY-7!|GF;r3`7AF)nGJFM$ST!j-? zk5GE3FM~|=)f5FfG|WBh^CSAC$Wtkv_0{j9{y*sxG$V)AYkygSy-n9$LJp~Q(gv!u zE3H#02Yq#nG?iEhBmgVrv8U0)Nh`!43NdLY1iYsaG8B-ZfSkq!0xtbex*#P>6C|UQ z8{`+h5SR+ToEqg|fu0&P3{Pop+*>96#ew`+rm#pvUKM$3cbd)5zPUE_h@_z#^ z?AZ1%12Yhtq4--TCj5~jDx$v0ok4waTuL-4@vYVaz{Jqp)_;Kr?Q_aF&kn^_!8mi` z!rp?4*fLKrwyYo+`Cil4+yuMuxD#xP01zQleA_|pBK4L!)Ep{zs(Q;TD2%?j+_~|e zddmVpH#+>WtftK77ulP5jK`>SP`32iZxu!SbGS{h-(J7`e>nB=vA>bh-4VUU+?N` zucKgOr_h(^m#Fl|GAE7?lqA4Yad`h0gjP`0r)Q@v*_8e9>st@C?}Ozw%zoZ@-siwX zh#u>QfT|CAE$Q$#A1&1HfK}bD`mu5ci{;@{{5R_qp7m>}3H1Q%dA4986QQzC^yvG5 zcC8b3xixI_sdw`kDmxUu6g-+wL0`|__DR87#N_5vVrhQDrCH*S1@aPrjw#~^p0~SZ}*`tCFR1)4D_3%<{ z!k@(4JgOLI#LlB{@14j$dW8p_z|+X4u}ScEP&^)M80PjaGo>#^tPvsk4Mj%hB#-DN zR;R^(hq1O7p_s_Omz224o8;D`F9RegBF0aeIHU!lX{XO4(%2P6mKQP-dNi$|`UwPY zn0t+w&j)`=Kd!fI1}s+El4!E5=UE+V^ce8m@uQ#Gn&OMy;EtD|fMH5r?crKK2D*&W zcVBJ`%^E29yrBU5A%Lt)fD#XMv4>D>SPY=}A&_dHwZI2qV$bDIywdgGGG0itcdeJZ z7?8#?Y4J4EVZ@eWo(>u2SS&_bZ?T?YE-%#_fzmuE&xo!;_PR*LE9220{fCT8FFZCb z-76xM0A{tPxOBYGw`5!jePMt0l)Ai4&Cn{G9Hj3&<+=u50O4%FJQJqEh0xWA6^FC2 z$urD%<28^*NbL$jC9MUJR(CuRjE(h*fYf}0wee3m9p-jx01X9F9jgrM z3;}G0C=g106Zd_RNVFQNnav&}->S>|VY`j)LMBcjj)c_j;s=01vi`^pH86f@f!_Kd z=yMZQ(Q>HiiB9?tER^l8uGf?CTX!6bGmw%F3?w{6Y*n#Yc{l!R5HzZ0DBw!pKgs**91h~E>KEpAVj5uTh;<)*A(ct(oc}B4Q}Wb|Dhe{^e}wYsn|2%erdN&O-BNwaI#)2; zO!8P3L33C5Lg-r2V{q7z)r!*A$=^l}JFY$3s2Tvc78>4>nxk0->aNy+nt(e#GUS_Y z^-bH1^+B~GWOms5c%$l2Eaz)>-L;MK;4$Mrv6GI?b^p+hZG%oE{n&@d3+2Ovhli)e z+wIS8OsV3E86KtUBYPfgwT|I*5Ds8q4eZfe>}f9n2IxSqn+_x~iW2$f0vyC%*&T?@ zDlKn$=_cKXttw9B4@trk`TdZ+Vh&~z+i4AX|CQWA!;5-%Y=n}7{teKxEV!_60n8b9 z;IC6^W@jRQ?{xHv`b7SVB6kg($!B`>7oz^%ME({);eHLXOIj+}SvaZ^n8F*};HFd9 zW!L8JAIqLqtceEf%Wghp)CYJlROp;@;hOzi3UbB*|<&R5d> zq4^~auC@r_uJjhS8^|T{17wx)1wuJJx)smWU~#F}sgs6w9|{ODpl^hEkT5NhX|YUw zOzq$#k$>Pa4+OwNagv^h&}9~$&~3y{uk&#t>MgbC$#>Z+~VA~QjUo$!b-g-eA8A<{}3V7!+11rURCG$uZ%M`lDmj45g z7&=m)tn$iqBvWZuS|`6fVcPPk?MoMk6SMqRrcxp}2W*c@$WsEc5>I?I+EdW8BO@`Q zo1f-H9TP-H0RZ{U9aviKtCRjC0CX?BdDGo;LK{g|93kt`^*LBDE4@X*&dC}ZBXu+N zcTN`5iL!@fq+(1h3FL|isW5Ny`8zWyP(6A$6J}?nH=yd#3{a$84WmkpOb|y@S?D1U z)Gv7v2U!A(4?+w*dLdA8=uiabS!z`EH)4}D<4njkWg2G|s86*{%!@pgr3asi>^qEe zE+^`P=41^4TcDjRC-U#9l;fEUEpiC`B!eJ5*%v9rf!5=_Wj|cNt(aaM4dU_LXQ9@m zFx4}$R9I{%4w?0($>Hf+n^dYp%M2{3Ky0CRWI0YNTdol6Eu~Sh+3xtr_b@lDE7U~( zATlEK%7nFuO@vvS4Xg2{9@WVebufN(A9WA2Y_wKF+24)-4b83LAe%fNz;qRX(UybQ z+d+;aV}0TDBS(rMvm!mR949^IF2gy=9eGMK`@$7tAkd5e7avluScF)smDb6a8`wWz z^U*3jdVephrsktd@U+0rHDS+a=dRYHhMilE*d4M0UQmy!m>uM1=+TqyT+L%xT8dsC z!XqvGCHW0t#LzG7k}m+qQpfa5<(%x)qmw~0fRPm8&jua8r=iyRts$hohcpkQGL_SG(8MJ)B*AMXz(R+$W+5}p>nqVwKPL62*BKix)_Js z(05Mn3IOeWuX!!v(a$Q(yr=U~)VZ z&SfBD%jS50iL!0TrLRmGs+%!{3iBI#MT?c(^`o{(t#>3_yzxl>QksjTR zEOd7<*;An|KwGS$W!D+q^7abec@`4@4M~=>#rTUBE(8lGtlTmnS^1b5oOjss6s@=0 z38G2E()AqAJ8TV(UJ3-vbZN;;WNCN|hj9UKseZ>(INPfg7NSLiHL5VY|NjZ$vTL`3_%AxUyI z-3xLw`1M#kB0@1t?B;Rd#xRYPQH_?t<^8M0AA%#FS5fv+(^Bgc3_#3Fu*&6)jkO&H zhU)g~n{f1v@8#I@9ZKYfl59Xx^yp4B3s&{>A_O!$WuO9F1e5rl$?bOhir0DIu@IZi zvaj^$UpQ1d5^1`_9|KCvaI??IC#v1hs5+=`>L+%1Vz)k3vueebz>epPDkw?7e3hfc zll!S4a2>W=UcoUad?mQNe+q;}4A?8f^n=qikVVYKE;$6eSIArYUY=VBztnW9jSpK5 zG@BdZ;J84eeUO232$QcG9-8z(%s{NPqIgnkI9EZegpLDP=bEwYBS#|NOAgriHadGv zkH*A`fMjr$MMOiUQLNwE0wWVJpEZ7cnQJUU$S?i+Di^}`o$j*3*IIscx4&$U9vua`6;v{fK}VDMlK6_!R3e#u>or?0O3&o}@8WYffqIB=5K5?MRrAMzvRrmRky#b4Sf}_+w|s(nvwxAY>-mrXbG{vJv9o z2r8{E)Y-Wu>6Gp!)~87b?!}-?oyQ9DyREi=*mIXn*_;bnNkJwf1?xqsD)0krWcV3| zbB}|KjUK&{b|5yZNQ6eA*u>J-%5Nh_9Luv}_MRtLg*!36WA-yxgO%c}CrgHs34K#1 zLP?m`de~y%@2ThpP)l5}md(NIW^%A-+0{l7{Re^4}rnYRXEQ4j}#ASNw2 zMTz_~l0*z3NWy&q6DG&1hG6k5#lCv;&xr(!-MGDDvR)#$pjr>2iuE3rWywpHM|dje zwyo?@TUMLu23yMI2hX7bbzXu)*vO3Xu@gud#{eF+<#k`e< zLu8y6zy2Sd7wNST0=Bl?M-zA#fj^7OcFG^;I zcjLBX_yrtMzIy?VC@+G50(`FWRQvt~BK+QiyHxQipo<&vwm)f~Cqwh+(Z+fm=D>zy z9FB0%AKC8`;|O0KDyxTuuXl4q9&n_u-jrnj=ovZJhTcsX|V;OolMk3wA`@gQE`kPte0A(mcEC*7jn- z@DqsTaINv{^TG8`K?EahSF1QoS@R}qcpMPF8BB;rn9l$dKYJHg6;gS40nzag(;7## z%adroC0b4j?b#ICG1oAEN%|LH!12>WLx_Db8@|l>G2cnM5x7TiWPJ+RiVJ!vZ!sJA zJhjrSQ!$qK>;EJ9^pH-hn~p2V0j7T;I_rA4rY-)Uz{WkqFD3wc4zSzT15aLt#Zu*3 zr~J`qG!k+59hpDs~M>t zjby=+d>eUBg<<#UEqtHY4xuVgVZ>~-EnHjBoqDF&ycw~}@j&@{w`rx$btCWbT&*a4 zO62fp{g%IFfavkD)vU#x>S!-?C6M{HO{<}qJ43OtVAJ{uU|)0aBtHh}@buMVn0R!W77t_K)x1TJ}= zwt`ID{5175?UbJJyVMB!OlkyEjJ@Q|Q0!{W>cR>ac6EY%3Fs*m2l_#^(=XGHlzD7#;KJnu%mj@AZh(Ut561)L<^|$>{ByYEBtJ96lU5Ta zf$)8i&($U?lGgCw@WjLcO^b^AcVTZm)SCh>LPI6;p2HZ9=l8tiU4VOjI9A*v1{^tB ztVeo5b=u4?45vM#k)7IvMnv#ft0V9r1eFsS^r#zsO~ARkmuXW?n;t!lIh@G{nELhT z5~dSzXOn4-9$mx~C-4G}^Y?35#wq<$rZ}Tt#us zxnaHmE6RuLKf>5CJ>l^I^T@VOh6L0jyN}@M=tzI-lmz1y^K)FOXq}#~8fv^v->m7I z2dve(A6$#ci>sls*P5)L`VNoZ{J7o6bs60cQw%}ZQxK~UQ`@lMR!nF#S{tzJM$mt( z&|AI}6%b}9xu{mp0BinOfAE7vTWMR5O4^EPuocr_D^Lh{rxJ1*AeR9$6{IVhS9(j8 zrYx8OwyS8p$<^{wg?UtuK8SgO3240(13^d{GQTy>$BsY%C8vrm0W?pJTr{XzQyOCzc|N5-fNz zP0tFW6|otN>eCba5T6oV#&w=+G0_M`5=Duv1*h+1|qEov5+HOF%xr6=*FonHK=4;zNvG4p=s=l==94Q0vigg4W2xHA9oC+_#9ZQC3RWK*k)Z~_tV|fQv z0y+z#F^^)`IHU@92lDS{lhnX&LzBpUwY{U-mcUxn!bSPIF~$J{8-@1s(VBE?j%n{< zmj`9zi&;f?k;tEY4AvJoP-(whbUy_Ze0L>f3$3p~La2uIIV^bEevo$#V_A6qIzfX?*UM@B^VuFn5Rm$Xdpo>m z$lExevlov#o3a_LqRcA3v-u|KQ}GgRLVX8jN@IGJ>z81&SxTcc`UmL8#qqrP-52|2ka$k$n7I#I}6j=5KSf!n~ z!++2)8*mRQ8|rVwuE)Dx3G8cQV+`}K@E=u(eCoB-!{lS`LIuk@o8G~D5$Le#Hd~(J zJ%-XWS1t9Mj}v$aO8B>LuqsnZg)mOO7UjVZ#2x_GhrR+kXoF3|nE|s(Zt=qTphEw9 z00a{G3h;@8+bo7z5bjG8Bg)(pc0!Uo4!s~lZ}}KnkMq7@Y^DeA5;|NsH}qI90oZLn zKqEYnjm1MKY*Aov%ISLHwbzyizJlfyZ1t9cF`Kqw0x5ZpE+0nO{ap*vI9KwBC5yiB zD8|D+gPl`6X;p*RUr4=7u1eflM|LoqC11mWP;jb(@q;fu zU4e8MCAHukLzg#rovy1PTRY!TMc*n*(?7OriE zTSUk*)*JuDHrR@7h#%k&2J6wQvFI3BiZBs7+lFE(l@8i$4_7V8AQt3X?|79^a2YRr z3MPY0ikmwaT$DpmV*TW^f>nG}FsmRKyB0^eFU7w?r<{x7&|kpZavu*I=xo(qUc$o7 zKm@Lz$Dbvt`nD}{7Y9?7bqqT8{g~%ZxW~owHhVg7_Ba^V6()Q1H3z5_7+UL8kl7`4 z;?2~&q~B+Qn&Un*$OP%eaaB{_be{3eyJG%~s$y}kO~p;GsYH{Y@3wK3 z?6s=U9_tg2&BS%4v7@E*b_nU|(cuspXG6prpW|j=oWB!by(gOaurx1BFTvrB5xdwOQ(;ypJs6di2jNn9 z6pAMkIOOld{QeZQlB;neW=yn3Aan!P5%DUu_+Q&W$-ay#V38GWCESE6#Fm4wJTR-o zyhe*Csue^J-RliLpNAbS0|2$Ygw>aJA~lpV(Y zyoTJ(PjgsioK_dUtQiHdcMe}q!{AQ#hu0R-rR)#auvy^&D!ML+Pe|*!13PjPqn+d6G!#fjGFImrGU`Y zAzuC!0}Y+1s{np(VU6&iC7&hozdaN4{kc$gpYk`%J62C>J*WBan?L2YEs}6BgsL}M z?PCnSvp$bO=3>Ubcx)T>HUo_Z8*7nbHpLM>XVYNANd{WjRV1N?M~Ki$ zTg1@n8gK(=c=OZj?1%mkn^bI6-Q2D=6p*+FXnx+Iu>C(3rkLBXsxODXft>}PDDI3e zf0C#8@PNTx>dRuo>|)p7Wvz1IqWSZY!-~Ex8;~s^ql8ySzSH!UQxI|>>Mst%4>FWk z=`E?(Ti&v>V`}x5-N+uo3oRy={$NFWk>bZ zZ$VRn<^{O#iW*FD5FSa7HlrWfq+;IuGu_h9Rec$BHlg|Z9A^B#p5W&5i}VqGLMdZl zxBdj}17#mHyukIWw_J{*i1MvFG0XATT9Y!RhzFYEA(A?|a3gO^A%})K!r%F2TZcOTD1@NGdKP#{w z)#*PgAl}0hFNpCyJiaj|-owKSV)lD@d}B<$hlls)@a+BLMqGN-*Pcc`%dmU*>;JVQ z#QWVb8o9VFF!WqGL`V)Joz$@~CSZ@e6 zUjyg*W^6(C9UC9ebclKIUW?j5PZ={j3U(4D<-)P4Z=F5DVtKr$X)dyM$$=ZiHAxKrm$%jt| zdAf;mXa;{mpcyg>nPP`Wr8FxwdtuxJvT5x)>~=WmNj42PVDC?iis3tP6rafdbrQw? zRfMpg^u#j@`xg)DwfJRNGO77);cw$u{n3wf(_s=|8&3RU*kB325^%!09!?27C_vRV zDt{e;>pH%DGnXqKZ|G6p)e}Dm@ftE%z=wxn0au~>^aUIgbNe-_?4|q@5lblTTQC#c zqHa&s)T2gn^CEzJDxeKU#`siV&c*H24sGu^w z`>;6Vy!EFwOAv+@JEU)T@g;r>>x);wmb?#LX?m34sWNzR~%`94o&1Mx?jQO^Snyme3=%--J7$3UGi+VJ!<{2+I*x? z54?yyAkLoM(U+P&HL9L9w&5tW^-4_*;t=~`1cu_m%{b&cPX&O@IKQC zexHFyaU!%l_V*d&e09H~v^^KGS;MCBGQ$y!kyibc`L=0fM z*8zY7E<*odZXRR-Q(te7p7=#Mjgl~XR zHs5J4l@)5L;ucicC^yn>7cH_^`Mx2^mNfuJ4j;jRy&l~J6^I=EHhgWnQxe(&Jl+R^ zJ(2It?);-r(C`Aj8uaZWn8V}Vo3(q>L6(nFpR2MvT$bvP=auabN$~6x_#J{jmS8`? zUAM$P*<{C|qe@VY{|Y^)9YOE0uE%0(uaqOo1B%6SVhG({U#Z_8;YJqzBl78r(4+W9Etojf7E{ZtRPJ0sD3 z!s>(+sh9TosIboAmvJ@p|S(K_HdG69!$xH z_bm~g7l+E?Oklx0_X;L>0vP=sY(is4;!Jl%(r4k?kDZF&>wtx!MJl4X zE2g>oS3kN1WL`3QAN=t53;44V&mx@ADpb5disO-T4M&6G_3EHBi$28Tsh<~lhD-tyv+sQjwfwco$-Tz;E^G6Aw(aTRcyE>?Q{)PLapJxPHP0zlBd|QKJZt1 zvz)*?t`NmAq6@g$Kub{dka$C-*sn*187qL3;UGji-TSuddpkP61s~ z+ClYI3VM}k^#e=d;XtRK;TwLMEv`osuzLpX3d2pDWPJ06SYPS-YrO*mUhnttftr2V zR-kXjr87hv(P#DO&oStdm)NegL2dpPamK55oPk=#87~>z-giJ;ZZ)|ot!qG1iUxrz zgiT@KM~|v@#hV|p#n63t3b?p5H4}~e=HBFCZX*B2L1H>_Jz1RT;&CrH;oOJtb@s`prj=sD`7 zN7zXe{t%%EDA@_;h}W!Rc=1(_K1;(NtM@>sM`FHAw>Y!(kVL&S)e(}&1H|@^xMRsH zZbAyFan1!!njl^f2(@0wb)k2k(K_mze8{17SR4r-k?#uOsau@ez=KqR!+hKn8ou9e z;tt;-W83#mJU+)|tEms5ADGZV9G`gA9~a3J{zSjGaK?`p+`F3aoFBjH!utZ4f`vF> zK+eMlvPC>mD26dCO`aEixgEcG$=~&e{NSfsfLv_uP6`mz^%jefF0otTx zO|=W_&Hyfce%n(6(jaUTPgU_px{s}zEO_vQmwEVu;i(o)b&XB+^~)N<)eAi}%NmxV zS=HkC4fCtQ)eXHB{4jWRL*0CE%-{3|3m%TDvAO|V_g2zKik}C!c}SX$WQ z=9gD{@FVjL;`i=7Rm+;{!eWL6HASgfRu^8fsA*YKqo**n2%+r@tDp)CJ+(`gE(x<| zp-Sh8sS}#QuI%*z`B4xkfH#{-;2$duyCD|I++~f|Q-R4|!!iiJ4&AU3$3?>Dc@{L) z)WAT5mo4*PrfO?Pdg@>qs5%R-3s+-_h|l!O(A>$hL*m`2d6r0Ze9@2TI+VzS|J9@zDseKZ@9=@NSeV!Ai^%7nw(}EuGdTRfSq`&Jln|{a8 z6Q^+r-zd`+J>d1!UXl1$czp^#8-|@YEtc>VGTrxY@Oz@uc9u=QUZ(G!VV93jOJ%+C zZ}5(9_y4!@Gb8QsDKh=v^5+|IV)^`U=_K(F4nLOO|JU@B{q&Uf)Zf2@_f+3gKRv;H zMJFDAlD<-E*B>l9ak@dm+hn?;2fUuz7fbqkC)@Pff+tSb8#de{)8;8B#_OrQCh<4S zwA;;|ed2W2EE_&grUf$X3IBNbE=j-n3Y*T0b55MTccl%#R;K-B+7tfq@CPM*<+x9S zEH6Qd<1eL2rd3F>MOGT|r{T|!KYk|KiBf}<@Ssd*$nlLtNNXQVBwk?oVeE{ZigG0mP1hlv@TWxLEu>FA z3c3)$;J=_hq_uy=RZW(0<@RZ$Pa^%0WxS#?HUso=uOo^ygl+yqNORr>e@x#^B&KJA zPrPY#FVYwAOMI>@{QFY>037K^yxq7GX+MmGANBgn6m^ALJvk>!Yg4n_gb&8w9luH> zMi4=MPK?D&-1Kt1@ej_ zoG-^!z4M9y@h4{|&@K0sX!i`x#NIwu?kD2kfZXo}GoW~!+^2NY<2sy;b$FfR=Qf9! z$8LH;e}vpac|K>siPgst1jTy6`dy3ld?kjL{ES3qEa1BU_sf3PIRbeFYdG$R%kgmU zyaIooJ0vxX`n3@F2VoB$q zkU!MVgWWh`f8FaSkhei~-gja_h!sNqz0l)*uv7POvG&OSBxJne^LHr8Vxdsdnm5%%C$z*`TzCwm%4w|-B_t9PDqVzJrtNt^U3=xMO4 zN2I>3b3iNQyiI}N9k2Dy^Gp)c2Qy-1JL=QRSSDAbmuhhw(TO|GX};B5pRm(B5?%3PlS70WbP&#B@^JS;$(BT9-=)Y~U= zxw7n?Z1PJnMP>c+c_PR4#80yR>!XQfEYEZJ@ZJ4y&aTg}%bXH^ z);oMml-}Z7Q3gszZEJ*myM*VCa_) zzf3pFbf-*TmFY(^JtWi2Y z@@a2?f7giHM9EMbpK}!{7sz5bXAf%!se=G@6t2i=XYo|^C=zF3vzjx8q=%?EsCE{vR&xTZ z_o(fl?JSI_IkQR4tNvY-*Qz&|584F5y|b`G&H0%17pVMk7H8qpc!tOa z*S(57EEnU8e^Q5fO+dZ?4}Xwomw;ezr~*f=X#D|7mRy<&Xm5oqW6Cwgq{)(7$$bJ~ z?e1Rhp?!h2ks{X~feX_fu%)kP-1BO`w}r21yu0Ls3MSqk)2wwT7dq7)%#BYQeuLU$CpHB!i)@s%hQXd#wn9uXyvb}1R0MP?m^ zMHu{dY^iZ{*&4@@t&!zyjm$aNefDgU>je{_7}=NqJOiBEPEM|{MGjqs!en2WoJ_uD zo;}Adx%<{NEmg9wvM~#^!|ZFW-M2?OiJZ(ML2#n|5mTH!-!2tvv)QpMm1_5~w7{DtsFo4^h{%L8B_BL9GNsZt+ElyJw<^F8S+}*&0oT zNBu3(T~k%HiJ0PxVnOv?_&!bjGf-VVn-~W#Pym0EB$|XYRgPLNm7!`4DtasR__iB~ z)v72jLzf)Ny8vsp6CVK$r4vtj|F(HP_N$BqOn5=po>CN@w$pXlp4utBpmw3C5>DKy zWmJO!r|mACw!3uNe$pxZqz|2Cw2+?TA*_>(HIteBZwMgc7LlC|3K?q!!o!eb#!m$F zOvL0FF#!d>lF{vHGlZuFbBrb&4ZTo#2Yqj*=Ge@>?h!t@m{d24EH9{KY!+Fa9X!Tt zhITTVgID3FmjfkpDRfxL>cp~gXRVltT5ScG$hw}v0u9bEu%C59Z}wWKQ91{J+KXhC z;;%Qo9HX2@6tabn(27xr{fmb7iqIm+?k+o-EGJWxSE?R*wS7Q8+Jm7)kX}U6^1;;o{sD7W=98i0X40 zZ)6w9VmOyGkv&LlM}l}GmudE?>S82}H*y(oWDilf!(zOV8(_Uh?G4(DH*y(oWP8;? zqP$kkWxSC+N_|e?x2d^|H?qg6oEXL%xr{fm&z0p3YA)lA>{40YsOB=>$S#xRN7P)# z8`p zX_sbe7qK+QE-ltt+27S14%9*E#TCpSHxNQ_C^$#Ozg~Z~Sc4y+_uT7+)%hzhTt639 zgOO0)#TNshi&?r7IXCU8jD+$+i$onY;#$^mYVAlUuVQto>P}V>N7i4BY~Cez1KLNW zXG7`$0Mi-xqgz~1JElPGIlsBVH zlw@BT2 zwFa8>U9xnMlDE`0jY?l!gi-S9Y?jf6h`LCX7z`UD^epTfn^a-s^YgfF!LOf z+F}b)>$_lqqOLg)NQ{6R(J)ym=v&oPF!+r5GQuo4MfFUB5@Weg*1lOMobz zOsRYA0Voa@(f~+a*@Qvi)GPL(lcAU&1zBvvk`MqJI5H703SNRVW^hdbc%gJK@ zCCstY0aqgo7r6p4@N6eXuH<)7)+M&1R$pNgOk#;>tmJRwsKz-}4qg3TR*n;u1BDpI zIa#ITyUF58moQwa7u*j($2Ynrqiz6XaFdIoR0i>%CsK1WRh9oj2D!}5B$or9vf+dd zpn~OPb|71DKMbtQlZq~o2P{O0?9SxO7c{cllQMS_xfglulSvu{_mE!SOm;A zWm0?t>Y+jTnJ=&#@Yg?+g24>>fS#dUEWWv>Gqh!BG^m~;uEH*Q00ca6BWYG??6*Ic zEb>CGAhgiVfyHVO@C~?@IWgq?Y<52*)0WIu5Tbl%h>=hLGRHB^5Mvss+YN|XFprZn zGn4jY0QY$6EWvU?e{yE$DVW)|U<6k`5+g0xKn$7ROEJp4kcOQX(zskm10$w<^3R84 z)VJj{enVy$kn?pA-w#RY_iKG0uR*#1H>k~M3aJS*6o&vFSBr= z(?;AuL=68zTTAC-%XpzvCeElC&p_dZ?0kPtNIzQ%PBA#yb()&oxhlGkf>20ZZPpd#RN)@##0uvV z{ga09kYky~&6e}_EjN1ZB!zm7xX#;m-FVuEc{T-YCa$jlI8>cM_)wf_XbXqp>;p$2 zL)FXJRw+Crk*~24dpR5C+pU4lR(Mb<87c-jkP_!2BED`z6A^G$DZ?g0;_7!o8eyYtz zz3cXl_EjSoI03+=LJ^O^Ro-NIBG%1_257-&qPG}|XYzrsgRxkh{9y8V&%RU==*I{35O9@CpLRY&ylVsks{Q`C*xhp)4a#~6JWP~N;5 z?Z7JBfJ|`?GB|DdSPHZb0<8oQOkU>g54Eql!-cucxP5K=s!R&FH&`jWQ1-V-;Gwn+ zwaRH#5_~&I+?uSC4YeB)j(RoE=}KYWlWeZ;}D@k4vpn3YW^N1KqU7+$Ujw0vls?%0dSUB`?W>qft4%j~HSvXH$w+pFTEU zWpTBnoO;)W-wHhU>K1^0^Nwqp(RvoshDAmFx64tk`9Bg<0t7O$#Kd3tUPFV#F zNaGl$It1JdjoX9_Z5qDCx?Td{SRObehA8KJMy=g#M-&?*nZNb3hqE0m)WP{!OD|BD zcZ(2c7}WmMrEoI4Gg%cy(Q`c!U&^FofK9n+96im8l2|c1QeV&1@WA=pTLHfqEB)Nn z$lQ#K_ic&wI;IBPt0lBz%aNVx;M20xcF6jFqJ9`i&_J!k_jI*bIn5>c95f4L?Mk&6 zO-bc4b<9xpN5C3$zQhvBb+If6<+@xJpj@WiyqEJuIdkM=CA4vo#JL!KjHyj0b$vQ1 zvzyc_NmABvr0z&3^^0^;ze^)ky1AQ_m`~RNdp0CTm`Uy{$`}`SNYwND+b9gz)js_p z;0dVh1v7Ep7-TY!@cTET4Se%5#pr3s{F<4$$h^$V5@dQIj2g{%8g64|9WsAnW<4@{ znBi$jHYRTLCS?4~G$XSDnZn$Bn}O$`5rXNHCDY3I+hvvdo?YjcY%Bj-heZ@fd<$=0M5MWynZ=3R|S~H-Uhd zVJ#}kISIs{4ZHT0q1Y4rk>=E{J@Za>bGrysOA0|r zZ0PKAE6QS$-;&EgIoXzwdY|h$2q{hJj>iy_{3_ZDr5ox^P4a~u7~du|F8Bs=Qy&u@ z7w{irl6kKoJ6Sl3^9f@OV>I#=2xp0`__0jYt*%c&=-h*-D@PA!9gi^TBh+A7QO`qz zeatHd@uzNcjl}eJvwwj{m3qDdbOg)8hNW0O?Kg7xE#PP-8dA&XLZ5k3TO>nLZC$rFi)bp7X`#^Do6w?LZv_H2 zy^A3Zb-Y6avg&K-qd$G+cn5u@QpTOCPwH`Sh>zVWt1%RHGBotOmrm6 zM0Jh+8p-O@ApjL-?>=T|jr*N}%m8E_VWtq7(jsI=A+rn_zlByqC)S^8clJ}6E;|`G zWx%-)ILbIKr#-T&62ew5b-W9VbDszN8DNZgUsgT?$&LA37KBe6DTg84>v^(3_gXqd z7KFn_U@~ig%>(?!dMSe==;T;`aoRvhoK9fSV0$(jr6YiCDD=wuvt*rCq@2wcvH20C zQW2AKK2H!TW!otBk=cdJIPNenms~Yd z*db@%Q^3Zb02ln+k4)BCigG~*YA0<)3F~hpn-zNOL7X8|b-r^>vZ)U(&SleDWX?Js z^IVd-7d4WBBn5?=s|C&nNrfoS07Y=p#SF>ijfQJJPj<)%hx1>ux|r0i zcJ5E|RD!mG$aTnEFb}n&lLIKp5&c%S+$>Y|8t1v39P)BHVn@MCkQp&FWW0Zps5URt z9bAZ089>-FIv}eD$O%_3cixtycz2TGjwHo6DLN%;`sf(`CC6BJ-w+=;R(=mc$LZ@r z*&SE#F1y;X90mgJO_@MdV)){1lUVzO)tmvI;pNV!i7m9fT(M-~fkGcUQnE`>_p?IV z%M}VQH)jmIoQM9PP&k?gP(GDM4TZu=_dXl$L7eeRr^{3w={oKI@b)g?RTWno z@IGgfu(@fJqCrs;f{G$Z0EGw%#ycd434xHvX3bh_)~uO* zJ0~A;9Ho!g;T8><4fB+@Ck|akXElJ|&K5IHrc$3E`zLMeOhZ>LLRM+Jwe0JJtnZ?& zYqhsO@~Hi@t!_oDqG*GC=47`@`3|Lx$@&kZ*$Dm^t!)G!H&!F~Y=EIRE9<`Tw${em za`bK2(>s*uZps~-b!q{$l=ZaF-r>};D9WeHs?8VoY1=0$qcrP!$gsLyCMt=e?xSwc zi*AoAYpQNFb_;GLUOuD(3gR4LNQE454KnKuktl*bqM##6;j}2H?Q{leGy_qBJdqr$ z${I05^|}x&R@^25GV6Z=F!aqK71GqBUhX7u4JcNx-wvq&^t_!zD&&9_HLHmdcT-}o z6IJ4|0NzQt24P)@__P;I&$gj`7HVvU-cKiDHJD;GSr3aaF>*a+{1RZoI@DUjD#l5# zR+U4v<#0X5re^g)FP3d3*sPda1c-4@01PFoGmfc8Qrb{or7&}d#RanpDsb>T*~pYb zwxnbUA6x-!^9mS|(qwv2>lMDPty&$ew>flfg-Ag!4-cu3qbFI+=69RHmTLxUL(Slr z+=GoB8ne$k#Qq5xgYEzw6xo6glIP2SPXcMsrP#;=%ayf3$GBEP&#M>y!InSoRl$c@ z{=D_QfDgCWJ57?_RyDfc&)jJv3UsA6P#SJ8+uvkZH zw0q)m7wuFjzYUkhT=@!=PpLQ(pZHs>$1&J6y0CrPUhDs!RNHObUgg+oAmRS_onW-v zxZi?f)PJ2@1;f)?yH?o=(so~k);Xu3ELW{7Y}E}Y4zKD3#*=Mq zUVAFa&t?bZ*{5L;aI?wPww;dJbr?V`pKvD1Hu_!tTT(tk#`P2{ZO$YYGpE|F|Bce{ z3DR22RVdqe#=ZytNdsR1dR|+xbmj6 zQC=LDw^pP4su*>;6?S`#w1y8{@y}CHZKLz_m_+BuT2#w=enw2z^Pi(Q+-@q)wD)!Y zV#}iDnbyeDr=h+@(t#_lk@CN@g7VWS<5j+(od2;nXku&~M#gOH=^8Gp9lq8}(#MeL z=o-_;mCle7ZbQ4$MwEuji)*pU*a*AnrUN{GW2ruQn1gI&_+S+Vk80o9eL9-k^NfgFzzFpXiOAd3=S)aiJcbW;nr>!(8RLV%&yUpJOoZ zMDWv)HeoAeFF{H!oUW`NrpV4Y!8NzjC{?zk!{@YtC&P4AY@x`ObT=Le)h56W0pADZ zdjcd$z6~&;0{k`|9@e1gutI>O!yN$XlKYQ!U9S`AOJh$_^Y_3qLEhc6Uge!HDRrB(hs`&~5qWJ>?MDxD_OgI<(R`Y^cs`+UGMDslW zs(IdVPP)DH^H!`=q>Il7%!Y_PB0|P5Q8Pf}!m{8h2?%@U{gE|LAC*qGs}_a~4xA>UWo^AnJLkFp*H9_oGL z7}q>wtX!c+oeMFsLGkNEw#3S3kY;0L^tk}y@g)Mp;|~E$*eu=3()k`rcInJ*1Q3sJ z0Dvm5>Xf*Ps#JIdbw^i7ohMt3pE^2ju65!9FK6BBj@sKSnOh;85cF?t%wzJIBgzP(nPQDdrJDXw!{UB!gGop+a5>5 zMW^|WAX_#Oy;>Rij!>8QO^(4U{6Zt(a90(Z=oLIT(pCN&2A^ojxTCiYH~zeWno(iZ zw0)`y=Z$t%OW8+|W(uch&|H>Y)mww@j`XTQTJ>alRk2pRmR@y|R{cG_>Kv^)ph&$C zYS^w-$E8<2qE%<6SN%$>=B8DR-mO)UNtEr&bI-kHz3D+Cd;hz)H_1N19vkEK61iiY zBX8H^cQHR=pM%@&CC1nV{bLZ_t^Bbu-UB~EUL7d4%WSNA=(n`FY+(=w?oRl?j}3%f zW@7LT?)u|Gi9E7#nR{ddC)t-fBnz}cxdL#7eb~S~out@4&2(kTBP>_hM_BA*D^~}P zt@PN(R=k1F<)F8%`e4xx^g77i^4n@}`Pt_gw%SL5291^FZEKFOC50^T=D{_8k z6})3Uo%w=s&fL>E+-mruwd(UGEdL)#Hg)Awn^8VbYOVwzjD*8( zHFTGx;x|kyF6oTz2W?J1PttsEWY>dGnsz=wKES^O3fQ|cBJ?o!DuBNT=mrpXPuMC3+=0^RO937L_@RKu0LHXpU;m1VlUuicaeBE7 zYxf(4R_mNxk;sZ1@CIDoUIkQYCX&E#3}oSS}VPwp)4ct z`f(iY!#!`dwy`(NZOa<*QNaY|DTfEwMdV^&V#j+0QT5PJfbWn6-P&t87sa{&|l`&ll*Ki@h02}$4|*!r9{Ogr-HtJn@8yq$Kg0Q@P1XJyW)yfsJ=(+Z&ij-2z?I#Fc86zof>$1biG5@* z(=SFC4!@#TP<~#@b7X09^&g>pgxo{?I7^=UFdO%Dy4%N}SVPO!f&Fj7?#icL1kJE= zePS=o-`9;=dn5eswzIzLQMRY+f6tO3*dXOQ z^IH_>`jnAq6_p1TR|xP2GD76q>kO>Qz`^|Uq7Wn4tPL6 z`*SoHE3tU|Hvo14%m65ga@sLmjT$?Kn*_)cjl!$4cb!rp*z-?y$JqSr%5hLeWV@#% zqa0S|PbjnhWkFonIJ-@U@uzx>os#{{edR?tth^G4u{y2^mtX_<@?J<#uVUr!+8CoMl>=jgL&BGY@#kK~gw|4Mr{54)bd`HWF4)F@kJjHog z)alVq?ei0QXBDZpaH@{PU9LW7V^3#JA+~SrN|(0JYFq0K+>h1Oz3^o9`kSuanOgX^ zQonH2l;;);g)-3d&C_yT5E-a%r}G^mkJ1tZYntfYoR`*8OsT2>hCYF_R9omn*0d!#= zdj){Vm{5Y+l6z1(c{4t|$Cinqp}%6{TWnz7;_JM)y~x zt+lPq6_zTieLc8h?>Y-Bl<8kpuKv$x9UF0qv+!MOMd?+}!gsBOFQFtB{?%DHXZTcu z7Or&J)mY5rRM!=MhvM*T>FjUzq;qhOuEOuxbJN&HRNH&Yt~^%C=k@~o`}U=mZj{|U zlMn1^?MG6ci?f^99{bYI^lMO-OWPmX*I1rHakzaqX0KIr$hA1J5hvEDiBF0XKh7C& zlDc0kvF;ZGCwTqR-Jj5w6{v&5tos`v*0#DDU_vWutoxrv$-2MrI_GD5Yw>SqI~mR=`mK*>${ZnM@l;MdPs_LT1g90 zgJozl)LjHY!$-@g9N$as_-#hj@aJVuaY8Q{_@AL{yZk`A`iNbg*6R?owaOoHgDQVI zKv9&_cDWWcSjNXrLL2-^wkxdDg5(l}W#5fka1l)N+NiZ!DYi*$|0+xMaIFbTCF<_8F?tzeff-*6Xm7 zF|_%hk7&S0@jQI=xzY0q8k9}0<7I(IB(>#gDjWR|t&OPc6@Ev}&bx*D^aK+rGjvDRxs1oP9;M zy~gBCc4mKmmOHM3yJPcD<4MOA*@$)Tu$y_(ab>nU>FCj`N>^n|B;SR4x7T*%UrJf7 z16`dh*L@EDrc@(e^jK-*q$n4STyeG(?Iov;*>VYL;Vmf3^}lPf<$n3)D7qU|-_L$c zl`Xhifm{*X?^LmWnmh(y@MERRN-^BhbCFL) zS1?q)BmH%z^fylF(%&rsKeUnl&elrl@2Pz%@x;CKClB?mk?2-N>Gk&kqgQaF(xumr zQ+mBy>C)=~7%Dp(#0S#rHm#IikKd=Vf>u7IEYjcPfW;gAw$g1hT{2JSgE#O5jA86f z_s&u5=V)+{4CbBojh}<;%RzVgGII9v=bgR`d0v;a`K~`3(IKyf-R0iZlu>suPaf5a z-EEhCZ(uJe%;;?+GB)#ch_V4Oqqjttd+&2b?-7W^gXC4F8NKCIri13;HKrN8BWvT2h0(V4Y`QNm6WIM>@w!cS_CdEssKDxt6E@W2>Fr z-W2DKj%n_g|1H$*s^mObZS7n3ZO)Sm^{q5H2ZgWJxVNJ=Y2dr!3sP)bja7TC_1Vm% zElW{My~6_fU3c-ktVZap7i^j}*tb^1Ub@EAHvCZ+cz(9Tdey>+G9eAD}o! z=Jg$FNHub6>{7pKBC_?BpiA##F9MizE5LGq>i{P7fbFcCP%;~Lbr#EjY3dCCd}-?$)l**DI`B*v zYUz_J%x7z3p@iz}fQ1@LUCk%WCYqfTMoNJV_f4^62L}YD>NEN{4@GWJtXSx4Q zE%d8)_StJjd0If8zR3yeZF-s=gE#8FT8FHVUunU%dqoRq_k3Er!Y{P;udI5QA`1`H z(96M)?VIomkJ73FR()%pDpFXkRb^>aqt4SR(Gk%hGrLxedcHrR<3@ig0(@)^=Hnw6 znX&%_!;d?TfZYJ2?gV%l;6i{2-hLR%1JPo{cL5Fu_^E(n0nWP%U<|-!0jB`` zN5B+-Z``dB)ThSjJxY(UuHJ`Eg0S#}Hp*cmD1HwFNd!#+;Aty-x3NKgMg_c&MH*Vik>J5%F_1(QMwCbJ|AxBMh zraeveU~^S?j#lkr)fJ77*DJh0tNzKVUCpezNUQe8Ah{*LD|}vQLmVxJy^F6AbwWrQ zuB1uY5_T6%QJVOr(bAni7At*?<4xUxY|yG3)2c?_s8##MDO}m1)B3k;<1cXbV1(?W zPosXLzLPg)y@B(y5r~6y?O9xfw2v!%gM8T;$P-M5ID}=zA@_3np>|n0SXP_CHuJhy z_Z^nyNRd3adzek8c~@tlpTlk9b$16Hws!%K@Sp7iT_(kTjb399xsB60ojebn)Rs?ER-;dhP}Nr(l@SBhxbn zZan_`0J#7?0tN%TA>e3$;XeQv4KPnYIl$WjCIUS3Lx5=jgB}Dp7vO9G|5EW|-MN zo-4*p@Ne5k&k37BEs@udOGGc`q5E_|o&d9*55cKM!75czUY_~8tF}+mPm9_2zU1-v zsmMU~{h2+T?!B+&I7z#*!Kq=zO`Y!wqN7~g?XMBJOLW|o-6a7a@24z;J);iMN_%nl zXf4=_yO(Ieu2|P;!Cu_mtOdJe-RI(NLGg6gx9r*OK}S%?y_#xIbmSdZSRh*mub^64 zWfE_9tj^ZBKg28ez1GT0itnV>X0>^xhj@jbYrQ#Jo!E<37YtJW%C*2lUA1KLf+D4h z$ni?IH`JWSf~1b6oPjm6-kyQ2(K9e?&I|8USFd5mhq2?rA8XaOSyif4$Yplj*rf~) zlVO-9J7i_`=_{-M z#lFFcyG_cHQg5`aUq{hi$a+)#k(&!Y+}`Vr8q6rUj(G5s0CFAiIe-c0qSjtVwAZB$ z{)t{n+^dbZO5>|~*@p8_X&Y_v zRo9`jovu^#7<;4FYy0XN<*+jEr_9d*R9BmCkDTM=l^g))J=N>zTGjKgr&P~N0VbS_ zS}W&Xl&o&Q79hGwJw{O$rYBTZkI356t6pTu!n9XJJSie%VOsjMG$<^dSs_Pn6}aqN zX>E1{&h0CeLB5~TG8{VBF?a<%>R8F@&$?=Rm0z>^+SIoqd-QGIwdiw=I_*u@CTrt6 zvSHn-RN0t)ZforPFBqie2t99_Rl+V6t~Nj6w2|5pTkEn$mC`F+3%muvyBjN0TFgyp zakJ9bx)v!Lz=FrMO0G5B>YB*63E;a*Hh0;)zqQLN*sV;G_n&k!oHr!z7anr1)AKb- zZwb=tY_0k`tK=7L?ceB&w8}a@*hjl>Z8#ix%07)Y!ke-PyQxElfzVH~m;F+Qa#rVh zXaCtC65gIFRl(b>{YH>;0Xh47)f;8!_s%j<`psbd*ID1&JNsi~lh|LrB~`)A!hS2H z*c&Y$AZI`C?5lFX`R>mx=eaG;pnl&$vF2~Et{IZu+Sr?rn0vFnEF<4;L7fsXDBhzw z$+Jw8WXQ*%-fLi%(xdYvIbH-$c6Ka_v$%^|iTEMu4 zaLxXW+M~R-?Nq6cHDU~Vd*@3G2!Bj&X}Z3|L+I*dROO!RD&RGujcJ9Vbl+HZm1zeNXJ9`AAOL(`_& zuk;@9b}SZ?+vZjR?EMAI>FxbSCRnMsOzy0vxU3;|3lz(}+I1aPxFEu}%f*h|Z$MwO z-=X_W&p7~3w#hf$#Sik#e&hO%?>lJ#E=R>;lLo{9vI@LO1B&6-?4e%Yz7x;}uO=%* z7rh3=`u3GZ!t3`BB$UGP-UDK0zp%E?{t$pyYvdqZ^i%HaNdtttKfA{z=cCXk{5mjp zbU&v>ZnmWykOx~26tZ+T00Mlcun72CQS79C&H`z6KMXL+KIOho%UF?7?9XSN2g*pPtlD-t#^@ ztUalp^nFAiH(RtWv+Cvt#J)$PnHXD;N+REokofhA{akyAhH!Yr3+aO!4rNw2l-V4Z z95+xH+SK8T4lVH; z$v6&439mv|A>^Ut!Pg6EpBVZ`q#dBODiw{-n zjL@ed_so# zBnAmh2B9IO2U*VkOoaEoO`DG9f|FPnZwq?bOTJU4w^P7t2;y0$fREjGs zUNpCO!Mu6JD@(^D#vDJQqviaTr7K!SEMC;ov2w(MmX2ckvq6;N6%`e?;XK;IFOs*9 z95uQK5EliT+Rt0kTC`9)#gE6MsF-wYEZf@W&u?l59cy*_s@A49Woe(kXel5#pa~(E z8<#C`%w=;s7A@wrXF`rTFrH>AqC4&KO*i z5a%?C%dDH0;rGu+Inx85!Cv|-#eHCJU$mqNyqH^o%fP#@%TQze3MRVP^4l&UPU>5v zdr+Nwp;1T6BG4&XbaJ?PUQ4@-0C<-yX>0*M zk6-V_vtl_#Ii`1yf34r~);BuF3uR-Ke?rxaD)U5VQA5L|N%%KEjdkC2(~V}o9@}C| zj+y1x`$IaU^b6CmX@@1Z=WLu@x4;y2o6TMRmX9|39cLe7`qXbsnhBe(i5Cv^->$m4 z>Kt?S-WkGf@;BY@uP8Uu_L>XuD>18!?%QGd_MBY1Ai3TQ^?L%5R&-C!g7qeMlYgRF z<@cCtFZ9d&!r?21pOh6h-OFEsu=Ra*1Aoy`W^vK+4gL{T4U;;KFE&f!N5_4FWR`6AJIY@$vnx$urCG7t9PGEF-d|!?RVFU3y3s6aH~W=s zHb3)ruP-(aboupWb-l?gyRXW$)SCg@%((7fno}xGOOF}wlIgv-!zBDorr@Ptm~+b@ z@x-&tk@Z%UIeyVKlgdX_nZKBN4#rJux|f^b5IL{X99C~W&)#j`UsdVvSZ|iTbpND= zt!A~q7srj}4O3P;>7wHCRaNGWH9eC*n0aE=WV5`-^erL#0h?eI^#|FW6g1Mk?T=WVlx{(DU`TtC_`YcO~Bg1K#?`ztFe&0W3f&C59U z!$>c#G+)CA>^8f4*PG4D>v7zKW99mDCb>CKnKN@zu?XBV!z|ilR&T;*@>Wx@NoLCz ztG9pdZ+N0=W0e_QZzk_H&w9;C^TV!}E`D_VW^;VIS%k5>Z@)_On+qy8RL#6^eAR*l zRqNMpFtfLRw7y}%E>pDqSI@vdzcP1rZSf1&uQwC6n;O5&EZJ=?ipP(MnHihRF_osS z(i~f4>gr8tkzXYfaO9Rx%vp%bBmL&8D#YcC$_vc6y{6u8uQCsIRU#yR<&~Kqbd~L} zU_ZaeJk+n!>}Zp!<^F;Ga9^GLM z5!vyNe^iC}IUBA%0(oPb z`Bnc)^MhrT4gSr@A{(kUnn_y_)9vQhottdHypN%}s%y9D?u?hj5IJYm`xirhuiHG< zRo}55A$3ys0tvi$?ZAc^>lZ~pF8b}aBmU3}(Q=9;cD^H;ClT;El{$n4iWe&f9* zkDAxK_6^cihk4br^EbzRnzD9l+-c6^?{`A~=VRMn@gJR0<$ul8#fQZnuNqN4-nuBK zS$OS0<=BxrQOXy|$Hnr|U|#9$PP#w;8goYBHp?YFwhp!XlW%JK#N z=$X^~k(ghVW+(K$8~WOTt2Aw86HK2nv%C_Y4H!i83$Oi}jZlAwdEc|+mgDE=V7Baj z)ZE&+&HPb(a%*Ri^~tNTZu8yFvh`+XtWp-cc$(UFDHDrg3*^JDpK#3%e~P)Ga~sx! zKSRU~o#JBiHsCEH?N3fxET=ig|K5G$%NNyExisV-nB(7X^M~zz8RFycEe-eGC!%w< z<;be_Si?B;2=sg|R%yPE$@YWTUXV6m=qh)dwQR)9Ws^-G|3J|-e&hf->^$po+{A-p z_F#^$=ytN~WXRcBev5Aw-Z#ujEPu837!NlKn){C`w!N{rw89M%Y{Guib1j15xou>2%LpOywWr<=&m0+w7L_p!G9k$9H`; zwnqp0r6@#p&+CzYRXHm~-JcHUe3ihq(RZa0@<4^xHEDyuRpx0zwP%}oEmhdwSh9avtE z@Y^S?_a}_UFc$fh$sOaX{DK#6FFzG~4S&E{4gLT>X>RO7Fn<8&E~uI@a$?nb)3@0y z^}EYQm;swMnp5h{grX{hXVrRXTxBZjJ7$>jEy)?CW=s6&f#QJp(Rt>V+3@~dtMO*7 zb;+@t%n!5uE%CwuTm7B)nI~3nLxZDP^Q?Hdo&`YS&= z?=5UHTeqA2%c{;c=NFlQJ+d&kg(t#doE~o29$M9Hrgxj+Jqs`pXPePwrPn_&oIw%{BoqlElA@pc$Fj1F!yyeo8KWp-q+QRJl>OK%)4v1`Hx~g z+#IjpIiq~XjOUUwT4prdXDTYqPmwU5=<3nqCLAl*LBn{CWPx~&?9k&QCM; zJH~&la!IN^rvt0T!g%4q$?@e$zo21*m4AKLZaMmP6#P<|5$%{XmHxeE=jxZt-P!S> zF|#q&zQZra+^)wojn~AiC;pXFSvZ-~!%mvo%W`Z=hR(9%byZwXzd4oBq z-pt=?Uh!Un2;1e7dh=8)J}PD|UtPJt{42Z2Y*<}iyu)uYpJw;$*osoO`FnQRtcC@3 zSVp?dtt*7J$^9IJ!bg}Gl< z3A&3*pYciZaj$%|-GB{1nYlEE{oJL{a{YCWVdXgQ%<{?WzxSQ-<>vhrMdmt$ zzUdpfcv*A zFay8mS8g!pVbf7HsmfZNW4Bg0kG}QM`1Nn0$!`24kc^-sn@d*u^*Qx9_nFUo+1!=0 zDaVxhTh`C8lLZSLwlUqhzq()Surui_L1)T`Ki(k!9r)<@^$U<(?DAsIr9Q~QcELOa zkLDJAZ^A_JNX*=_(q=+&O6+C%7$+YS7EV5H@{Z+OJI<<_Wac41{Mo63GZwcK8LRpA zG$hWeR{HtKGtK6MEWbWJ3>P>KSw9Jn=-xlRV+42d?|(caY3}U`;{J87r(^u@%l%QaO0V^clj4=d z=C-bSoDupL`#a6KduMe{o;11Yj9F%Ttlpl-H<;dA+zI?+^UeHbb6Am{!T)7#Aoj+1 z_f41iN8=QJLLJWDd+uNGqPY}H5?1G`$s5f(vE4g9LQ-tmWZhuV}@+n@zGoB zai&saMs2^wf4kfqu*EFfOl<(So#=D@Ni@N>KebesM?*Z3bH zHoMKqdlw}QPT2aCeSkLOPpg{LU<&tcURSko$F}OV*S1;V%hSQ0x-7|_ul;eC3R|&?;6^^sp&7L@d z=kB$Y{xj?TrX z&6`=+cyzA<`TBVKv!>6cw{F2%;trgSmXBXJ^BME{%6fZZknDw3ZPQ1l6?FqQnKzMQ zzST=I*$)j)O681j&+^^t*YCj6d{gh9x6C^@Ei^aa=aAoBUWQ}+@n+#}b4Zz)UuFh( zFF}^v`*#Feucb~jrV~+@Z)!|U7sNmW2U+usx_Nsl?G?c%epsPVV7B9Gh{IS(b?0` zajID*r;O#u`Zi9wbK*yRZAOEsw^`z?9J^VH=e#94+GJ@{i)5#`)U;U9Jx%T9(dl@)DEIPAqF`oS$gLQ&USC7cX8q&r8f(*ofEn zgr~W&y%C@DTD(L8mxdGao<*W<;nHR8f)=!jI9w+7T9-8~x3WM^%x!FIa;=v&HSOCt z(cZYgOEfRSuV5_=`)+EPZ}}H4U3xy0Yi(TCgdc=YG%s$%3kss4NEN08e!VU+Z|UNW zB~UN8a-CSZcs>;o?j?=O&Tm@gu7^6kt=fs@jf=gd%bS)pFJ8JLf$P%vZ)&viS1eo9 z-eg^XA6v2)zM)2zHvTq%@1Yfc^ud#jJ!o66#cR1c1PQbxB)%w^=bhLD|HGvhbmtUC{Wn6GOaS~FE^Um);KufGP2XU+xU?yM! zh=wjQoWdL+8^mqxiFvqc?;PkY>1Yw(gE)8b`7*8!Vz}VzM4M3H08wLp2drDRbZNWS z*xI^yQBzx@eQ5%ZEOyM32wAXbKKSO&ZCM%4(L_tr3eV~xLYGLVVSu4!TWgCa6Qs2f zv9q)lV=4XM>o;W{FKe@Cl-XJOl zXVE;&wUzA&7sK09yeKC4TBpT<>$0Wuy+%yDR#9YC+dKqqqD=x%4TG_WNgE+^ zm$o20Rzj;bCrgG;Mr;Y(CLNwkcgm1D&k4Dsr4{jYa)~FtY;9^fKQS+aNTCUPdquKF zWBa0|En!`22qkisAV)(hB=Cvml+jI$oC4>?y7R|>5ce!2cwnHa& zjp&2~UpkhyS|Y`R*$MR=++n9pVxA~MEQy79 zwAU>6@<2i4;Z_->wXL@1NS`*jI={o{QFo_Q&l=AI|tQK?Uwl^+X40{@p z9I&7?F2+hC0Um}13Ni?b+ET^=O9s*|5>cysk*@SA8Oz2arT=n z+&>PTs_CJ5rS+R|+mz_WL?RM*qR&UbXs+v6CLOsn?KL|GEo+&F+z10&y%mT*poC0e z+$<{WsY_wug=Ti`0*QX)k-U^@i$o(qhK0NNmuh@mV`uqN|;d|OJ=1nIYsO@6j zG(w8X^6=H+$$cex9-p>2tzU($5+#UNg|uAa)gjF%{zgc{s|x%6HE7*@J;uChHd`N( z_H7fE@bItw6Rn7!R~lR+KY5V(?@}ehHH1G1NHv5MmDx3{-Kh;l3F4(XD0X~UXjP&x zM%ALQa^-(U?f`&~TN^dxg4QWZtn?<-#6_bITmSl-NfboA8UqkV1mF3A# zhyKqEr)Fq~pBard9H^7(P(5PC5>8X?V_w}e3d`&xUGmsk9buJ{pcj4um8FY9M#4)2 zQZ?bV0jcf-g)|dAL{+U+6=w&k))BS@r24q3dU&AyoT#8}I_jqct!8sHjKo)_GCH>K zlRaFgJs>X;{xcxWA~Y(>ts5+{gG}i~Wo!s!O(XnMK&mCAK$pE(I!HT>d9{Q^DSAvx zvUGaLNH}{RMwXU^jD)nobshT0p-rkQ6^-HXT$RCwAbnY@ErF%ggx?QHX-TI?1z)2_ z8A{^oLRv2I%^@w1_?D2CPyDTrHjMb&A+3b?J0Y!Y@M7Y=f83@Y6|hYG zLSfi9UisbkFTGWDdaJbTdzT9Sksc-4zoPh0dc^9tZ&&!rFs-7a;`n+X;$+YaZyY2)w&o9Jo%7$ zPrNd0Ttd7$qzxlp6VmdDJ40F?@w$+fOMGca^NC;RouVKMuPRX#Bz`TVl@Pxk(uNVs z+xqf{w)w<=3~719e+p^2#P5VOpST3Ca>$?cpo8HjhkUYHhHOGeqY+<(7b%xpd|B!V z+Y(YAv?biFs=2l-$v3OX9~cScr>q=lIw4KS5b88wTA;*KLPi0$)#<8ErK$(3Uf`-w z_+UsP+@>VsU9cv}!p{S~8rmbjeD0L5yG!AN0jY*iejHA@b}IZ+K&m06L!cSqtiU%@ z34a=p>VB^9cLAw}u&)LIWF4aL=zvs182ULagQxqso_?lt4bFzTSfG1jUOgd=uzW0V zh`~olEi9jNRQNex$C>?rsi!ML4?SHO#Py^tu+!7UZO$ZabJucpYKnH7)5PsjaSSTS z*Tf^jXc?=J0T=UX@^$7a^xVxClA@p)6sT2^t9B31tx$ z2IJE}70Wa_`{%sS%gd`;38xQL4QI<6SxRJ4rLKC<$#MY z42!f2LK&v`)=YD9Yo;lVFWiXym1>l6VaFLgBZ^BYNF47_ue3`j6E%t$LNRY@`e>wW z{L))hr?*O*W0z}RH|tSip7`E?HZn>4gMgNPmfxdw1x#FuD1iVDP= z1KP+WF;kMXCH_3%D@hW6EeO+*Nn(0L+D3-Yi|U3g$~qN$tsY?!;f+C$%RS=91Gede zR1nL@HC-QTeXk&Ls|n@%5aciJEw|r|Aoz%YZ8{3>3pBu<3NfIv$Xd{!v zs{>lPGvr$|&NGliLVN2CB*U#tnvrGVZ_&jw0z?0LRud24IwR;cymbeiRC9X zdv=ZXkA#E6OBBbRLH-@x4;&~x0mv~`F^NH_NnpKd6yF$HiiQpp)<%2Jj>=5NI2;@&Aq)5oWG=uzU8RTD@Cja*;cUK_4=2DHK8}*1i+-`+` z(<8d<>H1g;{|foOOnZERhy9aGOU!QK-pC}oqA1}b{zWh(Ba_6R1+`ZP=0g zM%CeXgG5N%rDfFSa_#8kpu=jyY9$%3wJXWOTqXAMx=OFh8aX%^fIixPP!a8kV$ThF zno3Baaj&a{X8M79rxLOYVT(#%uTtqi#NOsEHlVvKalQ&>lvpB1kl|s8(LQQ*yqK7A zGRf{{2HMt9{yib-2MQ@24ZlqGMZpZKBmAb4jJMn*S>Q|rF)PUeg9~$!5MM!L|8V+2 z$SH+gAJu<00uKghtTTA0uw%ZrH8HyJT!-c!H`7k$@0=ceskFIEp;6F9e;kbc4j$3*oP8oT^B(4v}<9Sd7@I5{E*2ac^Fr2C<~ zAEdMgLO#MD2Lk{;7U*@1FdfU#v-0R#2A?G|{ODv$WPxsmL>fd-TE3`d|4|<@nlPS( zv`{X$GO|L2=cH$-w1MIbtPE8 z(LEqVJ+MVRuuYGWR*9btXd{!v&j+;h{p> z#FUPfQRQ=WMLtlE*v0w82Zyv=;=GWSM?5&BqTNb`vY;hRh454NQ(i&y5lx;ylkA-*Q5$QC^!^5%jbh2IDS)e@%2 zenD&B3AtSV;U`CAiVBq3GgUEF5E^xOFolnp%E%^;c&TMAzJk{s3g&j)PPgdBNcBc`d?{%`GKfm#S-^lz@prBKYTXtNAc zZgyI$S!`7tcwrVHJ&Q~AE0ZixsSIggk4o>YqT*hwPt1YC{%D?7UljB>_1g+LB$;y4 z-y+g8tSB`q=DI-goSPz&Gi&Hvbk+$o86@r8PedSuvLlZAnn!3|`gIvHj)W0H}RYH&0-Q|qD%Q_iAbP-+R+ zraFTK&H>|ftVyz?lpICKiILHh?3BujCn<{!GkNy{)rh$1}YEtfbaq~#Igdq3{%czPT#vYC zd5Ag{UkGIXGA(jvs7_P}YdGOo>qc)}p#re>%D12I^Y=s5CmUzN%*4>^(y zK(4@rbQ0jZksy8)?=TD=*P{;BZDK&d)9jb6yGxf!aa(}!XnaZNDR zX$v{c!w!Zl*9TH+ow4C3lM@pWb}3&R6;|(q$eS{K3E3Q%VAHp3Y)7U{n~H@RwB*Tf zo{-KmZ6EbeNM}jAadE456sD52?ZGW+ENLC3v!r#zbQz||Sp#(zaxP^sk_!M^rH)5* zB}lD{dV+FN(j(#D)jT^^EO5cGJ4$wxl1K@udd7ifr&L}BnzGn1)8N0W8vRp`8FrNE zENR0=7Mg@fOGxW7>?qgim|P!Z$mxW?S5oFZ2pfJoXgH1Vb|oQ~^h&bu%M@wTk}R>0 z46~OVYz{i8A^b%^swbpCcV@;?D842dAr!wckTsQ%twh$;wA@7ZuxB_my}Rkr?&uqu zaHQAaU6HKgSd-xbn);sW_`7yOAl3sOF)FMcG({$UUaDH7R<@V1bP@OCA+$-&Z352m4YB!q*;WY1f=PNR6j$Od|NyJDA23!3Kj6}Ku}$ZxfaULo5|mlpj9pP-V>4t z{~3_#2%7@gwdX0kJ|q#QXh29`UcJEm#nMy47fN=B z=FnBb6V)`+!zI+Ae@cI)icisFhHGh))QpC}d(+QRxF8_a5}qHBrbqRjmfkAL@-KUb3LlqH&;F`p-oZzoE~js+VMg# z{7}fX4L|=&OMck-teVw-uxl*Y=?Jy%*LoD%*YaKcP(6xz#3=^WzC3bB*En=Q}f) z`+VnR`HtfWJz}>)NULq*Yt?kd1Na!s^n~TRQeE(<9xd??T6jN|n8`6ob=*UGw5?y$ z!h5O2e`p~VhSu|)nPTunWne5?kqk&W-4gTE^CyOZ`F!U&TDTyU*r^3hRNI{K%=u}F z&bi^|e>s8=cm6&S*YNjH9ij<(L6ln6C-D3iW-X)b?P zk4Vjg2Zc%Ih0Y9_=Y@>(b+AThn;!AH7-32PzmO?_Ur2L+%$r|noH6d;sTVpkxrHGW zM3Xl?fa)D6lgW9rBF@9xFZ5$dP`%K}>CE7=szg&D8vi$r&*0EcJO6crYZ}XUM|ALM zCQp6ZS)&|tQaLkuC6m2Qc=%bWOAMD9bo*o{3tV1tnTu;Gbq9&CNP`8Z-h^DFz{NF| zQ4bPfi5h^0gj)mBY{DM}qY&72T?m==pada(2`;XT zbR|e!7@3ejB4loYEJDT$xCoh-z(vUH1TI1*DsT}pU4e^`nG0O$!8kjb%E0AC{@ztr zeipj)d37cIi0%mKM@%NVazd~LnoYPWAk`CYFLeFl3Q{b|!e>f^G(rx6<%_!25~E(U z#HiCOG3p~rjJm`UBR&Z>t(*svQ5o$FZA_G1oxZNm+_m7`h`~KU9cuX)Q4A*$$dF<@ zWlG!8*@>I-)G3^s3C>NbhAU~Db=*RM#9h=Q!AK_vIfq z-pQTdH-pSsO~`4kk~#e0L+ottjM`|4>5~(j>5~)0s6TA;|7P$m*DXxS zzGY9QeaoKC57T$ldonGvdpa|0KK6X&<|AbbyC>ro_Bq{aFv?-xo=h8yJ^$5d6m8}< z4$@xkWPuwwY$FL%eDiW9-@F|7hWj`xkp=GLAdxU-Q}=QvAHJN)hcEwEK146f7)%#3 zuQGV> z$4tpIiRGA~us7JH))9Udkg5rp6Em#iuWD-kN3iy$UE@AabJvA>#D2e9;gtcYnp1eF zo*T)Mrtp}6ly)VYvX=ycrV+BcOivj+r&;Z@AiLG=ujz=n3br!;aQVq#e)=|M4!1E( zW^zJ7Ns|IE%^?hhpA*eE>5|e8j63SA7mue?IgmVQ9^qbZh1?*)Snw*qlUH8w}wKol#Mi81+Mj zmb)^w+?6)c(Ux*+Iof5W+s)B-nTIf{=Z|!p-VDYo?Wq8=ysRuod+lFxkF#Cwakl$8 zIC03q?MgOyO&j*Y?aI+djUJjLft?QYF6ecEcY%ldrX?eW#k_+CShoL3*SJ@jjPi6w zwmDs?SMReNMXSbE2w8cSknZqoOj-fDA2nb!KRpJ_9ned_Ggl z=hNm+v}NWIi`rPMm-EgGF6*V;w>wp+*99u1sXO~^|UnBCNX>l{ew8qA>vPXtO;6NXC7NmnY(2j}SqFx>ek zxJ#oZGMwt_DS^uq(UVzl@l^JjFCX-E+TG>BzO$Mz)L>4!26NIim_rR3gYK#cc{K#i zOIIq*2lLe`ra7CYqE}Bc=B^AacXeiHnV!4Y^2)%Y)r3?dj%RkFvM@=aVMR%7hJi?L zl@^REv|nyoap^HC_!4EgSC2<~E5BqtUn%SP${;7P!Ts7W2gyuw63bzqX~wY6kR>g} z?$Y6YTaR)Fp1AE8X9OM**cD@;U5WNqeZ)u#J70NlDoDs??h&6zJ8zvf=uQz%ydk9J z5?>P1@`x`DY5BxggtTGASBA6_;*BA#lz7bW!1~QG7EV;6JRm_lE~J$ZmxZ)p#1leV zK5<1z%OgG|q~#J%3~4^`uA&qLzs#dQQ_C1@Zy(l-Of zX@r~ik;u}vfN?hAAt~;gmSl;efcrIs^r-7P8hTf%=XwWmR+}!XcCL1|DHz7I$Jv_I zJLd;pN)SE}km`<6L+GjumvIuxLMP$b7)BA*$ndz#`)bFiz>e8dwcGlj`)WdtG8T+< zjS{O>gLQ$|tLb$HKKx6#f8dj9LV6J5sruBAi*QCjO51$))}9XzG??~t<=zptB79y+ zxVn~0{HoG&K~51=}^M8_tci?OLs>&9nj|Ta@$-Jz_?&|8Tmb-SRy^xfx&xojgVu zLr7@Ek#N#0cwsDT)0K+}`Kwnj27#oc=}E>x=!*Yx1!H#P8ih53kYnX~V2LU5|CilL+^9yL1lVBoKJJ;YR+eHg^}-&ubv7$Htj|2`@=x3X@qoQ#`osv zGx|gxQqGC?M@L*22%r8vg)|dWFxrY*a(rXty9mdjl!jNro8U&U1G-YY1sB zR@wCKW>a=^FiEQkX%iYoO}SsY`Bm5*Vc1<=dUtiS?(ncX!eIfaj!K0Zq%9&*XJ&bQ zei%zzIUSXqo}oQBYP1tajatfi_olX$vsvQZAuX5q&mk?3_??iJPyCmVHjMahA+3b? zqmWigeCN5_=78srMXO)AT+oGkrJsj{vs{BR#emIjUrBodx;f+IPJEZw41NF;o1Oe!Nw zyOjz?!cPNI9igY@f{XA%CAofCqF;nD^2az!s8=L`5udHrW_xSBk%uIsei2qW=1=>w z(lcY#Gr~&TINGV8Qlq{R)M%?N zj0yx*6NVbpQqZ$O7Oo}?Wv88HFvHxFGEl@ED4f=O)iBW;U?Zej)>|ylMc^aMIB@ir zZ5;KOCDMH~84?L;s^w#WF)T4d%uz?%sK2@9hSRK;@Ig()_IoZ^_-U|QPbK_iK&mF( z8IWoS{}f2OpexD3pF=*va3Jb9Pky8G9p?&!uPX_^vDB4hfvFLETpU&gdx1K_ifmCY zVv@>mDU&fzw@O$rz!||pyF};w%Hv&xK-47)Lwo87X;-GigqG>ka_pFo_N|Q$-M+Qa zQQWtd1Nt2e-c+4P;{b=2kU|&lE0fNhqsw%vOw#D}P-fKWj1Q(P8NTS=5@VGqK6YxR z36o1A8Zsg+J>ewM6HZrGlG%l0gkCvJ92gN7br;y^A9_UCi0J{a5i$gYE$R*i8tp|Y z+}cTvsE#F4Cl0M8Mn}vNqkVj&3FVw1p`=ZPk2TYN5hUMg!e(ua%cQiCqn+Wl92X}} zBs{iFNK>(h`DuG-@NwK|z2#$puIMGZH+(}{+S~~$qSGd*h|ZXxf*z$aZO1HdtOIU3 zfun1=qb^VAzNS~o{+RfnU=6J%tPj@Ejq5rY3iL;6Ow$b*=XISdFfxRZm?_0F(j^CI zHn2n%=oV>B%$T=~EIbhI@CfM~%f|v8Bm#-6HD_2x78pjtNE~_<2D0!~6Nvj9Mj38` za83DD=x9Q2TH<(kl9=fPw65ql-k?hZ#{~L6*-80KK9dx;$#ov~E6m0~3^&kDgtnCi1=LIK-X z`HbEGTQm%~aB;0dbW=D72Bc`KbJ7B(mO=5SU{2IBVwqyU>_m!|rKFTk*D|I2zjxNe z$YG3RI73>dcCAYZ4dQD8+Q=mFHv?MwPgw9r2gsAbjZNySuj?^O-p)$W4fKGcMu*@E zT{W-MqeKt!w*uP8B=MaAZB&x@{(v?*N&KULc0!W)iGVgHN&NGGHa1E8TtF*L62BDC zPD~R2A)t**68|}%jZYGDUlI4plDF$Dxie+9JgN8>0S&)z0vU=tb3~& zU%tmmXQ}%#DJQ8EiJB{%|+5;JpU`dO7WmGN~w;sOHU<$?I+YltZ-!}a?f-Ev$PTvc4*6aOuwXfTvc3?PmKJnK=S}yTHAuW$MFQnxY^A0v*W*G4yAzuk`K}ahlo^YbmQoh;C zW8owv%6&xQijY=9d`d_gMtoXG%O^e~q~#G$3~9N<)gjF%ezrVC!7uaZBDD+wOqdKv zwS>PabM0O5v(!&J!0Jy}rzFS7(gh(SA(eBCU#148CCI&0_=naRYVmUYzf$v}ABFBJ9}=SBt>C&w!MSxEY&!qB`r!YOK=bQ$%i z(CCKC0yorcQW$!sj*yO*meEj&s}j@?!APN$m|=IiOMM(VwEpw)PV}I_q4k9HvGG=> ze_M9F`s&Yt`)2i0QAg_0enB;b+!4s1mF|UE)S0H^L@a7C1MRs$I(|upg%^~FrJs;v zf^*lcUF?$bEiu|dr<$@MFsYg_w6gXJH6%2smeRX|VXY?Qpkx?~-=_t94Fi6JYJlJ4 z%;f+T1`eztq;G{SYRp0nkkxvWAbLgd+j`7!N3B?uny*LXfoLFu6zwd%)%5gMwb53i zwU1Igii*S&1KP+W@ytM{n#BLp+|@wGS(WLV21@v83FR+ffvK$!5MxqmTLooGX|dRr zX%i}F+b@%3(u5{6*~z3NDrrH_S=@EC$K@O=AX7xK2X(h1t1QcE{VyK(m;)#vvI@&8 zE4o%hKvdZG-upcFesjNXfS%NIcFxJX&wal4@4olv`{tX>44_XlamuB4uaZmVl-NA( zLgn37pq^=4877W4bz?gSAc0iT8M}iTL~AOptI&aEvM_fn4Mg{wpYZ{mIsEy&~Zf1h9&1Ee9(e z37Lsi3{&Zc=i6O`!~`C}p>at4p^&G6fA6`L&4}F(srABePePyLld?6u8|EK#T}fp0 zW_V%J`n*JZ2ad^w1|esmTrCo^u%bn{z@;r8{Qz!tIphdA+r$|mi!aUynY_-7_#eG9 zLe462M)+y3MaU7<&ccE|g6=Y7@f50ThssBNWe7j-sLmGwkM!{gx#(oK8OG6ZuSLjJ zBU<<3C=-{$gh@?7<$g%BO#wgXxn|-Yd#;7}Vb5iVAMso(@lQP0PW-s%mJ+Yc+AL+w zPBpM`8AwTRDRIto?ZoRn*Gk;wxeW0J&$SR=;kjnwZqGFlufTOuLNax1-9Pr6fY-yW|=Y%tH{=s7g<(<5MI4JuE^F-u%bx#ry51JUh;~B<%{DU z*}5LAcqC+9(zm$YtaZcOWr;AA-9Bh#h1H_3l!e3!Ujm1EJ+gA2N0~H7yw`CZRpMI_ zQR@-k?y|@cGK;h&KaB7Z+{;@&^zOU3`QOnWg*lV*#?a{)#4otP-26XCG+@8glmE)o?k;7?O!0x%#pMeOOv1}*Im*+#F2oJbzH%G``i55qZ z=?N94B~+NyjYx*)Vo@Qyz=gYlyZn1R_1?tBzmcim>$R9v)}6qwU{Y02-3R!Pr@}n% zM4mr$#d9YWAFl36pIy?sN;2^r3(Pg4)mTQRtGO_#l}Ls~l-Ie098sAGce^>rIEG|{ zLB*KWVr-+w1Y&dR?#VEd)Xki|j^#3ymdjMyJfE6O37q^|xSyZ|PeJN35x?lTj;h0$ z8)@(8b8Kh0`I8vX9L{I!A@vJN;x5lM6L0Wb3-NnAmm%KdxmMzS&$Sbub&0LKyf)j{ zz(y-bNv56nY|ph4ztM9U;x~D&h4{^$YbI{@Tods_?~EnG#!o=%WQZU2Tr2Top34yb z%yTWok9)3}_$kjd5&!M#STf=C{ ztSwucF0~nnBH>kzx}5N~cR4M>J&wAZ@QvuGP8hJ=QI`|49HLdP7+-e9=pxLxK6Vna z`?^D2Rklt-H)XpfWXG%`TNT&MPQo+LC#%R-tLtee;b4s-TaS4~!sF0?>yfQ>t}2~` zV>OCw`C27TPnns%#i2X>uZf{I&CwZqt+~+Gd~C$$L+WWwyvA`!yWOj- zr~4qa-EV-OgOrcNoD3HXBNQ{8bl%&mUkBa~DQZWeoPHG7hq<$?yq=J=4u|Y?mqI7u zd{FXnm&2-T{MhUL3UH>&q4NYl7DNKDCak?s?9d)>crV}|JT)`XpH7aCpE-#W4ZFy2 zG9M14&71?1p);cyR%{O@`FGukW__|li8?2(a!ISin=G8At%xNbuRW~F#(P}?Il^wI zCqG=z2Kz5%W|cUbQ*NIy!^qSMJ!!SDQh$WmOw0wxcrcFy(p1VsPhVLD$Y%NmH1l6bySIcxa94s;UFcspAZ%)ywH-R)m#lP zstg%g?!>w3q1iEs1VQsPI~*evBm)ZPX* zehN|&TuS_y=h}&X=DAkl$32%J{x8q95dXL5nu&kmxhCRntW1+&y^7w6p2_PGLi&{d zv?QcUeQA7om948W!lFp{5l3B4$TURj)syIA67NEXWF-?`hdskypR@HNu%bxFWUL}v zKX9pa68;vHRb=Zz)J;4RvJX}<>;@Bjz~#J&C1RFxy%}aFRG5cQVML+Aa5p2&=Ulih z!tXdLmqT5A28k_~c~eEs0Xw#bX&N$2)R1ASh76PC%FQA(eNjQodWqqmC&P*vl9@3n zZB5K^HHvI7QLRYKaW#r;%)uaQMdB0Pz^@}*=+=;=$Ob#EZHYNUOpve$Us`LKZ$s*{ z!xZonkaCUr#mlVP_aL>}GK|`4H_a2T#9QH^Bj%lvy!R{D!|O&!IUmf!{6E(%jU3@6 zj#~e2z+Ok?2nQT>B@6K`SHv7)&QSoqKFR6Po|qo;nkAeZLUC&BM`3ia!l@x@$%)aP zm>8m#oEGhFT5#A!jgXzyL5Vp7M9uflqQ_BkKZuDdx0JQGGi@#I+@3P6cWw`pkZHJc zdzi)tu?9cmc8PU_`#>G7u92^Fm!DZ_%A8qcx&=4)))5YZlB=|aDjOV<8Yf{A+Y!lc zRqGjt_HxY?TJf~N;gtUE-u`LKK33k4ufcNf_D>}(_a@54m>inesfat5Js*U#)3WRh zCuQ9eR5+m1JR31><|yY~Cdldu#h|QR%Go(|q$hjmNpqnq&4r`zOeU@ZNk>uAQR3R;`^e;nkUDGPM;#~M#|HdMNV%?k8qjwJ)5#}G?_MRx zG>>>xiEiQ3}OqnkX{uy}JefSbE!^l8z6X2;W zt*bj`Wlh)KFx$%PF;;#U(j1IE-Ez2Xd=YXl9nMkOPpz zke`FR8#1(?0{KNUYO6J_IC^7-Ui8^c;xRU^4I;I zuT!7t+VjU0`D2B*%(XrK8ss-1e+0?8Ft4yahuYtq(`{zlwRpc^+2nQ2XPL z)ZO%Y8)-M>y^#DRIR5Ngn9p?WH)0&}ko?It{z_T+duw6*>Du3Qw)NP3j+Oj9t=4mG z`(elfkYW7k+VeZ^KZ*FaLjEr#zt^5WEz;9wGvL?ehxr_8f8jS4@mqHI4Lf1{UoW)G z?;!a#fG?pP>hoKT_{~53)}JsAzsZN+CpWS<^kmzI+8@8)h2I2n0AK&XuK@|OI9UDg zJ5yfG|H10>dqDWH>K#jM#vg?2e!Fe=LWcdBu6_7X^H+;^u=+dRW;6Z~BtM?qeZJ+V zAk_u7y$5m%GVJfO;F%{siObK}PFH^{Yd!G)`S}m@FW`UC$5+_n{3rM@-gNEx@6bE& zzmt0*88?h~u=;$*cM5N@^4|>~LHjAl?n`Z?4?woy-S`|N-&79sd9D82@n-2F$mz!8 z``_VP)%Egwt@_uY|F=Tk5BY1z1CTF3hViCrAHHK8zF8c`<1I_xc57Z^HF(eMB(z@# z$$PZCCGpqx7v2Vawfw?-rfbjJN4$e|6mGllR#6!5VD&!=f4m{IbiMV+dpM#0gVk4U zqZ7lGe2>UV*~$T;!D6LQ9#L(@Ql-$g?4ng~s^qtzwWT=L)-yIZ)c2;rKGmjM1NqSb z)z&vr6n|D$%J#^%LV0wsRIF)4a;#h!%4-9lk)eue8!QgWbEPmY&;8PnW2L@)C9m2F z15tlDKU|0g`oxwkYZ2wk<@|)TAikZFwndEd#VrNlZF8{LUn0);^pp$R*cuuv7Ko)@ghM3>W^Lgq9H4`5zfMdV+$aCEOf*D!EUjX|BrsbbP zd;Q^!=U#rf#Q5Davcf3U4PudLDaAX6O=wfB6`=19(tg*BthAKcMWWF()l3n(PPE4z z4fBzBtwQx(hi9cF_6T^2Hi|uhrg`)6OqkQ?Zf)9{~r>axcwEdzXJACaIEc*k-xBh9~Dm5 z1nH{Qqq5RcB8^bt{L``Gj}J>DZl8mF4)zCvf;YpM@`k{kx1_T=S$RC!WhI|!$M%f^ z;_(;cv*yr(ywy0;3ill5zgv!Id)7Y-`z-9g6x>?Qh;IC`M;dYaXNy^L_}QY>deRE_ z9LE2O9EsaMT*?~VhfCJvE)I-sy75C(?GrFt{;*8c&TZY&QX-8==yUw-QKfz$;8^*i z{Vv$=dX4rEi>=O|_Pb%f`!(7>CbqhZwBG~!J+PnB&gH=}Fn`X2U&yg|{PFQ_t**w$ zji}py`gvN^;`TdWzk~LOZ@u~TL;Gg~``r`WMs@duwa8iFo-+ox}t z!2T)I@=qBL4SHFgb&Bl)PkY?qcSqSB$|eECPDwz+`)q3@PHH}ApIpcOZ(x6OcdbEa zKfjLstVgZgcR28H6WVvwvA_RuYfw1pmE*r1_F?^&ykPBa)+eXfgYhZf3Hz9efe$oV zjeEXRdxUmmJL}m0!+losKrn!zy*}*b4xNg;=25Ge4-A5)8BgwgF>{sqh1G1qKDHOg+y>zw$(M#+TNFSYz(ay^ob zQwBH6RmrYYex_VMr0E}_czqCe)+klsdB2uFQt^CV%O9n9p04GOcIV$({usscYAruY z@qAg!&sIDS*7CrpCV%&FY`BN14(^~%2c+=rV^*V>+pi#|@Hyv(Nc%Q;C7Bni{ z|4;B|1Pt{vb@+J+Uaz0S)bI4RU-QuGGL4^8hu4`msN}euBm4|COYJ)*E66`C6sY+F z0k2=NYQ7!+T0n~d0S)RD)r9jI*ZtLoPtKED;3pUOxx?ru=i7b4r}g)T@Y6m!D@ds+ z^Q_b(B6XhX*sNi8n`fn-5UKgy;LXLfaDOC!d{&TBr=bH!h}8P~PO$tn;OB~LkSnQf zT>t6*>&KbU&z_Vu?F=pemxAv;)$)&F6J8EKKZhS~|Lf@IG^>9k^sfS+I|F{CtsmRL zx6jL(_5}1l2EO}D%YVMv99B09uk+uJxVU^*_2$oBqko*bew+1Uy(slH!zbs}_k~yD zE!-dUX{tdb_kky&&+A$Gf8OXP_kmf`zd154nS9o$qPyxe!zg>d0q2x9sQ?;ZF0bQ%gYoaL6QpS#1*0$f z-g~m9J%#l$0)A(=<@Nml{n%l6rS=}3HEllK0G@5iJLrE!)=<~rz?X&B^Ybb6m-=@@ z|0BWq==RrTa((2!fdY%J*?|jQ|gvs0L_*pG{20C$}_p`M5v#kz)z3_UTgmt)~j{ko$ zerBm1U0D-$3HtlhI{yE|@X71j2ZY!2nb&Dprb_9X#cjQ+QW&jtEIdz8Z@DsB8SC#C z7)6&ZUmvYr)!7wAs;^KkY#AJtyV+4?IO-iL73CIh3Kd0trD)4gsV6@a^;Jsc(I`JQ zuH+W+$WWnD=xbZNWZ@F=oT3!zo7MK#b0oKu%M;4ptnM2d9-a`BSS!+L*Qi!ThIBVZ zhN6DC)jecTsWdWbz?OVvK=Lk@iam03dFx;s9^2Ng+i3COpLS*j+XOn z=NVF((oOAlv``)@6z#D^mdQ&J6V`UP67>$`%T~2td)itkj6@Q^S}Znd(vy)`h_`sM zQi_HP!=|m1+LpJ6q$?wZ!q%v?74D;G<@#l7Rzxe-UMyo`2Z*?)CVeWp_{z1*)~s4C zTCpRem3+CPqDxj^cG0rc(Pb-FcCP4(x|UtEdWCj3G}zM{^^T62p^)+y3fb%>t5;pL zJX+Ycu+8Tys)cg7Sc;^a`HH+TQL83g??7bAFZcC}y~885$D>tUYa&0Py4Eb$)2S=p zBSWFzSBPwuW;7)SH8NHit@W^Nv^Y|h_g4CAX>Bo3Ds5F)mj^3B?oq+KWidQDQS7a? zvb~i|Wq@msXn$A9+a7wR)E*J--hpy0*Iy}*6{YV%U>VraLZwz!JJutsWFd_P`r>+Y zBuJ!O$oJKHz+jn5$vhhj3?yi>?2^V+iLr=c71zBA6$-^|GTd8+OGP^@X5RIUmZE`t zu}=m}M;e*%$#pD}pU1dNbo&O2(b#CA&rId9;z+)CYkZ37NvVeOLo$WDv7ThI(#NG+ zDHU5L1Egeckjd?5hzyPFL#ck`-6<#zj};R`sEcNDv)hA`Ik+WJ9y3rn^WOYWuS}G} zP+yeqlef=GBjIF;F5MQb#~!(SC_g$XJIA*Ev}sxx9}IdIMY0IEs`cvN&RVlJbTUJw Xe4mnWlJ!>#=AT*Ta!giMaOD30wd{sS literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test123.ans b/libs/libtpl-1.5/tests/test123.ans new file mode 100755 index 0000000000..41e76f1a96 --- /dev/null +++ b/libs/libtpl-1.5/tests/test123.ans @@ -0,0 +1 @@ +caught error! diff --git a/libs/libtpl-1.5/tests/test123.c b/libs/libtpl-1.5/tests/test123.c new file mode 100755 index 0000000000..7d82530d59 --- /dev/null +++ b/libs/libtpl-1.5/tests/test123.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include "tpl.h" + +jmp_buf env; +extern tpl_hook_t tpl_hook; + +int catch_oops(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + longjmp(env,-1); /* return to setjmp point */ + return 0; /* not reached */ +} + +int main() { + int err; + tpl_node *tn; + tpl_hook.oops = catch_oops; /* install fatal handler */ + + err = setjmp(env); /* on error, control will return here */ + if (err) { + printf("caught error!\n"); + return -1; + } + + tn = tpl_map("@"); /* generate a fatal error */ + printf("program ending, without error\n"); + return 0; +} diff --git a/libs/libtpl-1.5/tests/test123.err b/libs/libtpl-1.5/tests/test123.err new file mode 100644 index 0000000000..6db6f47b08 --- /dev/null +++ b/libs/libtpl-1.5/tests/test123.err @@ -0,0 +1 @@ +unsupported option @ diff --git a/libs/libtpl-1.5/tests/test123.out b/libs/libtpl-1.5/tests/test123.out new file mode 100644 index 0000000000..41e76f1a96 --- /dev/null +++ b/libs/libtpl-1.5/tests/test123.out @@ -0,0 +1 @@ +caught error! diff --git a/libs/libtpl-1.5/tests/test124 b/libs/libtpl-1.5/tests/test124 new file mode 100755 index 0000000000000000000000000000000000000000..cbf269dc0d4c19e86d0990e05379550082f00b99 GIT binary patch literal 128291 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%0APhNlaYNcq!e@ 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

    !UCUj6RJ#>%44tB!?{WLa$)7 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 +#include +#include +#include "tpl.h" +#include + +const char *filename = "/tmp/test110.tpl"; + +int nstrcmp(const char *a, const char *b) { + if (a==NULL || b==NULL) return (a==NULL && b==NULL)?0:1; + return strcmp(a,b); +} + +int main() { + tpl_node *tn; + + char *s1,*s2,*s3,*s4; + int i5,i6,i7,i8,i9, + i10,i11,i12,i13,i14,i15,i16,i17,i18,i19,i20, + i21,i22,i23,i24,i25,i26,i27,i28,i29,i30,i31,i32,i33; + double f34,f35,f36; + int i37,i38,i39,i40; + + char *S1,*S2,*S3,*S4; + int I5,I6,I7,I8,I9, + I10,I11,I12,I13,I14,I15,I16,I17,I18,I19,I20, + I21,I22,I23,I24,I25,I26,I27,I28,I29,I30,I31,I32,I33; + double F34,F35,F36; + int I37,I38,I39,I40; + + s1=NULL;s2=NULL;s3="testing";s4="some_string"; + i5=5;i6=6;i7=7;i8=8;i9=9; + i10=10;i11=11;i12=12;i13=13;i14=14;i15=15;i16=16;i17=17;i18=18;i19=19;i20=20; + i21=21;i22=22;i23=23;i24=24;i25=25;i26=26;i27=27;i28=28;i29=29;i30=30;i31=31; + i32=32;i33=33; + f34=34.0;f35=35.0;f36=36.0; + i37=37;i38=38;i39=39;i40=40; + + + tn = tpl_map("ssssiiiiiiiiiiiiiiiiiiiiiiiiiiiiifffiiii", + &s1,&s2,&s3,&s4, + &i5,&i6,&i7,&i8,&i9, + &i10,&i11,&i12,&i13,&i14,&i15,&i16,&i17,&i18,&i19,&i20, + &i21,&i22,&i23,&i24,&i25,&i26,&i27,&i28,&i29,&i30,&i31,&i32,&i33, + &f34,&f35,&f36, + &i37,&i38,&i39,&i40); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,filename); + tpl_free(tn); + + tn = tpl_map("ssssiiiiiiiiiiiiiiiiiiiiiiiiiiiiifffiiii", + &S1,&S2,&S3,&S4, + &I5,&I6,&I7,&I8,&I9, + &I10,&I11,&I12,&I13,&I14,&I15,&I16,&I17,&I18,&I19,&I20, + &I21,&I22,&I23,&I24,&I25,&I26,&I27,&I28,&I29,&I30,&I31,&I32,&I33, + &F34,&F35,&F36, + &I37,&I38,&I39,&I40); + tpl_load(tn,TPL_FILE,filename); + tpl_unpack(tn,0); + tpl_free(tn); + + if ( + !nstrcmp(s1,S1) && !nstrcmp(s2,S2) && !nstrcmp(s3,S3) && !nstrcmp(s4,S4) && + i5==I5 && i6==I6 && i7==I7 && i8==I8 && i9==I9 && i10==I10 && i11==I11 && + i12==I12 && i13==I13 && i14==I14 && i15==I15 && i16==I16 && i17==I17 && + i18==I18 && i19==I19 && i20==I20 && i21==I21 && i22==I22 && i23==I23 && + i24==I24 && i25==I25 && i26==I26 && i27==I27 && i28==I28 && i29==I29 && + i30==I30 && i31==I31 && i32==I32 && i33==I33 && f34==F34 && f35==F35 && + f36==F36 && i37==I37 && i38==I38 && i39==I39 && i40==I40 + ) { + printf("structures match\n"); + free(S1); free(S2); free(S3); free(S4); + } + else + printf("structures mismatch\n"); + + return 0; +} diff --git a/libs/libtpl-1.5/tests/test110.out b/libs/libtpl-1.5/tests/test110.out new file mode 100644 index 0000000000..3d6e6e2e94 --- /dev/null +++ b/libs/libtpl-1.5/tests/test110.out @@ -0,0 +1 @@ +structures match diff --git a/libs/libtpl-1.5/tests/test111 b/libs/libtpl-1.5/tests/test111 new file mode 100755 index 0000000000000000000000000000000000000000..d0b721355c8054e49fcfb90217c15aac8b00517f GIT binary patch literal 128369 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 La!i(ucjSKn;nl$l literal 0 HcmV?d00001 diff --git a/libs/libtpl-1.5/tests/test111.ans b/libs/libtpl-1.5/tests/test111.ans new file mode 100755 index 0000000000..3d6e6e2e94 --- /dev/null +++ b/libs/libtpl-1.5/tests/test111.ans @@ -0,0 +1 @@ +structures match diff --git a/libs/libtpl-1.5/tests/test111.c b/libs/libtpl-1.5/tests/test111.c new file mode 100755 index 0000000000..c03082d4d0 --- /dev/null +++ b/libs/libtpl-1.5/tests/test111.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include "tpl.h" + +const char *filename = "/tmp/test111.tpl"; + +#define NUM 100 + +struct st { + int i; + char c; + double f; + uint16_t v[2]; +}; + + +int main() { + struct st s[NUM], d[NUM]; + tpl_node *tn; + int i; + + memset(s, 0, sizeof(s)); /* clear s */ + memset(d, 0, sizeof(d)); /* clear d */ + + /* fill s with random stuff */ + for(i=0; i < NUM; i++) { + s[i].i = i; s[i].c='a'+i; s[i].f = 3.14159 * i; s[i].v[0] = NUM*i; s[i].v[1] = NUM+i; + } + + tn = tpl_map("S(icfv#)#", s, 2, NUM); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,filename); + tpl_free(tn); + + tn = tpl_map("S(icfv#)#", d, 2, NUM); + tpl_load(tn,TPL_FILE,filename); + tpl_unpack(tn,0); + tpl_free(tn); + + /* see if the result is the same as the s */ + printf("structures %s\n", (!memcmp(d,s,sizeof(d)))? "match" : "mismatch"); + return 0; +} + diff --git a/libs/libtpl-1.5/tests/test111.out b/libs/libtpl-1.5/tests/test111.out new file mode 100644 index 0000000000..3d6e6e2e94 --- /dev/null +++ b/libs/libtpl-1.5/tests/test111.out @@ -0,0 +1 @@ +structures match diff --git a/libs/libtpl-1.5/tests/test112 b/libs/libtpl-1.5/tests/test112 new file mode 100755 index 0000000000000000000000000000000000000000..b1336dfe3e923cd3765f0ab0d08c19eff2056bf2 GIT binary patch literal 129185 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 +#include +#include +#include "tpl.h" + +const char *filename = "/tmp/test112.tpl"; + +#define NUM 10 + +struct st { + int i; + char c[8]; + double f; + uint16_t v[2]; +}; + + +int main() { + struct st s[NUM], d[NUM]; + tpl_node *tn; + int i; + + memset(s, 0, sizeof(s)); /* clear s */ + memset(d, 0, sizeof(d)); /* clear d */ + + /* fill s with random stuff */ + for(i=0; i < NUM; i++) { + s[i].i = i; s[i].f = 3.14159 * i; s[i].v[0] = NUM*i; s[i].v[1] = NUM+i; + strncpy(s[i].c, "abcdefg",8); + s[i].c[0] += 1; + } + + tn = tpl_map("S(ic#fv#)#", s, 8, 2, NUM); + tpl_pack(tn,0); + tpl_dump(tn,TPL_FILE,filename); + tpl_free(tn); + + tn = tpl_map("S(ic#fv#)#", d, 8, 2, NUM); + tpl_load(tn,TPL_FILE,filename); + tpl_unpack(tn,0); + tpl_free(tn); + + /* see if the result is the same as the s */ + printf("structures %s\n", (!memcmp(d,s,sizeof(d)))? "match" : "mismatch"); + return 0; +} + diff --git a/libs/libtpl-1.5/tests/test112.out b/libs/libtpl-1.5/tests/test112.out new file mode 100644 index 0000000000..3d6e6e2e94 --- /dev/null +++ b/libs/libtpl-1.5/tests/test112.out @@ -0,0 +1 @@ +structures match diff --git a/libs/libtpl-1.5/tests/test113 b/libs/libtpl-1.5/tests/test113 new file mode 100755 index 0000000000000000000000000000000000000000..cb384ef4f63756f3423d15431d859ccb0af03e7b GIT binary patch literal 129785 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