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/Makefile.am b/Makefile.am index 8c61da454a..e7f1f799a5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -103,6 +103,7 @@ $(RECURSIVE_TARGETS): freeswitch CORE_CFLAGS = `$(switch_builddir)/libs/apr/apr-1-config --cflags --cppflags --includes` CORE_CFLAGS += `$(switch_builddir)/libs/apr-util/apu-1-config --includes` +CORE_CFLAGS += -I$(switch_srcdir)/libs/libtpl-1.5/src CORE_CFLAGS += -I$(switch_srcdir)/libs/stfu CORE_CFLAGS += -I$(switch_builddir)/libs/sqlite CORE_CFLAGS += -I$(switch_srcdir)/libs/pcre @@ -204,6 +205,7 @@ library_include_HEADERS = \ libs/libteletone/src/libteletone_detect.h \ libs/libteletone/src/libteletone_generate.h \ libs/libteletone/src/libteletone.h \ + libs/libtpl-1.5/src/tpl.h \ src/include/switch_limit.h \ src/include/switch_odbc.h @@ -266,6 +268,7 @@ libfreeswitch_la_SOURCES = \ src/switch_profile.c \ src/switch_json.c \ src/switch_curl.c \ + libs/libtpl-1.5/src/tpl.c \ libs/stfu/stfu.c \ libs/libteletone/src/libteletone_detect.c \ libs/libteletone/src/libteletone_generate.c \ 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 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/conf/vanilla/autoload_configs/oreka.conf.xml b/conf/vanilla/autoload_configs/oreka.conf.xml new file mode 100644 index 0000000000..29eabd5c29 --- /dev/null +++ b/conf/vanilla/autoload_configs/oreka.conf.xml @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/configure.in b/configure.in index 88aaf28ffc..5a97b86ace 100644 --- a/configure.in +++ b/configure.in @@ -3,10 +3,10 @@ # Must change all of the below together # For a release, set revision for that tagged release as well and uncomment -AC_INIT([freeswitch], [1.2.2], BUG-REPORT-ADDRESS) +AC_INIT([freeswitch], [1.3.0], BUG-REPORT-ADDRESS) AC_SUBST(SWITCH_VERSION_MAJOR, [1]) -AC_SUBST(SWITCH_VERSION_MINOR, [2]) -AC_SUBST(SWITCH_VERSION_MICRO, [2]) +AC_SUBST(SWITCH_VERSION_MINOR, [3]) +AC_SUBST(SWITCH_VERSION_MICRO, [0]) AC_SUBST(SWITCH_VERSION_REVISION, []) AC_SUBST(SWITCH_VERSION_REVISION_HUMAN, []) diff --git a/libs/esl/src/esl_json.c b/libs/esl/src/esl_json.c index 2926a3230b..5e7157cfe4 100644 --- a/libs/esl/src/esl_json.c +++ b/libs/esl/src/esl_json.c @@ -20,12 +20,22 @@ THE SOFTWARE. */ -// cJSON -// JSON parser in C. +/* cJSON */ +/* JSON parser in C. */ -#include "esl.h" +#include +#include +#include +#include #include #include +#include +#include "esl_json.h" +#include "esl.h" + +static const char *ep; + +ESL_DECLARE(const char *)cJSON_GetErrorPtr() {return ep;} static int cJSON_strcasecmp(const char *s1,const char *s2) { @@ -51,14 +61,15 @@ static char* cJSON_strdup(const char* str) { size_t len; char* copy; + const char *s = str ? str : ""; - len = strlen(str) + 1; + len = strlen(s) + 1; if (!(copy = (char*)cJSON_malloc(len))) return 0; - memcpy(copy,str,len); + memcpy(copy,s,len); return copy; } -void cJSON_InitHooks(cJSON_Hooks* hooks) +ESL_DECLARE(void)cJSON_InitHooks(cJSON_Hooks* hooks) { if (!hooks) { /* Reset hooks */ cJSON_malloc = malloc; @@ -70,16 +81,16 @@ void cJSON_InitHooks(cJSON_Hooks* hooks) cJSON_free = (hooks->free_fn)?hooks->free_fn:free; } -// Internal constructor. -static cJSON *cJSON_New_Item(void) +/* Internal constructor. */ +static cJSON *cJSON_New_Item() { cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); if (node) memset(node,0,sizeof(cJSON)); return node; } -// Delete a cJSON structure. -void cJSON_Delete(cJSON *c) +/* Delete a cJSON structure. */ +ESL_DECLARE(void)cJSON_Delete(cJSON *c) { cJSON *next; while (c) @@ -93,22 +104,22 @@ void cJSON_Delete(cJSON *c) } } -// Parse the input text to generate a number, and populate the result into item. +/* Parse the input text to generate a number, and populate the result into item. */ static const char *parse_number(cJSON *item,const char *num) { double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; - // Could use sscanf for this? - if (*num=='-') sign=-1,num++; // Has sign? - if (*num=='0') num++; // is zero - if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); // Number? - if (*num=='.') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} // Fractional part? - if (*num=='e' || *num=='E') // Exponent? - { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; // With sign? - while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); // Number? + /* Could use sscanf for this? */ + if (*num=='-') sign=-1,num++; /* Has sign? */ + if (*num=='0') num++; /* is zero */ + if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ + if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ + if (*num=='e' || *num=='E') /* Exponent? */ + { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ + while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ } - n=sign*n*pow(10.0,(scale+subscale*signsubscale)); // number = +/- number.fraction * 10^+/- exponent + n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ item->valuedouble=n; item->valueint=(int)n; @@ -116,40 +127,43 @@ static const char *parse_number(cJSON *item,const char *num) return num; } -// Render the number nicely from the given item into a string. +/* Render the number nicely from the given item into a string. */ static char *print_number(cJSON *item) { char *str; double d=item->valuedouble; if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) { - str=(char*)cJSON_malloc(21); // 2^64+1 can be represented in 21 chars. - sprintf(str,"%d",item->valueint); + str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */ + if (str) sprintf(str,"%d",item->valueint); } else { - str=(char*)cJSON_malloc(64); // This is a nice tradeoff. - if (fabs(floor(d)-d)<=DBL_EPSILON) sprintf(str,"%.0f",d); - else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); - else sprintf(str,"%f",d); + str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */ + if (str) + { + if (fabs(floor(d)-d)<=DBL_EPSILON) sprintf(str,"%.0f",d); + else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); + else sprintf(str,"%f",d); + } } return str; } -// Parse the input text into an unescaped cstring, and populate item. +/* Parse the input text into an unescaped cstring, and populate item. */ static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; static const char *parse_string(cJSON *item,const char *str) { - const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc; - if (*str!='\"') return 0; // not a string! + const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; + if (*str!='\"') {ep=str;return 0;} /* not a string! */ - while (*ptr!='\"' && (unsigned char)*ptr>31 && ++len) if (*ptr++ == '\\') ptr++; // Skip escaped quotes. + while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ - out=(char*)cJSON_malloc(len+1); // This is how long we need for the string, roughly. + out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */ if (!out) return 0; ptr=str+1;ptr2=out; - while (*ptr!='\"' && (unsigned char)*ptr>31) + while (*ptr!='\"' && *ptr) { if (*ptr!='\\') *ptr2++=*ptr++; else @@ -162,16 +176,31 @@ static const char *parse_string(cJSON *item,const char *str) case 'n': *ptr2++='\n'; break; case 'r': *ptr2++='\r'; break; case 't': *ptr2++='\t'; break; - case 'u': // transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY. - if (sscanf(ptr+1,"%4x",&uc) < 1) break; // get the unicode char. - len=3;if (uc<0x80) len=1;else if (uc<0x800) len=2;ptr2+=len; + case 'u': /* transcode utf16 to utf8. */ + if (sscanf(ptr+1,"%4x",&uc) < 1) break; + + ptr+=4; /* get the unicode char. */ + + if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; // check for invalid. + + if (uc>=0xD800 && uc<=0xDBFF) // UTF16 surrogate pairs. + { + if (ptr[1]!='\\' || ptr[2]!='u') break; // missing second-half of surrogate. + if (sscanf(ptr+3,"%4x",&uc2) < 1) break; + ptr+=6; + if (uc2<0xDC00 || uc2>0xDFFF) break; // invalid second-half of surrogate. + uc=0x10000 | ((uc&0x3FF)<<10) | (uc2&0x3FF); + } + + len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; switch (len) { + case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; case 1: *--ptr2 =(char)(uc | firstByteMark[len]); } - ptr2+=len;ptr+=4; + ptr2+=len; break; default: *ptr2++=*ptr; break; } @@ -185,15 +214,17 @@ static const char *parse_string(cJSON *item,const char *str) return ptr; } -// Render the cstring provided to an escaped version that can be printed. +/* Render the cstring provided to an escaped version that can be printed. */ static char *print_string_ptr(const char *str) { - const char *ptr;char *ptr2,*out;int len=0; + const char *ptr;char *ptr2,*out;int len=0;unsigned char token; if (!str) return cJSON_strdup(""); - ptr=str;while (*ptr && ++len) {if ((unsigned char)*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;} + ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} out=(char*)cJSON_malloc(len+3); + if (!out) return 0; + ptr2=out;ptr=str; *ptr2++='\"'; while (*ptr) @@ -202,7 +233,7 @@ static char *print_string_ptr(const char *str) else { *ptr2++='\\'; - switch (*ptr++) + switch (token=*ptr++) { case '\\': *ptr2++='\\'; break; case '\"': *ptr2++='\"'; break; @@ -211,17 +242,17 @@ static char *print_string_ptr(const char *str) case '\n': *ptr2++='n'; break; case '\r': *ptr2++='r'; break; case '\t': *ptr2++='t'; break; - default: ptr2--; break; // eviscerate with prejudice. + default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ } } } *ptr2++='\"';*ptr2++=0; return out; } -// Invote print_string_ptr (which is useful) on an item. +/* Invote print_string_ptr (which is useful) on an item. */ static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);} -// Predeclare these prototypes. +/* Predeclare these prototypes. */ static const char *parse_value(cJSON *item,const char *value); static char *print_value(cJSON *item,int depth,int fmt); static const char *parse_array(cJSON *item,const char *value); @@ -229,27 +260,28 @@ static char *print_array(cJSON *item,int depth,int fmt); static const char *parse_object(cJSON *item,const char *value); static char *print_object(cJSON *item,int depth,int fmt); -// Utility to jump whitespace and cr/lf -static const char *skip(const char *in) {while (in && (unsigned char)*in<=32) in++; return in;} +/* Utility to jump whitespace and cr/lf */ +static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} -// Parse an object - create a new root, and populate. -cJSON *cJSON_Parse(const char *value) +/* Parse an object - create a new root, and populate. */ +ESL_DECLARE(cJSON *)cJSON_Parse(const char *value) { cJSON *c=cJSON_New_Item(); + ep=0; if (!c) return 0; /* memory fail */ if (!parse_value(c,skip(value))) {cJSON_Delete(c);return 0;} return c; } -// 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);} +/* Render a cJSON item/entity/structure to text. */ +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. +/* Parser core - when encountering text, process appropriately. */ static const char *parse_value(cJSON *item,const char *value) { - if (!value) return 0; // Fail on null. + if (!value) return 0; /* Fail on null. */ if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } @@ -258,10 +290,10 @@ static const char *parse_value(cJSON *item,const char *value) if (*value=='[') { return parse_array(item,value); } if (*value=='{') { return parse_object(item,value); } - return 0; // failure. + ep=value;return 0; /* failure. */ } -// Render a value to text. +/* Render a value to text. */ static char *print_value(cJSON *item,int depth,int fmt) { char *out=0; @@ -279,35 +311,35 @@ static char *print_value(cJSON *item,int depth,int fmt) return out; } -// Build an array from input text. +/* Build an array from input text. */ static const char *parse_array(cJSON *item,const char *value) { cJSON *child; - if (*value!='[') return 0; // not an array! + if (*value!='[') {ep=value;return 0;} /* not an array! */ item->type=cJSON_Array; value=skip(value+1); - if (*value==']') return value+1; // empty array. + if (*value==']') return value+1; /* empty array. */ item->child=child=cJSON_New_Item(); - if (!item->child) return 0; // memory fail - value=skip(parse_value(child,skip(value))); // skip any spacing, get the value. + if (!item->child) return 0; /* memory fail */ + value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */ if (!value) return 0; while (*value==',') { cJSON *new_item; - if (!(new_item=cJSON_New_Item())) return 0; // memory fail + if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ child->next=new_item;new_item->prev=child;child=new_item; value=skip(parse_value(child,skip(value+1))); - if (!value) return 0; // memory fail + if (!value) return 0; /* memory fail */ } - if (*value==']') return value+1; // end of array - return 0; // malformed. + if (*value==']') return value+1; /* end of array */ + ep=value;return 0; /* malformed. */ } -// Render an array to text +/* Render an array to text */ static char *print_array(cJSON *item,int depth,int fmt) { char **entries; @@ -315,13 +347,13 @@ static char *print_array(cJSON *item,int depth,int fmt) cJSON *child=item->child; int numentries=0,i=0,fail=0; - // How many entries in the array? + /* How many entries in the array? */ while (child) numentries++,child=child->next; - // Allocate an array to hold the values for each + /* Allocate an array to hold the values for each */ entries=(char**)cJSON_malloc(numentries*sizeof(char*)); if (!entries) return 0; memset(entries,0,numentries*sizeof(char*)); - // Retrieve all the results: + /* Retrieve all the results: */ child=item->child; while (child && !fail) { @@ -331,12 +363,12 @@ static char *print_array(cJSON *item,int depth,int fmt) child=child->next; } - // If we didn't fail, try to malloc the output string - if (!fail) out=cJSON_malloc(len); - // If that fails, we fail. + /* If we didn't fail, try to malloc the output string */ + if (!fail) out=(char*)cJSON_malloc(len); + /* If that fails, we fail. */ if (!out) fail=1; - // Handle failure. + /* Handle failure. */ if (fail) { for (i=0;itype=cJSON_Object; value=skip(value+1); - if (*value=='}') return value+1; // empty array. + if (*value=='}') return value+1; /* empty array. */ item->child=child=cJSON_New_Item(); + if (!item->child) return 0; value=skip(parse_string(child,skip(value))); if (!value) return 0; child->string=child->valuestring;child->valuestring=0; - if (*value!=':') return 0; // fail! - value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value. + if (*value!=':') {ep=value;return 0;} /* fail! */ + value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ if (!value) return 0; while (*value==',') { cJSON *new_item; - if (!(new_item=cJSON_New_Item())) return 0; // memory fail + if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ child->next=new_item;new_item->prev=child;child=new_item; value=skip(parse_string(child,skip(value+1))); if (!value) return 0; child->string=child->valuestring;child->valuestring=0; - if (*value!=':') return 0; // fail! - value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value. + if (*value!=':') {ep=value;return 0;} /* fail! */ + value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ if (!value) return 0; } - if (*value=='}') return value+1; // end of array - return 0; // malformed. + if (*value=='}') return value+1; /* end of array */ + ep=value;return 0; /* malformed. */ } -// Render an object to text. +/* Render an object to text. */ static char *print_object(cJSON *item,int depth,int fmt) { char **entries=0,**names=0; char *out=0,*ptr,*ret,*str;int len=7,i=0,j; cJSON *child=item->child; int numentries=0,fail=0; - // Count the number of entries. + /* Count the number of entries. */ while (child) numentries++,child=child->next; - // Allocate space for the names and the objects + /* Allocate space for the names and the objects */ entries=(char**)cJSON_malloc(numentries*sizeof(char*)); if (!entries) return 0; names=(char**)cJSON_malloc(numentries*sizeof(char*)); @@ -410,7 +443,7 @@ static char *print_object(cJSON *item,int depth,int fmt) memset(entries,0,sizeof(char*)*numentries); memset(names,0,sizeof(char*)*numentries); - // Collect all the results into our arrays: + /* Collect all the results into our arrays: */ child=item->child;depth++;if (fmt) len+=depth; while (child) { @@ -420,19 +453,19 @@ static char *print_object(cJSON *item,int depth,int fmt) child=child->next; } - // Try to allocate the output string + /* Try to allocate the output string */ if (!fail) out=(char*)cJSON_malloc(len); if (!out) fail=1; - // Handle failure + /* Handle failure */ if (fail) { - for (i=0;ichild;int i=0;while(c)i++,c=c->next;return i;} -cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} -cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} +/* Get Array size/item / object item. */ +ESL_DECLARE(int) cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;} +ESL_DECLARE(cJSON *)cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} +ESL_DECLARE(cJSON *)cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} -// Utility for array list handling. +/* Utility for array list handling. */ static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} -// Utility for handling references. -static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} +/* Utility for handling references. */ +static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} -// Add item to array/object. -void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} -void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} -void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} -void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} +/* Add item to array/object. */ +ESL_DECLARE(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} +ESL_DECLARE(void) cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} +ESL_DECLARE(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} +ESL_DECLARE(void) cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} -cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; +ESL_DECLARE(cJSON *)cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} -void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} -cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} -void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} +ESL_DECLARE(void) cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} +ESL_DECLARE(cJSON *)cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} +ESL_DECLARE(void) cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} -// Replace array/object items with new ones. -void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; +/* Replace array/object items with new ones. */ +ESL_DECLARE(void) cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} -void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} +ESL_DECLARE(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} -// Create basic types: -cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();item->type=cJSON_NULL;return item;} -cJSON *cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();item->type=cJSON_True;return item;} -cJSON *cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();item->type=cJSON_False;return item;} -cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;return item;} -cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();item->type=cJSON_String;item->valuestring=cJSON_strdup(string);return item;} -cJSON *cJSON_CreateArray() {cJSON *item=cJSON_New_Item();item->type=cJSON_Array;return item;} -cJSON *cJSON_CreateObject() {cJSON *item=cJSON_New_Item();item->type=cJSON_Object;return item;} +/* Create basic types: */ +ESL_DECLARE(cJSON *)cJSON_CreateNull() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} +ESL_DECLARE(cJSON *)cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} +ESL_DECLARE(cJSON *)cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} +ESL_DECLARE(cJSON *)cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} +ESL_DECLARE(cJSON *)cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} +ESL_DECLARE(cJSON *)cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} +ESL_DECLARE(cJSON *)cJSON_CreateArray() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} +ESL_DECLARE(cJSON *)cJSON_CreateObject() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} -// Create Arrays: -cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} -cJSON *cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} -cJSON *cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} -cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} +/* 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!=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;} diff --git a/libs/esl/src/include/esl_json.h b/libs/esl/src/include/esl_json.h index 535498a06c..615645597a 100755 --- a/libs/esl/src/include/esl_json.h +++ b/libs/esl/src/include/esl_json.h @@ -19,9 +19,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - #include "esl.h" - #ifndef cJSON__h #define cJSON__h @@ -30,7 +28,7 @@ extern "C" { #endif -// cJSON Types: +/* cJSON Types: */ #define cJSON_False 0 #define cJSON_True 1 #define cJSON_NULL 2 @@ -41,18 +39,18 @@ extern "C" #define cJSON_IsReference 256 -// The cJSON structure: +/* The cJSON structure: */ typedef struct cJSON { - struct cJSON *next,*prev; // next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem - struct cJSON *child; // An array or object item will have a child pointer pointing to a chain of the items in the array/object. + struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ - int type; // The type of the item, as above. + int type; /* The type of the item, as above. */ - char *valuestring; // The item's string, if type==cJSON_String - int valueint; // The item's number, if type==cJSON_Number - double valuedouble; // The item's number, if type==cJSON_Number + char *valuestring; /* The item's string, if type==cJSON_String */ + int valueint; /* The item's number, if type==cJSON_Number */ + double valuedouble; /* The item's number, if type==cJSON_Number */ - char *string; // The item's name string, if this item is the child of, or is in the list of subitems of an object. + char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ } cJSON; typedef struct cJSON_Hooks { @@ -60,57 +58,61 @@ typedef struct cJSON_Hooks { void (*free_fn)(void *ptr); } cJSON_Hooks; -// Supply malloc, realloc and free functions to cJSON -extern void cJSON_InitHooks(cJSON_Hooks* hooks); +/* Supply malloc, realloc and free functions to cJSON */ +ESL_DECLARE(void) cJSON_InitHooks(cJSON_Hooks* hooks); -// Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. -extern cJSON *cJSON_Parse(const char *value); -// Render a cJSON entity to text for transfer/storage. Free the char* when finished. -extern char *cJSON_Print(cJSON *item); -// Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. -extern char *cJSON_PrintUnformatted(cJSON *item); -// Delete a cJSON entity and all subentities. -extern void cJSON_Delete(cJSON *c); +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ +ESL_DECLARE(cJSON *)cJSON_Parse(const char *value); +/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ +ESL_DECLARE(char *)cJSON_Print(cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ +ESL_DECLARE(char *)cJSON_PrintUnformatted(cJSON *item); +/* Delete a cJSON entity and all subentities. */ +ESL_DECLARE(void) cJSON_Delete(cJSON *c); -// Returns the number of items in an array (or object). -extern int cJSON_GetArraySize(cJSON *array); -// Retrieve item number "item" from array "array". Returns NULL if unsuccessful. -extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); -// Get item "string" from object. Case insensitive. -extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); +/* Returns the number of items in an array (or object). */ +ESL_DECLARE(int) cJSON_GetArraySize(cJSON *array); +/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ +ESL_DECLARE(cJSON *)cJSON_GetArrayItem(cJSON *array,int item); +/* Get item "string" from object. Case insensitive. */ +ESL_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. */ +ESL_DECLARE(const char *)cJSON_GetErrorPtr(); -// These calls create a cJSON item of the appropriate type. -extern cJSON *cJSON_CreateNull(void); -extern cJSON *cJSON_CreateTrue(void); -extern cJSON *cJSON_CreateFalse(void); -extern cJSON *cJSON_CreateNumber(double num); -extern cJSON *cJSON_CreateString(const char *string); -extern cJSON *cJSON_CreateArray(void); -extern cJSON *cJSON_CreateObject(void); +/* These calls create a cJSON item of the appropriate type. */ +ESL_DECLARE(cJSON *)cJSON_CreateNull(); +ESL_DECLARE(cJSON *)cJSON_CreateTrue(); +ESL_DECLARE(cJSON *)cJSON_CreateFalse(); +ESL_DECLARE(cJSON *)cJSON_CreateBool(int b); +ESL_DECLARE(cJSON *)cJSON_CreateNumber(double num); +ESL_DECLARE(cJSON *)cJSON_CreateString(const char *string); +ESL_DECLARE(cJSON *)cJSON_CreateArray(); +ESL_DECLARE(cJSON *)cJSON_CreateObject(); -// These utilities create an Array of count items. -extern cJSON *cJSON_CreateIntArray(int *numbers,int count); -extern cJSON *cJSON_CreateFloatArray(float *numbers,int count); -extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count); -extern cJSON *cJSON_CreateStringArray(const char **strings,int count); +/* These utilities create an Array of count items. */ +ESL_DECLARE(cJSON *)cJSON_CreateIntArray(int *numbers,int count); +ESL_DECLARE(cJSON *)cJSON_CreateFloatArray(float *numbers,int count); +ESL_DECLARE(cJSON *)cJSON_CreateDoubleArray(double *numbers,int count); +ESL_DECLARE(cJSON *)cJSON_CreateStringArray(const char **strings,int count); -// Append item to the specified array/object. -extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); -extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); -// Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. -extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); -extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); +/* Append item to the specified array/object. */ +ESL_DECLARE(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); +ESL_DECLARE(void) cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +ESL_DECLARE(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +ESL_DECLARE(void) cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); -// Remove/Detatch items from Arrays/Objects. -extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); -extern void cJSON_DeleteItemFromArray(cJSON *array,int which); -extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); -extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); +/* Remove/Detatch items from Arrays/Objects. */ +ESL_DECLARE(cJSON *)cJSON_DetachItemFromArray(cJSON *array,int which); +ESL_DECLARE(void) cJSON_DeleteItemFromArray(cJSON *array,int which); +ESL_DECLARE(cJSON *)cJSON_DetachItemFromObject(cJSON *object,const char *string); +ESL_DECLARE(void) cJSON_DeleteItemFromObject(cJSON *object,const char *string); -// Update array items. -extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); -extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +/* Update array items. */ +ESL_DECLARE(void) cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); +ESL_DECLARE(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) diff --git a/libs/freetdm/Makefile.am b/libs/freetdm/Makefile.am index 03477ad359..2c779fe0f7 100644 --- a/libs/freetdm/Makefile.am +++ b/libs/freetdm/Makefile.am @@ -214,6 +214,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/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/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 + 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 f38ededc8e..271f532a70 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 * Gideon Sadan * * mod_freetdm.c -- FreeTDM Endpoint Module @@ -47,6 +48,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); @@ -117,6 +120,7 @@ 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) */ @@ -166,6 +170,9 @@ 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); +#if 0 +void ctdm_init(switch_loadable_module_interface_t *module_interface); +#endif static switch_core_session_t *ftdm_channel_get_session(ftdm_channel_t *channel, int32_t id) { @@ -594,11 +601,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 *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; } - ftdm_channel_call_hangup_with_cause(tech_pvt->ftdmchan, hcause); + 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); + } } break; default: @@ -1134,10 +1150,10 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s break; case FTDM_CHAN_TYPE_B: status = channel_receive_message_b(session, msg); - break; + break; case FTDM_CHAN_TYPE_CAS: status = channel_receive_message_cas(session, msg); - break; + break; default: status = SWITCH_STATUS_FALSE; break; @@ -1172,20 +1188,21 @@ switch_io_routines_t freetdm_io_routines = { static const char* channel_get_variable(switch_core_session_t *session, switch_event_t *var_event, const char *variable_name) { - const char *variable = NULL; - if (var_event) { - if ((variable = switch_event_get_header(var_event, variable_name))) { - return variable; - } - } + const char *variable = NULL; - if (session) { - switch_channel_t *channel = switch_core_session_get_channel(session); - if ((variable = switch_channel_get_variable(channel, variable_name))) { - return variable; - } - } - return NULL; + if (var_event) { + if ((variable = switch_event_get_header(var_event, variable_name))) { + return variable; + } + } + + if (session) { + switch_channel_t *channel = switch_core_session_get_channel(session); + if ((variable = switch_channel_get_variable(channel, variable_name))) { + return variable; + } + } + return NULL; } typedef struct { @@ -1272,10 +1289,15 @@ 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; + 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; 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"); @@ -1298,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; } @@ -1359,9 +1381,12 @@ 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; + + 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); @@ -1403,6 +1428,31 @@ 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-Access-Transport-URLENC"); + 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) { + 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); @@ -1416,7 +1466,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"); @@ -1499,6 +1549,50 @@ 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); + } + + 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); + } + 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); + } + + 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)) { @@ -1509,6 +1603,10 @@ 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_bearer_capability"))) { caller_data.bearer_capability = (uint8_t)atoi(var); } @@ -1531,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); } @@ -1595,6 +1699,36 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi goto fail; } + 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); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Session %s is network-bridged with %s\n", + my_uuid, network_peer_uuid); + + 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); + } + /* 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); 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)); @@ -1606,6 +1740,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 && !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); @@ -1623,6 +1762,12 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi 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; } @@ -1748,6 +1893,8 @@ 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-SpanNumber", "%d", spanid); + 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); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-CallerName", "%s", channel_caller_data->cid_name); @@ -1767,53 +1914,94 @@ 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_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); + } + + 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); + } + + 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", "%d", 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"); 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"); 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"); 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"); */ @@ -1835,6 +2023,46 @@ 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_nadi"); + 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 */ @@ -2014,7 +2242,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxo_signal) ftdm_log(FTDM_LOG_DEBUG, "got FXO sig %d:%d [%s]\n", spanid, chanid, ftdm_signal_event2str(sigmsg->event_id)); - switch(sigmsg->event_id) { + switch (sigmsg->event_id) { case FTDM_SIGEVENT_PROGRESS_MEDIA: { if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) { @@ -2082,7 +2310,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxs_signal) ftdm_log(FTDM_LOG_DEBUG, "got FXS sig [%s]\n", ftdm_signal_event2str(sigmsg->event_id)); - switch(sigmsg->event_id) { + switch (sigmsg->event_id) { case FTDM_SIGEVENT_UP: { if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) { @@ -2578,14 +2806,14 @@ static uint32_t enable_analog_option(const char *str, uint32_t current_options) return current_options; } -#define CONFIG_ERROR(...) { \ +#define LOAD_ERROR(...) { \ ftdm_log(FTDM_LOG_ERROR, __VA_ARGS__); \ globals.config_error = 1; \ } /* - * Create ftdm_conf_node_t tree based on a fixed pattern XML configuration list - * last 2 args are for limited aka dumb recursivity + * Create ftdm_conf_node_t tree based on a fixed pattern XML configuration list. + * Last 2 args are for limited aka dumb recursivity. */ static int add_config_list_nodes(switch_xml_t swnode, ftdm_conf_node_t *rootnode, const char *list_name, const char *list_element_name, @@ -2639,11 +2867,85 @@ 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) +/* + * 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 *operating_mode) { 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); @@ -2665,8 +2967,11 @@ static ftdm_conf_node_t *get_ss7_config_node(switch_xml_t cfg, const char *confn 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; @@ -2677,8 +2982,21 @@ static ftdm_conf_node_t *get_ss7_config_node(switch_xml_t cfg, const char *confn } 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 */ @@ -2687,6 +3005,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 (operating_mode && ('\0' != operating_mode[0])) { + if (!strcasecmp(operating_mode, "ISUP")) { + is_isup = 0x01; + } + 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", operating_mode); + ftdm_conf_node_destroy(rootnode); + return NULL; + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Operating mode not specified, default to ISUP \n"); + is_isup = 0x01; + } + /* add sng_gen */ gen = switch_xml_child(isup, "sng_gen"); if (gen == NULL) { @@ -2728,39 +3063,72 @@ 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 (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 */ - 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; + } - /* 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 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; + /* 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_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; + } + + 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_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_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); @@ -2776,7 +3144,7 @@ static int add_profile_parameters(switch_xml_t cfg, const char *profname, ftdm_c profnode = switch_xml_child(cfg, "config_profiles"); if (!profnode) { - CONFIG_ERROR("cannot find profile '%s', there is no 'config_profiles' XML section\n", profname); + LOAD_ERROR("cannot find profile '%s', there is no 'config_profiles' XML section\n", profname); return 0; } @@ -2792,7 +3160,7 @@ static int add_profile_parameters(switch_xml_t cfg, const char *profname, ftdm_c } if (!profile) { - CONFIG_ERROR("failed to find profile '%s'\n", profname); + LOAD_ERROR("failed to find profile '%s'\n", profname); return 0; } @@ -2827,7 +3195,7 @@ static void parse_gsm_spans(switch_xml_t cfg, switch_xml_t spans) unsigned paramindex = 0; if (!name && !id) { - CONFIG_ERROR("GSM span missing required attribute 'id' or 'name', skipping ...\n"); + LOAD_ERROR("GSM span missing required attribute 'id' or 'name', skipping ...\n"); continue; } @@ -2845,7 +3213,7 @@ static void parse_gsm_spans(switch_xml_t cfg, switch_xml_t spans) } if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + LOAD_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); continue; } @@ -2868,7 +3236,7 @@ static void parse_gsm_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) { - CONFIG_ERROR("Too many parameters for GSM span, ignoring any parameter after %s\n", var); + LOAD_ERROR("Too many parameters for GSM span, ignoring any parameter after %s\n", var); break; } @@ -2887,13 +3255,15 @@ static void parse_gsm_spans(switch_xml_t cfg, switch_xml_t spans) "gsm", on_clear_channel_signal, spanparameters) != FTDM_SUCCESS) { - CONFIG_ERROR("Error configuring Sangoma GSM FreeTDM span %d\n", span_id); + LOAD_ERROR("Error configuring Sangoma GSM FreeTDM span %d\n", span_id); 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, "GSM", sizeof(SPAN_CONFIG[span_id].type)); + ftdm_log(FTDM_LOG_DEBUG, "Configured GSM FreeTDM span %d\n", span_id); ftdm_span_start(span); } @@ -2916,7 +3286,7 @@ static void parse_bri_pri_spans(switch_xml_t cfg, switch_xml_t spans) unsigned paramindex = 0; if (!name && !id) { - CONFIG_ERROR("sangoma isdn span missing required attribute 'id' or 'name', skipping ...\n"); + LOAD_ERROR("sangoma isdn span missing required attribute 'id' or 'name', skipping ...\n"); continue; } @@ -2934,7 +3304,7 @@ static void parse_bri_pri_spans(switch_xml_t cfg, switch_xml_t spans) } if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + LOAD_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); continue; } @@ -2962,7 +3332,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) { - CONFIG_ERROR("Too many parameters for ss7 span, ignoring any parameter after %s\n", var); + LOAD_ERROR("Too many parameters for ss7 span, ignoring any parameter after %s\n", var); break; } @@ -2992,10 +3362,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) { - CONFIG_ERROR("Invalid %s parameter, format example: 3/1 for 3 calls per second\n", var); + LOAD_ERROR("Invalid %s parameter, format example: 3/1 for 3 calls per second\n", var); } else { if (calls < 1 || seconds < 1) { - CONFIG_ERROR("Invalid %s parameter value, minimum call limit must be 1 per second\n", var); + LOAD_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; @@ -3005,7 +3375,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 { - CONFIG_ERROR("Invalid %s parameter value, only accepted event is 'answer'\n", var); + LOAD_ERROR("Invalid %s parameter value, only accepted event is 'answer'\n", var); } } else { spanparameters[paramindex].var = var; @@ -3018,13 +3388,15 @@ static void parse_bri_pri_spans(switch_xml_t cfg, switch_xml_t spans) "sangoma_isdn", on_clear_channel_signal, spanparameters) != FTDM_SUCCESS) { - CONFIG_ERROR("Error configuring Sangoma ISDN FreeTDM span %d\n", span_id); + LOAD_ERROR("Error configuring Sangoma ISDN FreeTDM span %d\n", span_id); 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 (ISDN)", sizeof(SPAN_CONFIG[span_id].type)); + ftdm_log(FTDM_LOG_DEBUG, "Configured Sangoma ISDN FreeTDM span %d\n", span_id); ftdm_span_start(span); } @@ -3042,6 +3414,7 @@ static switch_status_t load_config(void) memset(&globals, 0, sizeof(globals)); switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, module_pool); + if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf); return SWITCH_STATUS_TERM; @@ -3090,15 +3463,16 @@ 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 *operating_mode = (char *) switch_xml_attr(myspan, "operating_mode"); ftdm_span_t *span = NULL; uint32_t span_id = 0; unsigned paramindex = 0; if (!name && !id) { - CONFIG_ERROR("ss7 span missing required attribute 'id' or 'name', skipping ...\n"); + LOAD_ERROR("ss7 span missing required attribute 'id' or 'name', skipping ...\n"); continue; } if (!configname) { - CONFIG_ERROR("ss7 span missing required attribute, skipping ...\n"); + LOAD_ERROR("ss7 span missing required attribute, skipping ...\n"); continue; } if (name) { @@ -3115,7 +3489,7 @@ static switch_status_t load_config(void) } if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + LOAD_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); continue; } @@ -3123,23 +3497,31 @@ 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, operating_mode); if (!ss7confnode) { - CONFIG_ERROR("Error finding ss7config '%s' for FreeTDM span id: %s\n", configname, switch_str_nil(id)); + LOAD_ERROR("Error finding ss7config '%s' for FreeTDM span id: %s\n", configname, switch_str_nil(id)); continue; } memset(spanparameters, 0, sizeof(spanparameters)); paramindex = 0; + + if (operating_mode) { + spanparameters[paramindex].var = "operating-mode"; + spanparameters[paramindex].val = operating_mode; + paramindex++; + } + spanparameters[paramindex].var = "confnode"; spanparameters[paramindex].ptr = ss7confnode; 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) { - CONFIG_ERROR("Too many parameters for ss7 span, ignoring any parameter after %s\n", var); + LOAD_ERROR("Too many parameters for ss7 span, ignoring any parameter after %s\n", var); break; } @@ -3158,15 +3540,22 @@ static switch_status_t load_config(void) "sangoma_ss7", on_clear_channel_signal, spanparameters) != FTDM_SUCCESS) { - CONFIG_ERROR("Error configuring ss7 FreeTDM span %d\n", span_id); + LOAD_ERROR("Error configuring ss7 FreeTDM span %d\n", span_id); 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 (SS7)", sizeof(SPAN_CONFIG[span_id].type)); + ftdm_log(FTDM_LOG_DEBUG, "Configured ss7 FreeTDM span %d with config node %s\n", span_id, configname); - ftdm_span_start(span); + + if (FTDM_SUCCESS != ftdm_span_start(span)) { + LOAD_ERROR("Error Starting ss7 FreeTDM span %d\n", span_id); + continue; + } } } @@ -3210,7 +3599,7 @@ static switch_status_t load_config(void) } if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + LOAD_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); continue; } @@ -3244,10 +3633,10 @@ static switch_status_t load_config(void) int calls; int seconds; if (sscanf(val, "%d/%d", &calls, &seconds) != 2) { - CONFIG_ERROR("Invalid %s parameter, format example: 3/1 for 3 calls per second\n", var); + LOAD_ERROR("Invalid %s parameter, format example: 3/1 for 3 calls per second\n", var); } else { if (calls < 1 || seconds < 1) { - CONFIG_ERROR("Invalid %s parameter value, minimum call limit must be 1 per second\n", var); + LOAD_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; @@ -3257,7 +3646,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 { - CONFIG_ERROR("Invalid %s parameter value, only accepted event is 'answer'\n", var); + LOAD_ERROR("Invalid %s parameter value, only accepted event is 'answer'\n", var); } } else if (!strcasecmp(var, "dial-regex")) { dial_regex = val; @@ -3287,7 +3676,7 @@ static switch_status_t load_config(void) } if (!id && !name) { - CONFIG_ERROR("span missing required param 'id'\n"); + LOAD_ERROR("span missing required param 'id'\n"); continue; } @@ -3317,7 +3706,7 @@ static switch_status_t load_config(void) } if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + LOAD_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); continue; } @@ -3338,7 +3727,7 @@ static switch_status_t load_config(void) "callwaiting", &callwaiting, "wait_dialtone_timeout", &dialtone_timeout, FTDM_TAG_END) != FTDM_SUCCESS) { - CONFIG_ERROR("Error configuring FreeTDM analog span %s\n", ftdm_span_get_name(span)); + LOAD_ERROR("Error configuring FreeTDM analog span %s\n", ftdm_span_get_name(span)); continue; } @@ -3348,7 +3737,6 @@ static switch_status_t load_config(void) SPAN_CONFIG[span_id].analog_options = analog_options | globals.analog_options; chaniter = ftdm_span_get_chan_iterator(span, NULL); - curr = chaniter; for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { fchan = ftdm_iterator_current(curr); ftdm_channel_set_private(fchan, &SPAN_CONFIG[span_id].pvts[i]); @@ -3414,7 +3802,7 @@ static switch_status_t load_config(void) } if (!id && !name) { - CONFIG_ERROR("span missing required param 'id'\n"); + LOAD_ERROR("span missing required param 'id'\n"); continue; } @@ -3445,7 +3833,7 @@ static switch_status_t load_config(void) } if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + LOAD_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); continue; } @@ -3459,7 +3847,7 @@ static switch_status_t load_config(void) "digit_timeout", &to, "max_dialstr", &max, FTDM_TAG_END) != FTDM_SUCCESS) { - CONFIG_ERROR("Error starting FreeTDM span %d\n", span_id); + LOAD_ERROR("Error starting FreeTDM span %d\n", span_id); continue; } @@ -3496,7 +3884,7 @@ static switch_status_t load_config(void) uint32_t span_id = 0; if (!name) { - CONFIG_ERROR("span missing required attribute 'name'\n"); + LOAD_ERROR("span missing required attribute 'name'\n"); continue; } @@ -3507,7 +3895,7 @@ static switch_status_t load_config(void) char *val = (char *) switch_xml_attr_soft(param, "value"); if (ftdm_array_len(spanparameters) - 1 == paramindex) { - CONFIG_ERROR("Too many parameters for pri span '%s', ignoring everything after '%s'\n", name, var); + LOAD_ERROR("Too many parameters for pri span '%s', ignoring everything after '%s'\n", name, var); break; } @@ -3529,13 +3917,13 @@ static switch_status_t load_config(void) zstatus = ftdm_span_find_by_name(name, &span); if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM span %s\n", name); + LOAD_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) { - CONFIG_ERROR("Error configuring FreeTDM span %s\n", name); + LOAD_ERROR("Error configuring FreeTDM span %s\n", name); continue; } @@ -3562,7 +3950,7 @@ static switch_status_t load_config(void) int span_id = 0; if (!name) { - CONFIG_ERROR("span missing required attribute 'name'\n"); + LOAD_ERROR("span missing required attribute 'name'\n"); continue; } @@ -3573,7 +3961,7 @@ static switch_status_t load_config(void) char *val = (char *) switch_xml_attr_soft(param, "value"); if (ftdm_array_len(spanparameters) - 1 == paramindex) { - CONFIG_ERROR("Too many parameters for pritap span '%s', ignoring everything after '%s'\n", name, var); + LOAD_ERROR("Too many parameters for pritap span '%s', ignoring everything after '%s'\n", name, var); break; } @@ -3590,13 +3978,13 @@ static switch_status_t load_config(void) zstatus = ftdm_span_find_by_name(name, &span); if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM span %s\n", name); + LOAD_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) { - CONFIG_ERROR("Error configuring FreeTDM span %s\n", name); + LOAD_ERROR("Error configuring FreeTDM span %s\n", name); continue; } @@ -3622,7 +4010,7 @@ static switch_status_t load_config(void) uint32_t span_id = 0; if (!name) { - CONFIG_ERROR("span missing required attribute 'name'\n"); + LOAD_ERROR("span missing required attribute 'name'\n"); continue; } @@ -3633,7 +4021,7 @@ static switch_status_t load_config(void) char *val = (char *) switch_xml_attr_soft(param, "value"); if (ftdm_array_len(spanparameters) - 1 == paramindex) { - CONFIG_ERROR("Too many parameters for libpri span, ignoring everything after '%s'\n", var); + LOAD_ERROR("Too many parameters for libpri span, ignoring everything after '%s'\n", var); break; } @@ -3655,13 +4043,13 @@ static switch_status_t load_config(void) zstatus = ftdm_span_find_by_name(name, &span); if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM span %s\n", name); + LOAD_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) { - CONFIG_ERROR("Error configuring FreeTDM span %s\n", name); + LOAD_ERROR("Error configuring FreeTDM span %s\n", name); continue; } @@ -3692,7 +4080,7 @@ static switch_status_t load_config(void) unsigned paramindex = 0; if (!name) { - CONFIG_ERROR("'name' attribute required for R2 spans!\n"); + LOAD_ERROR("'name' attribute required for R2 spans!\n"); continue; } @@ -3727,13 +4115,13 @@ static switch_status_t load_config(void) zstatus = ftdm_span_find_by_name(name, &span); if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM R2 Span '%s'\n", name); + LOAD_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) { - CONFIG_ERROR("Error configuring FreeTDM R2 span %s, error: %s\n", name, ftdm_span_get_last_error(span)); + LOAD_ERROR("Error configuring FreeTDM R2 span %s, error: %s\n", name, ftdm_span_get_last_error(span)); continue; } @@ -3751,7 +4139,7 @@ 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) { - CONFIG_ERROR("Error starting FreeTDM R2 span %s, error: %s\n", name, ftdm_span_get_last_error(span)); + LOAD_ERROR("Error starting FreeTDM R2 span %s, error: %s\n", name, ftdm_span_get_last_error(span)); continue; } } @@ -4335,38 +4723,38 @@ end: FTDM_CLI_DECLARE(ftdm_cmd_alarms) { - ftdm_alarm_flag_t alarmbits = FTDM_ALARM_NONE; - uint32_t chan_id = 0; - ftdm_span_t *span; + ftdm_alarm_flag_t alarmbits = FTDM_ALARM_NONE; + uint32_t chan_id = 0; + ftdm_span_t *span; - if (argc < 3) { - print_usage(stream, cli); - goto end; - } + if (argc < 3) { + print_usage(stream, cli); + goto end; + } - ftdm_span_find_by_name(argv[1], &span); - chan_id = atoi(argv[2]); - if (!span) { - stream->write_function(stream, "-ERR invalid span\n"); - } else if (chan_id) { - if (chan_id > ftdm_span_get_chan_count(span)) { - stream->write_function(stream, "-ERR invalid channel\n"); - } else { - ftdm_channel_t *chan = ftdm_span_get_channel(span, chan_id); - if (!chan) { - stream->write_function(stream, "-ERR channel not configured\n"); - } else { - ftdm_channel_get_alarms(chan, &alarmbits); - if (!strlen(ftdm_channel_get_last_error(chan))) { - stream->write_function(stream, "+OK No alarms\n"); - } else { - stream->write_function(stream, "-ERR %s on %s:%d\n", ftdm_channel_get_last_error(chan), argv[1], chan); - } - } - } - } + ftdm_span_find_by_name(argv[1], &span); + chan_id = atoi(argv[2]); + if (!span) { + stream->write_function(stream, "-ERR invalid span\n"); + } else if (chan_id) { + if (chan_id > ftdm_span_get_chan_count(span)) { + stream->write_function(stream, "-ERR invalid channel\n"); + } else { + ftdm_channel_t *chan = ftdm_span_get_channel(span, chan_id); + if (!chan) { + stream->write_function(stream, "-ERR channel not configured\n"); + } else { + ftdm_channel_get_alarms(chan, &alarmbits); + if (!strlen(ftdm_channel_get_last_error(chan))) { + stream->write_function(stream, "+OK No alarms\n"); + } else { + stream->write_function(stream, "-ERR %s on %s:%d\n", ftdm_channel_get_last_error(chan), argv[1], chan); + } + } + } + } end: - return SWITCH_STATUS_SUCCESS; + return SWITCH_STATUS_SUCCESS; } FTDM_CLI_DECLARE(ftdm_cmd_sigstatus) @@ -4802,7 +5190,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 }, }; @@ -4977,7 +5366,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load) SWITCH_ADD_APP(app_interface, "disable_ec", "Disable Echo Canceller", "Disable Echo Canceller", disable_ec_function, "", SAF_NONE); 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); - +#if 0 + ctdm_init(*module_interface); +#endif /* indicate that the module should continue to be loaded */ 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..0f8b5814c1 --- /dev/null +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -0,0 +1,712 @@ +/* +* 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" +#define kSPAN_NAME "span_name" +#define kPREBUFFER_LEN "prebuffer_len" +#define kECHOCANCEL "echo_cancel" + + +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; + int prebuffer_len; + + unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; +} 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_receive_event(switch_core_session_t *session, switch_event_t *event); +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 +}; + +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, + .receive_event = channel_receive_event +}; + +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-trap"); + } else { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-clear"); + } + + 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_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Reporting [%s] alarms for %s:%d\n", + (alarmflag?"ftdm-alarm-trap":"ftdm-alarm-clear"), ftdm_channel_get_span_name(channel), ftdm_channel_get_id(channel)); + + switch_event_fire(&event); + return; +} + +static ftdm_channel_t *ctdm_get_channel_from_event(switch_event_t *event, ftdm_span_t *span) +{ + uint32_t chan_id = 0; + const char *chan_number = NULL; + + chan_number = switch_event_get_header(event, "chan-number"); + + if (zstr(chan_number)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No channel number specified\n"); + return NULL; + } + 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 NULL; + } + + return ftdm_span_get_channel_ph(span, chan_id); +} + + +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 *cond = switch_event_get_header(event, "condition"); + const char *command = switch_event_get_header(event, "command"); + if (zstr(cond)) { + return; + } + + span_name = switch_event_get_header(event, "span-name"); + + 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, "%s:prepared successfully\n", span_name); + } else if (status != FTDM_EINVAL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s:Failed to prepare span\n", span_name); + } + } else if (!strcmp(cond, "mg-tdm-check")) { + channel = ctdm_get_channel_from_event(event, span); + if (!channel) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find channel\n"); + 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); + } else if (!strcmp(cond, "mg-tdm-dtmfremoval")) { + uint8_t enable = 0; + channel = ctdm_get_channel_from_event(event, span); + if (!channel) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find channel\n"); + return; + } + + if (zstr(command)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s:No command specified for mg-tdm-dtmfremoval\n", span_name); + return; + } + + if (!strcmp(command, "enable")) { + enable = 1; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s DTMF-removal for %s:%d\n", + enable ? "Enabling" : "Disabling", ftdm_channel_get_span_name(channel), ftdm_channel_get_id(channel)); + + ftdm_channel_command(channel, enable ? FTDM_COMMAND_ENABLE_DTMF_REMOVAL : FTDM_COMMAND_DISABLE_DTMF_REMOVAL, 0); + } + } + break; + default: + break; + } + return; +} + +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; + + 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, + 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 *szchanid = switch_event_get_header(var_event, kCHAN_ID), + *span_name = switch_event_get_header(var_event, kSPAN_NAME), + *szprebuffer_len = switch_event_get_header(var_event, kPREBUFFER_LEN); + int chan_id; + int span_id; + switch_caller_profile_t *caller_profile; + 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 = 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; + } + + chan_id = atoi(szchanid); + + 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", span_name); + 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; + } + + channel = switch_core_session_get_channel(*new_session); + + if (ftdm_channel_open_ph(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; + tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf); + tech_pvt->read_frame.data = tech_pvt->databuf; + tech_pvt->prebuffer_len = zstr(szprebuffer_len) ? 0 : atoi(szprebuffer_len); + 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); + + 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; + } + + if (FTDM_SUCCESS != ftdm_channel_command(chan, FTDM_COMMAND_SET_PRE_BUFFER_SIZE, &tech_pvt->prebuffer_len)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to set channel pre buffer size.\n"); + return SWITCH_STATUS_GENERR; + } + + if (FTDM_SUCCESS != ftdm_channel_command(tech_pvt->ftdm_channel, FTDM_COMMAND_ENABLE_ECHOCANCEL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to set enable echo cancellation.\n"); + } + + 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; + } + + switch_channel_mark_answered(channel); + + 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) +{ + 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) +{ + ctdm_private_t *tech_pvt = switch_core_session_get_private(session); + + if ((tech_pvt = switch_core_session_get_private(session))) { + + if (FTDM_SUCCESS != ftdm_channel_command(tech_pvt->ftdm_channel, FTDM_COMMAND_ENABLE_ECHOCANCEL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to enable echo cancellation.\n"); + } + + 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; + 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; + } + + 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; +} + +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"); + ctdm_private_t *tech_pvt = switch_core_session_get_private(session); + + if (!zstr(command)) { + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeTDM received %s command \n",command); + + if (!strcasecmp(command, kPREBUFFER_LEN)) { + const char *szval = switch_event_get_header(event, kPREBUFFER_LEN); + int val = !zstr(szval) ? atoi(szval) : 0; + + if (tech_pvt->prebuffer_len == val) { + tech_pvt->prebuffer_len = val; + if (FTDM_SUCCESS != ftdm_channel_command(tech_pvt->ftdm_channel, FTDM_COMMAND_SET_PRE_BUFFER_SIZE, &tech_pvt->prebuffer_len)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to set channel pre buffer size.\n"); + return SWITCH_STATUS_GENERR; + } + } + } else if (!strcasecmp(command, kECHOCANCEL)) { + const char *szval = switch_event_get_header(event, kECHOCANCEL); + int enabled = !!switch_true(szval); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeTDM sending echo cancel [%s] command \n",enabled ? "enable" : "disable"); + + if (FTDM_SUCCESS != ftdm_channel_command(tech_pvt->ftdm_channel, enabled ? FTDM_COMMAND_ENABLE_ECHOCANCEL : FTDM_COMMAND_DISABLE_ECHOCANCEL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to %s echo cancellation.\n", enabled ? "enable" : "disable"); + } + + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeTDM received unknown command [%s] \n",command); + } + } + + return SWITCH_STATUS_SUCCESS; +} + diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 6986804753..d99561566c 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -36,10 +36,10 @@ * David Yat Sin * */ - #define _GNU_SOURCE #include "private/ftdm_core.h" #include +#include #ifdef WIN32 #include #endif @@ -52,9 +52,7 @@ struct tm *localtime_r(const time_t *clock, struct tm *result); #endif -#define FORCE_HANGUP_TIMER 3000 -#define SPAN_PENDING_CHANS_QUEUE_SIZE 1000 -#define SPAN_PENDING_SIGNALS_QUEUE_SIZE 1000 +#define FORCE_HANGUP_TIMER 30000 #define FTDM_READ_TRACE_INDEX 0 #define FTDM_WRITE_TRACE_INDEX 1 #define MAX_CALLIDS 6000 @@ -64,11 +62,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 *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; @@ -171,7 +236,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) @@ -223,7 +288,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; @@ -1060,7 +1125,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; @@ -1413,13 +1478,24 @@ 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->span->signal_type == FTDM_SIGTYPE_M2UA) || + (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) { + 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; } @@ -1825,7 +1901,7 @@ done: return status; } -static ftdm_status_t _ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan) +static ftdm_status_t _ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan, uint8_t physical) { ftdm_channel_t *check = NULL; ftdm_span_t *span = NULL; @@ -1854,14 +1930,46 @@ static ftdm_status_t _ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm 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 (physical) { /* Open by physical */ + ftdm_channel_t *fchan = NULL; + ftdm_iterator_t *citer = NULL; + ftdm_iterator_t *curr = NULL; - 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; + if (chan_id < 1) { + ftdm_log(FTDM_LOG_ERROR, "Invalid physical channel %d to open in span %d\n", chan_id, span_id); + status = FTDM_FAIL; + goto done; + } + + citer = ftdm_span_get_chan_iterator(span, NULL); + if (!citer) { + status = ENOMEM; + goto done; + } + + for (curr = citer ; curr; curr = ftdm_iterator_next(curr)) { + fchan = ftdm_iterator_current(curr); + if (fchan->physical_chan_id == chan_id) { + check = fchan; + break; + } + } + + ftdm_iterator_free(citer); + if (!check) { + ftdm_log(FTDM_LOG_CRIT, "Wow, no physical channel %d in span %d\n", chan_id, span_id); + goto done; + } + } else { /* Open by logical */ + 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); @@ -1932,7 +2040,18 @@ done: FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan) { ftdm_status_t status; - status = _ftdm_channel_open(span_id, chan_id, ftdmchan); + status = _ftdm_channel_open(span_id, chan_id, ftdmchan, 0); + if (status == FTDM_SUCCESS) { + ftdm_channel_t *fchan = *ftdmchan; + ftdm_channel_unlock(fchan); + } + return status; +} + +FT_DECLARE(ftdm_status_t) ftdm_channel_open_ph(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan) +{ + ftdm_status_t status; + status = _ftdm_channel_open(span_id, chan_id, ftdmchan, 1); if (status == FTDM_SUCCESS) { ftdm_channel_t *fchan = *ftdmchan; ftdm_channel_unlock(fchan); @@ -2229,6 +2348,15 @@ static ftdm_status_t _ftdm_channel_call_hangup_nl(const char *file, const char * { ftdm_status_t status = FTDM_SUCCESS; + /* 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; + } + 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 */ @@ -2255,6 +2383,8 @@ static ftdm_status_t _ftdm_channel_call_hangup_nl(const char *file, const char * ftdm_channel_close(&chan); } } + +done: return status; } @@ -2313,6 +2443,39 @@ FT_DECLARE(ftdm_channel_t *) ftdm_span_get_channel(const ftdm_span_t *span, uint return chan; } +FT_DECLARE(ftdm_channel_t *) ftdm_span_get_channel_ph(const ftdm_span_t *span, uint32_t chanid) +{ + ftdm_channel_t *chan = NULL; + ftdm_channel_t *fchan = NULL; + ftdm_iterator_t *citer = NULL; + ftdm_iterator_t *curr = NULL; + + ftdm_mutex_lock(span->mutex); + if (chanid == 0) { + ftdm_mutex_unlock(span->mutex); + return NULL; + } + + citer = ftdm_span_get_chan_iterator(span, NULL); + if (!citer) { + ftdm_mutex_unlock(span->mutex); + return NULL; + } + + for (curr = citer ; curr; curr = ftdm_iterator_next(curr)) { + fchan = ftdm_iterator_current(curr); + if (fchan->physical_chan_id == chanid) { + chan = fchan; + break; + } + } + + ftdm_iterator_free(citer); + + ftdm_mutex_unlock(span->mutex); + return chan; +} + FT_DECLARE(uint32_t) ftdm_span_get_chan_count(const ftdm_span_t *span) { uint32_t count; @@ -2350,6 +2513,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), @@ -2450,10 +2622,56 @@ 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; + + 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); + 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"); @@ -2489,6 +2707,16 @@ 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_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) { @@ -2544,7 +2772,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_call_place(const char *file, const char *func, i status = _ftdm_channel_open_by_group(hunting->mode_data.group.group_id, hunting->mode_data.group.direction, caller_data, &fchan); } else if (hunting->mode == FTDM_HUNT_CHAN) { - status = _ftdm_channel_open(hunting->mode_data.chan.span_id, hunting->mode_data.chan.chan_id, &fchan); + status = _ftdm_channel_open(hunting->mode_data.chan.span_id, hunting->mode_data.chan.chan_id, &fchan, 0); } else { ftdm_log(FTDM_LOG_ERROR, "Cannot make outbound call with invalid hunting mode %d\n", hunting->mode); return FTDM_EINVAL; @@ -2692,6 +2920,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; @@ -3553,6 +3782,11 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_queue_dtmf(ftdm_channel_t *ftdmchan, cons ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Queuing DTMF %s (debug = %d)\n", dtmf, ftdmchan->dtmfdbg.enabled); + if (ftdmchan->span->sig_dtmf && (ftdmchan->span->sig_dtmf(ftdmchan, dtmf) == FTDM_BREAK)) { + /* Signalling module wants to absorb this DTMF event */ + return FTDM_SUCCESS; + } + if (!ftdmchan->dtmfdbg.enabled) { goto skipdebug; } @@ -4001,10 +4235,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_process_media(ftdm_channel_t *ftdmchan, v char digit_str[2] = { 0 }; digit_str[0] = digit_char; - - if (!ftdmchan->span->sig_dtmf || (ftdmchan->span->sig_dtmf(ftdmchan, (const char*)digit_str) != FTDM_BREAK)) { - ftdm_channel_queue_dtmf(ftdmchan, digit_str); - } + + ftdm_channel_queue_dtmf(ftdmchan, digit_str); if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF)) { ftdmchan->skip_read_frames = 20; @@ -4291,7 +4523,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, unsigned long long flagval, int not, int *count) { ftdm_hash_iterator_t *i = NULL; ftdm_span_t *span; @@ -4301,40 +4533,147 @@ 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, 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, ftdm_val2str(flag, channel_flag_strs, ftdm_array_len(channel_flag_strs), "invalid")); + } + } else { + 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, 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, ftdm_val2str(flag, channel_flag_strs, ftdm_array_len(channel_flag_strs), "invalid")); + } + } } } 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] flag !%d(!%s)\n", + fchan->span_id, fchan->chan_id, + fchan->physical_span_id, fchan->physical_chan_id, + 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] flag %d(%s)\n", + fchan->span_id, fchan->chan_id, + fchan->physical_span_id, fchan->physical_chan_id, + flagval, ftdm_val2str(flag, channel_flag_strs, ftdm_array_len(channel_flag_strs), "invalid")); + mycount++; + } + } + ftdm_iterator_free(citer); + } + } + *count = mycount; +end: + ftdm_mutex_unlock(globals.mutex); +} + +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; + 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); } @@ -4386,12 +4725,52 @@ 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 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"); } + +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 < array_size; i++) { + if (!strcasecmp(val_str_table[i].str, str)) { + return val_str_table[i].val; + } + } + return default_val; +} + +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 < array_size; i++) { + if (val_str_table[i].val == val) { + return val_str_table[i].str; + } + } + 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].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); + } +} + static char *handle_core_command(const char *cmd) { char *mycmd = NULL; @@ -4401,11 +4780,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); @@ -4446,6 +4826,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); @@ -4456,9 +4837,77 @@ 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 = 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); + } + + /* 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], "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; @@ -4923,14 +5372,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); @@ -5298,16 +5748,70 @@ 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) +{ + 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++) { + 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_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; - 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; + } + + //ftdm_report_initial_channels_alarms(span); + ftdm_set_flag_locked(span, FTDM_SPAN_STARTED); + goto done; + } if (!span->start) { status = FTDM_ENOSYS; @@ -5331,7 +5835,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; @@ -5516,8 +6019,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) @@ -5551,7 +6056,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_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)); @@ -5682,28 +6187,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 OFF (idle:%d)\n", (int) 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_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 ON (idle:%d)\n", (int) 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; } } @@ -5712,7 +6221,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 @@ -5814,8 +6327,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.reset_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; @@ -5824,10 +6337,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; diff --git a/libs/freetdm/src/ftdm_state.c b/libs/freetdm/src/ftdm_state.c index db4097e84b..614044ac3b 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; } @@ -87,6 +104,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; @@ -262,6 +280,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); @@ -353,6 +374,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_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 */ diff --git a/libs/freetdm/src/ftmod/ftmod_misdn/ftmod_misdn.c b/libs/freetdm/src/ftmod/ftmod_misdn/ftmod_misdn.c index 84133601f3..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: @@ -2265,18 +2288,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 */ @@ -2348,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)); 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 40a89a80c8..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 @@ -288,6 +288,9 @@ typedef struct sngisdn_span_data { uint8_t force_sending_complete; 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; @@ -305,7 +308,6 @@ 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; @@ -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_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c index 47da32d865..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) @@ -433,6 +433,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; @@ -615,6 +616,8 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_ parse_timer(val, &signal_data->timer_t322); } else if (!strcasecmp(var, "trunkgroup")) { /* Do nothing, we already parsed this parameter */ + } 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_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_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c index 946b9769b0..862d4d5584 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 @@ -738,6 +738,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) { 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 c8f179b1e8..c2d18f01a9 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 @@ -1202,7 +1202,16 @@ void sngisdn_process_rst_cfm (sngisdn_event_data_t *sngisdn_event) return; } - if (rstEvnt->rstInd.eh.pres == PRSNT_NODEF && rstEvnt->rstInd.rstClass.pres == PRSNT_NODEF) { + ftdm_log(FTDM_LOG_DEBUG, "%s: Processing RESTART CFM (suId:%u dChan:%d ces:%d %s(%d))\n", + signal_data->ftdm_span->name, + suId, dChan, ces, + (evntType == IN_LNK_DWN)?"LNK_DOWN": + (evntType == IN_LNK_UP)?"LNK_UP": + (evntType == IN_INDCHAN)?"b-channel": + (evntType == IN_LNK_DWN_DM_RLS)?"NFAS service procedures": + (evntType == IN_SWCHD_BU_DCHAN)?"NFAS switchover to backup":"Unknown", evntType); + + 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) { 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; 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..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 @@ -77,7 +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 = 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, @@ -92,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"); @@ -207,30 +209,22 @@ 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; + 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)) */ - /* 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)) */ + if (g_ftdm_sngss7_data.gen_config != SNG_GEN_CFG_STATUS_DONE) { + SS7_CRITICAL("General configuration FAILED!\n"); + return 1; + } x = 1; while (x < (MAX_MTP_LINKS)) { @@ -272,160 +266,203 @@ 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.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)) */ + + /* 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)) */ + } + + /* 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))) { + + 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)) */ + } + + /* 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_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.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.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 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("ISUP ISAP %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.isap[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_ISAPS)) */ - 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))) { + 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)) */ - if (ftmod_ss7_isup_ckt_config(x)) { - SS7_CRITICAL("ISUP CKT %d configuration FAILED!\n", x); + 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)) */ + + 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_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 9eb737a7f3..c1595c39dd 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 @@ -119,6 +119,15 @@ 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_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_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); /******************************************************************************/ /* FUNCTIONS ******************************************************************/ @@ -383,14 +392,87 @@ 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 { - /**********************************************************************/ + } 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)) { + stream->write_function(stream, "Unknown \"xmlshow\" command\n"); + goto handle_cli_error; + } + c++; + /**************************************************************************/ + if (!strcasecmp(argv[c], "m2ua")) { + /**************************************************************************/ + 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 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; + } + break; + } + default: + 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 \"xmlshow\" command\n"); + goto handle_cli_error; + } + /**********************************************************************/ } else if (!strcasecmp(argv[c], "set")) { /**************************************************************************/ if (check_arg_count(argc, 4)) goto handle_cli_error_argc; @@ -460,7 +542,6 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha } /**************************************************************************/ } else if (!strcasecmp(argv[c], "blo")) { - /**************************************************************************/ if (check_arg_count(argc, 2)) goto handle_cli_error_argc; c++; @@ -752,6 +833,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; @@ -785,16 +888,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"); @@ -803,9 +914,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"); @@ -821,6 +935,21 @@ 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 :\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 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"); + + + 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; @@ -1315,10 +1444,14 @@ 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 - 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) */ @@ -1327,6 +1460,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; } @@ -1360,36 +1520,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); @@ -1426,33 +1576,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); } @@ -1632,7 +1771,9 @@ 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_RESET_TX); + sngss7_set_ckt_flag (sngss7_info, FLAG_LOCAL_REL); + sngss7_clear_ckt_flag (sngss7_info, FLAG_REMOTE_REL); + sngss7_tx_reset_restart(sngss7_info); switch (ftdmchan->state) { /**************************************************************************/ @@ -1796,6 +1937,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); @@ -1929,6 +2072,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) { @@ -2719,20 +2863,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; } @@ -2949,6 +3095,904 @@ 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) +{ + MwMgmt cfm; + MwMgmt rsp; + char buf[2048]; + char* xmlhdr = (char*)""; + int x = 0x00; + int idx = 0x00; + int len = 0x00; + + 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); + len = len + sprintf(buf + len, "\n"); + + if(ftmod_m2ua_ssta_req(STMWGEN, 0x00, &cfm)) { + stream->write_function(stream," Request to layer failed \n"); + 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.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"); + 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 M2UA 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"); + } + + 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 M2UA 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"); + + 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++) + { + int peer_id = rsp.t.ssta.s.clusterSta.peerSt[idx].peerId; + + memset(&cfm, 0, sizeof(MwMgmt)); + + 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 M2UA 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", (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); + 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 M2UA 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", (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"); + } + + len = len + sprintf(buf + len, "\n"); + } + x++; + } + + len = len + sprintf(buf + len, "\n"); + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_SUCCESS; + +} + +/****************************************************************************** +* 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*)""; + char buf[4096]; + int x = 0x00; + int idx = 0x00; + 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); + + /*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"); + len = len + sprintf(buf + len, " %s \n", m2ua_profile_name); + + if(ftmod_m2ua_ssta_req(STMWDLSAP,x,&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", 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, 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", 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"); + } + + memcpy((U8 *)&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 M2UA 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); +#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); + 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 M2UA 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"); +#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"); + } + + len = len + sprintf(buf + len, "\n"); + + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_SUCCESS; + +} + +/****************************************************************************** +* 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*)""; + char buf[4096]; + 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 SCTP layer failed \n"); + 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); + 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 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 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 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)) { + 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 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_SUCCESS; +} + +int get_assoc_resp_buf(char* buf,SbMgmt* cfm) +{ + int len = 0x00; + int idx = 0x00; + 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); + 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; +} + +/****************************************************************************** +* 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*)""; + char buf[4096]; + 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 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 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)) { + /* 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 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; +} + +/****************************************************************************** +* 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*)""; + char buf[4096]; + 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 NIF layer failed \n"); + 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"); + } + + /*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 NIF 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)); +#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"); + } + + len = len + sprintf(buf + len, "\n"); + } + x++; + } + + len = len + sprintf(buf + len, "\n"); + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_SUCCESS; +} + +/****************************************************************************** +* 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*)""; + char buf[4096]; + 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 NIF 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)); +#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"); + } + + len = len + sprintf(buf + len, "\n"); + + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +/****************************************************************************** +* 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[4096]; + int x = 0x00; + 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); + + /*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]; + + 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 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 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); + + 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; +} + /******************************************************************************/ /* For Emacs: * Local Variables: 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..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 @@ -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 ******************************************************************/ @@ -88,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); @@ -100,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); @@ -120,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; @@ -779,7 +757,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)); + } } @@ -811,7 +796,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)); + } } @@ -848,7 +840,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 +868,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 24ea92e6db..65a8b3720f 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 * */ @@ -87,6 +88,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__); @@ -94,9 +97,11 @@ 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); + /* 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); @@ -118,11 +123,24 @@ 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 */ } + + 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) { @@ -167,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 */ @@ -178,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", " "); } @@ -192,12 +221,16 @@ 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); 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); + copy_cdPtyNum_from_sngss7(ftdmchan, &siConEvnt->cdPtyNum); /* fill in the TMR/bearer capability */ if (siConEvnt->txMedReq.eh.pres) { @@ -213,9 +246,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) { @@ -247,7 +277,8 @@ 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 ); + + 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) { @@ -308,24 +339,26 @@ 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 */ 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_tx_reset_restart(sngss7_info); + sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); + /* go to RESTART */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + } break; /**************************************************************************/ } /* switch (ftdmchan->state) */ @@ -344,6 +377,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)) { @@ -389,11 +424,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_tx_reset_restart(sngss7_info); + sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); - /* 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) */ @@ -422,10 +460,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, siCnStEvnt); + + sngss7_set_ckt_flag(sngss7_info, FLAG_INR_RX); + break; /**************************************************************************/ case (SUBSADDR): @@ -599,6 +653,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)) { @@ -651,10 +707,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_tx_reset_restart(sngss7_info); + sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); - /* go to RESTART */ - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + /* go to RESTART */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + } break; /**************************************************************************/ @@ -674,6 +733,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)) { @@ -750,6 +811,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.%s\n", " "); + ft_to_sngss7_rlc (ftdmchan); + goto rel_ind_reset; } break; /**************************************************************************/ @@ -772,11 +837,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); +rel_ind_reset: + /* throw the TX reset flag */ + if (!sngss7_tx_reset_status_pending(sngss7_info)) { + sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); + sngss7_tx_reset_restart(sngss7_info); - /* 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) */ @@ -796,6 +865,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)) { @@ -847,6 +918,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)) { @@ -874,6 +947,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)) { @@ -901,6 +976,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)) { @@ -928,6 +1005,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)) { @@ -955,6 +1034,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)) { @@ -982,6 +1063,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)) { @@ -1006,6 +1089,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)) { @@ -1098,11 +1183,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 */ @@ -1206,6 +1292,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) { @@ -1235,6 +1323,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); @@ -1242,14 +1331,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 */ @@ -1269,6 +1389,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; @@ -1333,6 +1455,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; @@ -1397,6 +1521,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) { @@ -1452,6 +1578,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) { @@ -1497,6 +1625,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) { @@ -1565,6 +1695,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) { @@ -1597,6 +1729,7 @@ ftdm_status_t handle_blo_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* 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); @@ -1615,6 +1748,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) { @@ -1656,6 +1791,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) { @@ -1744,6 +1881,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) { @@ -1784,6 +1923,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; /**************************************************************************/ @@ -1803,6 +1943,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) { @@ -1861,6 +2003,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) { @@ -1917,7 +2061,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; /**********************************************************************/ @@ -1951,6 +2095,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) { @@ -2008,6 +2154,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) { @@ -2072,6 +2220,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) { @@ -2122,6 +2272,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) { @@ -2177,6 +2329,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) { @@ -2215,6 +2368,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; @@ -2227,6 +2382,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 */ @@ -2256,7 +2412,10 @@ 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); memset(&status[0], '\0', sizeof(status)); @@ -2321,61 +2480,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 */ - 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); + + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + + /* 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)) { @@ -2402,8 +2556,11 @@ 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); memset(&sigev, 0, sizeof (sigev)); memset(&status[0], '\0', sizeof(status)); @@ -2470,57 +2627,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++; + } 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)) */ + + 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_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + ftdm_mutex_unlock(ftdmchan->mutex); + + /* update the bit and byte counter*/ + bit ++; + if (bit == 8) { + byte++; + bit = 0; + } + } } - - /* 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 */ - 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++) */ + x++; + } /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -2541,6 +2703,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_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_logger.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c index cdedf791ce..043bf03a35 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 @@ -114,6 +114,7 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) { char buf[50]; int x = 1; + int log_level = FTDM_LOG_LEVEL_DEBUG; memset(buf, '\0', sizeof(buf)); @@ -158,11 +159,22 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) break; case (LCM_CAUSE_UNKNOWN): default: - ftdm_log(FTDM_LOG_DEBUG,"[MTP2]%s cause:%s event:%s\n", - buf, - DECODE_LCM_CAUSE(sta->t.usta.alarm.cause), - DECODE_LSD_EVENT(sta->t.usta.alarm.event)); - break; + { + if ((LSD_EVENT_ALIGN_LOST == sta->t.usta.alarm.event) || + (LSD_EVENT_PROT_ST_DN == sta->t.usta.alarm.event)) { + log_level = FTDM_LOG_LEVEL_WARNING; + } else if ((LSD_EVENT_LINK_ALIGNED == sta->t.usta.alarm.event) || + (LSD_EVENT_PROT_ST_UP == sta->t.usta.alarm.event)){ + log_level = FTDM_LOG_LEVEL_INFO; + } else { + log_level = FTDM_LOG_LEVEL_WARNING; + } + ftdm_log(FTDM_PRE, log_level,"[MTP2]%s cause:%s event:%s\n", + buf, + DECODE_LCM_CAUSE(sta->t.usta.alarm.cause), + DECODE_LSD_EVENT(sta->t.usta.alarm.event)); + break; + } /******************************************************************/ } /* switch (sta->t.usta.alarm.cause) */ break; @@ -184,7 +196,7 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) sprintf(buf, "[%s]", g_ftdm_sngss7_data.cfg.mtp2Link[x].name); } - ftdm_log(FTDM_LOG_ERROR,"[MTP2]%s %s : %s\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2]%s %s : %s\n", buf, DECODE_LSD_EVENT(sta->t.usta.alarm.event), DECODE_LSD_CAUSE(sta->t.usta.alarm.cause)); @@ -207,7 +219,7 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) sprintf(buf, "[%s]", g_ftdm_sngss7_data.cfg.mtp2Link[x].name); } - ftdm_log(FTDM_LOG_DEBUG,"[MTP2]%s %s : %s\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2]%s %s : %s\n", buf, DECODE_LSD_EVENT(sta->t.usta.alarm.event), DECODE_DISC_REASON(sta->t.usta.evntParm[1])); @@ -231,7 +243,7 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) sprintf(buf, "[%s]", g_ftdm_sngss7_data.cfg.mtp2Link[x].name); } - ftdm_log(FTDM_LOG_ERROR,"[MTP2]%s %s : RTB Queue Len(%d)|Oldest BSN(%d)|Tx Queue Len(%d)|Outstanding Frames(%d)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2]%s %s : RTB Queue Len(%d)|Oldest BSN(%d)|Tx Queue Len(%d)|Outstanding Frames(%d)\n", buf, DECODE_LSD_EVENT(sta->t.usta.alarm.event), sta->t.usta.evntParm[1], @@ -257,7 +269,7 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) sprintf(buf, "[%s]", g_ftdm_sngss7_data.cfg.mtp2Link[x].name); } - ftdm_log(FTDM_LOG_ERROR,"[MTP2]%s %s : RTB Queue Len(%d)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2]%s %s : RTB Queue Len(%d)\n", buf, DECODE_LSD_EVENT(sta->t.usta.alarm.event), sta->t.usta.evntParm[1]); @@ -280,7 +292,7 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) sprintf(buf, "[%s]", g_ftdm_sngss7_data.cfg.mtp2Link[x].name); } - ftdm_log(FTDM_LOG_ERROR,"[MTP2]%s %s : %s\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2]%s %s : %s\n", buf, DECODE_LSD_EVENT(sta->t.usta.alarm.event), DECODE_DISC_REASON(sta->t.usta.evntParm[1])); @@ -288,7 +300,7 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) /**********************************************************************/ case (LCM_EVENT_UI_INV_EVT): case (LCM_EVENT_LI_INV_EVT): - ftdm_log(FTDM_LOG_ERROR,"[MTP2] %s(%d) : %s(%d) : Primitive (%d)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2] %s(%d) : %s(%d) : Primitive (%d)\n", DECODE_LSD_EVENT(sta->t.usta.alarm.event), sta->t.usta.alarm.event, DECODE_LCM_CAUSE(sta->t.usta.alarm.cause), @@ -302,14 +314,14 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) /******************************************************************/ case (LCM_CAUSE_UNKNOWN): case (LCM_CAUSE_SWVER_NAVAIL): - ftdm_log(FTDM_LOG_ERROR,"[MTP2] %s : %s : Event (%d)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2] %s : %s : Event (%d)\n", DECODE_LSD_EVENT(sta->t.usta.alarm.event), DECODE_LCM_CAUSE(sta->t.usta.alarm.cause), sta->t.usta.evntParm[0]); break; /******************************************************************/ case (LCM_CAUSE_DECODE_ERR): - ftdm_log(FTDM_LOG_ERROR,"[MTP2] %s : %s : Primitive (%d)|Version (%d)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2] %s : %s : Primitive (%d)|Version (%d)\n", DECODE_LSD_EVENT(sta->t.usta.alarm.event), DECODE_LCM_CAUSE(sta->t.usta.alarm.cause), sta->t.usta.evntParm[0], @@ -317,7 +329,7 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) break; /******************************************************************/ default: - ftdm_log(FTDM_LOG_ERROR,"[MTP2] %s(%d) : %s(%d)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2] %s(%d) : %s(%d)\n", DECODE_LSD_EVENT(sta->t.usta.alarm.event), sta->t.usta.alarm.event, DECODE_LSD_CAUSE(sta->t.usta.alarm.cause), @@ -328,7 +340,7 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) break; /**********************************************************************/ default: - ftdm_log(FTDM_LOG_ERROR,"[MTP2] %s(%d) : %s(%d)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2] %s(%d) : %s(%d)\n", DECODE_LSD_EVENT(sta->t.usta.alarm.event), sta->t.usta.alarm.event, DECODE_LSD_CAUSE(sta->t.usta.alarm.cause), @@ -381,7 +393,7 @@ void handle_sng_mtp3_alarm(Pst *pst, SnMngmt *sta) /**********************************************************************/ case (LSN_EVENT_INV_OPC_OTHER_END): - ftdm_log(FTDM_LOG_ERROR,"[MTP3]%s %s : %s : OPC(0x%X%X%X%X)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP3]%s %s : %s : OPC(0x%X%X%X%X)\n", buf, DECODE_LSN_EVENT(sta->t.usta.alarm.event), DECODE_LSN_CAUSE(sta->t.usta.alarm.cause), @@ -392,7 +404,7 @@ void handle_sng_mtp3_alarm(Pst *pst, SnMngmt *sta) break; /**********************************************************************/ case (LSN_EVENT_INV_SLC_OTHER_END): - ftdm_log(FTDM_LOG_ERROR,"[MTP3]%s %s : %s : SLC(%d)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP3]%s %s : %s : SLC(%d)\n", buf, DECODE_LSN_EVENT(sta->t.usta.alarm.event), DECODE_LSN_CAUSE(sta->t.usta.alarm.cause), @@ -400,7 +412,7 @@ void handle_sng_mtp3_alarm(Pst *pst, SnMngmt *sta) break; /**********************************************************************/ default: - ftdm_log(FTDM_LOG_DEBUG,"[MTP3]%s %s(%d) : %s(%d)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP3]%s %s(%d) : %s(%d)\n", buf, DECODE_LSN_EVENT(sta->t.usta.alarm.event), sta->t.usta.alarm.event, @@ -412,7 +424,7 @@ void handle_sng_mtp3_alarm(Pst *pst, SnMngmt *sta) break; /**************************************************************************/ case (STNSAP): - ftdm_log(FTDM_LOG_ERROR,"[MTP3][SAPID:%d] %s : %s\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP3][SAPID:%d] %s : %s\n", sta->hdr.elmId.elmntInst1, DECODE_LSN_EVENT(sta->t.usta.alarm.event), DECODE_LSN_CAUSE(sta->t.usta.alarm.cause)); @@ -463,7 +475,7 @@ void handle_sng_mtp3_alarm(Pst *pst, SnMngmt *sta) break; /**********************************************************************/ default: - ftdm_log(FTDM_LOG_ERROR,"[MTP3][DPC:0x%X%X%X%X] %s : %s\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP3][DPC:0x%X%X%X%X] %s : %s\n", sta->t.usta.evntParm[0], sta->t.usta.evntParm[1], sta->t.usta.evntParm[2], @@ -733,7 +745,7 @@ void handle_sng_isup_alarm(Pst *pst, SiMngmt *sta) } /* switch (sta->t.usta.dgn.dgnVal[x].t.type) */ } /* for (x = 0; x < 5; x++) */ - ftdm_log(FTDM_LOG_ERROR,"%s %s : %s\n", + ftdm_log(FTDM_LOG_WARNING,"%s %s : %s\n", msg, DECODE_LSI_EVENT(sta->t.usta.alarm.event), DECODE_LSI_CAUSE(sta->t.usta.alarm.cause)); @@ -759,7 +771,7 @@ void handle_sng_relay_alarm(Pst *pst, RyMngmt *sta) switch (sta->hdr.elmId.elmnt) { /**************************************************************************/ case (LRY_USTA_ERR): /* ERROR */ - ftdm_log(FTDM_LOG_ERROR,"[RELAY] Error: tx procId %d: err procId %d: channel %d: seq %s: reason %s\n", + ftdm_log(FTDM_LOG_WARNING,"[RELAY] Error: tx procId %d: err procId %d: channel %d: seq %s: reason %s\n", sta->t.usta.s.ryErrUsta.sendPid, sta->t.usta.s.ryErrUsta.errPid, sta->t.usta.s.ryErrUsta.id, @@ -783,7 +795,7 @@ void handle_sng_relay_alarm(Pst *pst, RyMngmt *sta) break; /**************************************************************************/ case (LRY_USTA_CNG): /* Congestion */ - ftdm_log(FTDM_LOG_ERROR,"[RELAY] Congestion: tx procId %d: rem procId %d: channel %d: %s\n", + ftdm_log(FTDM_LOG_WARNING,"[RELAY] Congestion: tx procId %d: rem procId %d: channel %d: %s\n", sta->t.usta.s.ryCongUsta.sendPid, sta->t.usta.s.ryCongUsta.remPid, sta->t.usta.s.ryCongUsta.id, @@ -791,7 +803,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); @@ -801,7 +813,7 @@ void handle_sng_relay_alarm(Pst *pst, RyMngmt *sta) break; /**************************************************************************/ case (LRY_USTA_DN): /* channel down */ - ftdm_log(FTDM_LOG_ERROR,"[RELAY] Channel DOWN: tx procId %d: channel %d\n", + ftdm_log(FTDM_LOG_WARNING,"[RELAY] Channel DOWN: tx procId %d: channel %d\n", sta->t.usta.s.ryUpUsta.sendPid, sta->t.usta.s.ryUpUsta.id); @@ -810,6 +822,11 @@ void handle_sng_relay_alarm(Pst *pst, RyMngmt *sta) break; /**************************************************************************/ + case (LRY_USTA_TCP_CONN_FAILED): + ftdm_log(FTDM_LOG_WARNING,"[RELAY] TCP connection failed \n" ); + + break; + /**************************************************************************/ default: ftdm_log(FTDM_LOG_ERROR,"Unknown Relay Alram\n"); break; @@ -819,6 +836,311 @@ void handle_sng_relay_alarm(Pst *pst, RyMngmt *sta) return; } +/******************************************************************************/ +void handle_sng_m2ua_alarm(Pst *pst, MwMgmt *sta) +{ + /* 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_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"); + 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); + 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)," + " 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 (%u), ntfy status type (%d)," + " ntfy status id (%d)\n\n", sta->t.usta.s.peerId, + (uint32_t) 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 (%u)\n\n", + (uint32_t) sta->t.usta.t.error.errCode); + break; + } + default: + break; + } + +} /* handle_sng_m2ua_alarm */ + +/******************************************************************************/ +void handle_sng_nif_alarm(Pst *pst, NwMgmt *sta) +{ + /* 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) +{ + /* 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_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 */ +/******************************************************************************/ + + /******************************************************************************/ /* 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..810c5a2902 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c @@ -0,0 +1,1773 @@ +/* + * 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_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 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); +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_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_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); +static int ftmod_ss7_tucl_shutdown(void); + + +/******************************************************************************/ +ftdm_status_t ftmod_ss7_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"); + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_TUCL_PRESENT); + } + /****************************************************************************************************/ + + 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_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_m2ua_gen_config()) { + 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"); + } + /****************************************************************************************************/ + if(ftmod_nif_gen_config()){ + 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"); + } + /****************************************************************************************************/ + + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +void ftmod_ss7_m2ua_free() +{ + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_M2UA_PRESENT)) { + ftmod_ss7_m2ua_shutdown(); + sng_isup_free_m2ua(); + } + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_SCTP_PRESENT)) { + ftmod_ss7_sctp_shutdown(); + sng_isup_free_sctp(); + } + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_TUCL_PRESENT)) { + ftmod_ss7_tucl_shutdown(); + 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) +{ + int x=0; + + /* 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 ,"SCTP Configuration : OK\n"); + } + + /****************************************************************************************************/ + /* M2UA SCTP SAP configurations */ + x = 1; + while(xspId = 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; + 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_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)); +} + +/****************************************************************************************************/ +static int ftmod_cfg_sctp(void) +{ + int x=0; + + x = 1; + while(xid; + + c = &cfg.t.cfg.s.tSapCfg; + 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 = k->id; + c->reConfig.maxBndRetry = 3; + c->reConfig.tIntTmr = 200; + + ret = sng_cfg_sctp(&pst, &cfg); + 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); + return FTDM_FAIL; + } +} + +/****************************************************************************************************/ + +ftdm_status_t ftmod_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 = 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; + /* 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 (0 == ret) { + 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 int ftmod_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 = 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 = 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 */ + 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)); +} + +/**********************************************************************************************/ +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; + + 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++){ + 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_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[%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[%d] configuration for M2UA Intf Id[%d] config SUCCESS \n", peer_id, 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 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; + + /* 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 = sct_sap_id; + /* service provider ID */ + cfg.t.cfg.s.sctSapCfg.spId = sctp_id; + /* source port number */ + cfg.t.cfg.s.sctSapCfg.srcPort = sctp->port; + /* interface address */ + /*For multiple IP address support */ +#ifdef SCT_ENDP_MULTI_IPADDR + 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 = sctp->srcAddrList[1]; +#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; + + if (0 == (ret = sng_cfg_m2ua (&pst, &cfg))){ + sctp->flags |= SNGSS7_CONFIGURED; + } + + return ret; +} + +/****************************************************************************************************/ + +/* M2UA - Peer configuration */ +static int ftmod_m2ua_peer_config1(int m2ua_inf_id, int peer_id) +{ + int i; + Pst pst; + MwMgmt cfg; + 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)); + 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 = peer->id; /* peer id */ + cfg.t.cfg.s.peerCfg.aspIdFlag = peer->aspIdFlag; /* aspId flag */ +#ifdef MWASP + cfg.t.cfg.s.peerCfg.selfAspId = peer->selfAspId; /* aspId */ +#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 = 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++) { + 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 = peer->locOutStrms; +#ifdef SCT3 + cfg.t.cfg.s.peerCfg.assocCfg.tos = 0; +#endif + + return (sng_cfg_m2ua (&pst, &cfg)); +} +/**********************************************************************************************/ +/* M2UA - Cluster configuration */ +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)); + + 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 = 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 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)); + + 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; + + + 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 = m2ua->iid; + + cfg.t.cfg.s.dlSapCfg.swtch = LMW_SAP_ITU; + + 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; + 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 - General configuration */ +static int ftmod_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 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)); + + 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; + 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; + 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)); +} + +/*****************************************************************************/ +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; +} +/***********************************************************************************************************************/ +void ftmod_ss7_enable_m2ua_sg_logging(void){ + + /* Enable DEBUGs*/ + ftmod_sctp_debug(AENA); + ftmod_m2ua_debug(AENA); + ftmod_tucl_debug(AENA); +} + +/***********************************************************************************************************************/ +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; + while(xclusterId]; + + 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)); + + 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 = m2ua->id; /* M2UA sct sap Id */ + + + if(0 == (ret = sng_cntrl_m2ua (&pst, &cntrl))){ + clust->flags |= SNGSS7_M2UA_EP_OPENED; + } + return ret; + +} + +/***********************************************************************************************************************/ +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)); +} + +/***********************************************************************************************************************/ +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)); + + 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 = k->id; /* SCT sap id configured at SCTP layer */ + + return (sng_cntrl_sctp (&pst, &cntrl)); +} +/***********************************************************************************************************************/ + +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)); + + 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 = m2ua->id; + + if(0 == (ret = sng_cntrl_m2ua (&pst, &cntrl))){ + clust->flags |= SNGSS7_ACTIVE; + } + return ret; +} +/***********************************************************************************************************************/ +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)); + + 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 = nif->id; /* NIF DL sap Id */ + cntrl.t.cntrl.entity = ENTMW; /* M2UA */ + + return (sng_cntrl_nif (&pst, &cntrl)); + +} + +/***********************************************************************************************************************/ +static int ftmod_nif_mtp2_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)); + + 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 = nif->id; /* NIF DL sap Id */ + cntrl.t.cntrl.entity = ENTSD; /* MTP2 */ + + return (sng_cntrl_nif (&pst, &cntrl)); + +} + +/***********************************************************************************************************************/ +static int ftmod_sctp_debug(int action) +{ + 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 = action; + cntrl.t.cntrl.subAction = SADBG; + cntrl.t.cntrl.dbgMask = 0xFFFF; + + return (sng_cntrl_sctp (&pst, &cntrl)); +} +/***********************************************************************************************************************/ + +static int ftmod_m2ua_debug(int action) +{ + 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 = action; + cntrl.t.cntrl.subAction = SADBG; + cntrl.t.cntrl.s.dbgMask = 0xFFFF; + + return (sng_cntrl_m2ua (&pst, &cntrl)); +} +/***********************************************************************************************************************/ +static int ftmod_tucl_debug(int action) +{ + 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 = action; + cntrl.t.cntrl.subAction = SADBG; + cntrl.t.cntrl.ctlType.hiDbg.dbgMask = 0xFFFF; + + 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) + { + /*TODO - how to get assoc Id*/ + ssta.t.ssta.s.assocSta.assocId = 0; /* association id */ + } + return(sng_sta_sctp(&pst,&ssta,cfm)); +} + +int ftmod_m2ua_ssta_req(int elemt, int id, MwMgmt* cfm) +{ + MwMgmt ssta; + Pst pst; + sng_m2ua_cfg_t* m2ua = NULL; + sng_m2ua_cluster_cfg_t* clust = NULL; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&ssta, 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: + { + m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[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: + { + ssta.t.ssta.id.lnkNmb = id ; /* upper sap Id */ + break; + } + case STMWPEER: + { + ssta.t.ssta.id.peerId = 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; + } + default: + break; + } + + return(sng_sta_m2ua(&pst,&ssta,cfm)); +} + +int ftmod_nif_ssta_req(int elemt, int id, NwMgmt* cfm) +{ + NwMgmt ssta; + 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)); + + 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.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 */ + + return(sng_sta_nif(&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 new file mode 100644 index 0000000000..8bb564d284 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h @@ -0,0 +1,136 @@ +/* + * 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 */ + 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 */ +}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 */ + 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; + +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 */ + 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 */ + 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+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 */ +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); +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); +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); +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__*/ 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..bb011c364e --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c @@ -0,0 +1,690 @@ +/* + * 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 int ftmod_ss7_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)); + + 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); + 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, "m2ua-interface-id")) { + /**********************************************************************/ + sng_nif.m2uaLnkNmb = atoi(parm->val); + SS7_DEBUG("Found an nif m2ua-interface-id = %d\n", sng_nif.m2uaLnkNmb); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp2-interface-id")) { + /**********************************************************************/ + sng_nif.mtp2LnkNmb=atoi(parm->val); + + SS7_DEBUG("Found an nif mtp2-interface-id = %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++) */ + + /* 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; + + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_NIF_PRESENT); + + 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)); + + 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); + 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, "m2ua-cluster-interface-id")) { + /**********************************************************************/ + sng_m2ua.clusterId=atoi(parm->val); + + 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); + return FTDM_FAIL; + /**********************************************************************/ + } + + /* move to the next parameter */ + parm = parm + 1; + /**************************************************************************/ + } /* for (i = 0; i < num_parms; i++) */ + + sng_m2ua.nodeType = SNG_M2UA_NODE_TYPE_SGP; + + /* 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].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; +} + +/******************************************************************************/ +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)); + + 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); + 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, "include-asp-identifier")) { + /**********************************************************************/ + 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, "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-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, "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, "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); + } else { + SS7_ERROR("sng_m2ua_peer - too many dest address configured. dropping %s \n", parm->val); + } + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "number-of-outgoing-streams")) { + /**********************************************************************/ + sng_m2ua_peer.locOutStrms=atoi(parm->val); + + SS7_DEBUG("Found an sng_m2ua_peer number-of-outgoing-streams = %d\n", sng_m2ua_peer.locOutStrms); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "init-sctp-association")) { + /**********************************************************************/ + 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); + return FTDM_FAIL; + /**********************************************************************/ + } + + /* move to the next parameter */ + parm = parm + 1; + /**************************************************************************/ + } /* for (i = 0; i < num_parms; i++) */ + + /* 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; + 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]; + } + + + 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)); + + 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); + 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, "traffic-mode")) { + /**********************************************************************/ + 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, "load-share-algorithm")) { + /**********************************************************************/ + if(!strcasecmp(parm->val, "roundrobin")){ + sng_m2ua_cluster.loadShareAlgo = SNG_M2UA_LOAD_SHARE_ALGO_RR; + } else if(!strcasecmp(parm->val, "linkspecified")){ + sng_m2ua_cluster.loadShareAlgo = SNG_M2UA_LOAD_SHARE_ALGO_LS; + } 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); + return FTDM_FAIL; + } + + SS7_DEBUG("Found an sng_m2ua_cluster.loadShareAlgo = %d\n", sng_m2ua_cluster.loadShareAlgo); + /**********************************************************************/ + } 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); + 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+1); + 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++) */ + + /* 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_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; + 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; +} + +/******************************************************************************/ +int ftmod_ss7_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_ss7_parse_sctp_link(node_sctp_link) != FTDM_SUCCESS) { + SS7_ERROR("SCTP - Failed to parse . \n"); + return FTDM_FAIL; + } + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +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){ + SS7_ERROR("SCTP - NULL XML Node pointer \n"); + 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, "address")) { + 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 if (!strcasecmp(param->var, "source-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); + } + } + + 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].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]; + } + + 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.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 049aa1546d..55b95f6acf 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 * */ @@ -49,12 +50,14 @@ 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; /******************************************************************************/ /* 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); @@ -289,24 +292,45 @@ 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 [%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; + + /* 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->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_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 %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 { - sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); + } else if (e->enum_id == FTDM_OOB_ALARM_CLEAR) { + SS7_DEBUG_CHAN(ftdmchan,"handle_hw_alarm: Clear %s \n", " "); 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); + 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 %s\n"," "); + if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + } } } } @@ -314,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; @@ -332,6 +380,8 @@ 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); + + /* 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); @@ -344,6 +394,42 @@ 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; + /**********************************************************************/ + } + check_span_oob_events(ftdmspan); + + /* signal the core that sig events are queued for processing */ + ftdm_span_trigger_signals(ftdmspan); + } + goto ftdm_sangoma_ss7_stop; + } + while (ftdm_running () && !(ftdm_test_flag (ftdmspan, FTDM_SPAN_STOP_THREAD))) { int x = 0; if (b_alarm_test) { @@ -360,9 +446,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); + 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); @@ -371,18 +460,27 @@ 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 */ /* 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); @@ -441,31 +539,15 @@ 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: /* 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; @@ -487,6 +569,8 @@ 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)) { @@ -500,6 +584,95 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev /* 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) { + clone_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++; + } + + 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)) { + 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); + } + } + } + + /* clone the event and save it for later usage, we do not clone RLC messages */ + if (clone_event) { + event_clone = ftdm_calloc(1, sizeof(*sngss7_event)); + if (event_clone) { + memcpy(event_clone, sngss7_event, sizeof(*sngss7_event)); + /* if we have already a peer channel then enqueue the event in their queue */ + if (sngss7_info->peer_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_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++; + } + } + } + } + + /* 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_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + break; + default: + break; + } + goto done; + } + /* figure out the type of event and send it to the right handler */ switch (sngss7_event->event_id) { /**************************************************************************/ @@ -552,6 +725,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: @@ -560,6 +734,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); @@ -568,15 +743,372 @@ 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 && 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 (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) { + + case (SNGSS7_CON_IND_EVENT): + SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]Rx IAM while 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); + 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); + 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); + 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): + //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); + 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_CRITICAL("dazed and confused ... hu?!\n"); + break; + /**************************************************************************/ + default: + SS7_ERROR("Failed to relay unknown event id %d!\n", sngss7_event->event_id); + break; + /**************************************************************************/ + } + + 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)) { + 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); + } + } +} + +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: + { + 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); + } + 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: + { + /* 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 */ + 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; + + 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; 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); + + 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, + * 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); + } + } /*check what state we are supposed to be in */ switch (ftdmchan->state) { @@ -598,23 +1130,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) { @@ -670,6 +1270,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; @@ -680,6 +1289,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); @@ -729,6 +1343,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; @@ -748,7 +1368,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; @@ -798,6 +1423,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; /**************************************************************************/ @@ -840,19 +1473,24 @@ 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)) { 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); } 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 */ @@ -871,7 +1509,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)) { /* go to the down state as we have already received RSC-RLC */ @@ -887,16 +1525,21 @@ 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; /**************************************************************************/ 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 */ @@ -953,23 +1596,25 @@ 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", ""); /* 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; + SS7_DEBUG_CHAN(ftdmchan,"Down detected blocked flags go to SUSPEND %s\n", " "); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + break; + + } } else { SS7_DEBUG_CHAN(ftdmchan,"Reset flags present (0x%X)\n", sngss7_info->ckt_flags); @@ -977,7 +1622,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) { @@ -994,37 +1639,71 @@ 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)) { 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); } /* 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; } } 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)) || (sngss7_test_ckt_flag(sngss7_info, FLAG_GRP_RESET_RX))) { @@ -1131,6 +1810,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); } } @@ -1139,10 +1819,27 @@ 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", - 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)) { + /* 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); + 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); + } + } + } + /**********************************************************************/ if (sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_RESUME)) { @@ -1154,14 +1851,45 @@ 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 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))) { + /* 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 + 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. */ + 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 */ - 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 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 { /* bring the sig status back up */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); @@ -1176,6 +1904,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)) { */ /**********************************************************************/ @@ -1193,8 +1924,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)){ @@ -1207,17 +1936,18 @@ 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; } @@ -1237,46 +1967,50 @@ 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)) { + int skip_unblock=0; SS7_DEBUG_CHAN(ftdmchan, "Processing FLAG_GRP_HW_UNBLK_TX flag %s\n", ""); + 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 - ) - ) - ) { + 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) { + 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); } - 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 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; @@ -1288,16 +2022,18 @@ 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); + } + + /* 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)) { @@ -1313,10 +2049,8 @@ 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)) { SS7_DEBUG_CHAN(ftdmchan, "Processing CKT_MN_UNBLK_TX flag %s\n", ""); @@ -1328,17 +2062,18 @@ 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 */ + 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); } - /* check the last state and return to it to allow the call to finish */ - goto suspend_goto_last; } /**********************************************************************/ @@ -1348,13 +2083,20 @@ 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); + + 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); + } - /* 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)) { @@ -1369,11 +2111,13 @@ 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); + } - /* 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) && @@ -1395,8 +2139,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)) { @@ -1410,6 +2152,15 @@ 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); /* bring the channel into restart again */ @@ -1419,6 +2170,53 @@ 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_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 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 ); + + } 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; ftdm_set_state(ftdmchan, ftdmchan->last_state); break; @@ -1469,8 +2267,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 */ @@ -1495,6 +2295,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){ /**************************************************************************/ @@ -1566,7 +2374,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 x; + int first_channel; + + first_channel=0; SS7_INFO ("Starting span %s:%u.\n", span->name, span->span_id); @@ -1614,10 +2425,12 @@ static ftdm_status_t ftdm_sangoma_ss7_start(ftdm_span_t * span) #if 0 /* 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 */ @@ -1651,6 +2464,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 +2473,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 */ @@ -1722,15 +2543,23 @@ 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"); + ftdm_sleep (100); return FTDM_FAIL; } - /* configure libsngss7 */ - if (ft_to_sngss7_cfg_all()) { + if(SNG_SS7_OPR_MODE_M2UA_SG == g_ftdm_operating_mode){ + ftdm_log (FTDM_LOG_INFO, "FreeTDM running as M2UA_SG mode, Setting Span type to FTDM_SIGTYPE_M2UA\n"); + span->signal_type = FTDM_SIGTYPE_M2UA; + } + + if (ft_to_sngss7_cfg_all()) { /* configure libsngss7 */ ftdm_log (FTDM_LOG_CRIT, "Failed to configure LibSngSS7!\n"); + ftdm_sleep (100); return FTDM_FAIL; } @@ -1790,6 +2619,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); @@ -1798,9 +2631,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; } @@ -1870,6 +2700,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(); 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..4035eeed67 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__ @@ -46,17 +52,20 @@ #include "private/ftdm_core.h" #include "sng_ss7/sng_ss7.h" +#include "ftmod_sangoma_ss7_m2ua.h" /******************************************************************************/ /* DEFINES ********************************************************************/ #define MAX_NAME_LEN 25 -#define MAX_PATH 4096 #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 +#define SNGSS7_CHAN_EVENT_QUEUE_SIZE 100 #define MAX_SIZEOF_SUBADDR_IE 24 /* as per Q931 4.5.9 */ @@ -64,6 +73,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; @@ -82,8 +99,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), @@ -117,6 +138,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]; @@ -176,6 +203,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; @@ -328,6 +370,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 */ @@ -339,8 +382,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; @@ -351,6 +397,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; @@ -404,11 +451,34 @@ 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 port; + 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; - 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]; @@ -421,6 +491,10 @@ 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; + 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 { @@ -433,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; @@ -472,10 +554,14 @@ 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; sngss7_group_data_t ucic; + ftdm_queue_t *event_queue; + struct sngss7_chan_data *peer_data; + uint8_t peer_event_transfer_cnt; } sngss7_chan_data_t; #define SNGSS7_RX_GRS_PENDING (1 << 0) @@ -533,6 +619,18 @@ typedef enum { FLAG_INFID_RESUME = (1 << 14), 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_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; @@ -541,20 +639,28 @@ 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", \ "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) @@ -588,7 +694,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 \ @@ -652,11 +758,27 @@ 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_M2UA_EP_OPENED = (1 << 20), + SNGSS7_M2UA_INIT_ASSOC_DONE = (1 << 21), + + SNGSS7_NIF_PRESENT = (1 << 22), + SNGSS7_NIF_STARTED = (1 << 23), + } sng_task_flag_t; /******************************************************************************/ /* 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[]; @@ -679,6 +801,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); @@ -731,7 +857,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); @@ -767,6 +895,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, SiCnStEvnt *inr); + /* in ftmod_sangoma_ss7_in.c */ @@ -835,15 +966,27 @@ 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_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); 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_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); +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); @@ -889,6 +1032,8 @@ 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); + /******************************************************************************/ @@ -910,9 +1055,9 @@ 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 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,...) @@ -1039,6 +1184,40 @@ 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 | \ + FLAG_GRP_HW_UNBLK_TX | \ + FLAG_CKT_MN_UNBLK_TX ))) + +#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_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)) && \ + (!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 #define SS7_RELAY_DBG(a,...) printf(a"\n", ##__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 b729552092..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 @@ -44,8 +44,11 @@ /* FUNCTIONS ******************************************************************/ 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;; + sngss7_event_data_t *event_clone = NULL; SS7_FUNC_TRACE_ENTER (__FUNCTION__); @@ -55,9 +58,113 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) memset (&iam, 0x0, sizeof (iam)); - if (sngss7_info->circuit->transparent_iam && + 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); + } else { + 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 { + 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); + + /* retrieve only first message from the others guys queue (must be IAM) */ + event_clone = ftdm_queue_dequeue(peer_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; + } + } + } + + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { + if (!event_clone) { + 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); + } else { + 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 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; + if (iam.redirInfo.redirCnt.pres) { + 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_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_DEBUG_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), not found user supplied RDNIS digits\n", sngss7_info->circuit->cic); + } + } else { + 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); + + /* 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); + } + copy_access_transport_to_sngss7(ftdmchan, &iam.accTrnspt); + } + } 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); + + /* 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); + + /* Location Number information */ + copy_locPtyNum_to_sngss7(ftdmchan, &iam.cgPtyNum1); + + /* Forward Call Indicators */ + copy_fwdCallInd_to_sngss7(ftdmchan, &iam.fwdCallInd); + + /* Original Called Number */ + 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); @@ -79,6 +186,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); @@ -88,15 +198,30 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* Redirecting Number */ copy_redirgNum_to_sngss7(ftdmchan, &iam.redirgNum); - /* Access Transport */ - copy_accTrnspt_to_sngss7(ftdmchan, &iam.accTrnspt); + /* Redirecting Information */ + copy_redirgInfo_to_sngss7(ftdmchan, &iam.redirInfo); - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM clg = \"%s\" (NADI=%d), cld = \"%s\" (NADI=%d)\n", + /* Original Called Number */ + copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum); + + /* 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); + + 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, 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, @@ -106,16 +231,124 @@ 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); + } + + ftdm_safe_free(event_clone); + SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } +void ft_to_sngss7_inf(ftdm_channel_t *ftdmchan, SiCnStEvnt *inr) +{ + SiCnStEvnt evnt; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + memset (&evnt, 0x0, sizeof (evnt)); + + evnt.infoInd.eh.pres = PRSNT_NODEF; + evnt.infoInd.cgPtyAddrRespInd.pres = PRSNT_NODEF; + evnt.infoInd.cgPtyCatRespInd.pres = PRSNT_NODEF; + + 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; + + 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, + 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_REQ; + + evnt.infoReqInd.cgPtyCatReqInd.pres = PRSNT_NODEF; + evnt.infoReqInd.cgPtyCatReqInd.val = CGPRTYCATREQ_REQ; + + evnt.infoReqInd.chrgInfoReqInd.pres = PRSNT_NODEF; + evnt.infoReqInd.chrgInfoReqInd.val = CHRGINFO_REQ; + + evnt.infoReqInd.malCaIdReqInd.pres = PRSNT_NODEF; + evnt.infoReqInd.malCaIdReqInd.val = MLBG_INFOREQ; + + 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__); sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; SiCnStEvnt acm; + const char *backwardInd = NULL; memset (&acm, 0x0, sizeof (acm)); @@ -133,8 +366,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"); + 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; @@ -241,6 +482,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; @@ -250,7 +492,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; @@ -260,10 +510,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, @@ -518,8 +768,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_relay.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c index c99a14a7e7..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 @@ -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); @@ -66,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) { @@ -84,23 +80,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 +107,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); @@ -248,7 +247,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, @@ -331,6 +330,7 @@ static ftdm_status_t unblock_all_ckts_for_relay(uint32_t procId) } #endif + /******************************************************************************/ /* For Emacs: * Local Variables: 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 457964a95f..70d1315353 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,8 +87,12 @@ 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) ; +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[] = { @@ -186,31 +190,40 @@ 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); } 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) { + 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); + } + return FTDM_SUCCESS; } ftdm_status_t copy_cdPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cdPtyNum) { - const char *cld_nadi = NULL; + const 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); @@ -220,11 +233,78 @@ 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_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); } +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; + 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; + locPtyNum->natAddrInd.pres = pres_val; + 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"); + 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); + } else { + locPtyNum->scrnInd.val = caller_data->screen; + } + + locPtyNum->presRest.pres = pres_val; + 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->numPlan.pres = pres_val; + locPtyNum->numPlan.val = 0x01; + + locPtyNum->niInd.pres = pres_val; + 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; + 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); +} + ftdm_status_t copy_genNmb_to_sngss7(ftdm_channel_t *ftdmchan, SiGenNum *genNmb) { const char *val = NULL; @@ -369,11 +449,18 @@ 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; } } 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; } @@ -474,6 +561,227 @@ 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); + redirInfo->redirInd.pres = 1; + 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); + redirInfo->origRedirReas.pres = 1; + 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); + redirInfo->redirCnt.pres= 1; + 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); + redirInfo->redirReas.pres = 1; + 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_access_transport_from_sngss7(ftdm_channel_t *ftdmchan, SiAccTrnspt *accTrnspt) +{ + 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) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No Access Transport IE available\n"); + return FTDM_SUCCESS; + } + + ftdm_url_encode((const char*)accTrnspt->infoElmts.val, val, accTrnspt->infoElmts.len); + sngss7_add_var (sngss7_info, "ss7_access_transport_urlenc", 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]; + 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 - Digits: %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: %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: %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: %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; @@ -598,27 +906,323 @@ 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 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; + 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_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]; + 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; + int acc_val = ISDNACC_ISDN; 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; + + 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) { + 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, "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); + } + + 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) || @@ -628,6 +1232,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; } @@ -642,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; } @@ -866,11 +1633,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; @@ -879,10 +1641,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; } @@ -1366,7 +2139,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)) { @@ -1881,6 +2654,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; } @@ -2035,6 +2809,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) { @@ -2047,6 +2870,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++) { /**************************************************************************/ @@ -2071,12 +2895,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); @@ -2084,7 +2908,11 @@ 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)) { - SS7_ERROR("Failed to read isup ckt = %d status\n", sngss7_info->circuit->id); + /* 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; + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR,"Failed to read isup ckt = %d status\n", sngss7_info->circuit->id); continue; } @@ -2092,10 +2920,20 @@ 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 */ 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) { @@ -2118,8 +2956,22 @@ 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 { /* 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) { @@ -2129,16 +2981,27 @@ 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); + /* 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); + } + + /* 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); - /* set the channel to suspended state */ - SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); 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); @@ -2146,8 +3009,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_LC_BLOCK_RX); + 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); @@ -2199,7 +3065,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; @@ -2470,8 +3336,9 @@ ftdm_status_t sngss7_save_iam(ftdm_channel_t *ftdmchan, SiConEvnt *siConEvnt) ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "IAM variable length:%"FTDM_SIZE_FMT"\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:%"FTDM_SIZE_FMT" 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_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 1631aec216..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 @@ -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 ********************************************************************/ @@ -124,9 +130,13 @@ 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; + 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; @@ -136,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; @@ -187,18 +198,20 @@ 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); /******************************************************************************/ /* FUNCTIONS ******************************************************************/ + 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)); @@ -206,11 +219,31 @@ 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; + + 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")) { + 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_DEBUG("Operating mode not specified, defaulting to ISUP\n"); + } + 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)) { @@ -225,28 +258,20 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa } i++; - while (ftdm_parameters[i].var != NULL) { - /**************************************************************************/ + 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, "ccSpanId")) { - /**********************************************************************/ + } 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++; @@ -255,10 +280,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; @@ -280,6 +307,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")) { @@ -385,12 +417,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; @@ -417,34 +499,92 @@ 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; - } + 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 (ftmod_ss7_parse_mtp_routes(mtp_routes)) { - SS7_ERROR("Failed to parse \"mtp_routes\"!\n"); - 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_isup_interfaces(isup_interfaces)) { - SS7_ERROR("Failed to parse \"isup_interfaces\"!\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; + } + + 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_ss7_parse_sctp_links(sctp_ifaces) != FTDM_SUCCESS) { + SS7_ERROR("Failed to parse !\n"); + return FTDM_FAIL; + } + + 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; } +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) { @@ -452,31 +592,41 @@ 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; + g_ftdm_sngss7_data.cfg.force_inr = 0; + /* 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")) { - /**********************************************************************/ - 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"); + } + 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 if (!strcasecmp(parm->var, "force-inr")) { + if (ftdm_true(parm->val)) { + 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; - /**********************************************************************/ } /* move to the next parmeter */ @@ -1845,12 +1995,14 @@ 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; /* 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); @@ -1859,6 +2011,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++) { /**************************************************************************/ @@ -1904,6 +2064,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 = 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); + 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 %d\n", sng_ccSpan.cpg_on_progress); } else if (!strcasecmp(parm->var, "cicbase")) { /**********************************************************************/ sng_ccSpan.cicbase = atoi(parm->val); @@ -1946,6 +2115,12 @@ 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); + /**********************************************************************/ } else if (!strcasecmp(parm->var, "lpa_on_cot")) { /**********************************************************************/ if (*parm->val == '1') { @@ -2002,6 +2177,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); @@ -2035,6 +2215,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; @@ -2723,7 +2908,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; @@ -2738,17 +2923,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; @@ -2863,7 +3048,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); @@ -2872,7 +3057,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 */ @@ -2885,6 +3070,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_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]; g_ftdm_sngss7_data.cfg.isupCkt[x].obj = ss7_info; @@ -2919,12 +3107,16 @@ 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; + 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; if (ccSpan->t3 == 0) { g_ftdm_sngss7_data.cfg.isupCkt[x].t3 = 1200; @@ -2972,6 +3164,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 { @@ -3076,6 +3274,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++) */ diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index c26cbec02c..c1940a4bad 100755 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -764,6 +764,28 @@ static FIO_COMMAND_FUNCTION(wanpipe_command) ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Disabled DTMF events\n"); #else return FTDM_NOTIMPL; +#endif + } + break; + case FTDM_COMMAND_ENABLE_DTMF_REMOVAL: + { +#ifdef WP_API_FEATURE_DTMF_REMOVAL + int return_code = 0; + err = sangoma_hwec_set_hwdtmf_removal(ftdmchan->sockfd, ftdmchan->physical_chan_id, &return_code, 1, 0); + if (return_code) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Wanpipe failed to Enable HW-DTMF removal\n"); + } +#endif + } + break; + case FTDM_COMMAND_DISABLE_DTMF_REMOVAL: + { +#ifdef WP_API_FEATURE_DTMF_REMOVAL + int return_code = 0; + err = sangoma_hwec_set_hwdtmf_removal(ftdmchan->sockfd, ftdmchan->physical_chan_id, &return_code, 0, 0); + if (return_code) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Wanpipe failed to Disable HW-DTMF removal\n"); + } #endif } break; diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 1476ee0158..f430ae263e 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" @@ -368,6 +367,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*/ @@ -754,6 +754,10 @@ typedef enum { /*!< Enable/disable IO stats in the channel */ FTDM_COMMAND_SWITCH_IOSTATS = 60, + /*!< Enable/disable DTMF removal */ + FTDM_COMMAND_ENABLE_DTMF_REMOVAL = 61, + FTDM_COMMAND_DISABLE_DTMF_REMOVAL = 62, + FTDM_COMMAND_COUNT, } ftdm_command_t; @@ -1395,7 +1399,7 @@ FT_DECLARE(uint32_t) ftdm_group_get_id(const ftdm_group_t *group); * Only use ftdm_channel_close if there is no call (incoming or outgoing) in the channel * * \param span_id The span id the channel belongs to - * \param chan_id Channel id of the channel you want to open + * \param chan_id Logical channel id of the channel you want to open * \param ftdmchan Pointer to store the channel once is open * * \retval FTDM_SUCCESS success (the channel was found and is available) @@ -1403,6 +1407,23 @@ 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); +/*! + * \brief Open a channel specifying the span id and physical chan id (required before placing a call on the channel) + * + * \warning Try using ftdm_call_place instead if you plan to place a call after opening the channel + * + * \note You must call ftdm_channel_close() or ftdm_channel_call_hangup() to release the channel afterwards + * Only use ftdm_channel_close if there is no call (incoming or outgoing) in the channel + * + * \param span_id The span id the channel belongs to + * \param chan_id Physical channel id of the channel you want to open + * \param ftdmchan Pointer to store the channel once is open + * + * \retval FTDM_SUCCESS success (the channel was found and is available) + * \retval FTDM_FAIL failure (channel was not found or not available) + */ +FT_DECLARE(ftdm_status_t) ftdm_channel_open_ph(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan); + /*! * \brief Hunts and opens a channel specifying the span id only * @@ -1640,6 +1661,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) * @@ -1655,7 +1687,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 @@ -1796,15 +1827,25 @@ FT_DECLARE(ftdm_trunk_mode_t) ftdm_span_get_trunk_mode(const ftdm_span_t *span); FT_DECLARE(const char *) ftdm_span_get_trunk_mode_str(const ftdm_span_t *span); /*! - * \brief Return the channel identified by the provided id + * \brief Return the channel identified by the provided logical id * * \param span The span where the channel belongs - * \param chanid The channel id within the span + * \param chanid The logical channel id within the span * * \return The channel pointer if found, NULL otherwise */ FT_DECLARE(ftdm_channel_t *) ftdm_span_get_channel(const ftdm_span_t *span, uint32_t chanid); +/*! + * \brief Return the channel identified by the provided physical id + * + * \param span The span where the channel belongs + * \param chanid The physical channel id within the span + * + * \return The channel pointer if found, NULL otherwise + */ +FT_DECLARE(ftdm_channel_t *) ftdm_span_get_channel_ph(const ftdm_span_t *span, uint32_t chanid); + /*! \brief Return the channel count number for the given span */ FT_DECLARE(uint32_t) ftdm_span_get_chan_count(const ftdm_span_t *span); diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 6725f25655..e378001183 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -126,6 +126,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) @@ -473,6 +476,7 @@ struct ftdm_channel { int32_t txdrops; int32_t rxdrops; ftdm_usrmsg_t *usrmsg; + ftdm_time_t last_state_change_time; }; struct ftdm_span { @@ -690,6 +694,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 d87bcd423f..c92164dd8c 100755 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -162,6 +162,7 @@ typedef enum { FTDM_SIGTYPE_ANALOG, FTDM_SIGTYPE_SANGOMABOOST, FTDM_SIGTYPE_M3UA, + FTDM_SIGTYPE_M2UA, FTDM_SIGTYPE_R2, FTDM_SIGTYPE_SS7, FTDM_SIGTYPE_GSM @@ -198,6 +199,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 */ @@ -266,6 +269,12 @@ 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) + +/*!< This no more flags after this flag */ +#define FTDM_CHANNEL_MAX_FLAG (1ULL << 38) +/*!/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) + $(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 $(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 + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -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 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(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) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(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) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(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 + $(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: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { 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 +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: + $(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-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 + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-exec-am: + +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 -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) install-am \ + install-strip + +.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-lzma dist-shar dist-tarZ 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/libtpl-1.5/README b/libs/libtpl-1.5/README new file mode 100755 index 0000000000..aefeea2ed4 --- /dev/null +++ b/libs/libtpl-1.5/README @@ -0,0 +1,56 @@ +tpl: fast, easy serialization in C +============================================================================== + +Documentation for tpl is available in the doc/ directory or at: + + http://tpl.sourceforge.net + +You can build tpl as a library, like so: + + ./configure + make + make install + +This installs libtpl.so and libtpl.a into a standard system library directory. +You can customize the install directory using configure's "--prefix" option: + + ./configure --prefix=/some/directory + +For other options accepted by configure, run "./configure --help". + +NON-LIBRARY OPTION +------------------ +Alternatively, if you don't want to muck around with libraries, you can simply +copy these two files into your own C project and build them with your program: + + src/tpl.h + src/tpl.c + +WINDOWS +------- +You can build tpl as a DLL under Visual Studio 2008. Or you can use MinGW or +Cygwin. + +SELF-TEST SUITE +--------------- +The automated self-test can be run by doing: + + cd tests + make + +LICENSE +------- +The BSD license applies to this software. The text is in the LICENSE file. + +CREDITS +------- +Many people have contributed to tpl, both bits of code and ideas. Rather than +listing them all here, at risk of omitting anyone- I just wish to say thank +you. Some particular features are noted with contributors' names in the +ChangeLog. + +Feel free to send me questions, comments or bug reports. + +Troy D. Hanson, February 5, 2010 +thanson@users.sourceforge.net + diff --git a/libs/libtpl-1.5/bootstrap b/libs/libtpl-1.5/bootstrap new file mode 100755 index 0000000000..d717c2b87a --- /dev/null +++ b/libs/libtpl-1.5/bootstrap @@ -0,0 +1,11 @@ +#!/bin/sh + +# THIS SCRIPT IS FOR PROJECT MAINTAINER ONLY +# It is executed only to generate "configure" + +set -x +aclocal -I config +autoheader +libtoolize --copy --force +automake --foreign --add-missing --copy +autoconf diff --git a/libs/libtpl-1.5/configure.ac b/libs/libtpl-1.5/configure.ac new file mode 100755 index 0000000000..3d2fe0e7b6 --- /dev/null +++ b/libs/libtpl-1.5/configure.ac @@ -0,0 +1,28 @@ +AC_PREREQ(2.59) + +AC_INIT([libtpl], [1.4], [thanson@users.sourceforge.net]) +AC_CONFIG_SRCDIR(src/tpl.c) +AC_CONFIG_AUX_DIR(config) +AC_CONFIG_HEADERS(config/config.h) +AM_INIT_AUTOMAKE +AC_PROG_CC +dnl next 4 lines are a hack to avoid libtool's +dnl needless checks for C++ and Fortran compilers +m4_undefine([AC_PROG_CXX]) +m4_defun([AC_PROG_CXX],[]) +m4_undefine([AC_PROG_F77]) +m4_defun([AC_PROG_F77],[]) +AC_PROG_LIBTOOL + +dnl detect Cygwin or MinGW and use mmap family replacements +AC_CONFIG_LIBOBJ_DIR(src/win) +case $host in + *-*-mingw32* | *-*-cygwin* | *-*-windows*) + AC_LIBOBJ(mmap) + AC_MSG_NOTICE([using custom mmap for Cygwin/MinGW]) + ;; +esac + +AC_CONFIG_FILES(src/win/Makefile src/Makefile Makefile) +AC_OUTPUT + diff --git a/libs/libtpl-1.5/doc/Makefile b/libs/libtpl-1.5/doc/Makefile new file mode 100755 index 0000000000..eaa3d499c9 --- /dev/null +++ b/libs/libtpl-1.5/doc/Makefile @@ -0,0 +1,26 @@ +all: css userguide pdf changelog perl + +userguide: txt/userguide.txt + asciidoc --unsafe --out-file=html/userguide.html -a linkcss=1 -a theme=tdh txt/userguide.txt + +changelog: txt/ChangeLog.txt + asciidoc --out-file=html/ChangeLog.html txt/ChangeLog.txt + +.PHONY: pdf + +pdf: txt/userguide.txt + a2x -f pdf $< + mv txt/userguide.pdf pdf/ + cd html && ln -sf ../pdf/userguide.pdf userguide.pdf + rm txt/userguide.xml + +perl: txt/perl.txt + asciidoc --unsafe --out-file=html/perl.html -a linkcss=1 -a theme=tdh txt/perl.txt + +css: html/toc.css + cat /etc/asciidoc/stylesheets/xhtml11.css html/toc.css > html/tdh.css + cp /etc/asciidoc/stylesheets/xhtml11-quirks.css html/tdh-quirks.css + +docbook: txt/userguide.txt + asciidoc -b docbook --out-file=/tmp/userguide.xml txt/userguide.txt + xmlto -o html html-nochunks /tmp/userguide.xml diff --git a/libs/libtpl-1.5/doc/NOTES b/libs/libtpl-1.5/doc/NOTES new file mode 100755 index 0000000000..9133089b74 --- /dev/null +++ b/libs/libtpl-1.5/doc/NOTES @@ -0,0 +1,11 @@ +# maintainer notes + +# IE6 png gamma bug: +# PNG images in IE6 display with wrong background colors, +# solution: save PNG in Gimp *Without save gamma checked* + +#update sourceforge web site: +#cd html +#scp *.{html,css} thanson@shell.sourceforge.net:/home/groups/t/tp/tpl/htdocs +#cd img +#scp *.png *.jpg thanson@shell.sourceforge.net:/home/groups/t/tp/tpl/htdocs/img diff --git a/libs/libtpl-1.5/doc/html/ChangeLog.html b/libs/libtpl-1.5/doc/html/ChangeLog.html new file mode 100755 index 0000000000..a051e60c0d --- /dev/null +++ b/libs/libtpl-1.5/doc/html/ChangeLog.html @@ -0,0 +1,602 @@ + + + + + +tpl ChangeLog + + + + +

