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
This commit is contained in:
Ken Rice
2012-09-20 15:58:04 -04:00
776 changed files with 32280 additions and 1976 deletions
+14
View File
@@ -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}
+20
View File
@@ -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}
+3
View File
@@ -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 \
+8 -5
View File
@@ -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
+18 -12
View File
@@ -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>
+18 -12
View File
@@ -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>
+18 -17
View File
@@ -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 -3
View File
@@ -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, [])
+158 -124
View File
@@ -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;}
+56 -54
View File
@@ -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())
+2
View File
@@ -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
+1 -1
View File
@@ -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
+43
View File
@@ -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
+1
View File
@@ -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
File diff suppressed because it is too large Load Diff
+712
View File
@@ -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;
}
+594 -81
View File
@@ -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;
+25 -2
View File
@@ -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;
}
File diff suppressed because it is too large Load Diff
@@ -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:
File diff suppressed because it is too large Load Diff
@@ -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;
}
/******************************************************************************/
File diff suppressed because it is too large Load Diff
@@ -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:
File diff suppressed because it is too large Load Diff
@@ -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;
+46 -5
View File
@@ -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"
+21
View File
@@ -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.
+2
View File
@@ -0,0 +1,2 @@
SUBDIRS = src
EXTRA_DIST = LICENSE tests lang doc
+635
View File
@@ -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:
+56
View File
@@ -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
+11
View File
@@ -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
+28
View File
@@ -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
+26
View File
@@ -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
+11
View File
@@ -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
+602
View File
@@ -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>
Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

+429
View File
@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 B

+105
View File
@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 689 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

+242
View File
@@ -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

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.
+162
View File
@@ -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> &gt;
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)", &amp;id, &amp;name);
for(name=names[0]; id &lt; 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)", &amp;id, &amp;name);
tpl_load(tn, TPL_FILE, "users.tpl");
while ( tpl_unpack(tn,1) &gt; 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&amp;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>
+61
View File
@@ -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> &gt;
<a href="index.html">tpl home</a> &gt;
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&amp;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>
+403
View File
@@ -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>&lt;<a href="mailto:troydhanson@comcast.net">troydhanson@comcast.net</a>&gt;</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&amp;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> &gt;
<a style="padding: 8px;" href="index.html">tpl home</a> &gt;
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&#8217;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-&gt;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-&gt;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(&#8230;)</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(&#8230;)</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-&gt;tpl_map("S(si)", \$str, \$int);</tt></pre>
</div></div>
<div class="paragraph"><p>It really only makes sense to use <tt>S(&#8230;)</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-&gt;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-&gt;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-&gt;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&#8217;s not a reference, it&#8217;s assumed to be a filename to load.</p></div>
<div class="literalblock">
<div class="content">
<pre><tt>$tpl-&gt;tpl_load("demo.tpl");</tt></pre>
</div></div>
<div class="paragraph"><p>Otherwise, if the argument is a Perl reference, it&#8217;s construed as a variable
containing the tpl image:</p></div>
<div class="literalblock">
<div class="content">
<pre><tt>$tpl-&gt;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&#8217;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-&gt;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-&gt;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-&gt;tpl_map("A(i)",\$i);
for($i=0; $i&lt;10; $i++) {
$tpl-&gt;tpl_pack(1);
}
$tpl-&gt;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-&gt;tpl_map("A(i)",\$j);
$tpl2-&gt;tpl_load("demo.tpl");
while($tpl2-&gt;tpl_unpack(1) &gt; 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&#8217;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 = &lt;$client&gt;; # get request (slurp)
# read input array, and calculate total
my ($i,$total);
my $tpl = Tpl-&gt;tpl_map("A(i)", \$i);
eval { $tpl-&gt;tpl_load(\$request); };
die "received invalid tpl" if $@;
$total += $i while $tpl-&gt;tpl_unpack(1) &gt; 0;
# formulate response and send
my $tpl2 = Tpl-&gt;tpl_map("i", \$total);
$tpl2-&gt;tpl_pack(0);
my $response = $tpl2-&gt;tpl_dump();
print $client $response;
close $client;
}
my $server = IO::Socket::INET-&gt;new(LocalPort =&gt; $port,
Type =&gt; SOCK_STREAM,
Reuse =&gt; 1,
Listen =&gt; 10 )
or die "Can't listen on port $port: $!\n";
while (1) {
my $client = $server-&gt;accept();
next unless $client;
# new connection
my $pid = fork;
die "can't fork: $!\n" unless defined $pid;
if ($pid &gt; 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-&gt;tpl_map("A(i)",\$i);
$tpl-&gt;tpl_pack(1) while ($i=shift @ARGV);
my $request = $tpl-&gt;tpl_dump();
# send to server, get response
my $socket = IO::Socket::INET-&gt;new("localhost:$port") or die "can't connect";
print $socket $request;
shutdown($socket,1); # done writing (half-close)
undef $/;
my $response = &lt;$socket&gt;; # get reply (slurp)
# decode response (or print error)
my $total;
my $tpl2 = Tpl-&gt;tpl_map("i", \$total);
eval { $tpl2-&gt;tpl_load(\$response); };
die "invalid response\n" if $@;
$tpl2-&gt;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>
+160
View File
@@ -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;
}
+31
View File
@@ -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; }
+301
View File
@@ -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}
+35
View File
@@ -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}
File diff suppressed because it is too large Load Diff
Binary file not shown.
+59
View File
@@ -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:
+38
View File
@@ -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`.
+297
View File
@@ -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`.
+52
View File
@@ -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]}
+302
View File
@@ -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:
+5
View File
@@ -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&amp;type=16" width="150" height="40" alt="SourceForge.net" /></a>
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
endif::backend-xhtml11[]
+85
View File
@@ -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[]
+10
View File
@@ -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> &gt;
<a style="padding: 8px;" href="index.html">tpl home</a> &gt;
{doctitle}
<a style="padding: 8px;" href="userguide.pdf">[View PDF]</a>
</div>
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
endif::backend-xhtml11[]
+1264
View File
File diff suppressed because it is too large Load Diff
+475
View File
@@ -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
+9
View File
@@ -0,0 +1,9 @@
all: run_tests
run_tests:
perl ./do_tests
.PHONY: clean
clean:
rm -f test*.out
+29
View File
@@ -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)
+31
View File
@@ -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";
+20
View File
@@ -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";
+56
View File
@@ -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);
+23
View File
@@ -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" }
+10
View File
@@ -0,0 +1,10 @@
0
1
2
3
4
5
6
7
8
9
+16
View File
@@ -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;
+53
View File
@@ -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>
+24
View File
@@ -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";
+2
View File
@@ -0,0 +1,2 @@
+23
View File
@@ -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); }
+16
View File
@@ -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

Some files were not shown because too many files have changed in this diff Show More