Merge commit '2123925af751148381fce4091007a640c47d0cf1' into v1.2.stable
Conflicts: build/buildopal.sh conf/vanilla/autoload_configs/opal.conf.xml configure.in libs/freetdm/mod_freetdm/mod_freetdm.c libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h libs/freetdm/src/ftmod/ftmod_misdn/ftmod_misdn.c libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c libs/spandsp/configure.ac libs/spandsp/src/libtiff.2008.vcproj libs/spandsp/src/spandsp/private/t4_tx.h libs/tiff-4.0.2/Makefile.am libs/tiff-4.0.2/Makefile.vc libs/tiff-4.0.2/README libs/tiff-4.0.2/SConstruct libs/tiff-4.0.2/TODO libs/tiff-4.0.2/autogen.sh libs/tiff-4.0.2/contrib/Makefile.am libs/tiff-4.0.2/contrib/addtiffo/addtiffo.c libs/tiff-4.0.2/contrib/addtiffo/tif_overview.c libs/tiff-4.0.2/contrib/addtiffo/tif_ovrcache.c libs/tiff-4.0.2/contrib/addtiffo/tif_ovrcache.h libs/tiff-4.0.2/contrib/dbs/tiff-bi.c libs/tiff-4.0.2/contrib/dbs/tiff-grayscale.c libs/tiff-4.0.2/contrib/dbs/tiff-palette.c libs/tiff-4.0.2/contrib/dbs/tiff-rgb.c libs/tiff-4.0.2/contrib/dbs/xtiff/Makefile.am libs/tiff-4.0.2/contrib/dbs/xtiff/xtiff.c libs/tiff-4.0.2/contrib/dbs/xtiff/xtifficon.h libs/tiff-4.0.2/contrib/iptcutil/iptcutil.c libs/tiff-4.0.2/contrib/mfs/mfs_file.c libs/tiff-4.0.2/contrib/pds/tif_imageiter.c libs/tiff-4.0.2/contrib/pds/tif_imageiter.h libs/tiff-4.0.2/contrib/pds/tif_pdsdirread.c libs/tiff-4.0.2/contrib/pds/tif_pdsdirwrite.c libs/tiff-4.0.2/contrib/ras/ras2tif.c libs/tiff-4.0.2/contrib/ras/tif2ras.c libs/tiff-4.0.2/contrib/stream/tiffstream.cpp libs/tiff-4.0.2/contrib/stream/tiffstream.h libs/tiff-4.0.2/contrib/tags/listtif.c libs/tiff-4.0.2/contrib/tags/maketif.c libs/tiff-4.0.2/contrib/tags/xtif_dir.c libs/tiff-4.0.2/contrib/tags/xtiffio.h libs/tiff-4.0.2/contrib/tags/xtiffiop.h libs/tiff-4.0.2/contrib/win_dib/Tiffile.cpp libs/tiff-4.0.2/contrib/win_dib/tiff2dib.c libs/tiff-4.0.2/html/Makefile.am libs/tiff-4.0.2/html/addingtags.html libs/tiff-4.0.2/html/bugs.html libs/tiff-4.0.2/html/contrib.html libs/tiff-4.0.2/html/document.html libs/tiff-4.0.2/html/images.html libs/tiff-4.0.2/html/index.html libs/tiff-4.0.2/html/internals.html libs/tiff-4.0.2/html/intro.html libs/tiff-4.0.2/html/libtiff.html libs/tiff-4.0.2/html/man/Makefile.am libs/tiff-4.0.2/html/man/TIFFClose.3tiff.html libs/tiff-4.0.2/html/man/TIFFDataWidth.3tiff.html libs/tiff-4.0.2/html/man/TIFFError.3tiff.html libs/tiff-4.0.2/html/man/TIFFFlush.3tiff.html libs/tiff-4.0.2/html/man/TIFFOpen.3tiff.html libs/tiff-4.0.2/html/man/TIFFPrintDirectory.3tiff.html libs/tiff-4.0.2/html/man/TIFFRGBAImage.3tiff.html libs/tiff-4.0.2/html/man/TIFFReadDirectory.3tiff.html libs/tiff-4.0.2/html/man/TIFFReadEncodedStrip.3tiff.html libs/tiff-4.0.2/html/man/TIFFReadEncodedTile.3tiff.html libs/tiff-4.0.2/html/man/TIFFReadRGBAImage.3tiff.html libs/tiff-4.0.2/html/man/TIFFReadRGBAStrip.3tiff.html libs/tiff-4.0.2/html/man/TIFFReadRGBATile.3tiff.html libs/tiff-4.0.2/html/man/TIFFReadRawStrip.3tiff.html libs/tiff-4.0.2/html/man/TIFFReadRawTile.3tiff.html libs/tiff-4.0.2/html/man/TIFFReadScanline.3tiff.html libs/tiff-4.0.2/html/man/TIFFReadTile.3tiff.html libs/tiff-4.0.2/html/man/TIFFSetDirectory.3tiff.html libs/tiff-4.0.2/html/man/TIFFWarning.3tiff.html libs/tiff-4.0.2/html/man/TIFFWriteDirectory.3tiff.html libs/tiff-4.0.2/html/man/TIFFWriteEncodedStrip.3tiff.html libs/tiff-4.0.2/html/man/TIFFWriteEncodedTile.3tiff.html libs/tiff-4.0.2/html/man/TIFFWriteRawStrip.3tiff.html libs/tiff-4.0.2/html/man/TIFFWriteRawTile.3tiff.html libs/tiff-4.0.2/html/man/TIFFWriteScanline.3tiff.html libs/tiff-4.0.2/html/man/TIFFWriteTile.3tiff.html libs/tiff-4.0.2/html/man/TIFFbuffer.3tiff.html libs/tiff-4.0.2/html/man/TIFFcodec.3tiff.html libs/tiff-4.0.2/html/man/TIFFcolor.3tiff.html libs/tiff-4.0.2/html/man/TIFFmemory.3tiff.html libs/tiff-4.0.2/html/man/TIFFquery.3tiff.html libs/tiff-4.0.2/html/man/TIFFsize.3tiff.html libs/tiff-4.0.2/html/man/TIFFstrip.3tiff.html libs/tiff-4.0.2/html/man/TIFFswab.3tiff.html libs/tiff-4.0.2/html/man/TIFFtile.3tiff.html libs/tiff-4.0.2/html/man/fax2ps.1.html libs/tiff-4.0.2/html/man/fax2tiff.1.html libs/tiff-4.0.2/html/man/gif2tiff.1.html libs/tiff-4.0.2/html/man/index.html libs/tiff-4.0.2/html/man/pal2rgb.1.html libs/tiff-4.0.2/html/man/ppm2tiff.1.html libs/tiff-4.0.2/html/man/ras2tiff.1.html libs/tiff-4.0.2/html/man/raw2tiff.1.html libs/tiff-4.0.2/html/man/rgb2ycbcr.1.html libs/tiff-4.0.2/html/man/sgi2tiff.1.html libs/tiff-4.0.2/html/man/thumbnail.1.html libs/tiff-4.0.2/html/man/tiff2bw.1.html libs/tiff-4.0.2/html/man/tiff2pdf.1.html libs/tiff-4.0.2/html/man/tiff2ps.1.html libs/tiff-4.0.2/html/man/tiff2rgba.1.html libs/tiff-4.0.2/html/man/tiffcmp.1.html libs/tiff-4.0.2/html/man/tiffcrop.1.html libs/tiff-4.0.2/html/man/tiffdither.1.html libs/tiff-4.0.2/html/man/tiffdump.1.html libs/tiff-4.0.2/html/man/tiffgt.1.html libs/tiff-4.0.2/html/man/tiffinfo.1.html libs/tiff-4.0.2/html/man/tiffmedian.1.html libs/tiff-4.0.2/html/man/tiffset.1.html libs/tiff-4.0.2/html/man/tiffsplit.1.html libs/tiff-4.0.2/html/man/tiffsv.1.html libs/tiff-4.0.2/html/misc.html libs/tiff-4.0.2/html/support.html libs/tiff-4.0.2/html/tools.html libs/tiff-4.0.2/html/v3.4beta007.html libs/tiff-4.0.2/html/v3.4beta016.html libs/tiff-4.0.2/html/v3.4beta018.html libs/tiff-4.0.2/html/v3.4beta024.html libs/tiff-4.0.2/html/v3.4beta028.html libs/tiff-4.0.2/html/v3.4beta029.html libs/tiff-4.0.2/html/v3.4beta031.html libs/tiff-4.0.2/html/v3.4beta032.html libs/tiff-4.0.2/html/v3.4beta033.html libs/tiff-4.0.2/html/v3.4beta034.html libs/tiff-4.0.2/html/v3.4beta035.html libs/tiff-4.0.2/html/v3.4beta036.html libs/tiff-4.0.2/html/v3.5.1.html libs/tiff-4.0.2/html/v3.5.2.html libs/tiff-4.0.2/html/v3.5.3.html libs/tiff-4.0.2/html/v3.5.4.html libs/tiff-4.0.2/html/v3.5.5.html libs/tiff-4.0.2/html/v3.5.6-beta.html libs/tiff-4.0.2/html/v3.5.7.html libs/tiff-4.0.2/html/v3.6.0.html libs/tiff-4.0.2/html/v3.6.1.html libs/tiff-4.0.2/html/v3.7.0.html libs/tiff-4.0.2/html/v3.7.0alpha.html libs/tiff-4.0.2/html/v3.7.0beta.html libs/tiff-4.0.2/html/v3.7.1.html libs/tiff-4.0.2/html/v3.7.2.html libs/tiff-4.0.2/html/v3.7.3.html libs/tiff-4.0.2/html/v3.7.4.html libs/tiff-4.0.2/html/v3.8.0.html libs/tiff-4.0.2/html/v3.8.1.html libs/tiff-4.0.2/html/v3.8.2.html libs/tiff-4.0.2/html/v4.0.2.html libs/tiff-4.0.2/libtiff/Makefile.am libs/tiff-4.0.2/libtiff/Makefile.vc libs/tiff-4.0.2/libtiff/SConstruct libs/tiff-4.0.2/libtiff/libtiff.def libs/tiff-4.0.2/libtiff/mkg3states.c libs/tiff-4.0.2/libtiff/t4.h libs/tiff-4.0.2/libtiff/tif_aux.c libs/tiff-4.0.2/libtiff/tif_close.c libs/tiff-4.0.2/libtiff/tif_codec.c libs/tiff-4.0.2/libtiff/tif_color.c libs/tiff-4.0.2/libtiff/tif_compress.c libs/tiff-4.0.2/libtiff/tif_config.wince.h libs/tiff-4.0.2/libtiff/tif_dumpmode.c libs/tiff-4.0.2/libtiff/tif_error.c libs/tiff-4.0.2/libtiff/tif_extension.c libs/tiff-4.0.2/libtiff/tif_fax3.c libs/tiff-4.0.2/libtiff/tif_fax3.h libs/tiff-4.0.2/libtiff/tif_fax3sm.c libs/tiff-4.0.2/libtiff/tif_getimage.c libs/tiff-4.0.2/libtiff/tif_jpeg.c libs/tiff-4.0.2/libtiff/tif_luv.c libs/tiff-4.0.2/libtiff/tif_lzw.c libs/tiff-4.0.2/libtiff/tif_next.c libs/tiff-4.0.2/libtiff/tif_open.c libs/tiff-4.0.2/libtiff/tif_packbits.c libs/tiff-4.0.2/libtiff/tif_pixarlog.c libs/tiff-4.0.2/libtiff/tif_predict.c libs/tiff-4.0.2/libtiff/tif_predict.h libs/tiff-4.0.2/libtiff/tif_print.c libs/tiff-4.0.2/libtiff/tif_swab.c libs/tiff-4.0.2/libtiff/tif_thunder.c libs/tiff-4.0.2/libtiff/tif_tile.c libs/tiff-4.0.2/libtiff/tif_unix.c libs/tiff-4.0.2/libtiff/tif_warning.c libs/tiff-4.0.2/libtiff/tif_win32.c libs/tiff-4.0.2/libtiff/tif_write.c libs/tiff-4.0.2/libtiff/tif_zip.c libs/tiff-4.0.2/libtiff/tiff.h libs/tiff-4.0.2/libtiff/tiffconf.h.in libs/tiff-4.0.2/libtiff/tiffconf.wince.h libs/tiff-4.0.2/libtiff/tiffvers.h libs/tiff-4.0.2/libtiff/uvcode.h libs/tiff-4.0.2/man/Makefile.am libs/tiff-4.0.2/man/TIFFClose.3tiff libs/tiff-4.0.2/man/TIFFDataWidth.3tiff libs/tiff-4.0.2/man/TIFFError.3tiff libs/tiff-4.0.2/man/TIFFFlush.3tiff libs/tiff-4.0.2/man/TIFFGetField.3tiff libs/tiff-4.0.2/man/TIFFOpen.3tiff libs/tiff-4.0.2/man/TIFFPrintDirectory.3tiff libs/tiff-4.0.2/man/TIFFRGBAImage.3tiff libs/tiff-4.0.2/man/TIFFReadDirectory.3tiff libs/tiff-4.0.2/man/TIFFReadEncodedStrip.3tiff libs/tiff-4.0.2/man/TIFFReadEncodedTile.3tiff libs/tiff-4.0.2/man/TIFFReadRGBAImage.3tiff libs/tiff-4.0.2/man/TIFFReadRGBAStrip.3tiff libs/tiff-4.0.2/man/TIFFReadRGBATile.3tiff libs/tiff-4.0.2/man/TIFFReadRawStrip.3tiff libs/tiff-4.0.2/man/TIFFReadRawTile.3tiff libs/tiff-4.0.2/man/TIFFReadScanline.3tiff libs/tiff-4.0.2/man/TIFFReadTile.3tiff libs/tiff-4.0.2/man/TIFFSetDirectory.3tiff libs/tiff-4.0.2/man/TIFFSetField.3tiff libs/tiff-4.0.2/man/TIFFWarning.3tiff libs/tiff-4.0.2/man/TIFFWriteDirectory.3tiff libs/tiff-4.0.2/man/TIFFWriteEncodedStrip.3tiff libs/tiff-4.0.2/man/TIFFWriteEncodedTile.3tiff libs/tiff-4.0.2/man/TIFFWriteRawStrip.3tiff libs/tiff-4.0.2/man/TIFFWriteRawTile.3tiff libs/tiff-4.0.2/man/TIFFWriteScanline.3tiff libs/tiff-4.0.2/man/TIFFWriteTile.3tiff libs/tiff-4.0.2/man/TIFFbuffer.3tiff libs/tiff-4.0.2/man/TIFFcodec.3tiff libs/tiff-4.0.2/man/TIFFcolor.3tiff libs/tiff-4.0.2/man/TIFFmemory.3tiff libs/tiff-4.0.2/man/TIFFquery.3tiff libs/tiff-4.0.2/man/TIFFsize.3tiff libs/tiff-4.0.2/man/TIFFstrip.3tiff libs/tiff-4.0.2/man/TIFFswab.3tiff libs/tiff-4.0.2/man/TIFFtile.3tiff libs/tiff-4.0.2/man/bmp2tiff.1 libs/tiff-4.0.2/man/fax2ps.1 libs/tiff-4.0.2/man/fax2tiff.1 libs/tiff-4.0.2/man/gif2tiff.1 libs/tiff-4.0.2/man/libtiff.3tiff libs/tiff-4.0.2/man/pal2rgb.1 libs/tiff-4.0.2/man/ppm2tiff.1 libs/tiff-4.0.2/man/ras2tiff.1 libs/tiff-4.0.2/man/raw2tiff.1 libs/tiff-4.0.2/man/rgb2ycbcr.1 libs/tiff-4.0.2/man/sgi2tiff.1 libs/tiff-4.0.2/man/thumbnail.1 libs/tiff-4.0.2/man/tiff2bw.1 libs/tiff-4.0.2/man/tiff2pdf.1 libs/tiff-4.0.2/man/tiff2ps.1 libs/tiff-4.0.2/man/tiff2rgba.1 libs/tiff-4.0.2/man/tiffcmp.1 libs/tiff-4.0.2/man/tiffcp.1 libs/tiff-4.0.2/man/tiffdither.1 libs/tiff-4.0.2/man/tiffdump.1 libs/tiff-4.0.2/man/tiffgt.1 libs/tiff-4.0.2/man/tiffinfo.1 libs/tiff-4.0.2/man/tiffmedian.1 libs/tiff-4.0.2/man/tiffset.1 libs/tiff-4.0.2/man/tiffsplit.1 libs/tiff-4.0.2/man/tiffsv.1 libs/tiff-4.0.2/nmake.opt libs/tiff-4.0.2/port/Makefile.am libs/tiff-4.0.2/port/Makefile.vc libs/tiff-4.0.2/port/dummy.c libs/tiff-4.0.2/port/getopt.c libs/tiff-4.0.2/port/lfind.c libs/tiff-4.0.2/port/libport.h libs/tiff-4.0.2/port/strcasecmp.c libs/tiff-4.0.2/port/strtoull.c libs/tiff-4.0.2/test/ascii_tag.c libs/tiff-4.0.2/test/check_tag.c libs/tiff-4.0.2/test/long_tag.c libs/tiff-4.0.2/test/short_tag.c libs/tiff-4.0.2/test/strip.c libs/tiff-4.0.2/test/strip_rw.c libs/tiff-4.0.2/test/test_arrays.c libs/tiff-4.0.2/test/test_arrays.h libs/tiff-4.0.2/test/tifftest.h libs/tiff-4.0.2/tools/Makefile.am libs/tiff-4.0.2/tools/Makefile.vc libs/tiff-4.0.2/tools/bmp2tiff.c libs/tiff-4.0.2/tools/fax2ps.c libs/tiff-4.0.2/tools/fax2tiff.c libs/tiff-4.0.2/tools/gif2tiff.c libs/tiff-4.0.2/tools/pal2rgb.c libs/tiff-4.0.2/tools/ppm2tiff.c libs/tiff-4.0.2/tools/ras2tiff.c libs/tiff-4.0.2/tools/rasterfile.h libs/tiff-4.0.2/tools/raw2tiff.c libs/tiff-4.0.2/tools/rgb2ycbcr.c libs/tiff-4.0.2/tools/sgi2tiff.c libs/tiff-4.0.2/tools/sgisv.c libs/tiff-4.0.2/tools/thumbnail.c libs/tiff-4.0.2/tools/tiff2bw.c libs/tiff-4.0.2/tools/tiff2pdf.c libs/tiff-4.0.2/tools/tiff2rgba.c libs/tiff-4.0.2/tools/tiffcmp.c libs/tiff-4.0.2/tools/tiffcp.c libs/tiff-4.0.2/tools/tiffdither.c libs/tiff-4.0.2/tools/tiffdump.c libs/tiff-4.0.2/tools/tiffgt.c libs/tiff-4.0.2/tools/tiffinfo.c libs/tiff-4.0.2/tools/tiffmedian.c libs/tiff-4.0.2/tools/tiffset.c libs/tiff-4.0.2/tools/tiffsplit.c libs/tiff-4.0.2/tools/ycbcr.c libs/win32/libjpeg/libjpeg.2008.vcproj libs/win32/libjpeg/libjpeg.2010.vcxproj src/mod/applications/mod_spandsp/mod_spandsp_fax.c src/mod/endpoints/mod_opal/mod_opal.cpp src/mod/endpoints/mod_opal/mod_opal.h src/mod/endpoints/mod_sofia/mod_sofia.h src/mod/endpoints/mod_sofia/rtp.c src/mod/endpoints/mod_sofia/sofia.c src/mod/endpoints/mod_sofia/sofia_presence.c src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx src/mod/languages/mod_managed/managed/swig.2010.cs src/mod/xml_int/mod_xml_radius/mod_xml_radius.c src/switch_ivr_originate.c w32/Library/FreeSwitchCore.2008.vcproj w32/Library/FreeSwitchCore.2010.vcxproj
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
<configuration name="opal.conf" description="Opal Endpoints">
|
||||
<settings>
|
||||
<param name="trace-level" value="4"/>
|
||||
<param name="context" value="default"/>
|
||||
<param name="dialplan" value="XML"/>
|
||||
<param name="codec-prefs" value="PCMU"/>
|
||||
</settings>
|
||||
<listeners>
|
||||
<listener name="default">
|
||||
<param name="h323-ip" value="$${local_ip_v4}"/>
|
||||
<param name="h323-port" value="1720"/>
|
||||
</listener>
|
||||
</listeners>
|
||||
<settings>
|
||||
<param name="trace-level" value="3"/>
|
||||
<param name="context" value="default"/>
|
||||
<param name="dialplan" value="XML"/>
|
||||
<param name="dtmf-type" value="signal"/> <!-- string, signal, rfc2833, in-band -->
|
||||
<param name="jitter-size" value="40,100"/> <!-- Jitter buffer min/max size, milliseconds -->
|
||||
<!-- <param name="codec-prefs" value="PCMU,PCMA"/> --> <!-- list, and preferecnce order, of codecs -->
|
||||
<!-- <param name="disable-transcoding" value="true"/> --> <!-- do not transcode, use source channel codec only -->
|
||||
<param name="gk-address" value=""/> <!-- empty to disable, "*" to search LAN -->
|
||||
<param name="gk-identifer" value=""/> <!-- optional name of gk -->
|
||||
<param name="gk-interface" value="$${local_ip_v4}"/> <!-- optional listener interface name -->
|
||||
</settings>
|
||||
<listeners>
|
||||
<listener name="default">
|
||||
<param name="h323-ip" value="$${local_ip_v4}"/>
|
||||
<param name="h323-port" value="1720"/>
|
||||
</listener>
|
||||
</listeners>
|
||||
</configuration>
|
||||
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
<configuration name="opal.conf" description="Opal Endpoints">
|
||||
<settings>
|
||||
<param name="trace-level" value="4"/>
|
||||
<param name="context" value="default"/>
|
||||
<param name="dialplan" value="XML"/>
|
||||
<param name="codec-prefs" value="PCMU"/>
|
||||
</settings>
|
||||
<listeners>
|
||||
<listener name="default">
|
||||
<param name="h323-ip" value="$${local_ip_v4}"/>
|
||||
<param name="h323-port" value="1720"/>
|
||||
</listener>
|
||||
</listeners>
|
||||
<settings>
|
||||
<param name="trace-level" value="3"/>
|
||||
<param name="context" value="default"/>
|
||||
<param name="dialplan" value="XML"/>
|
||||
<param name="dtmf-type" value="signal"/> <!-- string, signal, rfc2833, in-band -->
|
||||
<param name="jitter-size" value="40,100"/> <!-- Jitter buffer min/max size, milliseconds -->
|
||||
<!-- <param name="codec-prefs" value="PCMU,PCMA"/> --> <!-- list, and preferecnce order, of codecs -->
|
||||
<!-- <param name="disable-transcoding" value="true"/> --> <!-- do not transcode, use source channel codec only -->
|
||||
<param name="gk-address" value=""/> <!-- empty to disable, "*" to search LAN -->
|
||||
<param name="gk-identifer" value=""/> <!-- optional name of gk -->
|
||||
<param name="gk-interface" value="$${local_ip_v4}"/> <!-- optional listener interface name -->
|
||||
</settings>
|
||||
<listeners>
|
||||
<listener name="default">
|
||||
<param name="h323-ip" value="$${local_ip_v4}"/>
|
||||
<param name="h323-port" value="1720"/>
|
||||
</listener>
|
||||
</listeners>
|
||||
</configuration>
|
||||
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
<configuration name="opal.conf" description="Opal Endpoints">
|
||||
<settings>
|
||||
<param name="trace-level" value="3"/>
|
||||
<param name="context" value="default"/>
|
||||
<param name="dialplan" value="XML"/>
|
||||
<param name="jitter-size" value="40,100"/> <!-- Jitter buffer min/max size, milliseconds -->
|
||||
<!-- <param name="codec-prefs" value="PCMU,PCMA"/> --> <!-- list, and preferecnce order, of codecs -->
|
||||
<!-- <param name="disable-transcoding" value="true"/> --> <!-- do not transcode, use source channel codec only -->
|
||||
<param name="gk-address" value=""/> <!-- empty to disable, "*" to search LAN -->
|
||||
<param name="gk-identifer" value=""/> <!-- optional name of gk -->
|
||||
<param name="gk-interface" value="$${local_ip_v4}"/> <!-- optional listener interface name -->
|
||||
</settings>
|
||||
<listeners>
|
||||
<listener name="default">
|
||||
<param name="h323-ip" value="$${local_ip_v4}"/>
|
||||
<param name="h323-port" value="1720"/>
|
||||
</listener>
|
||||
</listeners>
|
||||
<settings>
|
||||
<param name="trace-level" value="3"/>
|
||||
<param name="context" value="default"/>
|
||||
<param name="dialplan" value="XML"/>
|
||||
<param name="dtmf-type" value="signal"/> <!-- string, signal, rfc2833, in-band -->
|
||||
<param name="jitter-size" value="40,100"/> <!-- Jitter buffer min/max size, milliseconds -->
|
||||
<!-- <param name="codec-prefs" value="PCMU,PCMA"/> --> <!-- list, and preferecnce order, of codecs -->
|
||||
<!-- <param name="disable-transcoding" value="true"/> --> <!-- do not transcode, use source channel codec only -->
|
||||
<param name="gk-address" value=""/> <!-- empty to disable, "*" to search LAN -->
|
||||
<param name="gk-identifer" value=""/> <!-- optional name of gk -->
|
||||
<param name="gk-interface" value="$${local_ip_v4}"/> <!-- optional listener interface name -->
|
||||
</settings>
|
||||
<listeners>
|
||||
<listener name="default">
|
||||
<param name="h323-ip" value="$${local_ip_v4}"/>
|
||||
<param name="h323-port" value="1720"/>
|
||||
</listener>
|
||||
</listeners>
|
||||
</configuration>
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<!--
|
||||
To use this application simply install the open source Oreka recorder server (Orkaudio) and point
|
||||
the sip-server-addr and sip-server-port to the oreka server
|
||||
-->
|
||||
<configuration name="oreka.conf" description="Oreka Recorder configuration">
|
||||
<settings>
|
||||
<!-- Oreka/Orkaudio recording server address -->
|
||||
<!-- <param name="sip-server-addr" value="192.168.1.200"/> -->
|
||||
|
||||
<!-- Which port to send signaling to in the recording server -->
|
||||
<!-- <param name="sip-server-port" value="6000"/> -->
|
||||
</settings>
|
||||
</configuration>
|
||||
@@ -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, [])
|
||||
|
||||
|
||||
@@ -20,12 +20,22 @@
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// cJSON
|
||||
// JSON parser in C.
|
||||
/* cJSON */
|
||||
/* JSON parser in C. */
|
||||
|
||||
#include "esl.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
#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;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
|
||||
@@ -344,7 +376,7 @@ static char *print_array(cJSON *item,int depth,int fmt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Compose the output array.
|
||||
/* Compose the output array. */
|
||||
*out='[';
|
||||
ptr=out+1;*ptr=0;
|
||||
for (i=0;i<numentries;i++)
|
||||
@@ -358,51 +390,52 @@ static char *print_array(cJSON *item,int depth,int fmt)
|
||||
return out;
|
||||
}
|
||||
|
||||
// Build an object from the text.
|
||||
/* Build an object from the text. */
|
||||
static const char *parse_object(cJSON *item,const char *value)
|
||||
{
|
||||
cJSON *child;
|
||||
if (*value!='{') return 0; // not an object!
|
||||
if (*value!='{') {ep=value;return 0;} /* not an object! */
|
||||
|
||||
item->type=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;i<numentries;i++) {if (names[i]) free(names[i]);if (entries[i]) free(entries[i]);}
|
||||
free(names);free(entries);
|
||||
for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
|
||||
cJSON_free(names);cJSON_free(entries);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Compose the output:
|
||||
/* Compose the output: */
|
||||
*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
|
||||
for (i=0;i<numentries;i++)
|
||||
{
|
||||
@@ -451,45 +484,46 @@ static char *print_object(cJSON *item,int depth,int fmt)
|
||||
return out;
|
||||
}
|
||||
|
||||
// Get Array size/item / object item.
|
||||
int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;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;i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=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;i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=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;i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=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;i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=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 && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=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 && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=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 && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=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 && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,712 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* 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 <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Mathieu Rene <mrene@avgs.ca>
|
||||
*
|
||||
* tdm.c -- FreeTDM Controllable Channel Module
|
||||
*
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -36,10 +36,10 @@
|
||||
* David Yat Sin <dyatsin@sangoma.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "private/ftdm_core.h"
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#ifdef WIN32
|
||||
#include <io.h>
|
||||
#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 [!]<state_name> - List all channels in or not in the given state\n"
|
||||
"ftdm core flag <flag-int-value> - List all channels with the given flag value set\n"
|
||||
"ftdm core state [!]<state-name> - List all channels in or not in the given state\n"
|
||||
"ftdm core flag [!]<flag-int-value|flag-name> [<span_id|span_name>] [<chan_id>] - List all channels with the given flag value set\n"
|
||||
"ftdm core spanflag [!]<flag-int-value|flag-name> [<span_id|span_name>] - 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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010, Sangoma Technologies
|
||||
* David Yat Sin <davidy@sangoma.com>
|
||||
@@ -40,7 +41,6 @@
|
||||
#include <sys/mman.h>
|
||||
#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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
* Contributors:
|
||||
*
|
||||
* Ricardo Barroetaveña <rbarroetavena@anura.com.ar>
|
||||
* James Zhang <jzhang@sangoma.com>
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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__);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Kapil Gupta <kgupta@sangoma.com>
|
||||
* 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__*/
|
||||
@@ -0,0 +1,690 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Kapil Gupta <kgupta@sangoma.com>
|
||||
* 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; k<m2ua_peer_iface->numDestAddr; k++) {
|
||||
g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].destAddrList[k] = m2ua_peer_iface->destAddrList[k];
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int ftmod_ss7_parse_m2ua_clust_interfaces(ftdm_conf_node_t *m2ua_cluster_interfaces)
|
||||
{
|
||||
ftdm_conf_node_t *m2ua_cluster_interface = NULL;
|
||||
|
||||
/* confirm that we are looking at m2ua_cluster_interfaces */
|
||||
if (strcasecmp(m2ua_cluster_interfaces->name, "sng_m2ua_cluster_interfaces")) {
|
||||
SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"m2ua_cluster_interfaces\"!\n",m2ua_cluster_interfaces->name);
|
||||
return FTDM_FAIL;
|
||||
} else {
|
||||
SS7_DEBUG("Parsing \"m2ua_cluster_interfaces\"...\n");
|
||||
}
|
||||
|
||||
/* extract the m2ua_cluster_interfaces */
|
||||
m2ua_cluster_interface = m2ua_cluster_interfaces->child;
|
||||
|
||||
while (m2ua_cluster_interface != NULL) {
|
||||
/* parse the found m2ua_cluster_interface */
|
||||
if (ftmod_ss7_parse_m2ua_clust_interface(m2ua_cluster_interface)) {
|
||||
SS7_ERROR("Failed to parse \"m2ua_cluster_interface\"\n");
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
/* go to the next m2ua_cluster_interface */
|
||||
m2ua_cluster_interface = m2ua_cluster_interface->next;
|
||||
}
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static int ftmod_ss7_parse_m2ua_clust_interface(ftdm_conf_node_t *m2ua_cluster_interface)
|
||||
{
|
||||
sng_m2ua_cluster_cfg_t sng_m2ua_cluster;
|
||||
ftdm_conf_parameter_t *parm = m2ua_cluster_interface->parameters;
|
||||
int num_parms = m2ua_cluster_interface->n_parameters;
|
||||
int i;
|
||||
|
||||
/* initalize the m2ua_cluster_interface */
|
||||
memset(&sng_m2ua_cluster, 0x0, sizeof(sng_m2ua_cluster));
|
||||
|
||||
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;k<m2ua_cluster_iface->numOfPeers;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 <sng_sctp_interfaces>!\n", node->name);
|
||||
return FTDM_FAIL;
|
||||
} else {
|
||||
SS7_DEBUG("SCTP - Parsing <sng_sctp_interface> 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 <node_sctp_link>. \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 <sng_sctp_interface>!\n", node->name);
|
||||
return FTDM_FAIL;
|
||||
} else {
|
||||
SS7_DEBUG("SCTP - Parsing <sng_sctp_interface> configurations\n");
|
||||
}
|
||||
|
||||
for (i=0; i<num_params; i++, param++) {
|
||||
if (!strcasecmp(param->var, "name")) {
|
||||
int n_strlen = strlen(param->val);
|
||||
strncpy((char*)t_link.name, param->val, (n_strlen>MAX_NAME_LEN)?MAX_NAME_LEN:n_strlen);
|
||||
SS7_DEBUG("SCTP - Parsing <sng_sctp_interface> with name = %s\n", param->val);
|
||||
}
|
||||
else if (!strcasecmp(param->var, "id")) {
|
||||
t_link.id = atoi(param->val);
|
||||
SS7_DEBUG("SCTP - Parsing <sng_sctp_interface> 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 <sng_sctp_interface> 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 <sng_sctp_interface> 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;
|
||||
}
|
||||
/******************************************************************************/
|
||||
@@ -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 <jzhang@sangoma.com>
|
||||
*
|
||||
*/
|
||||
/******************************************************************************/
|
||||
#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__)
|
||||
|
||||
@@ -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__);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 <jzhang@sangoma.com>
|
||||
*
|
||||
*/
|
||||
|
||||
/* 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 <sng_sctp_interfaces> section!\n");
|
||||
} else {
|
||||
SS7_ERROR("Found a second <sng_sctp_interfaces> 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 <sctp_links>!\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++) */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
/*!<When adding a new flag, need to update ftdm_io.c:channel_flag_strs */
|
||||
|
||||
#include "ftdm_state.h"
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
Copyright (c) 2005-2010, 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.
|
||||
|
||||
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.
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
SUBDIRS = src
|
||||
EXTRA_DIST = LICENSE tests lang doc
|
||||
@@ -0,0 +1,635 @@
|
||||
# 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 = .
|
||||
DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
|
||||
$(srcdir)/Makefile.in $(top_srcdir)/config/config.h.in \
|
||||
$(top_srcdir)/configure config/config.guess config/config.sub \
|
||||
config/depcomp config/install-sh config/ltmain.sh \
|
||||
config/missing
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
|
||||
configure.lineno config.status.lineno
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/config/config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
SOURCES =
|
||||
DIST_SOURCES =
|
||||
RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
|
||||
html-recursive info-recursive install-data-recursive \
|
||||
install-dvi-recursive install-exec-recursive \
|
||||
install-html-recursive install-info-recursive \
|
||||
install-pdf-recursive install-ps-recursive install-recursive \
|
||||
installcheck-recursive installdirs-recursive pdf-recursive \
|
||||
ps-recursive uninstall-recursive
|
||||
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
|
||||
distclean-recursive maintainer-clean-recursive
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DIST_SUBDIRS = $(SUBDIRS)
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
distdir = $(PACKAGE)-$(VERSION)
|
||||
top_distdir = $(distdir)
|
||||
am__remove_distdir = \
|
||||
{ test ! -d $(distdir) \
|
||||
|| { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
|
||||
&& rm -fr $(distdir); }; }
|
||||
DIST_ARCHIVES = $(distdir).tar.gz
|
||||
GZIP_ENV = --best
|
||||
distuninstallcheck_listfiles = find . -type f -print
|
||||
distcleancheck_listfiles = find . -type f -print
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
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 = src
|
||||
EXTRA_DIST = LICENSE tests lang doc
|
||||
all: all-recursive
|
||||
|
||||
.SUFFIXES:
|
||||
am--refresh:
|
||||
@:
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \
|
||||
cd $(srcdir) && $(AUTOMAKE) --foreign \
|
||||
&& exit 0; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
|
||||
cd $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
echo ' $(SHELL) ./config.status'; \
|
||||
$(SHELL) ./config.status;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
$(SHELL) ./config.status --recheck
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(srcdir) && $(AUTOCONF)
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
|
||||
|
||||
config/config.h: config/stamp-h1
|
||||
@if test ! -f $@; then \
|
||||
rm -f config/stamp-h1; \
|
||||
$(MAKE) $(AM_MAKEFLAGS) config/stamp-h1; \
|
||||
else :; fi
|
||||
|
||||
config/stamp-h1: $(top_srcdir)/config/config.h.in $(top_builddir)/config.status
|
||||
@rm -f config/stamp-h1
|
||||
cd $(top_builddir) && $(SHELL) ./config.status config/config.h
|
||||
$(top_srcdir)/config/config.h.in: $(am__configure_deps)
|
||||
cd $(top_srcdir) && $(AUTOHEADER)
|
||||
rm -f config/stamp-h1
|
||||
touch $@
|
||||
|
||||
distclean-hdr:
|
||||
-rm -f config/config.h config/stamp-h1
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
distclean-libtool:
|
||||
-rm -f libtool config.lt
|
||||
|
||||
# This directory's subdirectories are mostly independent; you can cd
|
||||
# into them and run `make' without going through this Makefile.
|
||||
# To change the values of `make' variables: instead of editing Makefiles,
|
||||
# (1) if the variable is set in `config.status', edit `config.status'
|
||||
# (which will cause the Makefiles to be regenerated when you run `make');
|
||||
# (2) otherwise, pass the desired values on the `make' command line.
|
||||
$(RECURSIVE_TARGETS):
|
||||
@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)
|
||||
$(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:
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,602 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="generator" content="AsciiDoc 8.5.0" />
|
||||
<title>tpl ChangeLog</title>
|
||||
<style type="text/css">
|
||||
/* 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;
|
||||
color: navy;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: bold;
|
||||
color: #083194;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ul, ol, li > p {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
span#author {
|
||||
color: #527bbd;
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
span#email {
|
||||
}
|
||||
span#revnumber, span#revdate, span#revremark {
|
||||
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 {
|
||||
margin-top: 1.5em;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
div.tableblock, div.imageblock, div.exampleblock, div.verseblock,
|
||||
div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
|
||||
div.admonitionblock {
|
||||
margin-top: 0.25em;
|
||||
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 {
|
||||
color: #527bbd;
|
||||
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 > div.content {
|
||||
border: 1px solid silver;
|
||||
background: #f4f4f4;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
div.quoteblock {
|
||||
padding-left: 2.0em;
|
||||
margin-right: 10%;
|
||||
}
|
||||
div.quoteblock > div.attribution {
|
||||
padding-top: 0.5em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
div.verseblock {
|
||||
padding-left: 2.0em;
|
||||
margin-right: 10%;
|
||||
}
|
||||
div.verseblock > div.content {
|
||||
white-space: pre;
|
||||
}
|
||||
div.verseblock > div.attribution {
|
||||
padding-top: 0.75em;
|
||||
text-align: left;
|
||||
}
|
||||
/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
|
||||
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.imageblock div.content { padding-left: 0; }
|
||||
span.image img { border-style: none; }
|
||||
a.image:visited { color: white; }
|
||||
|
||||
dl {
|
||||
margin-top: 0.8em;
|
||||
margin-bottom: 0.8em;
|
||||
}
|
||||
dt {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0;
|
||||
font-style: normal;
|
||||
color: navy;
|
||||
}
|
||||
dd > *:first-child {
|
||||
margin-top: 0.1em;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
list-style-position: outside;
|
||||
}
|
||||
ol.arabic {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
ol.loweralpha {
|
||||
list-style-type: lower-alpha;
|
||||
}
|
||||
ol.upperalpha {
|
||||
list-style-type: upper-alpha;
|
||||
}
|
||||
ol.lowerroman {
|
||||
list-style-type: lower-roman;
|
||||
}
|
||||
ol.upperroman {
|
||||
list-style-type: upper-roman;
|
||||
}
|
||||
|
||||
div.compact ul, div.compact ol,
|
||||
div.compact p, div.compact p,
|
||||
div.compact div, div.compact div {
|
||||
margin-top: 0.1em;
|
||||
margin-bottom: 0.1em;
|
||||
}
|
||||
|
||||
div.tableblock > table {
|
||||
border: 3px solid #527bbd;
|
||||
}
|
||||
thead {
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
tfoot {
|
||||
font-weight: bold;
|
||||
}
|
||||
td > div.verse {
|
||||
white-space: pre;
|
||||
}
|
||||
p.table {
|
||||
margin-top: 0;
|
||||
}
|
||||
/* Because the table frame attribute is overriden by CSS in most browsers. */
|
||||
div.tableblock > table[frame="void"] {
|
||||
border-style: none;
|
||||
}
|
||||
div.tableblock > table[frame="hsides"] {
|
||||
border-left-style: none;
|
||||
border-right-style: none;
|
||||
}
|
||||
div.tableblock > table[frame="vsides"] {
|
||||
border-top-style: none;
|
||||
border-bottom-style: none;
|
||||
}
|
||||
|
||||
|
||||
div.hdlist {
|
||||
margin-top: 0.8em;
|
||||
margin-bottom: 0.8em;
|
||||
}
|
||||
div.hdlist tr {
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
dt.hdlist1.strong, td.hdlist1.strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
td.hdlist1 {
|
||||
vertical-align: top;
|
||||
font-style: normal;
|
||||
padding-right: 0.8em;
|
||||
color: navy;
|
||||
}
|
||||
td.hdlist2 {
|
||||
vertical-align: top;
|
||||
}
|
||||
div.hdlist.compact tr {
|
||||
margin: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.comment {
|
||||
background: yellow;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
/* 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 {
|
||||
color: #527bbd;
|
||||
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-attribution {
|
||||
padding-top: 0.5em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
div.verseblock-content {
|
||||
white-space: pre;
|
||||
}
|
||||
div.verseblock-attribution {
|
||||
padding-top: 0.75em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
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; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">
|
||||
<h1>tpl ChangeLog</h1>
|
||||
</div>
|
||||
<h2 id="_version_1_5_2010_02_05">Version 1.5 (2010-02-05)</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="ulist"><ul>
|
||||
<li>
|
||||
<p>
|
||||
tpl now builds as a DLL under Microsoft Visual Studio! (thanks, degski and Zhang Yafei!)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
there are now two download options: the <a href="http://downloads.sourceforge.net/tpl/libtpl-1.5.tar.bz2">tarball</a> and the Visual Studio <a href="http://downloads.sourceforge.net/tpl/tpl-1.5-vs2008.zip">solution</a>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
a crash in <tt>tpl_free</tt> on certain format strings has been fixed (thanks, Eric Rose!)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
fixed a bug in <tt>tpl_dump</tt> on 64-bit, big-endian platforms
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
changed some pointer casts from <tt>long</tt> to <tt>uintptr_t</tt> since 64-bit Windows has 32-bit longs
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
tpl has been downloaded 4,195 times.
|
||||
</p>
|
||||
</li>
|
||||
</ul></div>
|
||||
</div>
|
||||
<h2 id="_version_1_4_2009_04_21">Version 1.4 (2009-04-21)</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="ulist"><ul>
|
||||
<li>
|
||||
<p>
|
||||
fixed-length arrays can now be multi-dimensional like <tt>i##</tt>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
fixed-length string arrays like <tt>s#</tt> are now supported
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
nested structures can now be expressed, using the dollar symbol, e.g. <tt>S(ci$(cc))</tt>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<tt>tpl_dump</tt> can use a caller-allocated output buffer (<tt>TPL_MEM|TPL_PREALLOCD</tt>)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<tt>tpl_load</tt> can tolerate excess space in input buffer (<tt>TPL_MEM|TPL_EXCESS_OK</tt>)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
implement <tt>TPL_FXLENS</tt> flag for <tt>tpl_peek</tt> to get lengths of fixed-length arrays
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
implement <tt>TPL_GETSIZE</tt> flag for <tt>tpl_dump</tt> to get dump size without dumping
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
fix success return code from <tt>tpl_dump(TPL_FD,...)</tt> (thanks, Max Lapan!)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
deprecated the wildcard unpacking <tt>S(*)</tt> feature
|
||||
</p>
|
||||
</li>
|
||||
</ul></div>
|
||||
</div>
|
||||
<h2 id="_version_1_3_2009_02_10">Version 1.3 (2009-02-10)</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="ulist"><ul>
|
||||
<li>
|
||||
<p>
|
||||
added <tt>TPL_DATAPEEK</tt> mode for <tt>tpl_peek</tt>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
added support for <tt>NULL</tt> strings
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
added support for 16-bit integer types (<tt>j</tt>,<tt>v</tt>)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
added <tt>tpl_jot</tt>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
added support for fixed-length arrays of structures <tt>S(...)#</tt>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
added support for pre-C99 compilers (thanks, Wei Wei!)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
improved structure alignment calculation (thanks, Wu Yongwei!)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
added RPM spec file (thanks, Alessandro Ren!)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
compiles cleanly with <tt>-Wall</tt> and <tt>-pedantic</tt> and with <tt>-O3</tt>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
made <a href="license.html">BSD license</a> terms even more permissive
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
test suite: exit with status zero when all tests pass
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
added PDF user guide
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
added <a href="http://troydhanson.wordpress.com/feed/">update news</a> <span class="image">
|
||||
<img src="img/rss.png" alt="(RSS)" />
|
||||
</span>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
added <a href="http://apps.sourceforge.net/mediawiki/tpl/">tpl wiki</a>
|
||||
</p>
|
||||
</li>
|
||||
</ul></div>
|
||||
</div>
|
||||
<h2 id="_version_1_2_2007_04_27">Version 1.2 (2007-04-27)</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="ulist"><ul>
|
||||
<li>
|
||||
<p>
|
||||
Perl API and XML converter support 64-bit types
|
||||
</p>
|
||||
</li>
|
||||
</ul></div>
|
||||
</div>
|
||||
<h2 id="_version_1_1_2007_04_25">Version 1.1 (2007-04-25)</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="ulist"><ul>
|
||||
<li>
|
||||
<p>
|
||||
support for serializing C structures
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
support for serializing fixed-length arrays
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
MinGW support (thanks, Horea Haitonic!)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
revised User Guide
|
||||
</p>
|
||||
</li>
|
||||
</ul></div>
|
||||
</div>
|
||||
<h2 id="_version_1_0_2006_09_28">Version 1.0 (2006-09-28)</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="ulist"><ul>
|
||||
<li>
|
||||
<p>
|
||||
Initial version
|
||||
</p>
|
||||
</li>
|
||||
</ul></div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2010-02-05 19:31:37 PDT
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,429 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="728px"
|
||||
height="90px"
|
||||
id="svg1323"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.44"
|
||||
sodipodi:docbase="/home/thanson/code/tpl/trunk/doc/html/img"
|
||||
sodipodi:docname="banner.svg"
|
||||
inkscape:export-filename="/home/thanson/code/tpl/trunk/doc/html/img/banner.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs1325">
|
||||
<linearGradient
|
||||
id="linearGradient22211">
|
||||
<stop
|
||||
style="stop-color:#2e7ce0;stop-opacity:0;"
|
||||
offset="0"
|
||||
id="stop22237" />
|
||||
<stop
|
||||
id="stop22215"
|
||||
offset="1"
|
||||
style="stop-color:#2e7ce0;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient20106">
|
||||
<stop
|
||||
style="stop-color:#f0f3f7;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop20108" />
|
||||
<stop
|
||||
style="stop-color:#f0f3f7;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop20110" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient19154">
|
||||
<stop
|
||||
style="stop-color:#005fd9;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop19156" />
|
||||
<stop
|
||||
style="stop-color:#005fd9;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop19158" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient19142">
|
||||
<stop
|
||||
style="stop-color:#4ec2f0;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop19144" />
|
||||
<stop
|
||||
style="stop-color:#4ec2f0;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop19146" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient19132">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop19134" />
|
||||
<stop
|
||||
id="stop19140"
|
||||
offset="0.5"
|
||||
style="stop-color:#00d1f6;stop-opacity:0.49803922;" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop19136" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19142"
|
||||
id="radialGradient19150"
|
||||
cx="651"
|
||||
cy="50"
|
||||
fx="651"
|
||||
fy="50"
|
||||
r="49.5"
|
||||
gradientTransform="matrix(1,0,0,0.616162,1.124101e-15,19.19192)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19154"
|
||||
id="linearGradient19160"
|
||||
x1="588"
|
||||
y1="47"
|
||||
x2="722"
|
||||
y2="47"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19154"
|
||||
id="linearGradient19224"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="588"
|
||||
y1="47"
|
||||
x2="722"
|
||||
y2="47"
|
||||
gradientTransform="matrix(5.590915,0,0,1.101015,-3310.4,161.4223)" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient20106"
|
||||
id="radialGradient20112"
|
||||
cx="125.1579"
|
||||
cy="213.03658"
|
||||
fx="125.1579"
|
||||
fy="213.03658"
|
||||
r="27.577164"
|
||||
gradientTransform="matrix(1,0,0,0.923077,0,16.38742)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19154"
|
||||
id="linearGradient20176"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="588"
|
||||
y1="47"
|
||||
x2="722"
|
||||
y2="47"
|
||||
gradientTransform="translate(-38.18377,318.1981)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19154"
|
||||
id="linearGradient20203"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-38.18377,318.1981)"
|
||||
x1="588"
|
||||
y1="47"
|
||||
x2="722"
|
||||
y2="47" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19154"
|
||||
id="linearGradient20269"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-38.18377,318.1981)"
|
||||
x1="588"
|
||||
y1="47"
|
||||
x2="722"
|
||||
y2="47" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19154"
|
||||
id="linearGradient20389"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.755096,0,0,1.101015,-1053.937,335.4223)"
|
||||
x1="588"
|
||||
y1="47"
|
||||
x2="722"
|
||||
y2="47" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19154"
|
||||
id="linearGradient22243"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.867037,0,0,1.101015,-1120.758,425.4223)"
|
||||
x1="588"
|
||||
y1="47"
|
||||
x2="722"
|
||||
y2="47" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19154"
|
||||
id="linearGradient24137"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.755096,0,0,1.101015,-1052.937,435.4223)"
|
||||
x1="588"
|
||||
y1="47"
|
||||
x2="722"
|
||||
y2="47" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19154"
|
||||
id="linearGradient24144"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.755096,0,0,1.101015,-1049.937,270.4223)"
|
||||
x1="588"
|
||||
y1="47"
|
||||
x2="722"
|
||||
y2="47" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="497.48754"
|
||||
inkscape:cy="-4.5816549"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:window-width="1176"
|
||||
inkscape:window-height="633"
|
||||
inkscape:window-x="23"
|
||||
inkscape:window-y="48" />
|
||||
<metadata
|
||||
id="metadata1328">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<rect
|
||||
style="fill:#3c85e2;fill-opacity:1;fill-rule:nonzero;stroke:#ffcb53;stroke-width:4.0415926;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect20271"
|
||||
width="240.0993"
|
||||
height="77.071068"
|
||||
x="4.1015167"
|
||||
y="3.6345825"
|
||||
rx="29.60623" />
|
||||
<rect
|
||||
y="46.014687"
|
||||
x="-236.92256"
|
||||
height="16.982321"
|
||||
width="16.982321"
|
||||
id="rect24091"
|
||||
style="fill:#2fa4db;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
transform="scale(-1,1)" />
|
||||
<rect
|
||||
y="46.014687"
|
||||
x="-219.80927"
|
||||
height="16.982321"
|
||||
width="16.982321"
|
||||
id="rect24093"
|
||||
style="fill:#2fa4db;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
transform="scale(-1,1)" />
|
||||
<rect
|
||||
style="fill:#2fa4db;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect24095"
|
||||
width="16.982321"
|
||||
height="16.982321"
|
||||
x="-202.92258"
|
||||
y="46.014687"
|
||||
transform="scale(-1,1)" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#e33019;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path24097"
|
||||
sodipodi:cx="231.91481"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:ry="3.7148824"
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
transform="translate(-102.0443,123.8305)" />
|
||||
<path
|
||||
transform="translate(-76.04438,87.8305)"
|
||||
sodipodi:type="arc"
|
||||
style="fill:#e38c19;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path24099"
|
||||
sodipodi:cx="231.91481"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:ry="3.7148824"
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z" />
|
||||
<path
|
||||
transform="translate(-64.0444,105.8305)"
|
||||
sodipodi:type="arc"
|
||||
style="fill:#88dfdb;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path24101"
|
||||
sodipodi:cx="231.91481"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:ry="3.7148824"
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24103"
|
||||
style="fill:#79c71a;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="translate(-76.04438,123.8305)" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24105"
|
||||
style="fill:#f5e1a2;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="translate(-88.04433,105.8305)" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24107"
|
||||
style="fill:#d8643e;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="matrix(-1,0,0,1,460.1983,124.4007)" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24109"
|
||||
style="fill:#d8643e;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="matrix(-1,0,0,1,442.9488,124.4007)" />
|
||||
<path
|
||||
transform="matrix(-1,0,0,1,426.1983,124.4007)"
|
||||
sodipodi:type="arc"
|
||||
style="fill:#d8643e;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path24111"
|
||||
sodipodi:cx="231.91481"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:ry="3.7148824"
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 146.68046,40.305464 L 153.06062,49.875694"
|
||||
id="path24113"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 146.68046,31.875694 L 153.06062,22.305464"
|
||||
id="path24115"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;marker-end:none;stroke-opacity:1"
|
||||
d="M 158.68046,22.305464 L 165.06062,31.875694"
|
||||
id="path24117"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 224.06859,54.660809 L 215.24887,54.660809"
|
||||
id="path24119"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 206.81911,54.660809 L 198.49837,54.660809"
|
||||
id="path24121"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 140.5923,40.305464 L 133.14878,49.875694"
|
||||
id="path24123"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 198.08195,67.740894 L 198.08195,67.740894"
|
||||
id="path24125"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24127"
|
||||
style="fill:#d8643e;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="matrix(-1,0,0,1,410.1983,124.4007)" />
|
||||
<path
|
||||
inkscape:connector-type="polyline"
|
||||
id="path24129"
|
||||
d="M 190.81911,54.660809 L 182.49837,54.660809"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 170.23387,40.305398 L 175.92003,50.445833"
|
||||
id="path24131"
|
||||
inkscape:connector-type="polyline" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:57.24448395px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ff8900;fill-opacity:1;stroke:#ffc900;stroke-width:2.58558559px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.95530725;font-family:Bitstream Vera Sans Mono"
|
||||
x="13.482153"
|
||||
y="61.413116"
|
||||
id="text24133"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan24135"
|
||||
x="13.482153"
|
||||
y="61.413116"
|
||||
style="font-size:57.24448395px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ff8900;fill-opacity:1;stroke:#ffc900;stroke-opacity:0.95530725;font-family:Bitstream Vera Sans Mono">tpl</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:33.35416794px;font-style:normal;font-weight:normal;fill:#ff8900;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
||||
x="313.95825"
|
||||
y="31.16275"
|
||||
id="text24140"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan24142"
|
||||
x="313.95825"
|
||||
y="31.16275"
|
||||
style="stroke:none;stroke-opacity:1">easily store and retrieve </tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="313.95825"
|
||||
y="72.85546"
|
||||
style="font-weight:bold;stroke:none;stroke-opacity:1"
|
||||
id="tspan1941">binary data in C</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="313.95825"
|
||||
y="114.54817"
|
||||
style="stroke:none;stroke-opacity:1"
|
||||
id="tspan1939" /></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 409 B |
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="744.09448819"
|
||||
height="1052.3622047"
|
||||
id="svg2"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.43"
|
||||
sodipodi:docbase="/home/thanson/code/tpl/doc/html/img"
|
||||
sodipodi:docname="grad_cyan.svg">
|
||||
<defs
|
||||
id="defs4">
|
||||
<linearGradient
|
||||
id="linearGradient2194">
|
||||
<stop
|
||||
style="stop-color:#1190ed;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop2196" />
|
||||
<stop
|
||||
style="stop-color:#f9f9f9;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop2198" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient2184">
|
||||
<stop
|
||||
style="stop-color:#0000e0;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop2186" />
|
||||
<stop
|
||||
style="stop-color:#0000e0;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop2188" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2184"
|
||||
id="linearGradient2190"
|
||||
x1="76.642857"
|
||||
y1="679.50504"
|
||||
x2="523.35714"
|
||||
y2="679.50504"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2194"
|
||||
id="linearGradient2200"
|
||||
x1="335.5"
|
||||
y1="654.61218"
|
||||
x2="506"
|
||||
y2="654.61218"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="2"
|
||||
inkscape:cx="488.2215"
|
||||
inkscape:cy="372.85714"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:window-width="797"
|
||||
inkscape:window-height="575"
|
||||
inkscape:window-x="112"
|
||||
inkscape:window-y="25" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<rect
|
||||
style="opacity:0.96629214;fill:url(#linearGradient2200);fill-opacity:1.0;stroke:none;stroke-width:4.68499994;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect2192"
|
||||
width="170.5"
|
||||
height="9.5"
|
||||
x="335.5"
|
||||
y="649.86218"
|
||||
inkscape:export-filename="/home/thanson/code/tpl/doc/html/img/grad_cyan.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 689 B |
|
After Width: | Height: | Size: 3.1 KiB |
@@ -0,0 +1,242 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="105.05521"
|
||||
height="34.90324"
|
||||
id="svg2267"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.44"
|
||||
version="1.0"
|
||||
sodipodi:docbase="/home/thanson/code/uthash/trunk/doc/html/img"
|
||||
sodipodi:docname="tpl-mini.svg">
|
||||
<defs
|
||||
id="defs3" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="63.027613"
|
||||
inkscape:cy="11.686998"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
width="118.44px"
|
||||
height="22.66px"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:window-width="916"
|
||||
inkscape:window-height="626"
|
||||
inkscape:window-x="15"
|
||||
inkscape:window-y="95">
|
||||
<sodipodi:guide
|
||||
orientation="horizontal"
|
||||
position="28.768574"
|
||||
id="guide2299" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2271">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-69.67658,-43.42744)">
|
||||
<rect
|
||||
style="fill:#3c85e2;fill-opacity:1;fill-rule:nonzero;stroke:#ffcb53;stroke-width:1.73912036;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect20271"
|
||||
width="103.31609"
|
||||
height="33.16412"
|
||||
x="70.546143"
|
||||
y="44.296997"
|
||||
rx="12.739729" />
|
||||
<rect
|
||||
y="62.533398"
|
||||
x="-170.73035"
|
||||
height="7.3075895"
|
||||
width="7.3075895"
|
||||
id="rect24091"
|
||||
style="fill:#2fa4db;fill-opacity:1;stroke:black;stroke-width:0.43030569;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
transform="scale(-1,1)" />
|
||||
<rect
|
||||
y="62.533398"
|
||||
x="-163.36638"
|
||||
height="7.3075895"
|
||||
width="7.3075895"
|
||||
id="rect24093"
|
||||
style="fill:#2fa4db;fill-opacity:1;stroke:black;stroke-width:0.43030569;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
transform="scale(-1,1)" />
|
||||
<rect
|
||||
style="fill:#2fa4db;fill-opacity:1;stroke:black;stroke-width:0.43030569;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect24095"
|
||||
width="7.3075895"
|
||||
height="7.3075895"
|
||||
x="-156.09996"
|
||||
y="62.533398"
|
||||
transform="scale(-1,1)" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#e33019;fill-opacity:1;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path24097"
|
||||
sodipodi:cx="231.91481"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:ry="3.7148824"
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
transform="matrix(0.430306,0,0,0.430306,24.87099,96.01799)" />
|
||||
<path
|
||||
transform="matrix(0.430306,0,0,0.430306,36.05889,80.52698)"
|
||||
sodipodi:type="arc"
|
||||
style="fill:#e38c19;fill-opacity:1;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path24099"
|
||||
sodipodi:cx="231.91481"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:ry="3.7148824"
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z" />
|
||||
<path
|
||||
transform="matrix(0.430306,0,0,0.430306,41.22256,88.27247)"
|
||||
sodipodi:type="arc"
|
||||
style="fill:#88dfdb;fill-opacity:1;fill-rule:nonzero;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path24101"
|
||||
sodipodi:cx="231.91481"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:ry="3.7148824"
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24103"
|
||||
style="fill:#79c71a;fill-opacity:1;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="matrix(0.430306,0,0,0.430306,36.05889,96.01799)" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24105"
|
||||
style="fill:#f5e1a2;fill-opacity:1;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="matrix(0.430306,0,0,0.430306,30.89524,88.27247)" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24107"
|
||||
style="fill:#d8643e;fill-opacity:1;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="matrix(-0.430306,0,0,0.430306,266.8073,96.26334)" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24109"
|
||||
style="fill:#d8643e;fill-opacity:1;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="matrix(-0.430306,0,0,0.430306,259.3847,96.26334)" />
|
||||
<path
|
||||
transform="matrix(-0.430306,0,0,0.430306,252.1769,96.26334)"
|
||||
sodipodi:type="arc"
|
||||
style="fill:#d8643e;fill-opacity:1;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path24111"
|
||||
sodipodi:cx="231.91481"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:ry="3.7148824"
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:0.43030569px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 131.89866,60.076683 L 134.64408,64.194808"
|
||||
id="path24113"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:0.43030569px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 131.89866,56.449305 L 134.64408,52.33118"
|
||||
id="path24115"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:0.43030569px;stroke-linecap:square;stroke-linejoin:miter;marker-end:none;stroke-opacity:1"
|
||||
d="M 137.06234,52.33118 L 139.80775,56.449305"
|
||||
id="path24117"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:0.43030569px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 165.19922,66.25387 L 161.40404,66.25387"
|
||||
id="path24119"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:0.43030569px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 157.77667,66.25387 L 154.19622,66.25387"
|
||||
id="path24121"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:0.43030569px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 129.2789,60.076683 L 126.07591,64.194808"
|
||||
id="path24123"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:0.43030569px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 154.01702,71.882304 L 154.01702,71.882304"
|
||||
id="path24125"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24127"
|
||||
style="fill:#d8643e;fill-opacity:1;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="matrix(-0.430306,0,0,0.430306,245.292,96.26334)" />
|
||||
<path
|
||||
inkscape:connector-type="polyline"
|
||||
id="path24129"
|
||||
d="M 150.89178,66.25387 L 147.31131,66.25387"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:0.43030569px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:0.43030569px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 142.03383,60.076654 L 144.48062,64.440141"
|
||||
id="path24131"
|
||||
inkscape:connector-type="polyline" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:24.63262939px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ff8900;fill-opacity:1;stroke:#ffc900;stroke-width:1.11259222px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.95530725;font-family:Bitstream Vera Sans Mono"
|
||||
x="74.58268"
|
||||
y="69.159424"
|
||||
id="text24133"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan24135"
|
||||
x="74.58268"
|
||||
y="69.159424"
|
||||
style="font-size:24.63262939px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ff8900;fill-opacity:1;stroke:#ffc900;stroke-width:1.11259222;stroke-opacity:0.95530725;font-family:Bitstream Vera Sans Mono">tpl</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,162 @@
|
||||
<!DOCTYPE html
|
||||
PUBLIC "-//W3C//DTD XTHML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="styles.css" />
|
||||
<title>tpl home page</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="banner">
|
||||
<img src="img/banner.png" alt="easy data storage and retrieval in C" />
|
||||
</div> <!-- banner -->
|
||||
|
||||
<div id="topnav">
|
||||
<a href="http://sourceforge.net/projects/tpl/">sf.net summary page</a> >
|
||||
tpl home
|
||||
</div> <!-- topnav -->
|
||||
|
||||
<hr />
|
||||
<div id="mid">
|
||||
|
||||
<div id="nav">
|
||||
|
||||
|
||||
<h2>documentation</h2>
|
||||
<div><a href="userguide.html">user guide</a> (<a href="userguide.html">html</a>, <a href="userguide.pdf">pdf</a>)</div>
|
||||
|
||||
<h2>download</h2>
|
||||
<h3>Linux, Mac OSX, Solaris, BSD</h3>
|
||||
<div><a href="http://downloads.sourceforge.net/tpl/libtpl-1.5.tar.bz2">libtpl-1.5.tar.bz2</a></div>
|
||||
<h3>Visual Studio 2008 Solution</h3>
|
||||
<div><a href="http://downloads.sourceforge.net/tpl/tpl-1.5-vs2008.zip">tpl-1.5-vs2008.zip</a></div>
|
||||
|
||||
<h2>last release</h2>
|
||||
<div>February, 2010</div>
|
||||
<div><a href="ChangeLog.html">ChangeLog</a></div>
|
||||
|
||||
<h2>license</h2>
|
||||
<div><a href="license.html">BSD revised</a></div>
|
||||
|
||||
<h2>news feed</h2>
|
||||
<div><a href="http://troydhanson.wordpress.com/">updates blog</a> (<a href="http://troydhanson.wordpress.com/feed/">rss</a>)<img alt=" rss" src="img/rss.png"/></div>
|
||||
|
||||
<h2>platforms</h2>
|
||||
<div>linux</div>
|
||||
<div>os x</div>
|
||||
<div>windows</div>
|
||||
<div>solaris</div>
|
||||
<div>openbsd</div>
|
||||
|
||||
<h2>other projects</h2>
|
||||
<div><a href="http://uthash.sourceforge.net/">uthash</a></div>
|
||||
<div><a href="http://tkhanson.net/misc/">scripts & snippets</a></div>
|
||||
|
||||
<h2>developer</h2>
|
||||
<div>Troy D. Hanson</div>
|
||||
<div>tdh at tkhanson.net</div>
|
||||
|
||||
</div> <!-- nav -->
|
||||
|
||||
<div id="main">
|
||||
|
||||
<div>
|
||||
<div class="lead">Efficient serialization in C</div>
|
||||
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.
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="lead">Express your data</div>
|
||||
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 <em>A(is)</em>. 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.
|
||||
</div>
|
||||
|
||||
<div class="listing">
|
||||
<table summary="example of storing and reloading an integer array">
|
||||
<tr>
|
||||
<th>
|
||||
Storing ids and usernames
|
||||
</th>
|
||||
<th>
|
||||
Reloading ids and usernames
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="code">
|
||||
<pre>
|
||||
#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);
|
||||
}
|
||||
</pre>
|
||||
</div> <!-- code -->
|
||||
</td>
|
||||
<td>
|
||||
<div class="code">
|
||||
<pre>
|
||||
#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);
|
||||
}
|
||||
</pre>
|
||||
</div> <!-- code -->
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div> <!-- listing -->
|
||||
|
||||
<div>
|
||||
<div class="lead">No library dependencies</div>
|
||||
Tpl does not make your software dependent on any libraries. You can compile its
|
||||
source code (one file) right into your program.
|
||||
</div>
|
||||
|
||||
<div class="lead">For more information</div>
|
||||
For a more thorough explanation and more examples, please read the
|
||||
<a href="userguide.html">User Guide.</a>
|
||||
|
||||
</div> <!-- main -->
|
||||
</div> <!-- mid -->
|
||||
|
||||
<hr />
|
||||
<div id="footer">
|
||||
<a href="http://sourceforge.net/projects/tpl"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=157637&type=13" width="120" height="30" alt="SourceForge.net." /></a>
|
||||
<p>This project is hosted on SourceForge.net</p>
|
||||
<p>$Id: index.html 192 2009-04-24 10:35:30Z thanson $</p>
|
||||
</div> <!-- footer -->
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,61 @@
|
||||
<!DOCTYPE html
|
||||
PUBLIC "-//W3C//DTD XTHML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="styles.css" />
|
||||
<title>tpl home page</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="banner">
|
||||
<img src="img/banner.png" alt="serialization in C: easy data storage and retrieval" />
|
||||
</div> <!-- banner -->
|
||||
|
||||
<div id="topnav">
|
||||
<a href="http://sourceforge.net/projects/tpl/">sf.net summary page</a> >
|
||||
<a href="index.html">tpl home</a> >
|
||||
BSD license
|
||||
</div> <!-- topnav -->
|
||||
|
||||
<hr />
|
||||
<div id="mid">
|
||||
|
||||
|
||||
<div id="main">
|
||||
|
||||
<pre>
|
||||
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.
|
||||
</pre>
|
||||
</div> <!-- main -->
|
||||
</div> <!-- mid -->
|
||||
|
||||
<hr />
|
||||
<div id="footer">
|
||||
<a href="http://sourceforge.net/projects/tpl"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=157637&type=13" width="120" height="30" alt="SourceForge.net." /></a>
|
||||
<p>This project is hosted on SourceForge.net</p>
|
||||
<p>$Id: index.html 124 2007-04-27 06:41:36Z thanson $</p>
|
||||
</div> <!-- footer -->
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,403 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="generator" content="AsciiDoc 8.3.4" />
|
||||
<title>tpl Perl API</title>
|
||||
<link rel="stylesheet" href="./tdh.css" type="text/css" />
|
||||
<link rel="stylesheet" href="./tdh-quirks.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">
|
||||
<h1>tpl Perl API</h1>
|
||||
<span id="author">Troy D. Hanson</span><br />
|
||||
<span id="email"><tt><<a href="mailto:troydhanson@comcast.net">troydhanson@comcast.net</a>></tt></span><br />
|
||||
<span id="revision">version 1.1,</span>
|
||||
April 2007
|
||||
</div>
|
||||
<div id="preamble">
|
||||
<div class="sectionbody">
|
||||
<a style="float: right;" href="http://sourceforge.net/projects/tpl"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=157637&type=16" width="150" height="40" alt="SourceForge.net" /></a>
|
||||
<div id="topnav" style="font-size: 9pt; font-family: sans-serif;">
|
||||
<a style="padding: 8px;" href="http://sourceforge.net/projects/tpl/">sf.net summary page</a> >
|
||||
<a style="padding: 8px;" href="index.html">tpl home</a> >
|
||||
tpl Perl API
|
||||
<a style="padding: 8px;" href="userguide.pdf">[View PDF]</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2 id="_perl_api">Perl API</h2>
|
||||
<div class="sectionbody">
|
||||
<div id="toc"></div>
|
||||
<script>
|
||||
window.onload=generate_TOC
|
||||
|
||||
/* Author: Mihai Bazon, September 2002
|
||||
* <a href="http://students.infoiasi.ro/~mishoo">http://students.infoiasi.ro/~mishoo</a>
|
||||
*
|
||||
* Table Of Content generator
|
||||
* Version: 0.4
|
||||
*
|
||||
* Feel free to use this script under the terms of the GNU General Public
|
||||
* License, as long as you do not remove or alter this notice.
|
||||
*/
|
||||
|
||||
/* modified by Troy D. Hanson, September 2006. License: GPL */
|
||||
|
||||
function H_getText(el) {
|
||||
var text = "";
|
||||
for (var i = el.firstChild; i != null; i = i.nextSibling) {
|
||||
if (i.nodeType == 3 /* Node.TEXT_NODE, IE doesn't speak constants */)
|
||||
text += i.data;
|
||||
else if (i.firstChild != null)
|
||||
text += H_getText(i);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
function TOC_EL(el, text, level) {
|
||||
this.element = el;
|
||||
this.text = text;
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
function getHeadlines(el) {
|
||||
var l = new Array;
|
||||
var rx = /[hH]([2-3])/;
|
||||
// internal recursive function that scans the DOM tree
|
||||
var rec = function (el) {
|
||||
for (var i = el.firstChild; i != null; i = i.nextSibling) {
|
||||
if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
|
||||
if (rx.exec(i.tagName))
|
||||
l[l.length] = new TOC_EL(i, H_getText(i), parseInt(RegExp.$1));
|
||||
rec(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
rec(el);
|
||||
return l;
|
||||
}
|
||||
|
||||
function generate_TOC() {
|
||||
var parent = document.getElementById("toc");
|
||||
var toc_hdr = document.createElement("div");
|
||||
var toc_hdr_txt = document.createTextNode("CONTENTS");
|
||||
toc_hdr.appendChild(toc_hdr_txt);
|
||||
/* toc_hdr.setAttribute("id","hdr"); */
|
||||
toc_hdr.id = "hdr";
|
||||
parent.appendChild(toc_hdr);
|
||||
var hs = getHeadlines(document.getElementsByTagName("body")[0]);
|
||||
for (var i = 0; i < hs.length; ++i) {
|
||||
var hi = hs[i];
|
||||
var d = document.createElement("div");
|
||||
if (hi.element.id == "") hi.element.id = "gen" + i;
|
||||
var a = document.createElement("a");
|
||||
a.href = "#" + hi.element.id;
|
||||
a.appendChild(document.createTextNode(hi.text));
|
||||
d.appendChild(a);
|
||||
d.className = "level" + hi.level;
|
||||
parent.appendChild(d);
|
||||
/*
|
||||
if (hi.level == 3) {
|
||||
var dvtop = document.createElement("div");
|
||||
dvtop.className = "toplink";
|
||||
dvtop.appendChild(document.createTextNode("^top^"));
|
||||
dvtop.onclick=function(){scrollTo(0,0);};
|
||||
hi.element.appendChild(dvtop);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<div class="paragraph"><p>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.</p></div>
|
||||
<div class="admonitionblock">
|
||||
<table><tr>
|
||||
<td class="icon">
|
||||
<div class="title">Tip</div>
|
||||
</td>
|
||||
<td class="content">
|
||||
<div class="title">Start with the C API</div>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
|
||||
<a href="userguide.html">User Guide</a>.</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
<h3 id="_tpl_pm">Tpl.pm</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>The <tt>Tpl.pm</tt> file (in the <tt>lang/perl</tt>) directory contains the Perl module. You
|
||||
can copy it to another directory if you wish. Your Perl program may need to
|
||||
include a <tt>use lib</tt> statement to find the module.</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>#!/usr/bin/perl
|
||||
use lib "/some/directory";
|
||||
use Tpl;</tt></pre>
|
||||
</div></div>
|
||||
<h3 id="_tpl_map">tpl_map</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>This function resembles the C version, except that it’s invoked via the <tt>Tpl</tt>
|
||||
module, and it takes references to Perl variables after the format string.</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>my $i;
|
||||
my $tpl = Tpl->tpl_map("A(i)",\$i);</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>The return value is a tpl object; all other API calls are object methods.
|
||||
Incidentally, there is no <tt>tpl_free()</tt> method corresponding to the C API.</p></div>
|
||||
<h4 id="_fixed_length_arrays">Fixed-length arrays</h4>
|
||||
<div class="paragraph"><p>Format strings such as <tt>i#</tt> denote a fixed-length array. In the Perl API,
|
||||
fixed-length arrays require two arguments: a list reference, and the fixed
|
||||
length. For example:</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>my @x;
|
||||
my $tpl = Tpl->tpl_map("i#", \@x, 10);</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>When fixed-length arrays are packed or unpacked, the specified number of
|
||||
elements will be copied from (or placed into) the designated list.</p></div>
|
||||
<h4 id="_structures">Structures</h4>
|
||||
<div class="paragraph"><p>Format strings containing <tt>S(…)</tt> 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 <tt>S(…)</tt> and consider only its interior format characters when
|
||||
constructing the argument list:</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>my ($str, $int);
|
||||
my $tpl = Tpl->tpl_map("S(si)", \$str, \$int);</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>It really only makes sense to use <tt>S(…)</tt> in a format string in the Perl API if
|
||||
you are communicating with a C program that uses structures.</p></div>
|
||||
<h3 id="_tpl_pack">tpl_pack</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>This is nearly identical to the C version. The only argument is the index
|
||||
number to pack.</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>$tpl->tpl_pack(1);</tt></pre>
|
||||
</div></div>
|
||||
<h3 id="_tpl_dump">tpl_dump</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>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.</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>$tpl->tpl_dump("demo.tpl"); # writes demo.tpl</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>Or,</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>my $img = $tpl->tpl_dump();</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>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 <tt>tpl_load()</tt>.</p></div>
|
||||
<h3 id="_tpl_load">tpl_load</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>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.</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>$tpl->tpl_load("demo.tpl");</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>Otherwise, if the argument is a Perl reference, it’s construed as a variable
|
||||
containing the tpl image:</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>$tpl->tpl_load(\$img);</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>The method will <tt>die</tt> if the image is invalid or the file doesn’t exist. You
|
||||
can wrap it with <tt>eval</tt> to catch such errors:</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>eval { $tpl->tpl_load(\$img); };
|
||||
print "failed to load\n" if $@;</tt></pre>
|
||||
</div></div>
|
||||
<h3 id="_tpl_unpack">tpl_unpack</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>This is nearly identical to the C version. The only argument is the index
|
||||
number to unpack.</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>$tpl->tpl_unpack(1);</tt></pre>
|
||||
</div></div>
|
||||
</div>
|
||||
<h2 id="_examples">Examples</h2>
|
||||
<div class="sectionbody">
|
||||
<h3 id="_integer_array">Integer array</h3><div style="clear:left"></div>
|
||||
<div class="listingblock">
|
||||
<div class="title">Packing A(i) to file</div>
|
||||
<div class="content">
|
||||
<pre><tt>#!/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");</tt></pre>
|
||||
</div></div>
|
||||
<div class="listingblock">
|
||||
<div class="title">Unpacking A(i) from file</div>
|
||||
<div class="content">
|
||||
<pre><tt>#!/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";
|
||||
}</tt></pre>
|
||||
</div></div>
|
||||
<h3 id="_message_passing">Message-passing</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>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.</p></div>
|
||||
<div class="sidebarblock">
|
||||
<div class="sidebar-content">
|
||||
<div class="sidebar-title">A server that sums integers</div>
|
||||
<div class="paragraph"><p>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.</p></div>
|
||||
</div></div>
|
||||
<h4 id="_server">Server</h4>
|
||||
<div class="paragraph"><p>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.</p></div>
|
||||
<div class="paragraph"><p>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.</p></div>
|
||||
<div class="listingblock">
|
||||
<div class="title">Server</div>
|
||||
<div class="content">
|
||||
<pre><tt>#!/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);</tt></pre>
|
||||
</div></div>
|
||||
<h4 id="_client">Client</h4>
|
||||
<div class="paragraph"><p>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.</p></div>
|
||||
<div class="listingblock">
|
||||
<div class="title">Client</div>
|
||||
<div class="content">
|
||||
<pre><tt>#!/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";</tt></pre>
|
||||
</div></div>
|
||||
<h4 id="_running_thise_example">Running thise example</h4>
|
||||
<div class="paragraph"><p>If the client and server programs are in <tt>client.pl</tt> and <tt>server.pl</tt>, then
|
||||
you can run the example by starting the server in one window:</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>./server.pl</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>Then run the client in another window. E.g.,</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>./client.pl 1 2 3 4 5</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>The client runs and then exits, printing:</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>total is 15</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>You can re-run the client with different arguments. When done, type <tt>Ctrl-C</tt> in
|
||||
the server window to terminate it.</p></div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Version 1.1<br />
|
||||
Last updated 2009-04-30 21:22:12 EDT
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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; }
|
||||
@@ -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}
|
||||
@@ -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}
|
||||
@@ -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:
|
||||
|
||||
@@ -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`.
|
||||
@@ -0,0 +1,297 @@
|
||||
tpl examples
|
||||
============
|
||||
Troy D. Hanson <troydhanson@comcast.net>>
|
||||
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 <stdio.h>
|
||||
#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 <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);
|
||||
}
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
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 <stdio.h>
|
||||
#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 <stdio.h>
|
||||
#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 <sys/time.h>
|
||||
|
||||
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`.
|
||||
@@ -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]}
|
||||
@@ -0,0 +1,302 @@
|
||||
tpl Perl API
|
||||
============
|
||||
Troy D. Hanson <troydhanson@comcast.net>
|
||||
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:
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
ifdef::backend-xhtml11[]
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
<a style="float: right;" href="http://sourceforge.net/projects/tpl"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=157637&type=16" width="150" height="40" alt="SourceForge.net" /></a>
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
endif::backend-xhtml11[]
|
||||
@@ -0,0 +1,85 @@
|
||||
ifdef::backend-xhtml11[]
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
<div id="toc"></div>
|
||||
<script>
|
||||
window.onload=generate_TOC
|
||||
|
||||
/* Author: Mihai Bazon, September 2002
|
||||
* http://students.infoiasi.ro/~mishoo
|
||||
*
|
||||
* Table Of Content generator
|
||||
* Version: 0.4
|
||||
*
|
||||
* Feel free to use this script under the terms of the GNU General Public
|
||||
* License, as long as you do not remove or alter this notice.
|
||||
*/
|
||||
|
||||
/* modified by Troy D. Hanson, September 2006. License: GPL */
|
||||
|
||||
function H_getText(el) {
|
||||
var text = "";
|
||||
for (var i = el.firstChild; i != null; i = i.nextSibling) {
|
||||
if (i.nodeType == 3 /* Node.TEXT_NODE, IE doesn't speak constants */)
|
||||
text += i.data;
|
||||
else if (i.firstChild != null)
|
||||
text += H_getText(i);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
function TOC_EL(el, text, level) {
|
||||
this.element = el;
|
||||
this.text = text;
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
function getHeadlines(el) {
|
||||
var l = new Array;
|
||||
var rx = /[hH]([2-3])/;
|
||||
// internal recursive function that scans the DOM tree
|
||||
var rec = function (el) {
|
||||
for (var i = el.firstChild; i != null; i = i.nextSibling) {
|
||||
if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
|
||||
if (rx.exec(i.tagName))
|
||||
l[l.length] = new TOC_EL(i, H_getText(i), parseInt(RegExp.$1));
|
||||
rec(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
rec(el);
|
||||
return l;
|
||||
}
|
||||
|
||||
function generate_TOC() {
|
||||
var parent = document.getElementById("toc");
|
||||
var toc_hdr = document.createElement("div");
|
||||
var toc_hdr_txt = document.createTextNode("CONTENTS");
|
||||
toc_hdr.appendChild(toc_hdr_txt);
|
||||
/* toc_hdr.setAttribute("id","hdr"); */
|
||||
toc_hdr.id = "hdr";
|
||||
parent.appendChild(toc_hdr);
|
||||
var hs = getHeadlines(document.getElementsByTagName("body")[0]);
|
||||
for (var i = 0; i < hs.length; ++i) {
|
||||
var hi = hs[i];
|
||||
var d = document.createElement("div");
|
||||
if (hi.element.id == "") hi.element.id = "gen" + i;
|
||||
var a = document.createElement("a");
|
||||
a.href = "#" + hi.element.id;
|
||||
a.appendChild(document.createTextNode(hi.text));
|
||||
d.appendChild(a);
|
||||
d.className = "level" + hi.level;
|
||||
parent.appendChild(d);
|
||||
/*
|
||||
if (hi.level == 3) {
|
||||
var dvtop = document.createElement("div");
|
||||
dvtop.className = "toplink";
|
||||
dvtop.appendChild(document.createTextNode("^top^"));
|
||||
dvtop.onclick=function(){scrollTo(0,0);};
|
||||
hi.element.appendChild(dvtop);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
</script>
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
endif::backend-xhtml11[]
|
||||
@@ -0,0 +1,10 @@
|
||||
ifdef::backend-xhtml11[]
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
<div id="topnav" style="font-size: 9pt; font-family: sans-serif;">
|
||||
<a style="padding: 8px;" href="http://sourceforge.net/projects/tpl/">sf.net summary page</a> >
|
||||
<a style="padding: 8px;" href="index.html">tpl home</a> >
|
||||
{doctitle}
|
||||
<a style="padding: 8px;" href="userguide.pdf">[View PDF]</a>
|
||||
</div>
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
endif::backend-xhtml11[]
|
||||
@@ -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 = <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 = <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<n>
|
||||
# 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<n>
|
||||
# advances through the tpl image.
|
||||
#
|
||||
# Similarly, elements
|
||||
# N1
|
||||
# N2
|
||||
# ...
|
||||
# N<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
|
||||
@@ -0,0 +1,9 @@
|
||||
all: run_tests
|
||||
|
||||
run_tests:
|
||||
perl ./do_tests
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
clean:
|
||||
rm -f test*.out
|
||||
@@ -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)
|
||||
@@ -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";
|
||||
@@ -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";
|
||||
@@ -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);
|
||||
@@ -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" }
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
@@ -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;
|
||||
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE tplxml [
|
||||
<!ELEMENT tplxml (A|i|u|I|U|B|s|c|f|fx)*>
|
||||
<!ATTLIST tplxml
|
||||
format CDATA #REQUIRED
|
||||
fxlens CDATA #REQUIRED
|
||||
>
|
||||
<!ELEMENT i (#PCDATA)>
|
||||
<!ELEMENT u (#PCDATA)>
|
||||
<!ELEMENT I (#PCDATA)>
|
||||
<!ELEMENT U (#PCDATA)>
|
||||
<!ELEMENT B (#PCDATA)>
|
||||
<!ELEMENT s (#PCDATA)>
|
||||
<!ELEMENT c (#PCDATA)>
|
||||
<!ELEMENT f (#PCDATA)>
|
||||
<!ELEMENT A (el)*>
|
||||
<!ELEMENT el (A|i|u|I|U|B|s|c|f|fx)+>
|
||||
<!ELEMENT fx (i|u|I|U|c|f)*>
|
||||
]>
|
||||
<tplxml format="A(u)" fxlens="">
|
||||
<A>
|
||||
<el>
|
||||
<u>0</u>
|
||||
</el>
|
||||
<el>
|
||||
<u>1</u>
|
||||
</el>
|
||||
<el>
|
||||
<u>2</u>
|
||||
</el>
|
||||
<el>
|
||||
<u>3</u>
|
||||
</el>
|
||||
<el>
|
||||
<u>4</u>
|
||||
</el>
|
||||
<el>
|
||||
<u>5</u>
|
||||
</el>
|
||||
<el>
|
||||
<u>6</u>
|
||||
</el>
|
||||
<el>
|
||||
<u>7</u>
|
||||
</el>
|
||||
<el>
|
||||
<u>8</u>
|
||||
</el>
|
||||
<el>
|
||||
<u>9</u>
|
||||
</el>
|
||||
</A>
|
||||
</tplxml>
|
||||
@@ -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";
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -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
|
||||