Version 1.5 (2010-02-05)

+
+
    +
  • +

    +tpl now builds as a DLL under Microsoft Visual Studio! (thanks, degski and Zhang Yafei!) +

    +
  • +
  • +

    +there are now two download options: the tarball and the Visual Studio solution +

    +
  • +
  • +

    +a crash in tpl_free on certain format strings has been fixed (thanks, Eric Rose!) +

    +
  • +
  • +

    +fixed a bug in tpl_dump on 64-bit, big-endian platforms +

    +
  • +
  • +

    +changed some pointer casts from long to uintptr_t since 64-bit Windows has 32-bit longs +

    +
  • +
  • +

    +tpl has been downloaded 4,195 times. +

    +
  • +
+
+

Version 1.4 (2009-04-21)

+
+
    +
  • +

    +fixed-length arrays can now be multi-dimensional like i## +

    +
  • +
  • +

    +fixed-length string arrays like s# are now supported +

    +
  • +
  • +

    +nested structures can now be expressed, using the dollar symbol, e.g. S(ci$(cc)) +

    +
  • +
  • +

    +tpl_dump can use a caller-allocated output buffer (TPL_MEM|TPL_PREALLOCD) +

    +
  • +
  • +

    +tpl_load can tolerate excess space in input buffer (TPL_MEM|TPL_EXCESS_OK) +

    +
  • +
  • +

    +implement TPL_FXLENS flag for tpl_peek to get lengths of fixed-length arrays +

    +
  • +
  • +

    +implement TPL_GETSIZE flag for tpl_dump to get dump size without dumping +

    +
  • +
  • +

    +fix success return code from tpl_dump(TPL_FD,...) (thanks, Max Lapan!) +

    +
  • +
  • +

    +deprecated the wildcard unpacking S(*) feature +

    +
  • +
+
+

Version 1.3 (2009-02-10)

+
+
    +
  • +

    +added TPL_DATAPEEK mode for tpl_peek +

    +
  • +
  • +

    +added support for NULL strings +

    +
  • +
  • +

    +added support for 16-bit integer types (j,v) +

    +
  • +
  • +

    +added tpl_jot +

    +
  • +
  • +

    +added support for fixed-length arrays of structures S(...)# +

    +
  • +
  • +

    +added support for pre-C99 compilers (thanks, Wei Wei!) +

    +
  • +
  • +

    +improved structure alignment calculation (thanks, Wu Yongwei!) +

    +
  • +
  • +

    +added RPM spec file (thanks, Alessandro Ren!) +

    +
  • +
  • +

    +compiles cleanly with -Wall and -pedantic and with -O3 +

    +
  • +
  • +

    +made BSD license terms even more permissive +

    +
  • +
  • +

    +test suite: exit with status zero when all tests pass +

    +
  • +
  • +

    +added PDF user guide +

    +
  • +
  • +

    +added update news +(RSS) + +

    +
  • +
  • +

    +added tpl wiki +

    +
  • +
+
+

Version 1.2 (2007-04-27)

+
+
    +
  • +

    +Perl API and XML converter support 64-bit types +

    +
  • +
+
+

Version 1.1 (2007-04-25)

+
+
    +
  • +

    +support for serializing C structures +

    +
  • +
  • +

    +support for serializing fixed-length arrays +

    +
  • +
  • +

    +MinGW support (thanks, Horea Haitonic!) +

    +
  • +
  • +

    +revised User Guide +

    +
  • +
+
+

Version 1.0 (2006-09-28)

+
+
    +
  • +

    +Initial version +

    +
  • +
+
+ + + diff --git a/libs/libtpl-1.5/doc/html/img/banner.png b/libs/libtpl-1.5/doc/html/img/banner.png new file mode 100755 index 0000000000..ba9ffe8f96 Binary files /dev/null and b/libs/libtpl-1.5/doc/html/img/banner.png differ diff --git a/libs/libtpl-1.5/doc/html/img/banner.svg b/libs/libtpl-1.5/doc/html/img/banner.svg new file mode 100755 index 0000000000..f9f1f8508f --- /dev/null +++ b/libs/libtpl-1.5/doc/html/img/banner.svg @@ -0,0 +1,429 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + tpl + easily store and retrieve binary data in C + + diff --git a/libs/libtpl-1.5/doc/html/img/grad_azure.png b/libs/libtpl-1.5/doc/html/img/grad_azure.png new file mode 100755 index 0000000000..bf5c0cf2d4 Binary files /dev/null and b/libs/libtpl-1.5/doc/html/img/grad_azure.png differ diff --git a/libs/libtpl-1.5/doc/html/img/grad_azure.svg b/libs/libtpl-1.5/doc/html/img/grad_azure.svg new file mode 100755 index 0000000000..ab5fc49f3e --- /dev/null +++ b/libs/libtpl-1.5/doc/html/img/grad_azure.svg @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/libs/libtpl-1.5/doc/html/img/rss.png b/libs/libtpl-1.5/doc/html/img/rss.png new file mode 100755 index 0000000000..b3c949d224 Binary files /dev/null and b/libs/libtpl-1.5/doc/html/img/rss.png differ diff --git a/libs/libtpl-1.5/doc/html/img/tpl-mini.png b/libs/libtpl-1.5/doc/html/img/tpl-mini.png new file mode 100755 index 0000000000..7c193e9442 Binary files /dev/null and b/libs/libtpl-1.5/doc/html/img/tpl-mini.png differ diff --git a/libs/libtpl-1.5/doc/html/img/tpl-mini.svg b/libs/libtpl-1.5/doc/html/img/tpl-mini.svg new file mode 100755 index 0000000000..07df268d52 --- /dev/null +++ b/libs/libtpl-1.5/doc/html/img/tpl-mini.svg @@ -0,0 +1,242 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + tpl + + diff --git a/libs/libtpl-1.5/doc/html/img/tpl.dia b/libs/libtpl-1.5/doc/html/img/tpl.dia new file mode 100755 index 0000000000..d63ed77247 Binary files /dev/null and b/libs/libtpl-1.5/doc/html/img/tpl.dia differ diff --git a/libs/libtpl-1.5/doc/html/img/tpl.png b/libs/libtpl-1.5/doc/html/img/tpl.png new file mode 100755 index 0000000000..59f775cd8d Binary files /dev/null and b/libs/libtpl-1.5/doc/html/img/tpl.png differ diff --git a/libs/libtpl-1.5/doc/html/img/tpl_aai.dia b/libs/libtpl-1.5/doc/html/img/tpl_aai.dia new file mode 100755 index 0000000000..464ccbceeb Binary files /dev/null and b/libs/libtpl-1.5/doc/html/img/tpl_aai.dia differ diff --git a/libs/libtpl-1.5/doc/html/index.html b/libs/libtpl-1.5/doc/html/index.html new file mode 100755 index 0000000000..ac74a00caf --- /dev/null +++ b/libs/libtpl-1.5/doc/html/index.html @@ -0,0 +1,162 @@ + + + + + tpl home page + + + + + +
+ sf.net summary page > + tpl home +
+ +
+
+ + + +
+ +
+
Efficient serialization in C
+You can use tpl to store and reload your C data quickly and easily. +Tpl works with files, memory buffers and file descriptors so it's +suitable for use as a file format, IPC message format or any scenario +where you need to store and retrieve your data. +
+ +
+
Express your data
+Just express the type of data you are working with as a tpl format string. For +example, if you have a list of numeric ids and corresponding usernames, your +format string is A(is). Map your C variables to the format string and +then pack or unpack data. The format string lets you focus on your data, +rather than the storage format. +
+ +
+ + + + + + + + + +
+Storing ids and usernames + +Reloading ids and usernames +
+
+
+#include "tpl.h"
+
+int main(int argc, char *argv[]) {
+    tpl_node *tn;
+    int id=0;
+    char *name, *names[] = { "joe", "bob", "cary" };
+
+    tn = tpl_map("A(is)", &id, &name);
+
+    for(name=names[0]; id < 3; name=names[++id]) {
+        tpl_pack(tn,1);
+    }
+
+    tpl_dump(tn, TPL_FILE, "users.tpl");
+    tpl_free(tn);
+}
+
+
+
+
+
+#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, "users.tpl");
+
+    while ( tpl_unpack(tn,1) > 0 ) {
+        printf("id %d, user %s\n", id, name);
+        free(name);
+    }
+    tpl_free(tn);
+}
+
+
+
+
+ +
+
No library dependencies
+Tpl does not make your software dependent on any libraries. You can compile its +source code (one file) right into your program. +
+ +
For more information
+For a more thorough explanation and more examples, please read the +User Guide. + +
+
+ +
+ + + + + diff --git a/libs/libtpl-1.5/doc/html/license.html b/libs/libtpl-1.5/doc/html/license.html new file mode 100755 index 0000000000..43aa2e9c1c --- /dev/null +++ b/libs/libtpl-1.5/doc/html/license.html @@ -0,0 +1,61 @@ + + + + + tpl home page + + + + + +
+ sf.net summary page > + tpl home > + BSD license +
+ +
+
+ + +
+ +
+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.
+
+
+
+ +
+ + + + + diff --git a/libs/libtpl-1.5/doc/html/perl.html b/libs/libtpl-1.5/doc/html/perl.html new file mode 100755 index 0000000000..c2baedf32c --- /dev/null +++ b/libs/libtpl-1.5/doc/html/perl.html @@ -0,0 +1,403 @@ + + + + + +tpl Perl API + + + + + +
+
+SourceForge.net +
+ sf.net summary page > + tpl home > + tpl Perl API + [View PDF] +
+
+
+

Perl API

+
+
+ +

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 0000000000..b870fdcb9b Binary files /dev/null and b/libs/libtpl-1.5/doc/pdf/userguide.pdf differ diff --git a/libs/libtpl-1.5/doc/txt/ChangeLog.txt b/libs/libtpl-1.5/doc/txt/ChangeLog.txt new file mode 100755 index 0000000000..b55964db16 --- /dev/null +++ b/libs/libtpl-1.5/doc/txt/ChangeLog.txt @@ -0,0 +1,59 @@ +tpl ChangeLog +============= + +Version 1.5 (2010-02-05) +-------------------------- +* tpl now builds as a DLL under Microsoft Visual Studio! (thanks, degski and Zhang Yafei!) +* there are now two download options: the http://downloads.sourceforge.net/tpl/libtpl-1.5.tar.bz2[tarball] and the Visual Studio http://downloads.sourceforge.net/tpl/tpl-1.5-vs2008.zip[solution] +* a crash in `tpl_free` on certain format strings has been fixed (thanks, Eric Rose!) +* fixed a bug in `tpl_dump` on 64-bit, big-endian platforms +* changed some pointer casts from `long` to `uintptr_t` since 64-bit Windows has 32-bit longs +* tpl has been downloaded 4,195 times. + + +Version 1.4 (2009-04-21) +-------------------------- +* fixed-length arrays can now be multi-dimensional like `i##` +* fixed-length string arrays like `s#` are now supported +* nested structures can now be expressed, using the dollar symbol, e.g. `S(ci$(cc))` +* `tpl_dump` can use a caller-allocated output buffer (`TPL_MEM|TPL_PREALLOCD`) +* `tpl_load` can tolerate excess space in input buffer (`TPL_MEM|TPL_EXCESS_OK`) +* implement `TPL_FXLENS` flag for `tpl_peek` to get lengths of fixed-length arrays +* implement `TPL_GETSIZE` flag for `tpl_dump` to get dump size without dumping +* fix success return code from `tpl_dump(TPL_FD,...)` (thanks, Max Lapan!) +* deprecated the wildcard unpacking `S(*)` feature + +Version 1.3 (2009-02-10) +-------------------------- +* added `TPL_DATAPEEK` mode for `tpl_peek` +* added support for `NULL` strings +* added support for 16-bit integer types (`j`,`v`) +* added `tpl_jot` +* added support for fixed-length arrays of structures `S(...)#` +* added support for pre-C99 compilers (thanks, Wei Wei!) +* improved structure alignment calculation (thanks, Wu Yongwei!) +* added RPM spec file (thanks, Alessandro Ren!) +* compiles cleanly with `-Wall` and `-pedantic` and with `-O3` +* made link:license.html[BSD license] terms even more permissive +* test suite: exit with status zero when all tests pass +* added PDF user guide +* added http://troydhanson.wordpress.com/feed/[update news] image:img/rss.png[(RSS)] +* added http://apps.sourceforge.net/mediawiki/tpl/[tpl wiki] + +Version 1.2 (2007-04-27) +-------------------------- +* Perl API and XML converter support 64-bit types + +Version 1.1 (2007-04-25) +-------------------------- +* support for serializing C structures +* support for serializing fixed-length arrays +* MinGW support (thanks, Horea Haitonic!) +* revised User Guide + +Version 1.0 (2006-09-28) +-------------------------- +* Initial version + +// vim: set tw=80 wm=2 nowrap syntax=asciidoc: + diff --git a/libs/libtpl-1.5/doc/txt/compiling.txt b/libs/libtpl-1.5/doc/txt/compiling.txt new file mode 100755 index 0000000000..abb73ecf17 --- /dev/null +++ b/libs/libtpl-1.5/doc/txt/compiling.txt @@ -0,0 +1,38 @@ +Compiling libtpl.a and libtpl.so +-------------------------------- + +******************************************************************************** +Normally in the top-level directory you simply run: + + ./configure + make + make install + +The rest of the document is not needed if you use this method. +******************************************************************************** + + +Manual compilation of static and shared library on a GNU Linux system: +---------------------------------------------------------------------- + +First cd into the "src" directory. + +Static library +~~~~~~~~~~~~~~ +You can build the static library `libtpl.a` using these commands: + + cc -c tpl.c + ar rc libtpl.a tpl.o + ranlib libtpl.a + +Dynamic library +~~~~~~~~~~~~~~ +You can build the dynamic library `libtpl.so` using these commands: + + cc -fpic -c tpl.c + cc -shared -o libtpl.so tpl.o + +Keep in mind that you need to set the `LD_LIBRARY_PATH` environment variable +to include the directory where `libtpl.so` is installed in order for your +program to run. Alternatively you can put `libtpl.so` in a standard place like +`/usr/lib` and regenerate `ld.so.cache` using `ldconfig`. diff --git a/libs/libtpl-1.5/doc/txt/examples.txt b/libs/libtpl-1.5/doc/txt/examples.txt new file mode 100755 index 0000000000..9faca3fd69 --- /dev/null +++ b/libs/libtpl-1.5/doc/txt/examples.txt @@ -0,0 +1,297 @@ +tpl examples +============ +Troy D. Hanson > +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 0000000000..f11ee5fae5 Binary files /dev/null and b/libs/libtpl-1.5/lang/perl/tests/test14.tpl differ 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 0000000000..69249f79a7 Binary files /dev/null and b/libs/libtpl-1.5/lang/perl/tests/test15.tpl differ 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..649da903b6 --- /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 = 0,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 0000000000..611d57af28 Binary files /dev/null and b/libs/libtpl-1.5/tests/test1 differ 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 0000000000..a16c6d9f3c Binary files /dev/null and b/libs/libtpl-1.5/tests/test10 differ 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 0000000000..a811f623c7 Binary files /dev/null and b/libs/libtpl-1.5/tests/test10.tpl differ diff --git a/libs/libtpl-1.5/tests/test100 b/libs/libtpl-1.5/tests/test100 new file mode 100755 index 0000000000..b9d6dad987 Binary files /dev/null and b/libs/libtpl-1.5/tests/test100 differ diff --git a/libs/libtpl-1.5/tests/test100.ans b/libs/libtpl-1.5/tests/test100.ans new file mode 100755 index 0000000000..402ddaef7b --- /dev/null +++ b/libs/libtpl-1.5/tests/test100.ans @@ -0,0 +1,2 @@ +fmt: S(ic) +p: 1 diff --git a/libs/libtpl-1.5/tests/test100.c b/libs/libtpl-1.5/tests/test100.c new file mode 100755 index 0000000000..ae34b465f6 --- /dev/null +++ b/libs/libtpl-1.5/tests/test100.c @@ -0,0 +1,27 @@ +#include "tpl.h" +#include + +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 0000000000..ce2746653c Binary files /dev/null and b/libs/libtpl-1.5/tests/test101 differ 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 0000000000..c5e6804fde Binary files /dev/null and b/libs/libtpl-1.5/tests/test102 differ diff --git a/libs/libtpl-1.5/tests/test102.ans b/libs/libtpl-1.5/tests/test102.ans new file mode 100755 index 0000000000..a29caa72ee --- /dev/null +++ b/libs/libtpl-1.5/tests/test102.ans @@ -0,0 +1,2 @@ +fmt: c +q: ! diff --git a/libs/libtpl-1.5/tests/test102.c b/libs/libtpl-1.5/tests/test102.c new file mode 100755 index 0000000000..0b8fd8c235 --- /dev/null +++ b/libs/libtpl-1.5/tests/test102.c @@ -0,0 +1,22 @@ +#include "tpl.h" +#include + +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 0000000000..a2c1618b8f Binary files /dev/null and b/libs/libtpl-1.5/tests/test103 differ 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 0000000000..10be0c7dcd Binary files /dev/null and b/libs/libtpl-1.5/tests/test104 differ diff --git a/libs/libtpl-1.5/tests/test104.ans b/libs/libtpl-1.5/tests/test104.ans new file mode 100755 index 0000000000..5e79c697de --- /dev/null +++ b/libs/libtpl-1.5/tests/test104.ans @@ -0,0 +1,2 @@ +fmt: S(iscsiu) +pi: 1, ps: NULL, pc: ^, pt: world, pi: 2 diff --git a/libs/libtpl-1.5/tests/test104.c b/libs/libtpl-1.5/tests/test104.c new file mode 100755 index 0000000000..9c2e309755 --- /dev/null +++ b/libs/libtpl-1.5/tests/test104.c @@ -0,0 +1,33 @@ +#include "tpl.h" +#include + +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 0000000000..abeb3d1d24 Binary files /dev/null and b/libs/libtpl-1.5/tests/test105 differ 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 0000000000..5eb1331971 Binary files /dev/null and b/libs/libtpl-1.5/tests/test106 differ 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); + + for(j=0;j +#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 0000000000..df948b4731 Binary files /dev/null and b/libs/libtpl-1.5/tests/test108 differ 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 0000000000..70813e3c51 Binary files /dev/null and b/libs/libtpl-1.5/tests/test109 differ diff --git a/libs/libtpl-1.5/tests/test109.ans b/libs/libtpl-1.5/tests/test109.ans new file mode 100755 index 0000000000..0515356ccf --- /dev/null +++ b/libs/libtpl-1.5/tests/test109.ans @@ -0,0 +1,2 @@ +sizeof(s): 12 +structures match diff --git a/libs/libtpl-1.5/tests/test109.c b/libs/libtpl-1.5/tests/test109.c new file mode 100755 index 0000000000..616f04840f --- /dev/null +++ b/libs/libtpl-1.5/tests/test109.c @@ -0,0 +1,35 @@ +#include +#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 0000000000..06ad4ff34e Binary files /dev/null and b/libs/libtpl-1.5/tests/test11 differ 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 0000000000..d3a3e3de65 Binary files /dev/null and b/libs/libtpl-1.5/tests/test11.tpl differ diff --git a/libs/libtpl-1.5/tests/test110 b/libs/libtpl-1.5/tests/test110 new file mode 100755 index 0000000000..790c293697 Binary files /dev/null and b/libs/libtpl-1.5/tests/test110 differ diff --git a/libs/libtpl-1.5/tests/test110.ans b/libs/libtpl-1.5/tests/test110.ans new file mode 100755 index 0000000000..3d6e6e2e94 --- /dev/null +++ b/libs/libtpl-1.5/tests/test110.ans @@ -0,0 +1 @@ +structures match diff --git a/libs/libtpl-1.5/tests/test110.c b/libs/libtpl-1.5/tests/test110.c new file mode 100755 index 0000000000..3e812141ae --- /dev/null +++ b/libs/libtpl-1.5/tests/test110.c @@ -0,0 +1,78 @@ +#include +#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 0000000000..d0b721355c Binary files /dev/null and b/libs/libtpl-1.5/tests/test111 differ 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 0000000000..b1336dfe3e Binary files /dev/null and b/libs/libtpl-1.5/tests/test112 differ diff --git a/libs/libtpl-1.5/tests/test112.ans b/libs/libtpl-1.5/tests/test112.ans new file mode 100755 index 0000000000..3d6e6e2e94 --- /dev/null +++ b/libs/libtpl-1.5/tests/test112.ans @@ -0,0 +1 @@ +structures match diff --git a/libs/libtpl-1.5/tests/test112.c b/libs/libtpl-1.5/tests/test112.c new file mode 100755 index 0000000000..4dd84021e7 --- /dev/null +++ b/libs/libtpl-1.5/tests/test112.c @@ -0,0 +1,47 @@ +#include +#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 0000000000..cb384ef4f6 Binary files /dev/null and b/libs/libtpl-1.5/tests/test113 differ diff --git a/libs/libtpl-1.5/tests/test113.ans b/libs/libtpl-1.5/tests/test113.ans new file mode 100755 index 0000000000..a317aed3ef --- /dev/null +++ b/libs/libtpl-1.5/tests/test113.ans @@ -0,0 +1,5 @@ +structures match +A matches +B matches +C matches +D matches diff --git a/libs/libtpl-1.5/tests/test113.c b/libs/libtpl-1.5/tests/test113.c new file mode 100755 index 0000000000..3cf827ecdd --- /dev/null +++ b/libs/libtpl-1.5/tests/test113.c @@ -0,0 +1,53 @@ +#include +#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 0000000000..dfd7bf6eb2 Binary files /dev/null and b/libs/libtpl-1.5/tests/test114 differ 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; i +#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; i +#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;i +#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;i +#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 0000000000..d5b2d9a94e Binary files /dev/null and b/libs/libtpl-1.5/tests/test119 differ 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 0000000000..632091d299 Binary files /dev/null and b/libs/libtpl-1.5/tests/test12 differ diff --git a/libs/libtpl-1.5/tests/test12.ans b/libs/libtpl-1.5/tests/test12.ans new file mode 100755 index 0000000000..c8e233338a --- /dev/null +++ b/libs/libtpl-1.5/tests/test12.ans @@ -0,0 +1 @@ +test12.tpl: not a valid tpl file diff --git a/libs/libtpl-1.5/tests/test12.c b/libs/libtpl-1.5/tests/test12.c new file mode 100755 index 0000000000..51c50bc2ad --- /dev/null +++ b/libs/libtpl-1.5/tests/test12.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,"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 0000000000..de74a8b2ac Binary files /dev/null and b/libs/libtpl-1.5/tests/test12.tpl differ diff --git a/libs/libtpl-1.5/tests/test120 b/libs/libtpl-1.5/tests/test120 new file mode 100755 index 0000000000..bf27ab7d7d Binary files /dev/null and b/libs/libtpl-1.5/tests/test120 differ 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 0000000000..52477ccebc Binary files /dev/null and b/libs/libtpl-1.5/tests/test121 differ 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 0000000000..362df690e6 Binary files /dev/null and b/libs/libtpl-1.5/tests/test122 differ 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 0000000000..a4de2c3a0e Binary files /dev/null and b/libs/libtpl-1.5/tests/test123 differ 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 0000000000..cbf269dc0d Binary files /dev/null and b/libs/libtpl-1.5/tests/test124 differ diff --git a/libs/libtpl-1.5/tests/test124.ans b/libs/libtpl-1.5/tests/test124.ans new file mode 100755 index 0000000000..121d371ebe --- /dev/null +++ b/libs/libtpl-1.5/tests/test124.ans @@ -0,0 +1,4 @@ +mapped +freed +abcdefghi first +jklmnopqr second diff --git a/libs/libtpl-1.5/tests/test124.c b/libs/libtpl-1.5/tests/test124.c new file mode 100755 index 0000000000..02020d628b --- /dev/null +++ b/libs/libtpl-1.5/tests/test124.c @@ -0,0 +1,38 @@ +#include +#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 0000000000..4657448f1e Binary files /dev/null and b/libs/libtpl-1.5/tests/test13 differ diff --git a/libs/libtpl-1.5/tests/test13.ans b/libs/libtpl-1.5/tests/test13.ans new file mode 100755 index 0000000000..7ebe6e278b --- /dev/null +++ b/libs/libtpl-1.5/tests/test13.ans @@ -0,0 +1 @@ +test13.tpl: not a valid tpl file diff --git a/libs/libtpl-1.5/tests/test13.c b/libs/libtpl-1.5/tests/test13.c new file mode 100755 index 0000000000..140afef531 --- /dev/null +++ b/libs/libtpl-1.5/tests/test13.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,"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 0000000000..bf10054303 Binary files /dev/null and b/libs/libtpl-1.5/tests/test13.tpl differ diff --git a/libs/libtpl-1.5/tests/test14 b/libs/libtpl-1.5/tests/test14 new file mode 100755 index 0000000000..35b0421907 Binary files /dev/null and b/libs/libtpl-1.5/tests/test14 differ diff --git a/libs/libtpl-1.5/tests/test14.ans b/libs/libtpl-1.5/tests/test14.ans new file mode 100755 index 0000000000..e803c7d9f1 --- /dev/null +++ b/libs/libtpl-1.5/tests/test14.ans @@ -0,0 +1 @@ +test14.tpl: not a valid tpl file diff --git a/libs/libtpl-1.5/tests/test14.c b/libs/libtpl-1.5/tests/test14.c new file mode 100755 index 0000000000..d22f04c4e8 --- /dev/null +++ b/libs/libtpl-1.5/tests/test14.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,"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 0000000000..8dfd4a5148 Binary files /dev/null and b/libs/libtpl-1.5/tests/test14.tpl differ diff --git a/libs/libtpl-1.5/tests/test15 b/libs/libtpl-1.5/tests/test15 new file mode 100755 index 0000000000..40c34881e7 Binary files /dev/null and b/libs/libtpl-1.5/tests/test15 differ diff --git a/libs/libtpl-1.5/tests/test15.ans b/libs/libtpl-1.5/tests/test15.ans new file mode 100755 index 0000000000..f0c2f49907 --- /dev/null +++ b/libs/libtpl-1.5/tests/test15.ans @@ -0,0 +1 @@ +test15.tpl: not a valid tpl file diff --git a/libs/libtpl-1.5/tests/test15.c b/libs/libtpl-1.5/tests/test15.c new file mode 100755 index 0000000000..89cf40a0f4 --- /dev/null +++ b/libs/libtpl-1.5/tests/test15.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,"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 0000000000..80a83384cc Binary files /dev/null and b/libs/libtpl-1.5/tests/test15.tpl differ diff --git a/libs/libtpl-1.5/tests/test16 b/libs/libtpl-1.5/tests/test16 new file mode 100755 index 0000000000..180a87528a Binary files /dev/null and b/libs/libtpl-1.5/tests/test16 differ 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 0000000000..4ef0eaad69 Binary files /dev/null and b/libs/libtpl-1.5/tests/test16.tpl differ diff --git a/libs/libtpl-1.5/tests/test17 b/libs/libtpl-1.5/tests/test17 new file mode 100755 index 0000000000..403f8e5799 Binary files /dev/null and b/libs/libtpl-1.5/tests/test17 differ diff --git a/libs/libtpl-1.5/tests/test17.ans b/libs/libtpl-1.5/tests/test17.ans new file mode 100755 index 0000000000..7519cbfb43 --- /dev/null +++ b/libs/libtpl-1.5/tests/test17.ans @@ -0,0 +1 @@ +test17.tpl: format signature mismatch diff --git a/libs/libtpl-1.5/tests/test17.c b/libs/libtpl-1.5/tests/test17.c new file mode 100755 index 0000000000..551e3825d9 --- /dev/null +++ b/libs/libtpl-1.5/tests/test17.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(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 0000000000..a811f623c7 Binary files /dev/null and b/libs/libtpl-1.5/tests/test17.tpl differ diff --git a/libs/libtpl-1.5/tests/test18 b/libs/libtpl-1.5/tests/test18 new file mode 100755 index 0000000000..d7fcd4ae6d Binary files /dev/null and b/libs/libtpl-1.5/tests/test18 differ diff --git a/libs/libtpl-1.5/tests/test18.ans b/libs/libtpl-1.5/tests/test18.ans new file mode 100755 index 0000000000..c12a153fea --- /dev/null +++ b/libs/libtpl-1.5/tests/test18.ans @@ -0,0 +1,2 @@ +failed to parse A(i +tpl map failed diff --git a/libs/libtpl-1.5/tests/test18.c b/libs/libtpl-1.5/tests/test18.c new file mode 100755 index 0000000000..3a8f1060a4 --- /dev/null +++ b/libs/libtpl-1.5/tests/test18.c @@ -0,0 +1,15 @@ +#include +#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 0000000000..af939cd636 Binary files /dev/null and b/libs/libtpl-1.5/tests/test19 differ diff --git a/libs/libtpl-1.5/tests/test19.ans b/libs/libtpl-1.5/tests/test19.ans new file mode 100755 index 0000000000..3cf2a7d534 --- /dev/null +++ b/libs/libtpl-1.5/tests/test19.ans @@ -0,0 +1,2 @@ +failed to parse A(i)) +tpl map failed diff --git a/libs/libtpl-1.5/tests/test19.c b/libs/libtpl-1.5/tests/test19.c new file mode 100755 index 0000000000..accac4491d --- /dev/null +++ b/libs/libtpl-1.5/tests/test19.c @@ -0,0 +1,15 @@ +#include +#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 0000000000..d515e4a70d Binary files /dev/null and b/libs/libtpl-1.5/tests/test2 differ 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 0000000000..b591f64bd7 Binary files /dev/null and b/libs/libtpl-1.5/tests/test20 differ 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 0000000000..fa4f6b8611 Binary files /dev/null and b/libs/libtpl-1.5/tests/test21 differ diff --git a/libs/libtpl-1.5/tests/test21.ans b/libs/libtpl-1.5/tests/test21.ans new file mode 100755 index 0000000000..c79f83ab55 --- /dev/null +++ b/libs/libtpl-1.5/tests/test21.ans @@ -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/test21.c b/libs/libtpl-1.5/tests/test21.c new file mode 100755 index 0000000000..67a5b570d4 --- /dev/null +++ b/libs/libtpl-1.5/tests/test21.c @@ -0,0 +1,18 @@ +#include +#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 0000000000..9e9ceebe6c Binary files /dev/null and b/libs/libtpl-1.5/tests/test22 differ 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 0000000000..8dea604364 Binary files /dev/null and b/libs/libtpl-1.5/tests/test23 differ 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 0000000000..a6bbe6845c Binary files /dev/null and b/libs/libtpl-1.5/tests/test24 differ 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 0000000000..1b03586065 Binary files /dev/null and b/libs/libtpl-1.5/tests/test24.tpl differ diff --git a/libs/libtpl-1.5/tests/test25 b/libs/libtpl-1.5/tests/test25 new file mode 100755 index 0000000000..daa4c560a4 Binary files /dev/null and b/libs/libtpl-1.5/tests/test25 differ 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 0000000000..1b03586065 Binary files /dev/null and b/libs/libtpl-1.5/tests/test25.tpl differ diff --git a/libs/libtpl-1.5/tests/test26 b/libs/libtpl-1.5/tests/test26 new file mode 100755 index 0000000000..9ef5356e1e Binary files /dev/null and b/libs/libtpl-1.5/tests/test26 differ diff --git a/libs/libtpl-1.5/tests/test26.ans b/libs/libtpl-1.5/tests/test26.ans new file mode 100755 index 0000000000..bf8028a425 --- /dev/null +++ b/libs/libtpl-1.5/tests/test26.ans @@ -0,0 +1,2 @@ +3 tpls gathered. +999045 is their sum. diff --git a/libs/libtpl-1.5/tests/test26.c b/libs/libtpl-1.5/tests/test26.c new file mode 100755 index 0000000000..dc3dc4febc --- /dev/null +++ b/libs/libtpl-1.5/tests/test26.c @@ -0,0 +1,85 @@ +#include +#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 0000000000..a811f623c7 Binary files /dev/null and b/libs/libtpl-1.5/tests/test26_0.tpl differ 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 0000000000..85ae076aa7 Binary files /dev/null and b/libs/libtpl-1.5/tests/test26_1.tpl differ diff --git a/libs/libtpl-1.5/tests/test26_2.tpl b/libs/libtpl-1.5/tests/test26_2.tpl new file mode 100755 index 0000000000..73e62d31b7 Binary files /dev/null and b/libs/libtpl-1.5/tests/test26_2.tpl differ 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 0000000000..bb209fcd20 Binary files /dev/null and b/libs/libtpl-1.5/tests/test26_3.tpl differ diff --git a/libs/libtpl-1.5/tests/test27 b/libs/libtpl-1.5/tests/test27 new file mode 100755 index 0000000000..ec6951b78f Binary files /dev/null and b/libs/libtpl-1.5/tests/test27 differ diff --git a/libs/libtpl-1.5/tests/test27.ans b/libs/libtpl-1.5/tests/test27.ans new file mode 100755 index 0000000000..903c08cf1f --- /dev/null +++ b/libs/libtpl-1.5/tests/test27.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/test27.c b/libs/libtpl-1.5/tests/test27.c new file mode 100755 index 0000000000..671fa0306c --- /dev/null +++ b/libs/libtpl-1.5/tests/test27.c @@ -0,0 +1,35 @@ +#include +#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 0000000000..4ce901af21 Binary files /dev/null and b/libs/libtpl-1.5/tests/test28 differ 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 0000000000..2c6f04aedc Binary files /dev/null and b/libs/libtpl-1.5/tests/test29 differ 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 0000000000..baa0e84848 Binary files /dev/null and b/libs/libtpl-1.5/tests/test3 differ diff --git a/libs/libtpl-1.5/tests/test3.ans b/libs/libtpl-1.5/tests/test3.ans new file mode 100755 index 0000000000..c35e4ea80e --- /dev/null +++ b/libs/libtpl-1.5/tests/test3.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/test3.c b/libs/libtpl-1.5/tests/test3.c new file mode 100755 index 0000000000..57f92cca84 --- /dev/null +++ b/libs/libtpl-1.5/tests/test3.c @@ -0,0 +1,18 @@ +#include +#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 0000000000..15039ab428 Binary files /dev/null and b/libs/libtpl-1.5/tests/test30 differ 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 0000000000..7565901fbe Binary files /dev/null and b/libs/libtpl-1.5/tests/test31 differ 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 0000000000..91bcd967f5 Binary files /dev/null and b/libs/libtpl-1.5/tests/test32 differ diff --git a/libs/libtpl-1.5/tests/test32.ans b/libs/libtpl-1.5/tests/test32.ans new file mode 100755 index 0000000000..bda4a86032 --- /dev/null +++ b/libs/libtpl-1.5/tests/test32.ans @@ -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/test32.c b/libs/libtpl-1.5/tests/test32.c new file mode 100755 index 0000000000..4d61461c3b --- /dev/null +++ b/libs/libtpl-1.5/tests/test32.c @@ -0,0 +1,44 @@ +#include "tpl.h" +#include +#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 0000000000..f47bbec0e3 Binary files /dev/null and b/libs/libtpl-1.5/tests/test33 differ diff --git a/libs/libtpl-1.5/tests/test33.ans b/libs/libtpl-1.5/tests/test33.ans new file mode 100755 index 0000000000..8805eb3396 --- /dev/null +++ b/libs/libtpl-1.5/tests/test33.ans @@ -0,0 +1,2 @@ +sizeof(double) is 8 +y is 1.000000 diff --git a/libs/libtpl-1.5/tests/test33.c b/libs/libtpl-1.5/tests/test33.c new file mode 100755 index 0000000000..6018b2aac7 --- /dev/null +++ b/libs/libtpl-1.5/tests/test33.c @@ -0,0 +1,23 @@ +#include +#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 0000000000..59db46b7c1 Binary files /dev/null and b/libs/libtpl-1.5/tests/test34 differ 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 0000000000..fb842626fb Binary files /dev/null and b/libs/libtpl-1.5/tests/test35 differ diff --git a/libs/libtpl-1.5/tests/test35.ans b/libs/libtpl-1.5/tests/test35.ans new file mode 100755 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test35.c b/libs/libtpl-1.5/tests/test35.c new file mode 100755 index 0000000000..65980e70ed --- /dev/null +++ b/libs/libtpl-1.5/tests/test35.c @@ -0,0 +1,16 @@ +#include "tpl.h" + +int main(int argc, char *argv[]) { + tpl_node *tn; + int id; + char *name, *names[] = { "joe", "bob", "cary" }; + + 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); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test35.out b/libs/libtpl-1.5/tests/test35.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test36 b/libs/libtpl-1.5/tests/test36 new file mode 100755 index 0000000000..f4064456db Binary files /dev/null and b/libs/libtpl-1.5/tests/test36 differ diff --git a/libs/libtpl-1.5/tests/test36.ans b/libs/libtpl-1.5/tests/test36.ans new file mode 100755 index 0000000000..0b21bfe31e --- /dev/null +++ b/libs/libtpl-1.5/tests/test36.ans @@ -0,0 +1,3 @@ +id 0, user joe +id 1, user bob +id 2, user cary diff --git a/libs/libtpl-1.5/tests/test36.c b/libs/libtpl-1.5/tests/test36.c new file mode 100755 index 0000000000..5e4867bdc0 --- /dev/null +++ b/libs/libtpl-1.5/tests/test36.c @@ -0,0 +1,22 @@ +#include +#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 0000000000..b68ae4ac80 Binary files /dev/null and b/libs/libtpl-1.5/tests/test37 differ 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 0000000000..347f3b3d5f Binary files /dev/null and b/libs/libtpl-1.5/tests/test38 differ diff --git a/libs/libtpl-1.5/tests/test38.ans b/libs/libtpl-1.5/tests/test38.ans new file mode 100755 index 0000000000..157e8cf278 --- /dev/null +++ b/libs/libtpl-1.5/tests/test38.ans @@ -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/test38.c b/libs/libtpl-1.5/tests/test38.c new file mode 100755 index 0000000000..fd8fc7547e --- /dev/null +++ b/libs/libtpl-1.5/tests/test38.c @@ -0,0 +1,19 @@ +#include +#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 0000000000..bac2966b50 Binary files /dev/null and b/libs/libtpl-1.5/tests/test39 differ diff --git a/libs/libtpl-1.5/tests/test39.ans b/libs/libtpl-1.5/tests/test39.ans new file mode 100755 index 0000000000..b2035d820c --- /dev/null +++ b/libs/libtpl-1.5/tests/test39.ans @@ -0,0 +1,2 @@ +test39.tpl: not a valid tpl file +load failed (rc=-1) diff --git a/libs/libtpl-1.5/tests/test39.c b/libs/libtpl-1.5/tests/test39.c new file mode 100755 index 0000000000..cb892dc3b3 --- /dev/null +++ b/libs/libtpl-1.5/tests/test39.c @@ -0,0 +1,17 @@ +#include +#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 0000000000..37d246ccf5 Binary files /dev/null and b/libs/libtpl-1.5/tests/test39.tpl differ diff --git a/libs/libtpl-1.5/tests/test4 b/libs/libtpl-1.5/tests/test4 new file mode 100755 index 0000000000..1699276b85 Binary files /dev/null and b/libs/libtpl-1.5/tests/test4 differ 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 0000000000..62dcb1a51e Binary files /dev/null and b/libs/libtpl-1.5/tests/test40 differ 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 0000000000..7613162f74 Binary files /dev/null and b/libs/libtpl-1.5/tests/test41 differ 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 0000000000..043f4fdfae Binary files /dev/null and b/libs/libtpl-1.5/tests/test42 differ diff --git a/libs/libtpl-1.5/tests/test42.ans b/libs/libtpl-1.5/tests/test42.ans new file mode 100755 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test42.c b/libs/libtpl-1.5/tests/test42.c new file mode 100755 index 0000000000..0f330e8b96 --- /dev/null +++ b/libs/libtpl-1.5/tests/test42.c @@ -0,0 +1,16 @@ +#include "tpl.h" + +int main(int argc, char *argv[]) { + tpl_node *tn; + char id; + char *name, *names[] = { "joe", "bob", "cary" }; + + tn = tpl_map("A(cs)", &id, &name); + + for(id=0,name=names[(int)id]; id < 3; name=names[(int)++id]) + tpl_pack(tn,1); + + tpl_dump(tn, TPL_FILE, "/tmp/test42.tpl"); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test42.out b/libs/libtpl-1.5/tests/test42.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test43 b/libs/libtpl-1.5/tests/test43 new file mode 100755 index 0000000000..e432f40452 Binary files /dev/null and b/libs/libtpl-1.5/tests/test43 differ diff --git a/libs/libtpl-1.5/tests/test43.ans b/libs/libtpl-1.5/tests/test43.ans new file mode 100755 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test43.c b/libs/libtpl-1.5/tests/test43.c new file mode 100755 index 0000000000..ad0162eb03 --- /dev/null +++ b/libs/libtpl-1.5/tests/test43.c @@ -0,0 +1,20 @@ +#include "tpl.h" + +int main(int argc, char *argv[]) { + tpl_node *tn; + char id; + tpl_bin bin; + + char *junk = "0123456789"; + bin.sz = 10; + bin.addr = junk; + + tn = tpl_map("A(cB)", &id, &bin); + + for(id=0; id < 3; ++id) + tpl_pack(tn,1); /* pack same bin buffer, doesn't matter */ + + tpl_dump(tn, TPL_FILE, "/tmp/test43.tpl"); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test43.out b/libs/libtpl-1.5/tests/test43.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test44 b/libs/libtpl-1.5/tests/test44 new file mode 100755 index 0000000000..b37213ba64 Binary files /dev/null and b/libs/libtpl-1.5/tests/test44 differ diff --git a/libs/libtpl-1.5/tests/test44.ans b/libs/libtpl-1.5/tests/test44.ans new file mode 100755 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test44.c b/libs/libtpl-1.5/tests/test44.c new file mode 100755 index 0000000000..cc257449a0 --- /dev/null +++ b/libs/libtpl-1.5/tests/test44.c @@ -0,0 +1,23 @@ +#include "tpl.h" + +int main(int argc, char *argv[]) { + tpl_node *tn; + char id,j; + tpl_bin bin; + + char *junk = "0123456789"; + bin.sz = 10; + bin.addr = junk; + + tn = tpl_map("A(cA(B))", &id, &bin); + + for(id=0; id < 3; ++id) { + for(j=0;j<2;j++) + tpl_pack(tn,2); /* pack same bin buffer, doesn't matter */ + tpl_pack(tn,1); + } + + tpl_dump(tn, TPL_FILE, "/tmp/test44.tpl"); + tpl_free(tn); + return(0); +} diff --git a/libs/libtpl-1.5/tests/test44.out b/libs/libtpl-1.5/tests/test44.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test45 b/libs/libtpl-1.5/tests/test45 new file mode 100755 index 0000000000..fecd446084 Binary files /dev/null and b/libs/libtpl-1.5/tests/test45 differ diff --git a/libs/libtpl-1.5/tests/test45.ans b/libs/libtpl-1.5/tests/test45.ans new file mode 100755 index 0000000000..462cb89ee0 --- /dev/null +++ b/libs/libtpl-1.5/tests/test45.ans @@ -0,0 +1,2 @@ +x is 0.500000 +y is 0.500000 diff --git a/libs/libtpl-1.5/tests/test45.c b/libs/libtpl-1.5/tests/test45.c new file mode 100755 index 0000000000..ca0fc59258 --- /dev/null +++ b/libs/libtpl-1.5/tests/test45.c @@ -0,0 +1,21 @@ +#include +#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 0000000000..4d22b71ff7 Binary files /dev/null and b/libs/libtpl-1.5/tests/test46 differ 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 0000000000..eb682ed4fa Binary files /dev/null and b/libs/libtpl-1.5/tests/test47 differ 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 0000000000..1fb859d390 Binary files /dev/null and b/libs/libtpl-1.5/tests/test48 differ 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 0000000000..3c03a59785 Binary files /dev/null and b/libs/libtpl-1.5/tests/test49 differ diff --git a/libs/libtpl-1.5/tests/test49.ans b/libs/libtpl-1.5/tests/test49.ans new file mode 100755 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test49.c b/libs/libtpl-1.5/tests/test49.c new file mode 100755 index 0000000000..9e7f8f23a3 --- /dev/null +++ b/libs/libtpl-1.5/tests/test49.c @@ -0,0 +1,18 @@ + #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, "/tmp/test49.tpl"); + tpl_free(tn); + return(0); + } diff --git a/libs/libtpl-1.5/tests/test49.out b/libs/libtpl-1.5/tests/test49.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test5 b/libs/libtpl-1.5/tests/test5 new file mode 100755 index 0000000000..e28ecefb08 Binary files /dev/null and b/libs/libtpl-1.5/tests/test5 differ 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 0000000000..aee87af5f5 Binary files /dev/null and b/libs/libtpl-1.5/tests/test50 differ 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 0000000000..3a06d153ab Binary files /dev/null and b/libs/libtpl-1.5/tests/test51 differ diff --git a/libs/libtpl-1.5/tests/test51.ans b/libs/libtpl-1.5/tests/test51.ans new file mode 100755 index 0000000000..bb58756b59 --- /dev/null +++ b/libs/libtpl-1.5/tests/test51.ans @@ -0,0 +1 @@ +num_tpls: 4, sum: 180 diff --git a/libs/libtpl-1.5/tests/test51.c b/libs/libtpl-1.5/tests/test51.c new file mode 100755 index 0000000000..49834d729b --- /dev/null +++ b/libs/libtpl-1.5/tests/test51.c @@ -0,0 +1,57 @@ +#include +#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 0000000000..a811f623c7 Binary files /dev/null and b/libs/libtpl-1.5/tests/test51_0.tpl differ 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 0000000000..b056e6b04d Binary files /dev/null and b/libs/libtpl-1.5/tests/test51_1.tpl differ 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 0000000000..328940bfea Binary files /dev/null and b/libs/libtpl-1.5/tests/test51_2.tpl differ 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 0000000000..bb7446337b Binary files /dev/null and b/libs/libtpl-1.5/tests/test51_3.tpl differ diff --git a/libs/libtpl-1.5/tests/test51_4.tpl b/libs/libtpl-1.5/tests/test51_4.tpl new file mode 100755 index 0000000000..0219500bf0 Binary files /dev/null and b/libs/libtpl-1.5/tests/test51_4.tpl differ diff --git a/libs/libtpl-1.5/tests/test52 b/libs/libtpl-1.5/tests/test52 new file mode 100755 index 0000000000..532c908dee Binary files /dev/null and b/libs/libtpl-1.5/tests/test52 differ 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 0000000000..042b51215b Binary files /dev/null and b/libs/libtpl-1.5/tests/test53 differ 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 0000000000..94b05f49e0 Binary files /dev/null and b/libs/libtpl-1.5/tests/test54 differ diff --git a/libs/libtpl-1.5/tests/test54.ans b/libs/libtpl-1.5/tests/test54.ans new file mode 100755 index 0000000000..5125c4fb0a --- /dev/null +++ b/libs/libtpl-1.5/tests/test54.ans @@ -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.c b/libs/libtpl-1.5/tests/test54.c new file mode 100755 index 0000000000..0eecceaddd --- /dev/null +++ b/libs/libtpl-1.5/tests/test54.c @@ -0,0 +1,63 @@ +#include +#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 0000000000..a811f623c7 Binary files /dev/null and b/libs/libtpl-1.5/tests/test54_0.tpl differ 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 0000000000..b056e6b04d Binary files /dev/null and b/libs/libtpl-1.5/tests/test54_1.tpl differ 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 0000000000..328940bfea Binary files /dev/null and b/libs/libtpl-1.5/tests/test54_2.tpl differ 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 0000000000..bb7446337b Binary files /dev/null and b/libs/libtpl-1.5/tests/test54_3.tpl differ diff --git a/libs/libtpl-1.5/tests/test54_4.tpl b/libs/libtpl-1.5/tests/test54_4.tpl new file mode 100755 index 0000000000..0219500bf0 Binary files /dev/null and b/libs/libtpl-1.5/tests/test54_4.tpl differ diff --git a/libs/libtpl-1.5/tests/test55 b/libs/libtpl-1.5/tests/test55 new file mode 100755 index 0000000000..c64d022dfe Binary files /dev/null and b/libs/libtpl-1.5/tests/test55 differ 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 0000000000..a811f623c7 Binary files /dev/null and b/libs/libtpl-1.5/tests/test55_0.tpl differ 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 0000000000..85ae076aa7 Binary files /dev/null and b/libs/libtpl-1.5/tests/test55_1.tpl differ diff --git a/libs/libtpl-1.5/tests/test55_2.tpl b/libs/libtpl-1.5/tests/test55_2.tpl new file mode 100755 index 0000000000..73e62d31b7 Binary files /dev/null and b/libs/libtpl-1.5/tests/test55_2.tpl differ 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 0000000000..bb209fcd20 Binary files /dev/null and b/libs/libtpl-1.5/tests/test55_3.tpl differ diff --git a/libs/libtpl-1.5/tests/test56 b/libs/libtpl-1.5/tests/test56 new file mode 100755 index 0000000000..20e3e32272 Binary files /dev/null and b/libs/libtpl-1.5/tests/test56 differ 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 0000000000..63980a5601 Binary files /dev/null and b/libs/libtpl-1.5/tests/test57 differ diff --git a/libs/libtpl-1.5/tests/test57.ans b/libs/libtpl-1.5/tests/test57.ans new file mode 100755 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test57.c b/libs/libtpl-1.5/tests/test57.c new file mode 100755 index 0000000000..43bed41423 --- /dev/null +++ b/libs/libtpl-1.5/tests/test57.c @@ -0,0 +1,28 @@ +#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; + + 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 0000000000..a5c5a862b2 Binary files /dev/null and b/libs/libtpl-1.5/tests/test58 differ diff --git a/libs/libtpl-1.5/tests/test58.ans b/libs/libtpl-1.5/tests/test58.ans new file mode 100755 index 0000000000..f235fc6acf --- /dev/null +++ b/libs/libtpl-1.5/tests/test58.ans @@ -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/test58.c b/libs/libtpl-1.5/tests/test58.c new file mode 100755 index 0000000000..15f875e4bf --- /dev/null +++ b/libs/libtpl-1.5/tests/test58.c @@ -0,0 +1,30 @@ +#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; + + 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 0000000000..4cd0109de8 Binary files /dev/null and b/libs/libtpl-1.5/tests/test59 differ 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 0000000000..0760800d62 Binary files /dev/null and b/libs/libtpl-1.5/tests/test6 differ diff --git a/libs/libtpl-1.5/tests/test6.ans b/libs/libtpl-1.5/tests/test6.ans new file mode 100755 index 0000000000..e972e9fa3c --- /dev/null +++ b/libs/libtpl-1.5/tests/test6.ans @@ -0,0 +1 @@ +t is hello, world! diff --git a/libs/libtpl-1.5/tests/test6.c b/libs/libtpl-1.5/tests/test6.c new file mode 100755 index 0000000000..da3aec547e --- /dev/null +++ b/libs/libtpl-1.5/tests/test6.c @@ -0,0 +1,25 @@ +#include +#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 0000000000..dac0a361e5 Binary files /dev/null and b/libs/libtpl-1.5/tests/test60 differ diff --git a/libs/libtpl-1.5/tests/test60.ans b/libs/libtpl-1.5/tests/test60.ans new file mode 100755 index 0000000000..903c08cf1f --- /dev/null +++ b/libs/libtpl-1.5/tests/test60.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/test60.c b/libs/libtpl-1.5/tests/test60.c new file mode 100755 index 0000000000..b797bf5524 --- /dev/null +++ b/libs/libtpl-1.5/tests/test60.c @@ -0,0 +1,18 @@ +#include +#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 0000000000..a0683bbb1e Binary files /dev/null and b/libs/libtpl-1.5/tests/test61 differ diff --git a/libs/libtpl-1.5/tests/test61.ans b/libs/libtpl-1.5/tests/test61.ans new file mode 100755 index 0000000000..71580ae9a7 --- /dev/null +++ b/libs/libtpl-1.5/tests/test61.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 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.c b/libs/libtpl-1.5/tests/test61.c new file mode 100755 index 0000000000..efa64ff27a --- /dev/null +++ b/libs/libtpl-1.5/tests/test61.c @@ -0,0 +1,18 @@ +#include +#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 0000000000..d928efa399 Binary files /dev/null and b/libs/libtpl-1.5/tests/test61_0.tpl differ 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 0000000000..0ee24de064 Binary files /dev/null and b/libs/libtpl-1.5/tests/test61_1.tpl differ diff --git a/libs/libtpl-1.5/tests/test62 b/libs/libtpl-1.5/tests/test62 new file mode 100755 index 0000000000..4e07a1c99e Binary files /dev/null and b/libs/libtpl-1.5/tests/test62 differ 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 0000000000..d928efa399 Binary files /dev/null and b/libs/libtpl-1.5/tests/test62_0.tpl differ diff --git a/libs/libtpl-1.5/tests/test63 b/libs/libtpl-1.5/tests/test63 new file mode 100755 index 0000000000..4f1ab3897a Binary files /dev/null and b/libs/libtpl-1.5/tests/test63 differ diff --git a/libs/libtpl-1.5/tests/test63.ans b/libs/libtpl-1.5/tests/test63.ans new file mode 100755 index 0000000000..61287c2b8e --- /dev/null +++ b/libs/libtpl-1.5/tests/test63.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/test63.c b/libs/libtpl-1.5/tests/test63.c new file mode 100755 index 0000000000..b60b8fe490 --- /dev/null +++ b/libs/libtpl-1.5/tests/test63.c @@ -0,0 +1,22 @@ +#include +#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 0000000000..b6f9024c34 Binary files /dev/null and b/libs/libtpl-1.5/tests/test64 differ diff --git a/libs/libtpl-1.5/tests/test64.ans b/libs/libtpl-1.5/tests/test64.ans new file mode 100755 index 0000000000..c9162af499 --- /dev/null +++ b/libs/libtpl-1.5/tests/test64.ans @@ -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/test64.c b/libs/libtpl-1.5/tests/test64.c new file mode 100755 index 0000000000..3800f2845c --- /dev/null +++ b/libs/libtpl-1.5/tests/test64.c @@ -0,0 +1,80 @@ +#include +#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 0000000000..d7405b16b7 Binary files /dev/null and b/libs/libtpl-1.5/tests/test65 differ diff --git a/libs/libtpl-1.5/tests/test65.ans b/libs/libtpl-1.5/tests/test65.ans new file mode 100755 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test65.c b/libs/libtpl-1.5/tests/test65.c new file mode 100755 index 0000000000..fba332eb98 --- /dev/null +++ b/libs/libtpl-1.5/tests/test65.c @@ -0,0 +1,16 @@ +#include +#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 0000000000..94ce5d8123 Binary files /dev/null and b/libs/libtpl-1.5/tests/test66 differ diff --git a/libs/libtpl-1.5/tests/test66.ans b/libs/libtpl-1.5/tests/test66.ans new file mode 100755 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test66.c b/libs/libtpl-1.5/tests/test66.c new file mode 100755 index 0000000000..d7ca5190dc --- /dev/null +++ b/libs/libtpl-1.5/tests/test66.c @@ -0,0 +1,18 @@ +#include +#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 0000000000..b6d5363558 Binary files /dev/null and b/libs/libtpl-1.5/tests/test67 differ diff --git a/libs/libtpl-1.5/tests/test67.ans b/libs/libtpl-1.5/tests/test67.ans new file mode 100755 index 0000000000..3ec435578e --- /dev/null +++ b/libs/libtpl-1.5/tests/test67.ans @@ -0,0 +1,3 @@ +load succeeded +/tmp/test67.tpl: array lengths mismatch +load failed diff --git a/libs/libtpl-1.5/tests/test67.c b/libs/libtpl-1.5/tests/test67.c new file mode 100755 index 0000000000..460240fd34 --- /dev/null +++ b/libs/libtpl-1.5/tests/test67.c @@ -0,0 +1,40 @@ +#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}; + + 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 0000000000..e8c337e37a Binary files /dev/null and b/libs/libtpl-1.5/tests/test68 differ diff --git a/libs/libtpl-1.5/tests/test68.ans b/libs/libtpl-1.5/tests/test68.ans new file mode 100755 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test68.c b/libs/libtpl-1.5/tests/test68.c new file mode 100755 index 0000000000..2af8e59a54 --- /dev/null +++ b/libs/libtpl-1.5/tests/test68.c @@ -0,0 +1,37 @@ +#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; + + 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); + + for(x=0;x +#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 0000000000..1b46d69b50 Binary files /dev/null and b/libs/libtpl-1.5/tests/test7 differ 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 0000000000..ed9d7c5ff6 Binary files /dev/null and b/libs/libtpl-1.5/tests/test70 differ 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 0000000000..90106c7e6c Binary files /dev/null and b/libs/libtpl-1.5/tests/test71 differ 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 0000000000..444c6500ba Binary files /dev/null and b/libs/libtpl-1.5/tests/test72 differ 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 0000000000..1c32d97c41 Binary files /dev/null and b/libs/libtpl-1.5/tests/test73 differ 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 0000000000..e16a6d77c9 Binary files /dev/null and b/libs/libtpl-1.5/tests/test74 differ 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 0000000000..d9919fc942 Binary files /dev/null and b/libs/libtpl-1.5/tests/test75 differ 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 0000000000..67c28b70f5 Binary files /dev/null and b/libs/libtpl-1.5/tests/test76 differ 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 0000000000..a1bfd3a864 Binary files /dev/null and b/libs/libtpl-1.5/tests/test77 differ 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 0000000000..af888db01c Binary files /dev/null and b/libs/libtpl-1.5/tests/test78 differ 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 0000000000..ba5996756f Binary files /dev/null and b/libs/libtpl-1.5/tests/test79 differ 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 0000000000..804800be2b Binary files /dev/null and b/libs/libtpl-1.5/tests/test8 differ 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 0000000000..7cdd125748 Binary files /dev/null and b/libs/libtpl-1.5/tests/test80 differ diff --git a/libs/libtpl-1.5/tests/test80.ans b/libs/libtpl-1.5/tests/test80.ans new file mode 100755 index 0000000000..ee45485c57 --- /dev/null +++ b/libs/libtpl-1.5/tests/test80.ans @@ -0,0 +1 @@ +a 0 1 2 3 4 5 6 7 8 9 diff --git a/libs/libtpl-1.5/tests/test80.c b/libs/libtpl-1.5/tests/test80.c new file mode 100755 index 0000000000..17b8b4aa86 --- /dev/null +++ b/libs/libtpl-1.5/tests/test80.c @@ -0,0 +1,30 @@ +#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); + 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 +#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); + for(j=0;j +#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 0000000000..e9e1e6415f Binary files /dev/null and b/libs/libtpl-1.5/tests/test83 differ diff --git a/libs/libtpl-1.5/tests/test83.ans b/libs/libtpl-1.5/tests/test83.ans new file mode 100755 index 0000000000..39a07f8702 --- /dev/null +++ b/libs/libtpl-1.5/tests/test83.ans @@ -0,0 +1,7 @@ +& z 0.90 0.80 0.70 0.60 0.50 +-1 -2 -3 -4 -5 -6 -7 -8 -9 -10 +-2 -3 -4 -5 -6 -7 -8 -9 -10 -11 +-3 -4 -5 -6 -7 -8 -9 -10 -11 -12 +x 100 200 300 400 500 600 700 800 +y 150 250 350 450 550 650 750 850 +z 200 300 400 500 600 700 800 900 diff --git a/libs/libtpl-1.5/tests/test83.c b/libs/libtpl-1.5/tests/test83.c new file mode 100755 index 0000000000..8cadf29cb1 --- /dev/null +++ b/libs/libtpl-1.5/tests/test83.c @@ -0,0 +1,42 @@ +#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; + 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); + for(j=0;j +#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 +#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 0000000000..bb934e3e4c Binary files /dev/null and b/libs/libtpl-1.5/tests/test85.tpl differ diff --git a/libs/libtpl-1.5/tests/test86 b/libs/libtpl-1.5/tests/test86 new file mode 100755 index 0000000000..b68dbeb1f2 Binary files /dev/null and b/libs/libtpl-1.5/tests/test86 differ 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 0000000000..32313a740a Binary files /dev/null and b/libs/libtpl-1.5/tests/test87 differ 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 0000000000..7e665d14a9 Binary files /dev/null and b/libs/libtpl-1.5/tests/test88 differ 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 0000000000..5849716ba1 Binary files /dev/null and b/libs/libtpl-1.5/tests/test89 differ diff --git a/libs/libtpl-1.5/tests/test89.ans b/libs/libtpl-1.5/tests/test89.ans new file mode 100755 index 0000000000..626f9b8a80 --- /dev/null +++ b/libs/libtpl-1.5/tests/test89.ans @@ -0,0 +1,3 @@ +1 +abc +3.14 diff --git a/libs/libtpl-1.5/tests/test89.c b/libs/libtpl-1.5/tests/test89.c new file mode 100755 index 0000000000..f632db49a5 --- /dev/null +++ b/libs/libtpl-1.5/tests/test89.c @@ -0,0 +1,21 @@ +#include "tpl.h" +#include + +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 0000000000..ed6ac3b017 Binary files /dev/null and b/libs/libtpl-1.5/tests/test9 differ 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 0000000000..d928efa399 Binary files /dev/null and b/libs/libtpl-1.5/tests/test9.tpl differ diff --git a/libs/libtpl-1.5/tests/test90 b/libs/libtpl-1.5/tests/test90 new file mode 100755 index 0000000000..8097d117d4 Binary files /dev/null and b/libs/libtpl-1.5/tests/test90 differ 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 0000000000..70108c0e5a Binary files /dev/null and b/libs/libtpl-1.5/tests/test91 differ diff --git a/libs/libtpl-1.5/tests/test91.ans b/libs/libtpl-1.5/tests/test91.ans new file mode 100755 index 0000000000..4f2784a1b3 --- /dev/null +++ b/libs/libtpl-1.5/tests/test91.ans @@ -0,0 +1 @@ +cn is equal to cn2 diff --git a/libs/libtpl-1.5/tests/test91.c b/libs/libtpl-1.5/tests/test91.c new file mode 100755 index 0000000000..0e9f659faa --- /dev/null +++ b/libs/libtpl-1.5/tests/test91.c @@ -0,0 +1,23 @@ +#include +#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 0000000000..96207afea2 Binary files /dev/null and b/libs/libtpl-1.5/tests/test92 differ diff --git a/libs/libtpl-1.5/tests/test92.ans b/libs/libtpl-1.5/tests/test92.ans new file mode 100755 index 0000000000..e69de29bb2 diff --git a/libs/libtpl-1.5/tests/test92.c b/libs/libtpl-1.5/tests/test92.c new file mode 100755 index 0000000000..55d47f7c47 --- /dev/null +++ b/libs/libtpl-1.5/tests/test92.c @@ -0,0 +1,39 @@ +#include +#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 0000000000..b26847e208 Binary files /dev/null and b/libs/libtpl-1.5/tests/test93 differ diff --git a/libs/libtpl-1.5/tests/test93.ans b/libs/libtpl-1.5/tests/test93.ans new file mode 100755 index 0000000000..8023187790 --- /dev/null +++ b/libs/libtpl-1.5/tests/test93.ans @@ -0,0 +1 @@ +s is null diff --git a/libs/libtpl-1.5/tests/test93.c b/libs/libtpl-1.5/tests/test93.c new file mode 100755 index 0000000000..944cc760d6 --- /dev/null +++ b/libs/libtpl-1.5/tests/test93.c @@ -0,0 +1,21 @@ +#include "tpl.h" +#include + +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 0000000000..4b55885189 Binary files /dev/null and b/libs/libtpl-1.5/tests/test94 differ diff --git a/libs/libtpl-1.5/tests/test94.ans b/libs/libtpl-1.5/tests/test94.ans new file mode 100755 index 0000000000..572008b421 --- /dev/null +++ b/libs/libtpl-1.5/tests/test94.ans @@ -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/test94.c b/libs/libtpl-1.5/tests/test94.c new file mode 100755 index 0000000000..43843a2442 --- /dev/null +++ b/libs/libtpl-1.5/tests/test94.c @@ -0,0 +1,26 @@ +#include "tpl.h" +#include + +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 0000000000..0ad682341b Binary files /dev/null and b/libs/libtpl-1.5/tests/test95 differ 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 0000000000..b336b843d0 Binary files /dev/null and b/libs/libtpl-1.5/tests/test96 differ 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 0000000000..962283dfba Binary files /dev/null and b/libs/libtpl-1.5/tests/test97 differ 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 0000000000..ed86027110 Binary files /dev/null and b/libs/libtpl-1.5/tests/test98 differ 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 0000000000..c4f065e595 Binary files /dev/null and b/libs/libtpl-1.5/tests/test99 differ 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 0000000000..bb934e3e4c Binary files /dev/null and b/libs/libtpl-1.5/tests/test99.tpl differ diff --git a/libs/libtpl-1.5/tests/threads/Makefile b/libs/libtpl-1.5/tests/threads/Makefile new file mode 100755 index 0000000000..f44ca2e00f --- /dev/null +++ b/libs/libtpl-1.5/tests/threads/Makefile @@ -0,0 +1,26 @@ +TPLSRC = ../../src +PROGS = test1 + +# Thread support requires compiler-specific options +# ---------------------------------------------------------------------------- +# GNU +CFLAGS = -I$(TPLSRC) -g -pthread +# Solaris (Studio 11 on Sparc Ultra3) +#CFLAGS = -I$(TPLSRC) -g -mt +# ---------------------------------------------------------------------------- + +all: $(PROGS) run_tests + +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: $(PROGS) + perl ../do_tests + +.PHONY: clean + +clean: + rm -f $(PROGS) tpl.o test*.out diff --git a/libs/libtpl-1.5/tests/threads/README b/libs/libtpl-1.5/tests/threads/README new file mode 100755 index 0000000000..44f5e5c0da --- /dev/null +++ b/libs/libtpl-1.5/tests/threads/README @@ -0,0 +1,3 @@ +Tests for using tpl in threaded programs. + +thread_ipc.c a thread version of the pipe IPC test ../test28.c diff --git a/libs/libtpl-1.5/tests/threads/test1.ans b/libs/libtpl-1.5/tests/threads/test1.ans new file mode 100755 index 0000000000..5b92e81a60 --- /dev/null +++ b/libs/libtpl-1.5/tests/threads/test1.ans @@ -0,0 +1,2 @@ +sum is 49995000 +thread result: 0 null diff --git a/libs/libtpl-1.5/tests/threads/test1.c b/libs/libtpl-1.5/tests/threads/test1.c new file mode 100755 index 0000000000..388021de8d --- /dev/null +++ b/libs/libtpl-1.5/tests/threads/test1.c @@ -0,0 +1,48 @@ +#include +#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/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 diff --git a/libs/spandsp/configure.ac b/libs/spandsp/configure.ac index 22fccd6d25..9928098765 100644 --- a/libs/spandsp/configure.ac +++ b/libs/spandsp/configure.ac @@ -534,7 +534,7 @@ fi if test "$ac_cv_header_tif_dir_h" = "yes" ; then AC_DEFINE([SPANDSP_SUPPORT_TIFF_FX], [1], [Support TIFF/FX in TIFF file handling]) - SPANDSP_SUPPORT_TIFF_FX="#define SPANDSP_SUPPORT_TIFF_FX" + SPANDSP_SUPPORT_TIFF_FX="#define SPANDSP_SUPPORT_TIFF_FX 1" else SPANDSP_SUPPORT_TIFF_FX="#undef SPANDSP_SUPPORT_TIFF_FX" fi diff --git a/libs/spandsp/src/libspandsp.2010.vcxproj b/libs/spandsp/src/libspandsp.2010.vcxproj index 70740132d1..5f48082eb1 100644 --- a/libs/spandsp/src/libspandsp.2010.vcxproj +++ b/libs/spandsp/src/libspandsp.2010.vcxproj @@ -434,4 +434,4 @@ - + \ No newline at end of file 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/libs/spandsp/src/spandsp/private/t4_tx.h b/libs/spandsp/src/spandsp/private/t4_tx.h index dee5f84b92..078ac97b8a 100644 --- a/libs/spandsp/src/spandsp/private/t4_tx.h +++ b/libs/spandsp/src/spandsp/private/t4_tx.h @@ -38,7 +38,7 @@ typedef struct /*! \brief The compression type used in the TIFF file */ uint16_t compression; - /*! \brief Image type - bilevel, gray, colour */ + /*! \brief Image type - bi-level, gray, colour, etc. */ int image_type; /*! \brief The TIFF photometric setting for the current page. */ uint16_t photo_metric; @@ -96,6 +96,11 @@ struct t4_tx_state_s int line_encoding_gray; int line_encoding_colour; + /*! \brief When superfine and fine resolution images need to be squahed vertically + to a lower resolution, this value sets the number of source rows which + must be squashed to form each row on the wire. */ + int row_squashing_ratio; + /*! \brief The width of the current page, in pixels. */ uint32_t image_width; /*! \brief The length of the current page, in pixels. */ diff --git a/libs/spandsp/src/spandsp/t4_tx.h b/libs/spandsp/src/spandsp/t4_tx.h index 3eccc679c8..3bf942ca88 100644 --- a/libs/spandsp/src/spandsp/t4_tx.h +++ b/libs/spandsp/src/spandsp/t4_tx.h @@ -342,6 +342,12 @@ SPAN_DECLARE(void) t4_tx_set_header_overlays_image(t4_tx_state_t *s, int header_ \return 0 for success, otherwise -1. */ SPAN_DECLARE(int) t4_tx_set_row_read_handler(t4_tx_state_t *s, t4_row_read_handler_t handler, void *user_data); +/*! \brief Set the row squashing ratio, for adjusting row-to-row (y) resolution of bi-level + images for a T.4 transmit context. + \param s The T.4 transmit context. + \param row_squashing_ratio Vertical squashing ratio. */ +SPAN_DECLARE(void) t4_tx_set_row_squashing_ratio(t4_tx_state_t *s, int row_squashing_ratio); + /*! \brief Get the row-to-row (y) resolution of the current page. \param s The T.4 context. \return The resolution, in pixels per metre. */ diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c index e22f60b01f..a12d357f76 100644 --- a/libs/spandsp/src/t30.c +++ b/libs/spandsp/src/t30.c @@ -1308,6 +1308,7 @@ static int build_dcs(t30_state_t *s) { int i; int bad; + int row_squashing_ratio; /* Make a DCS frame based on local issues and the latest received DIS/DTC frame. Negotiate the result based on what both parties can do. */ @@ -1369,6 +1370,7 @@ static int build_dcs(t30_state_t *s) set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_RECEIVE_FAX_DOCUMENT); /* Set the Y resolution bits */ bad = T30_ERR_OK; + row_squashing_ratio = 1; switch (s->y_resolution) { case T4_Y_RESOLUTION_1200: @@ -1425,27 +1427,6 @@ static int build_dcs(t30_state_t *s) break; } break; - case T4_Y_RESOLUTION_SUPERFINE: - if (!(s->supported_resolutions & T30_SUPPORT_SUPERFINE_RESOLUTION)) - { - bad = T30_ERR_NORESSUPPORT; - } - else - { - switch (s->x_resolution) - { - case T4_X_RESOLUTION_R8: - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_400); - break; - case T4_X_RESOLUTION_R16: - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_400); - break; - default: - bad = T30_ERR_NORESSUPPORT; - break; - } - } - break; case T4_Y_RESOLUTION_300: switch (s->x_resolution) { @@ -1460,12 +1441,27 @@ static int build_dcs(t30_state_t *s) break; } break; - case T4_Y_RESOLUTION_FINE: - if (!(s->supported_resolutions & T30_SUPPORT_FINE_RESOLUTION)) + case T4_Y_RESOLUTION_SUPERFINE: + if ((s->supported_resolutions & T30_SUPPORT_SUPERFINE_RESOLUTION)) { - bad = T30_ERR_NORESSUPPORT; + switch (s->x_resolution) + { + case T4_X_RESOLUTION_R8: + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_400); + break; + case T4_X_RESOLUTION_R16: + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_400); + break; + default: + bad = T30_ERR_NORESSUPPORT; + break; + } + break; } - else + row_squashing_ratio <<= 1; + /* Fall through */ + case T4_Y_RESOLUTION_FINE: + if ((s->supported_resolutions & T30_SUPPORT_FINE_RESOLUTION)) { switch (s->x_resolution) { @@ -1476,8 +1472,10 @@ static int build_dcs(t30_state_t *s) bad = T30_ERR_NORESSUPPORT; break; } + break; } - break; + row_squashing_ratio <<= 1; + /* Fall through */ default: case T4_Y_RESOLUTION_STANDARD: switch (s->x_resolution) @@ -1491,6 +1489,7 @@ static int build_dcs(t30_state_t *s) } break; } + t4_tx_set_row_squashing_ratio(&s->t4.tx, row_squashing_ratio); if (bad != T30_ERR_OK) { t30_set_status(s, bad); @@ -1915,23 +1914,21 @@ static int set_min_scan_time_code(t30_state_t *s) switch (s->y_resolution) { case T4_Y_RESOLUTION_SUPERFINE: - if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_400_CAPABLE)) + if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_400_CAPABLE)) { - t30_set_status(s, T30_ERR_NORESSUPPORT); - span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support super-fine resolution.\n"); - return -1; + s->min_scan_time_code = translate_min_scan_time[(test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_MIN_SCAN_TIME_HALVES)) ? 2 : 1][min_bits_field]; + break; } - s->min_scan_time_code = translate_min_scan_time[(test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_MIN_SCAN_TIME_HALVES)) ? 2 : 1][min_bits_field]; - break; + span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support super-fine resolution. Squashing image.\n"); + /* Fall through */ case T4_Y_RESOLUTION_FINE: - if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE)) + if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE)) { - t30_set_status(s, T30_ERR_NORESSUPPORT); - span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support fine resolution.\n"); - return -1; + s->min_scan_time_code = translate_min_scan_time[1][min_bits_field]; + break; } - s->min_scan_time_code = translate_min_scan_time[1][min_bits_field]; - break; + span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support fine resolution. Squashing image.\n"); + /* Fall through */ default: case T4_Y_RESOLUTION_STANDARD: s->min_scan_time_code = translate_min_scan_time[0][min_bits_field]; @@ -2122,7 +2119,7 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len) } } } - span_log(&s->logging, SPAN_LOG_FLOW, "Selected compression %s (%d)\n", t4_encoding_to_str(s->line_encoding), s->line_encoding); + span_log(&s->logging, SPAN_LOG_FLOW, "Choose compression %s (%d)\n", t4_encoding_to_str(s->line_encoding), s->line_encoding); switch (s->far_dis_dtc_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3)) { case (DISBIT6 | DISBIT4 | DISBIT3): @@ -2410,7 +2407,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { s->line_encoding = T4_COMPRESSION_ITU_T4_1D; } - span_log(&s->logging, SPAN_LOG_FLOW, "Selected compression %s (%d)\n", t4_encoding_to_str(s->line_encoding), s->line_encoding); + span_log(&s->logging, SPAN_LOG_FLOW, "Far end selected compression %s (%d)\n", t4_encoding_to_str(s->line_encoding), s->line_encoding); if (!test_ctrl_bit(dcs_frame, T30_DCS_BIT_RECEIVE_FAX_DOCUMENT)) span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Remote is not requesting receive in DCS\n"); @@ -3389,12 +3386,18 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, send_simple_frame(s, T30_RTP); break; case T30_COPY_QUALITY_BAD: +#if 0 + /* Some people want to keep even the bad pages */ + if (s->keep_bad_pages) + rx_end_page(s); +#endif if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); set_state(s, T30_STATE_III_Q_RTN); send_simple_frame(s, T30_RTN); break; } + break; case T30_DCN: t30_set_status(s, T30_ERR_RX_DCNFAX); @@ -6306,9 +6309,13 @@ SPAN_DECLARE(t30_state_t *) t30_init(t30_state_t *s, /* Default to the basic modems. */ s->supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17; s->supported_compressions = T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION; - s->supported_resolutions = T30_SUPPORT_STANDARD_RESOLUTION | T30_SUPPORT_FINE_RESOLUTION | T30_SUPPORT_SUPERFINE_RESOLUTION + s->supported_resolutions = T30_SUPPORT_STANDARD_RESOLUTION + | T30_SUPPORT_FINE_RESOLUTION + | T30_SUPPORT_SUPERFINE_RESOLUTION | T30_SUPPORT_R8_RESOLUTION; - s->supported_image_sizes = T30_SUPPORT_US_LETTER_LENGTH | T30_SUPPORT_US_LEGAL_LENGTH | T30_SUPPORT_UNLIMITED_LENGTH + s->supported_image_sizes = T30_SUPPORT_US_LETTER_LENGTH + | T30_SUPPORT_US_LEGAL_LENGTH + | T30_SUPPORT_UNLIMITED_LENGTH | T30_SUPPORT_215MM_WIDTH; /* Set the output encoding to something safe. Most things get 1D and 2D encoding right. Quite a lot get other things wrong. */ diff --git a/libs/spandsp/src/t4_tx.c b/libs/spandsp/src/t4_tx.c index 6aeef44d22..2e2f25c706 100644 --- a/libs/spandsp/src/t4_tx.c +++ b/libs/spandsp/src/t4_tx.c @@ -484,12 +484,23 @@ static int open_tiff_input_file(t4_tx_state_t *s, const char *file) static int tiff_row_read_handler(void *user_data, uint8_t buf[], size_t len) { t4_tx_state_t *s; + int i; + int j; s = (t4_tx_state_t *) user_data; if (s->tiff.row >= s->image_length) return 0; memcpy(buf, &s->tiff.image_buffer[s->tiff.row*len], len); s->tiff.row++; + + /* If this is a bi-level image which has more vertical resolution than the + far end will accept, we need to squash it down to size. */ + for (i = 1; i < s->row_squashing_ratio && s->tiff.row < s->image_length; i++) + { + for (j = 0; j < s->image_width/8; j++) + buf[j] |= s->tiff.image_buffer[s->tiff.row*len + j]; + s->tiff.row++; + } return len; } /*- End of function --------------------------------------------------------*/ @@ -497,7 +508,7 @@ static int tiff_row_read_handler(void *user_data, uint8_t buf[], size_t len) static int row_read(void *user_data, uint8_t buf[], size_t len) { t4_tx_state_t *s; - + s = (t4_tx_state_t *) user_data; if (s->tiff.raw_row >= s->tiff.image_length) @@ -650,7 +661,7 @@ static int make_header(t4_tx_state_t *s) if ((s->header_text = malloc(132 + 1)) == NULL) return -1; } - /* This is very English oriented, but then most FAX machines are, too. Some + /* This is very English oriented, but then most FAX machines are. Some measure of i18n in the time and date, and even the header_info string, is entirely possible, although the font area would need some serious work to properly deal with East Asian script. There is no spec for what the header @@ -711,6 +722,7 @@ static int header_row_read_handler(void *user_data, uint8_t buf[], size_t len) repeats = 1; break; } + repeats /= s->row_squashing_ratio; if (s->header_overlays_image) { /* Read and dump a row of the real image, allowing for the possibility @@ -721,23 +733,37 @@ static int header_row_read_handler(void *user_data, uint8_t buf[], size_t len) return len; } } - row = s->header_row/repeats; - pos = 0; - for (t = s->header_text; *t && pos <= len - 2; t++) + switch (s->tiff.image_type) { - pattern = header_font[(uint8_t) *t][row]; - buf[pos++] = (uint8_t) (pattern >> 8); - buf[pos++] = (uint8_t) (pattern & 0xFF); + case T4_IMAGE_TYPE_BILEVEL: + row = s->header_row/repeats; + pos = 0; + for (t = s->header_text; *t && pos <= len - 2; t++) + { + pattern = header_font[(uint8_t) *t][row]; + buf[pos++] = (uint8_t) (pattern >> 8); + buf[pos++] = (uint8_t) (pattern & 0xFF); + } + while (pos < len) + buf[pos++] = 0; + s->header_row++; + if (s->header_row >= 16*repeats) + { + /* End of header. Change to normal image row data. */ + set_row_read_handler(s, s->row_handler, s->row_handler_user_data); + } + break; } - while (pos < len) - buf[pos++] = 0; - s->header_row++; - if (s->header_row >= 16*repeats) - set_row_read_handler(s, s->row_handler, s->row_handler_user_data); return len; } /*- End of function --------------------------------------------------------*/ +SPAN_DECLARE(void) t4_tx_set_row_squashing_ratio(t4_tx_state_t *s, int row_squashing_ratio) +{ + s->row_squashing_ratio = row_squashing_ratio; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(int) t4_tx_next_page_has_different_format(t4_tx_state_t *s) { span_log(&s->logging, SPAN_LOG_FLOW, "Checking for the existence of page %d\n", s->current_page + 1); @@ -1143,6 +1169,8 @@ SPAN_DECLARE(t4_tx_state_t *) t4_tx_init(t4_tx_state_t *s, const char *file, int s->row_handler = tiff_row_read_handler; s->row_handler_user_data = (void *) s; + s->row_squashing_ratio = 1; + if (file) { if (open_tiff_input_file(s, file) < 0) diff --git a/libs/spandsp/tests/t4_tests.c b/libs/spandsp/tests/t4_tests.c index db9581aaee..b159ad81a8 100644 --- a/libs/spandsp/tests/t4_tests.c +++ b/libs/spandsp/tests/t4_tests.c @@ -575,7 +575,7 @@ int main(int argc, char *argv[]) if (compression < 0 || (block_size == 0 && compression_step >= 3)) break; } - t4_tx_set_tx_encoding(&send_state, compression, T4_COMPRESSION_NONE); + t4_tx_set_tx_encoding(&send_state, compression); t4_rx_set_rx_encoding(&receive_state, compression); rows_read = 0; @@ -716,7 +716,7 @@ int main(int argc, char *argv[]) compression = compression_sequence[compression_step++]; } } - t4_tx_set_tx_encoding(&send_state, compression, T4_COMPRESSION_NONE); + t4_tx_set_tx_encoding(&send_state, compression); t4_rx_set_rx_encoding(&receive_state, compression); if (t4_tx_start_page(&send_state)) 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 @@ > - + \ No newline at end of file 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/include/switch_json.h b/src/include/switch_json.h index 36f51be6df..b4ca229c39 100755 --- a/src/include/switch_json.h +++ b/src/include/switch_json.h @@ -19,9 +19,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - #include "switch.h" - #ifndef cJSON__h #define cJSON__h @@ -30,7 +28,7 @@ extern "C" { #endif -// cJSON Types: +/* cJSON Types: */ #define cJSON_False 0 #define cJSON_True 1 #define cJSON_NULL 2 @@ -41,18 +39,18 @@ extern "C" #define cJSON_IsReference 256 -// The cJSON structure: +/* The cJSON structure: */ typedef struct cJSON { - struct cJSON *next,*prev; // next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem - struct cJSON *child; // An array or object item will have a child pointer pointing to a chain of the items in the array/object. + struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ - int type; // The type of the item, as above. + int type; /* The type of the item, as above. */ - char *valuestring; // The item's string, if type==cJSON_String - int valueint; // The item's number, if type==cJSON_Number - double valuedouble; // The item's number, if type==cJSON_Number + char *valuestring; /* The item's string, if type==cJSON_String */ + int valueint; /* The item's number, if type==cJSON_Number */ + double valuedouble; /* The item's number, if type==cJSON_Number */ - char *string; // The item's name string, if this item is the child of, or is in the list of subitems of an object. + char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ } cJSON; typedef struct cJSON_Hooks { @@ -60,55 +58,59 @@ typedef struct cJSON_Hooks { void (*free_fn)(void *ptr); } cJSON_Hooks; -// Supply malloc, realloc and free functions to cJSON +/* Supply malloc, realloc and free functions to cJSON */ SWITCH_DECLARE(void) cJSON_InitHooks(cJSON_Hooks* hooks); -// Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ SWITCH_DECLARE(cJSON *)cJSON_Parse(const char *value); -// Render a cJSON entity to text for transfer/storage. Free the char* when finished. +/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ SWITCH_DECLARE(char *)cJSON_Print(cJSON *item); -// Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. +/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ SWITCH_DECLARE(char *)cJSON_PrintUnformatted(cJSON *item); -// Delete a cJSON entity and all subentities. +/* Delete a cJSON entity and all subentities. */ SWITCH_DECLARE(void) cJSON_Delete(cJSON *c); -// Returns the number of items in an array (or object). +/* Returns the number of items in an array (or object). */ SWITCH_DECLARE(int) cJSON_GetArraySize(cJSON *array); -// Retrieve item number "item" from array "array". Returns NULL if unsuccessful. +/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ SWITCH_DECLARE(cJSON *)cJSON_GetArrayItem(cJSON *array,int item); -// Get item "string" from object. Case insensitive. +/* Get item "string" from object. Case insensitive. */ 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(void); -// These calls create a cJSON item of the appropriate type. +/* These calls create a cJSON item of the appropriate type. */ 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(void); SWITCH_DECLARE(cJSON *)cJSON_CreateObject(void); -// These utilities create an Array of count items. +/* These utilities create an Array of count items. */ SWITCH_DECLARE(cJSON *)cJSON_CreateIntArray(int *numbers,int count); SWITCH_DECLARE(cJSON *)cJSON_CreateFloatArray(float *numbers,int count); SWITCH_DECLARE(cJSON *)cJSON_CreateDoubleArray(double *numbers,int count); SWITCH_DECLARE(cJSON *)cJSON_CreateStringArray(const char **strings,int count); -// Append item to the specified array/object. +/* Append item to the specified array/object. */ SWITCH_DECLARE(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); SWITCH_DECLARE(void) cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); -// Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ SWITCH_DECLARE(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); SWITCH_DECLARE(void) cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); -// Remove/Detatch items from Arrays/Objects. +/* Remove/Detatch items from Arrays/Objects. */ SWITCH_DECLARE(cJSON *)cJSON_DetachItemFromArray(cJSON *array,int which); SWITCH_DECLARE(void) cJSON_DeleteItemFromArray(cJSON *array,int which); SWITCH_DECLARE(cJSON *)cJSON_DetachItemFromObject(cJSON *object,const char *string); SWITCH_DECLARE(void) cJSON_DeleteItemFromObject(cJSON *object,const char *string); -// Update array items. +/* Update array items. */ SWITCH_DECLARE(void) cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); SWITCH_DECLARE(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); diff --git a/src/include/switch_types.h b/src/include/switch_types.h index db9cf5cb0e..9fa47ac2b8 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -108,12 +108,13 @@ 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 #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 @@ -1747,7 +1748,8 @@ typedef enum { 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 } switch_call_cause_t; typedef enum { 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/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); 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/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]; 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/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; } 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 + */ diff --git a/src/mod/applications/mod_spandsp/mod_spandsp_fax.c b/src/mod/applications/mod_spandsp/mod_spandsp_fax.c index 57fb05a439..51dcc6ba57 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); @@ -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 (%i)\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/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 + + + + + + diff --git a/src/mod/codecs/mod_opus/Makefile b/src/mod/codecs/mod_opus/Makefile index 21a526a671..c57e047461 100644 --- a/src/mod/codecs/mod_opus/Makefile +++ b/src/mod/codecs/mod_opus/Makefile @@ -1,32 +1,28 @@ BASE=../../../.. -OPUS=opus-0.9.0 +OPUS=opus-1.0.1 OPUS_DIR=$(switch_srcdir)/libs/$(OPUS) OPUS_BUILDDIR=$(switch_builddir)/libs/$(OPUS) -LOCAL_CFLAGS=-I$(OPUS_DIR)/src -g -O2 +LOCAL_CFLAGS=-I$(OPUS_DIR)/include -g -O2 -IETF_LA=$(OPUS_BUILDDIR)/src/libietfcodec.la -CELT_LA=$(OPUS_BUILDDIR)/celt/libcelt/libcelt0.la -SILK_LA=$(OPUS_BUILDDIR)/silk/libSKP_SILK_SDK.la +OPUS_LA=$(OPUS_BUILDDIR)/.libs/libopus.la -LOCAL_LIBADD=$(IETF_LA) $(CELT_LA) $(SILK_LA) -lm -lz +LOCAL_LIBADD=$(OPUS_LA) -lm -lz include $(BASE)/build/modmake.rules $(OPUS_DIR): $(GETLIB) $(OPUS).tar.gz -$(OPUS_BUILDDIR)/Makefile: $(OPUS_DIR) - mkdir -p $(OPUS_BUILDDIR) +$(OPUS_DIR)/Makefile: $(OPUS_DIR) cd $(OPUS_BUILDDIR) && $(DEFAULT_VARS) $(OPUS_DIR)/configure --disable-shared --with-pic --srcdir=$(OPUS_DIR) $(TOUCH_TARGET) -$(IETF_LA): $(OPUS_BUILDDIR)/Makefile +$(OPUS_LA): $(OPUS_DIR)/Makefile cd $(OPUS_BUILDDIR) && $(MAKE) - $(TOUCH_TARGET) -$(CELT_LA): $(IETF_LA) -$(SILK_LA): $(IETF_LA) -$(MODNAME).lo: $(IETF_LA) $(CELT_LA) $(SILK_LA) + +$(MODNAME).lo: $(OPUS_LA) + diff --git a/src/mod/codecs/mod_opus/mod_opus.c b/src/mod/codecs/mod_opus/mod_opus.c index 285557fd96..d88e88fe43 100644 --- a/src/mod/codecs/mod_opus/mod_opus.c +++ b/src/mod/codecs/mod_opus/mod_opus.c @@ -57,27 +57,48 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag if (encoding) { /* come up with a way to specify these */ int bitrate_bps = codec->implementation->bits_per_second; - int mode = MODE_HYBRID; int use_vbr = 1; int complexity = 10; int use_inbandfec = 1; int use_dtx = 1; - int bandwidth = BANDWIDTH_FULLBAND; + int bandwidth = OPUS_BANDWIDTH_FULLBAND; + int err; - context->encoder_object = opus_encoder_create(codec->implementation->actual_samples_per_second, codec->implementation->number_of_channels); + context->encoder_object = opus_encoder_create(codec->implementation->actual_samples_per_second, + codec->implementation->number_of_channels, OPUS_APPLICATION_VOIP, &err); + + if (err != OPUS_OK) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot create encoder: %s\n", opus_strerror(err)); + return SWITCH_STATUS_GENERR; + } - opus_encoder_ctl(context->encoder_object, OPUS_SET_MODE(mode)); opus_encoder_ctl(context->encoder_object, OPUS_SET_BITRATE(bitrate_bps)); opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(bandwidth)); - opus_encoder_ctl(context->encoder_object, OPUS_SET_VBR_FLAG(use_vbr)); + opus_encoder_ctl(context->encoder_object, OPUS_SET_VBR(use_vbr)); opus_encoder_ctl(context->encoder_object, OPUS_SET_COMPLEXITY(complexity)); - opus_encoder_ctl(context->encoder_object, OPUS_SET_INBAND_FEC_FLAG(use_inbandfec)); - opus_encoder_ctl(context->encoder_object, OPUS_SET_DTX_FLAG(use_dtx)); + opus_encoder_ctl(context->encoder_object, OPUS_SET_INBAND_FEC(use_inbandfec)); + opus_encoder_ctl(context->encoder_object, OPUS_SET_DTX(use_dtx)); } if (decoding) { - context->decoder_object = opus_decoder_create(codec->implementation->actual_samples_per_second, codec->implementation->number_of_channels); + int err; + + context->decoder_object = opus_decoder_create(codec->implementation->actual_samples_per_second, + codec->implementation->number_of_channels, &err); + + + if (err != OPUS_OK) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot create decoder: %s\n", opus_strerror(err)); + + if (context->encoder_object) { + opus_encoder_destroy(context->encoder_object); + context->encoder_object = NULL; + } + + return SWITCH_STATUS_GENERR; + } + } codec->private_info = context; @@ -87,6 +108,19 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag static switch_status_t switch_opus_destroy(switch_codec_t *codec) { + struct opus_context *context = codec->private_info; + + if (context) { + if (context->decoder_object) { + opus_decoder_destroy(context->decoder_object); + context->decoder_object = NULL; + } + if (context->encoder_object) { + opus_encoder_destroy(context->encoder_object); + context->encoder_object = NULL; + } + } + codec->private_info = NULL; return SWITCH_STATUS_SUCCESS; } @@ -133,7 +167,7 @@ static switch_status_t switch_opus_decode(switch_codec_t *codec, return SWITCH_STATUS_FALSE; } - samples = opus_decode(context->decoder_object, encoded_data, encoded_data_len, decoded_data, *decoded_data_len); + samples = opus_decode(context->decoder_object, (*flag & SFF_PLC) ? NULL : encoded_data, encoded_data_len, decoded_data, *decoded_data_len, 0); if (samples < 0) { return SWITCH_STATUS_GENERR; @@ -157,12 +191,12 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load) /* connect my internal structure to the blank pointer passed to me */ *module_interface = switch_loadable_module_create_module_interface(pool, modname); - SWITCH_ADD_CODEC(codec_interface, "OPUS (BETA 0.9.0)"); + SWITCH_ADD_CODEC(codec_interface, "OPUS (STANDARD)"); for (x = 0; x < 2; x++) { switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ 115, /* the IANA code number */ - "Opus-0.9.0",/* the IANA code name */ + "opus",/* the IANA code name */ NULL, /* default fmtp to send (can be overridden by the init function) */ rate, /* samples transferred per second */ rate, /* actual samples transferred per second */ diff --git a/src/mod/endpoints/mod_opal/mod_opal.cpp b/src/mod/endpoints/mod_opal/mod_opal.cpp index cf160ba527..53c504b059 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.cpp +++ b/src/mod/endpoints/mod_opal/mod_opal.cpp @@ -26,12 +26,15 @@ #include "mod_opal.h" #include #include +#if PTLIB_CHECK_VERSION(2,11,1) +#include +#endif #include #include /* 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 @@ -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 = { @@ -101,7 +105,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); @@ -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 @@ -310,13 +314,20 @@ 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 + 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", @@ -361,6 +372,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") { @@ -441,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) @@ -453,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."); @@ -478,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)); @@ -485,13 +506,15 @@ 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 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; } @@ -602,6 +625,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 @@ -632,6 +669,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; } @@ -743,6 +781,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, "_preconfigured_t38_options"); + 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 } @@ -763,17 +824,25 @@ 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(); + 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) { - // Have open media in both directions. - if (IsEstablished()) - switch_channel_mark_answered(m_fsChannel); - else if (!IsReleased()) - switch_channel_mark_pre_answered(m_fsChannel); + 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()) { + PTRACE(3, "mod_opal\tOnPatchMediaStream for outbound call, making call answered"); + switch_channel_mark_answered(m_fsChannel); + } + else if (!IsReleased()) { + PTRACE(3, "mod_opal\tOnPatchMediaStream for outbound call, making call pre-answered"); + switch_channel_mark_pre_answered(m_fsChannel); + } + } } } @@ -813,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); @@ -851,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; } @@ -860,14 +929,18 @@ 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 channel KILL on connection " << *this); + CloseMediaStreams(); 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; } @@ -877,6 +950,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; } @@ -952,6 +1026,29 @@ 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: + { + PTRACE(2, "mod_opal\tRequesting switch to T.38"); + PSafePtr other = GetOtherPartyConnection(); + 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"); + m_udptl = true; + break; +#endif // HAVE_T38 + default: PTRACE(3, "mod_opal\tReceived unhandled message " << msg->message_id << " on connection " << *this); } @@ -977,6 +1074,97 @@ bool FSConnection::WaitForMedia() } +#if HAVE_T38 +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, varname); + 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, varname, t38_options); + PTRACE(3, "mod_opal\tSet " << varname); +} + + +void FSConnection::OnSwitchedT38(bool toT38, bool success) +{ + 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()) { + PTRACE(3, "mod_opal\tMode change request to T.38 started"); + } + else { + 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) { + 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()) { + PTRACE(3, "mod_opal\tCan't change to T.38, no remote capability"); + return false; + } + + 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_t38"); + switch_channel_api_on(m_fsChannel, "opal_api_on_t38"); + return true; +} +#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); @@ -993,13 +1181,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) { - return read_frame(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) { - return write_frame(OpalMediaType::Audio(), frame, flags); + return write_frame(m_udptl ? OpalMediaType::Fax() : OpalMediaType::Audio(), frame, flags); } @@ -1017,15 +1205,32 @@ 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 (!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); + } + + // 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)); - 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; } @@ -1034,6 +1239,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)); @@ -1052,11 +1259,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|SFF_PROXY_PACKET; + return OpalMediaStream::Open(); + } +#endif + else { + PTRACE(1, "mod_opal\tUnsupported media type: " << mediaType); return false; } @@ -1083,13 +1298,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 +1317,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 +1337,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(); } @@ -1148,17 +1363,12 @@ PBoolean FSMediaStream::RequiresPatchThread(OpalMediaStream *) const 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!"); + PTRACE(1, "mod_opal\tNot open!"); return -1; } if (!m_connection.IsChannelReady()) { - PTRACE(2, "mod_opal\tChannel not ready!"); + PTRACE(1, "mod_opal\tChannel not ready!"); return -1; } @@ -1167,7 +1377,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; } @@ -1177,6 +1387,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 : @@ -1189,9 +1402,12 @@ 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!"); return SWITCH_STATUS_FALSE; } } @@ -1202,13 +1418,24 @@ 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; } } - m_readFrame.packet = m_readRTP.GetPointer(); - m_readFrame.packetlen = m_readRTP.GetHeaderSize() + m_readFrame.datalen; + 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. @@ -1224,11 +1451,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; - *frame = &m_readFrame; + 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; } @@ -1244,27 +1472,36 @@ switch_status_t FSMediaStream::write_frame(const switch_frame_t *frame, switch_i return SWITCH_STATUS_SUCCESS; } - if ((frame->flags & 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.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 if (m_switchCodec != NULL) + timestamp += m_switchCodec->implementation->samples_per_packet; + rtp.SetTimestamp(timestamp); } - RTP_DataFrame rtp(frame->datalen); - memcpy(rtp.GetPayloadPtr(), frame->data, frame->datalen); + if (mediaPatch->PushFrame(rtp)) + return SWITCH_STATUS_SUCCESS; - 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; + 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 5edc21f8a0..da2ea1fa5b 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. */ @@ -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; @@ -242,12 +248,17 @@ 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); 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 +305,11 @@ class FSConnection : public OpalLocalConnection protected: void SetCodecs(); bool WaitForMedia(); +#if HAVE_T38 + 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); switch_status_t write_frame(const OpalMediaType & mediaType, const switch_frame_t *frame, switch_io_flag_t flags); @@ -315,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(); }; 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) 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/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.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" > + + diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index d25eabba39..aa3f3207d5 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -5795,6 +5795,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 f0c57cb988..683929a88a 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -272,6 +272,7 @@ typedef enum { PFLAG_THREAD_PER_REG, PFLAG_MWI_USE_REG_CALLID, PFLAG_FIRE_MESSAGE_EVENTS, + PFLAG_SEND_DISPLAY_UPDATE, /* No new flags below this line */ PFLAG_MAX } PFLAGS; diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index bcdce473c3..b807cf962b 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -124,6 +124,7 @@ switch_io_routines_t crtp_io_routines = { /*write_video_frame*/ NULL, /*state_run*/ NULL + }; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index c95a00b820..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); @@ -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++; } @@ -2497,12 +2500,13 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created agent for %s\n", profile->name); nua_set_params(profile->nua, - SIPTAG_ALLOW_STR("INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, UPDATE, INFO"), + SIPTAG_ALLOW_STR("INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO"), NUTAG_AUTOANSWER(0), NUTAG_AUTOACK(0), NUTAG_AUTOALERT(0), NUTAG_ENABLEMESSENGER(1), NTATAG_EXTRA_100(0), + TAG_IF(sofia_test_pflag(profile, PFLAG_SEND_DISPLAY_UPDATE), NUTAG_ALLOW("UPDATE")), TAG_IF((profile->mflags & MFLAG_REGISTER), NUTAG_ALLOW("REGISTER")), TAG_IF((profile->mflags & MFLAG_REFER), NUTAG_ALLOW("REFER")), TAG_IF(!sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_ALLOW("PRACK")), @@ -3609,6 +3613,12 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile) } else { sofia_clear_pflag(profile, PFLAG_CONFIRM_BLIND_TRANSFER); } + } else if (!strcasecmp(var, "send-display-update")) { + if (switch_true(val)) { + sofia_set_pflag(profile, PFLAG_SEND_DISPLAY_UPDATE); + } else { + sofia_clear_pflag(profile, PFLAG_SEND_DISPLAY_UPDATE); + } } else if (!strcasecmp(var, "mwi-use-reg-callid")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_MWI_USE_REG_CALLID); @@ -4359,6 +4369,7 @@ switch_status_t config_sofia(int reload, char *profile_name) sofia_set_pflag(profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE); profile->contact_user = SOFIA_DEFAULT_CONTACT_USER; sofia_set_pflag(profile, PFLAG_PASS_CALLEE_ID); + sofia_set_pflag(profile, PFLAG_SEND_DISPLAY_UPDATE); sofia_set_pflag(profile, PFLAG_MESSAGE_QUERY_ON_FIRST_REGISTER); //sofia_set_pflag(profile, PFLAG_PRESENCE_ON_FIRST_REGISTER); sofia_set_pflag(profile, PFLAG_SQL_IN_TRANS); @@ -4432,6 +4443,12 @@ switch_status_t config_sofia(int reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_CONFIRM_BLIND_TRANSFER); } + } else if (!strcasecmp(var, "send-display-update")) { + if (switch_true(val)) { + sofia_set_pflag(profile, PFLAG_SEND_DISPLAY_UPDATE); + } else { + sofia_clear_pflag(profile, PFLAG_SEND_DISPLAY_UPDATE); + } } else if (!strcasecmp(var, "mwi-use-reg-callid")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_MWI_USE_REG_CALLID); @@ -4925,6 +4942,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; @@ -6396,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); } } @@ -6528,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"); @@ -7117,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"); @@ -7387,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"); @@ -7491,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); @@ -7699,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); 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)) { 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; diff --git a/src/mod/event_handlers/mod_erlang_event/mod_erlang_event.c b/src/mod/event_handlers/mod_erlang_event/mod_erlang_event.c index c462cf30e1..0aeaece8dd 100644 --- a/src/mod/event_handlers/mod_erlang_event/mod_erlang_event.c +++ b/src/mod/event_handlers/mod_erlang_event/mod_erlang_event.c @@ -1720,8 +1720,7 @@ SWITCH_STANDARD_API(erlang_cmd) } else if (!strcasecmp(argv[0], "bindings")) { int found = 0; struct erlang_binding *ptr; - switch_thread_rwlock_wrlock(globals.bindings_rwlock); - switch_xml_set_binding_sections(bindings.search_binding, SWITCH_XML_SECTION_MAX); + switch_thread_rwlock_rdlock(globals.bindings_rwlock); for (ptr = bindings.head; ptr; ptr = ptr->next) { 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 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, 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"); } 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..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 ) { - goto err; + 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 ) { - goto err; + 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 ) { - goto err; + 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; 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_channel.c b/src/switch_channel.c index 3f767ae21d..f823b22e49 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -4032,6 +4032,23 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_timestamps(switch_channel_t * switch_channel_set_variable(channel, "progress_media_stamp", progress_media); } + if (channel->hold_record) { + switch_hold_record_t *hr; + switch_stream_handle_t stream = { 0 }; + + SWITCH_STANDARD_STREAM(stream); + + stream.write_function(&stream, "{", SWITCH_VA_NONE); + + for (hr = channel->hold_record; hr; hr = hr->next) { + stream.write_function(&stream, "{%"SWITCH_TIME_T_FMT",%"SWITCH_TIME_T_FMT"},", hr->on, hr->off); + } + end_of((char *)stream.data) = '}'; + + switch_channel_set_variable(channel, "hold_events", (char *)stream.data); + free(stream.data); + } + switch_time_exp_lt(&tm, caller_profile->times->hungup); switch_strftime_nocheck(end, &retsize, sizeof(end), fmt, &tm); switch_channel_set_variable(channel, "end_stamp", end); diff --git a/src/switch_core.c b/src/switch_core.c index 3f1a6d5075..30f1ef3bae 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; @@ -926,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 = NULL; + 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; @@ -962,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_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; } 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; } diff --git a/src/switch_event.c b/src/switch_event.c index 242165d69f..3a02e3a449 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 @@ -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; } @@ -1284,6 +1285,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; diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index ed2506a4f6..0b02d2ba2c 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -781,11 +781,10 @@ static uint8_t check_channel_status(originate_global_t *oglobals, originate_stat end: if (rval == 0 && pickups) { - *force_reason = SWITCH_CAUSE_NO_ANSWER; for (i = 0; i < len; i++) { if (originate_status[i].peer_channel && switch_channel_test_flag(originate_status[i].peer_channel, CF_PICKUP) && switch_channel_up(originate_status[i].peer_channel)) { - switch_channel_hangup(originate_status[i].peer_channel, SWITCH_CAUSE_NO_ANSWER); + switch_channel_hangup(originate_status[i].peer_channel, SWITCH_CAUSE_NO_PICKUP); } } } @@ -1632,7 +1631,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_enterprise_originate(switch_core_sess } switch_mutex_unlock(handles[i].mutex); - if (getcause && *cause != handles[i].cause && handles[i].cause != SWITCH_CAUSE_LOSE_RACE) { + if (getcause && *cause != handles[i].cause && handles[i].cause != SWITCH_CAUSE_LOSE_RACE && handles[i].cause != SWITCH_CAUSE_NO_PICKUP) { *cause = handles[i].cause; getcause++; } @@ -2497,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, diff --git a/src/switch_json.c b/src/switch_json.c index 4bef601f8e..c68e678ebf 100644 --- a/src/switch_json.c +++ b/src/switch_json.c @@ -20,12 +20,23 @@ THE SOFTWARE. */ -// cJSON -// JSON parser in C. +/* cJSON */ +/* JSON parser in C. */ +#include +#include +#include +#include +#include +#include #include "switch.h" +#include "switch_json.h" #include +static const char *ep; + +SWITCH_DECLARE(const char *)cJSON_GetErrorPtr() {return ep;} + static int cJSON_strcasecmp(const char *s1,const char *s2) { if (!s1) return (s1==s2)?0:1;if (!s2) return 1; @@ -58,7 +69,7 @@ static char* cJSON_strdup(const char* str) return copy; } -SWITCH_DECLARE(void) cJSON_InitHooks(cJSON_Hooks* hooks) +SWITCH_DECLARE(void)cJSON_InitHooks(cJSON_Hooks* hooks) { if (!hooks) { /* Reset hooks */ cJSON_malloc = malloc; @@ -70,16 +81,16 @@ SWITCH_DECLARE(void) cJSON_InitHooks(cJSON_Hooks* hooks) cJSON_free = (hooks->free_fn)?hooks->free_fn:free; } -// Internal constructor. -static cJSON *cJSON_New_Item(void) +/* Internal constructor. */ +static cJSON *cJSON_New_Item() { cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); if (node) memset(node,0,sizeof(cJSON)); return node; } -// Delete a cJSON structure. -SWITCH_DECLARE(void) cJSON_Delete(cJSON *c) +/* Delete a cJSON structure. */ +SWITCH_DECLARE(void)cJSON_Delete(cJSON *c) { cJSON *next; while (c) @@ -93,22 +104,22 @@ SWITCH_DECLARE(void) cJSON_Delete(cJSON *c) } } -// Parse the input text to generate a number, and populate the result into item. +/* Parse the input text to generate a number, and populate the result into item. */ static const char *parse_number(cJSON *item,const char *num) { double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; - // Could use sscanf for this? - if (*num=='-') sign=-1,num++; // Has sign? - if (*num=='0') num++; // is zero - if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); // Number? - if (*num=='.') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} // Fractional part? - if (*num=='e' || *num=='E') // Exponent? - { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; // With sign? - while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); // Number? + /* Could use sscanf for this? */ + if (*num=='-') sign=-1,num++; /* Has sign? */ + if (*num=='0') num++; /* is zero */ + if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ + if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ + if (*num=='e' || *num=='E') /* Exponent? */ + { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ + while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ } - n=sign*n*pow(10.0,(scale+subscale*signsubscale)); // number = +/- number.fraction * 10^+/- exponent + n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ item->valuedouble=n; item->valueint=(int)n; @@ -116,40 +127,43 @@ static const char *parse_number(cJSON *item,const char *num) return num; } -// Render the number nicely from the given item into a string. +/* Render the number nicely from the given item into a string. */ static char *print_number(cJSON *item) { char *str; double d=item->valuedouble; if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) { - str=(char*)cJSON_malloc(21); // 2^64+1 can be represented in 21 chars. - sprintf(str,"%d",item->valueint); + str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */ + if (str) sprintf(str,"%d",item->valueint); } else { - str=(char*)cJSON_malloc(64); // This is a nice tradeoff. - if (fabs(floor(d)-d)<=DBL_EPSILON) sprintf(str,"%.0f",d); - else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); - else sprintf(str,"%f",d); + str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */ + if (str) + { + if (fabs(floor(d)-d)<=DBL_EPSILON) sprintf(str,"%.0f",d); + else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); + else sprintf(str,"%f",d); + } } return str; } -// Parse the input text into an unescaped cstring, and populate item. +/* Parse the input text into an unescaped cstring, and populate item. */ static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; static const char *parse_string(cJSON *item,const char *str) { - const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc; - if (*str!='\"') return 0; // not a string! + const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; + if (*str!='\"') {ep=str;return 0;} /* not a string! */ - while (*ptr!='\"' && (unsigned char)*ptr>31 && ++len) if (*ptr++ == '\\') ptr++; // Skip escaped quotes. + while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ - out=(char*)cJSON_malloc(len+1); // This is how long we need for the string, roughly. + out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */ if (!out) return 0; ptr=str+1;ptr2=out; - while (*ptr!='\"' && (unsigned char)*ptr>31) + while (*ptr!='\"' && *ptr) { if (*ptr!='\\') *ptr2++=*ptr++; else @@ -162,16 +176,31 @@ static const char *parse_string(cJSON *item,const char *str) case 'n': *ptr2++='\n'; break; case 'r': *ptr2++='\r'; break; case 't': *ptr2++='\t'; break; - case 'u': // transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY. - if (sscanf(ptr+1,"%4x",&uc) < 1) break; // get the unicode char. - len=3;if (uc<0x80) len=1;else if (uc<0x800) len=2;ptr2+=len; + case 'u': /* transcode utf16 to utf8. */ + if (sscanf(ptr+1,"%4x",&uc) < 1) break; + + ptr+=4; /* get the unicode char. */ + + if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; // check for invalid. + + if (uc>=0xD800 && uc<=0xDBFF) // UTF16 surrogate pairs. + { + if (ptr[1]!='\\' || ptr[2]!='u') break; // missing second-half of surrogate. + if (sscanf(ptr+3,"%4x",&uc2) < 1) break; + ptr+=6; + if (uc2<0xDC00 || uc2>0xDFFF) break; // invalid second-half of surrogate. + uc=0x10000 | ((uc&0x3FF)<<10) | (uc2&0x3FF); + } + + len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; switch (len) { + case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; case 1: *--ptr2 =(char)(uc | firstByteMark[len]); } - ptr2+=len;ptr+=4; + ptr2+=len; break; default: *ptr2++=*ptr; break; } @@ -185,15 +214,17 @@ static const char *parse_string(cJSON *item,const char *str) return ptr; } -// Render the cstring provided to an escaped version that can be printed. +/* Render the cstring provided to an escaped version that can be printed. */ static char *print_string_ptr(const char *str) { - const char *ptr;char *ptr2,*out;int len=0; + const char *ptr;char *ptr2,*out;int len=0;unsigned char token; if (!str) return cJSON_strdup(""); - ptr=str;while (*ptr && ++len) {if ((unsigned char)*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;} + ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} out=(char*)cJSON_malloc(len+3); + if (!out) return 0; + ptr2=out;ptr=str; *ptr2++='\"'; while (*ptr) @@ -202,7 +233,7 @@ static char *print_string_ptr(const char *str) else { *ptr2++='\\'; - switch (*ptr++) + switch (token=*ptr++) { case '\\': *ptr2++='\\'; break; case '\"': *ptr2++='\"'; break; @@ -211,17 +242,17 @@ static char *print_string_ptr(const char *str) case '\n': *ptr2++='n'; break; case '\r': *ptr2++='r'; break; case '\t': *ptr2++='t'; break; - default: ptr2--; break; // eviscerate with prejudice. + default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ } } } *ptr2++='\"';*ptr2++=0; return out; } -// Invote print_string_ptr (which is useful) on an item. +/* Invote print_string_ptr (which is useful) on an item. */ static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);} -// Predeclare these prototypes. +/* Predeclare these prototypes. */ static const char *parse_value(cJSON *item,const char *value); static char *print_value(cJSON *item,int depth,int fmt); static const char *parse_array(cJSON *item,const char *value); @@ -229,27 +260,28 @@ static char *print_array(cJSON *item,int depth,int fmt); static const char *parse_object(cJSON *item,const char *value); static char *print_object(cJSON *item,int depth,int fmt); -// Utility to jump whitespace and cr/lf -static const char *skip(const char *in) {while (in && (unsigned char)*in<=32) in++; return in;} +/* Utility to jump whitespace and cr/lf */ +static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} -// Parse an object - create a new root, and populate. +/* Parse an object - create a new root, and populate. */ SWITCH_DECLARE(cJSON *)cJSON_Parse(const char *value) { cJSON *c=cJSON_New_Item(); + ep=0; if (!c) return 0; /* memory fail */ if (!parse_value(c,skip(value))) {cJSON_Delete(c);return 0;} return c; } -// Render a cJSON item/entity/structure to text. +/* Render a cJSON item/entity/structure to text. */ 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. +/* Parser core - when encountering text, process appropriately. */ static const char *parse_value(cJSON *item,const char *value) { - if (!value) return 0; // Fail on null. + if (!value) return 0; /* Fail on null. */ if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } @@ -258,10 +290,10 @@ static const char *parse_value(cJSON *item,const char *value) if (*value=='[') { return parse_array(item,value); } if (*value=='{') { return parse_object(item,value); } - return 0; // failure. + ep=value;return 0; /* failure. */ } -// Render a value to text. +/* Render a value to text. */ static char *print_value(cJSON *item,int depth,int fmt) { char *out=0; @@ -279,35 +311,35 @@ static char *print_value(cJSON *item,int depth,int fmt) return out; } -// Build an array from input text. +/* Build an array from input text. */ static const char *parse_array(cJSON *item,const char *value) { cJSON *child; - if (*value!='[') return 0; // not an array! + if (*value!='[') {ep=value;return 0;} /* not an array! */ item->type=cJSON_Array; value=skip(value+1); - if (*value==']') return value+1; // empty array. + if (*value==']') return value+1; /* empty array. */ item->child=child=cJSON_New_Item(); - if (!item->child) return 0; // memory fail - value=skip(parse_value(child,skip(value))); // skip any spacing, get the value. + if (!item->child) return 0; /* memory fail */ + value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */ if (!value) return 0; while (*value==',') { cJSON *new_item; - if (!(new_item=cJSON_New_Item())) return 0; // memory fail + if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ child->next=new_item;new_item->prev=child;child=new_item; value=skip(parse_value(child,skip(value+1))); - if (!value) return 0; // memory fail + if (!value) return 0; /* memory fail */ } - if (*value==']') return value+1; // end of array - return 0; // malformed. + if (*value==']') return value+1; /* end of array */ + ep=value;return 0; /* malformed. */ } -// Render an array to text +/* Render an array to text */ static char *print_array(cJSON *item,int depth,int fmt) { char **entries; @@ -315,13 +347,13 @@ static char *print_array(cJSON *item,int depth,int fmt) cJSON *child=item->child; int numentries=0,i=0,fail=0; - // How many entries in the array? + /* How many entries in the array? */ while (child) numentries++,child=child->next; - // Allocate an array to hold the values for each + /* Allocate an array to hold the values for each */ entries=(char**)cJSON_malloc(numentries*sizeof(char*)); if (!entries) return 0; memset(entries,0,numentries*sizeof(char*)); - // Retrieve all the results: + /* Retrieve all the results: */ child=item->child; while (child && !fail) { @@ -331,12 +363,12 @@ static char *print_array(cJSON *item,int depth,int fmt) child=child->next; } - // If we didn't fail, try to malloc the output string - if (!fail) out=cJSON_malloc(len); - // If that fails, we fail. + /* If we didn't fail, try to malloc the output string */ + if (!fail) out=(char*)cJSON_malloc(len); + /* If that fails, we fail. */ if (!out) fail=1; - // Handle failure. + /* Handle failure. */ if (fail) { for (i=0;itype=cJSON_Object; value=skip(value+1); - if (*value=='}') return value+1; // empty array. + if (*value=='}') return value+1; /* empty array. */ item->child=child=cJSON_New_Item(); + if (!item->child) return 0; value=skip(parse_string(child,skip(value))); if (!value) return 0; child->string=child->valuestring;child->valuestring=0; - if (*value!=':') return 0; // fail! - value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value. + if (*value!=':') {ep=value;return 0;} /* fail! */ + value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ if (!value) return 0; while (*value==',') { cJSON *new_item; - if (!(new_item=cJSON_New_Item())) return 0; // memory fail + if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ child->next=new_item;new_item->prev=child;child=new_item; value=skip(parse_string(child,skip(value+1))); if (!value) return 0; child->string=child->valuestring;child->valuestring=0; - if (*value!=':') return 0; // fail! - value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value. + if (*value!=':') {ep=value;return 0;} /* fail! */ + value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ if (!value) return 0; } - if (*value=='}') return value+1; // end of array - return 0; // malformed. + if (*value=='}') return value+1; /* end of array */ + ep=value;return 0; /* malformed. */ } -// Render an object to text. +/* Render an object to text. */ static char *print_object(cJSON *item,int depth,int fmt) { char **entries=0,**names=0; char *out=0,*ptr,*ret,*str;int len=7,i=0,j; cJSON *child=item->child; int numentries=0,fail=0; - // Count the number of entries. + /* Count the number of entries. */ while (child) numentries++,child=child->next; - // Allocate space for the names and the objects + /* Allocate space for the names and the objects */ entries=(char**)cJSON_malloc(numentries*sizeof(char*)); if (!entries) return 0; names=(char**)cJSON_malloc(numentries*sizeof(char*)); @@ -410,7 +443,7 @@ static char *print_object(cJSON *item,int depth,int fmt) memset(entries,0,sizeof(char*)*numentries); memset(names,0,sizeof(char*)*numentries); - // Collect all the results into our arrays: + /* Collect all the results into our arrays: */ child=item->child;depth++;if (fmt) len+=depth; while (child) { @@ -420,19 +453,19 @@ static char *print_object(cJSON *item,int depth,int fmt) child=child->next; } - // Try to allocate the output string + /* Try to allocate the output string */ if (!fail) out=(char*)cJSON_malloc(len); if (!out) fail=1; - // Handle failure + /* Handle failure */ if (fail) { - for (i=0;ichild;int i=0;while(c)i++,c=c->next;return i;} +/* Get Array size/item / object item. */ +SWITCH_DECLARE(int) cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;} SWITCH_DECLARE(cJSON *)cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} SWITCH_DECLARE(cJSON *)cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} -// Utility for array list handling. +/* Utility for array list handling. */ static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} -// Utility for handling references. -static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} +/* Utility for handling references. */ +static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} -// Add item to array/object. -SWITCH_DECLARE(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} -SWITCH_DECLARE(void) cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} +/* Add item to array/object. */ +SWITCH_DECLARE(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} +SWITCH_DECLARE(void) cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} SWITCH_DECLARE(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} SWITCH_DECLARE(void) cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} SWITCH_DECLARE(cJSON *)cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} -SWITCH_DECLARE(void) cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} +SWITCH_DECLARE(void) cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} SWITCH_DECLARE(cJSON *)cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} -SWITCH_DECLARE(void) cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} +SWITCH_DECLARE(void) cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} -// Replace array/object items with new ones. -SWITCH_DECLARE(void) cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; +/* Replace array/object items with new ones. */ +SWITCH_DECLARE(void) cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} -SWITCH_DECLARE(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} +SWITCH_DECLARE(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} -// Create basic types: -SWITCH_DECLARE(cJSON *)cJSON_CreateNull() {cJSON *item=cJSON_New_Item();item->type=cJSON_NULL;return item;} -SWITCH_DECLARE(cJSON *)cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();item->type=cJSON_True;return item;} -SWITCH_DECLARE(cJSON *)cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();item->type=cJSON_False;return item;} -SWITCH_DECLARE(cJSON *)cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;return item;} -SWITCH_DECLARE(cJSON *)cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();item->type=cJSON_String;item->valuestring=cJSON_strdup(string);return item;} -SWITCH_DECLARE(cJSON *)cJSON_CreateArray() {cJSON *item=cJSON_New_Item();item->type=cJSON_Array;return item;} -SWITCH_DECLARE(cJSON *)cJSON_CreateObject() {cJSON *item=cJSON_New_Item();item->type=cJSON_Object;return item;} +/* Create basic types: */ +SWITCH_DECLARE(cJSON *)cJSON_CreateNull() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} +SWITCH_DECLARE(cJSON *)cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} +SWITCH_DECLARE(cJSON *)cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} +SWITCH_DECLARE(cJSON *)cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} +SWITCH_DECLARE(cJSON *)cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} +SWITCH_DECLARE(cJSON *)cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} +SWITCH_DECLARE(cJSON *)cJSON_CreateArray() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} +SWITCH_DECLARE(cJSON *)cJSON_CreateObject() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} -// Create Arrays: -SWITCH_DECLARE(cJSON *)cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} -SWITCH_DECLARE(cJSON *)cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} -SWITCH_DECLARE(cJSON *)cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} -SWITCH_DECLARE(cJSON *)cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} +/* Create Arrays: */ +SWITCH_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;} +SWITCH_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;} +SWITCH_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;} +SWITCH_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;} 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 585b867995..a4da3ca6cf 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) { @@ -3076,7 +3100,7 @@ done: #define RANGE '-' #define RBRACKET ']' #define SEP '/' -#define WIN_SEP '\\' +#define WIN_SEP '/' #define STAR '*' #define TILDE '~' #define UNDERSCORE '_' diff --git a/w32/Library/FreeSwitchCore.2008.vcproj b/w32/Library/FreeSwitchCore.2008.vcproj index d8785d7bae..e4303b904d 100644 --- a/w32/Library/FreeSwitchCore.2008.vcproj +++ b/w32/Library/FreeSwitchCore.2008.vcproj @@ -47,8 +47,8 @@ + + + + + + + + + + + + + + @@ -850,6 +898,54 @@ RelativePath="..\..\src\switch_xml_config.c" > + + + + + + + + + + + + + + @@ -1392,6 +1488,10 @@ RelativePath="..\..\src\include\g711.h" > + + @@ -1540,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) - 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 @@ -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 + 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" > + + + +